Python 3D Graphics Tutorial 8: NonBlocking Dual Animations in Vpython

preview_player
Показать описание
You guys can help me out over at Patreon, and that will help me keep my gear updated, and help me keep this quality content coming:

In this video we show step-by-step instructions on how animate 3D designs and models in vpython, (visual python), and how to bring your models to life. In this example I will show how to animate two animations running at different rates. I show a simple way to develop nonblocking synchronized animations. I do not assume you are an expert, so these lessons are designed for complete beginners.
#Python
#Lessons
#Graphics
Рекомендации по теме
Комментарии
Автор

Paul after a long journey participating your lesson, i couldnt finish the home excersise, and i folded it like a cheap sandwich.
And i am really happy because i tried hard on finding the solution even if i didnt make it.
Now after watching you doing it, I ll go do it on my own.
Thanks Paul!

johnnyjohn
Автор

this is a version with the text label going up and down displaying the column value: lab = label(pos=vector(myTemp, 0, 0)) lab.text = "t {:.2f}" .format(myTemp) placed in both for loops... also, rotated the column objects with... axis=vector(0, 1, 0) for a vertical animation. thanks a lot, this is more fun than a game...:)

qzorn
Автор

I did this homework using threading. Managed to do it this way without any problems, however the result was not smooth and I got a jittery animation. I couldn't make out why this is so and would love to know why threading doesn't work quite well in this case. I then just peeked a little at your solution and saw some if statements and realized that you had gone to a completely different solution. I didn't want to see exactly what you did, so I started thinking of an alternative. I remembered about the bouncing ball animation and how we had an imaginary wall on the front, and figured out that now we have the same imaginary boundaries. So I arrived at the solution that you outline in this tutorial. I tried my best not to fold out like a cheap Walmart lawn chair!!!

ecassar
Автор

I went to Walmart and sat on a cheap lawn chair while watching your solution. The chair folded while I was trying to use threads for this problem. It must be frustrating for an instructor to teach with a system that fails to do things like correctly comparing values in if statements. I had jailbreaks with both cylinders, one increasing and the other decreasing. I am glad that you had the patience to take the time to show us how to get around the problems. Thanks for all your work on these lessons!

cbrombaugh
Автор

Finally managed to do the previous lessons homework using threads, up the frame rate and its working pretty well, its lagging a bit but I'm happy with it, did a bit of reading and found that Vpython is not the best for using threads, excited to see your solution !

daviddeegan
Автор

Hi Paul, I folded like a cheap lawn chair: I worked until after midnight and got the 2 thermometers working side by side but very jittery. I didn't want to cheat so I just kept trying different permutations and combinations: but to no avail. I almost got myself divorced as I got up early and got stuck back into it: my wife was not happy. Anyway, I then allowed myself to check out this tutorial and found that "I was barking up the wrong tree": I using using For Loops, Numpy and Threading and I couldn't get it to work properly. I've now reworked it from the memory of your tutorial and it works like a charm. It was a good exercise because although I spent a lot of time with Threading, it helped me understand that a lot more. Thanks again for a great tutorial.
ps: My wife is talking to me again! 😇

alfredcalleja
Автор

i did this on my own with a help of direction variable and it worked "im a legend"

RDKCREATIONS
Автор

I chose the threading method but i couldn't figure out why the motion was lagging. I tried to run them one at a time with the same code and then it worked perfectly fine. I also checked the cpu, gpu usage and none of them were bottlenecked.

darthdaenerys
Автор

At first I tried threads but it wasn't really good so I folded up like a cheap walmart lawn chair and watched until 10 minutes and then I did it alone with your method and it worked. The most difficult homework until now..

alonb
Автор

I am legend! I've used the thread library that Paul taught us!

patfacunla
Автор

It won't be a Paul McWhorter video without having coffee in one of his videos

chernoblyat
Автор

Loads of fun Mr McWorther, loads of fun. Thank you very much.

wendygrant
Автор

The method I used to generate the two thermometers was to define one thermometer in a function and then return the alcohol cylinder. Then I did use your method of rate change with each instance of the respective thermometer.
def thermometer
....
return(column)
thermOne = thermometer()
thermTwo = thermometer()
while True:
using thermOne.length and thermTwo.length in here.

kennethstephens
Автор

I was able to achieve a really good result using two seperate threads !

arnaudmasse
Автор

I did find a solution to your dual thermometer assignment using for loops that I think is more elegant than using a delta approach.

Here is the key part of the code

While True:
for myTemp in np.linspace(1, 6, 100):

rate(25)
alcColumnRed.length=myTemp
BlueTemp=myTemp*2








for myTemp in np.linspace(6, 1, 100):
rate(25)
alcColumnRed.length=myTemp
BlueTemp=myTemp*2
alcColumnBlue.length=BlueTemp

peternorris
Автор

I am Legend. I cannot believe that I did it the same as you. The hardest part was having the graphics start in the Vertical position not Horizontal.

petefontana
Автор

I created two programs. One with a while-loop, similar to the solution in this video. My other solution used two threads. I had some problem to get it working as expected. I think having rate() in each thread-loop cause timing issues.

peterkarlsson
Автор

Aprendiendo vpython en sus inicios. Thanks,

eduardovelez
Автор

I am Legend! My first thermometer was fully parametized, so it was not too difficult to add the second thermometer. However, my thermometer had a lot of pieces, so it was time consuming to rename all of the variables and made my code very long (See below: ridiculous! lol). I think in all future homeworks I will create classes for all of my graphics so that I can more easily add multiples of the same graphic. Also, because of how I have my parameters set up, I had to use two thread definitions (one for each thermometer). Creating a class for my graphics will fix this in the future.

#Paul McWhorter
#Python 3D Graphics Tutorial
#Lesson 8: HW NonBlocking Dual Animations in V Python
#by Jonathan Landers
#May 24, 2023

#Paul McWhorter
#Python 3D Graphics Tutorial
#Lesson 7: HW Vpython Model of a Thermometer
#by Jonathan Landers
#May 23, 2023

from vpython import*
import numpy as np
from threading import Thread

Thread Definition
'''
Note: I had to use a different thread definition for each thermometer.
This is because I did not create a class for the thermometer graphics, but posted them separately
(I did not know where the assignment was going.).
In the future, create graphics in a class. This way you can use one thread definition for multiple objects with similar shape (different sizes).
'''
def practiceThermo1(MERCTUBEL, RATE):
while True:
for mercL in np.linspace(0, MERCTUBEL, 6000): #Start pos, End pos, Steps in between.
rate(RATE)
mercTube.axis = vector(0, mercL, 0)
for mercL in np.linspace(MERCTUBEL, 0, 6000): #Start pos, End pos, Steps in between.
rate(RATE)
mercTube.axis = vector(0, mercL, 0)
def practiceThermo2(MERCTUBEL, RATE):
while True:
for mercL in np.linspace(0, MERCTUBEL, 2000):
rate(RATE)
bmercTube.axis = vector(0, mercL, 0)
for mercL in np.linspace(MERCTUBEL, 0, 2000):
rate(RATE)
bmercTube.axis = vector(0, mercL, 0)

Parameters: Thermometer 1
#Independent Parameters: These are the dimensions everything is alligned to.
BoardXsize = 1200
BoardYsize = 6000
BoardZsize = 200
BoardX = - 650
BoardY = 0
BoardZ = 0
tickNum = 25
#Dependent Parameters
mercBallR = BoardZsize/2
mercBallX = BoardX
mercBallY = BoardY-(BoardYsize/2) + mercBallR + (mercBallR/2)
mercBallZ = BoardZ
glTubeR = mercBallR * .5
glTubeLength = BoardYsize * .95
glTubeX = BoardX
glTubeY = mercBallY + mercBallR/2
glTubeZ = BoardZ
SidesXsize = (BoardXsize - (mercBallR*2)) /2
SidesYsize = BoardYsize
SidesZsize = BoardZsize
SideLX = BoardX - ((SidesXsize/2) + mercBallR)
SideRX = BoardX + (SidesXsize/2) + mercBallR
SidesY = BoardY
SidesZ = BoardZ
BoardbackZ = BoardZ - BoardZsize
stopR = glTubeR
stopX = BoardX
stopY = glTubeY + glTubeLength
stopZ = BoardZ
mercTubeR = glTubeR
mercTubeLength = int(glTubeLength * .9)
mercTubeX = glTubeX
mercTubeY = glTubeY
mercTubeZ = glTubeZ
tickXsize = SidesXsize
tickYsize = BoardYsize * .005
tickZsize = BoardYsize * .01
tickX = SideRX
tickY = SideLX
tickZ = BoardZ + BoardZsize / 2
tickstart = glTubeY + (mercTubeLength * .05)
tickend = tickstart + (glTubeLength * .9)
mercTubestartY = mercTubeLength * .05
#Appearance
BoardColor = color.white
sideColor = color.yellow
sideOP = 1
mercColor = color.red
mercOP = .5
glTubeColor = color.cyan
glTubeOP = .2
stopColor = color.green
tickColor = color.black
Parameters Thermometer 2
#Independent Parameters: These are the dimensions everything is alligned to.
bBoardXsize = 1200
bBoardYsize = 6000
bBoardZsize = 200
bBoardX = 650
bBoardY = 0
bBoardZ = 0
btickNum = 25
#Dependent Parameters
bmercBallR = bBoardZsize/2
bmercBallX = bBoardX
bmercBallY = bBoardY-(bBoardYsize/2) + bmercBallR + (bmercBallR/2)
bmercBallZ = bBoardZ
bglTubeR = bmercBallR * .5
bglTubeLength = bBoardYsize * .95
bglTubeX =bBoardX
bglTubeY = bmercBallY + bmercBallR/2
bglTubeZ = bBoardZ
bSidesXsize = (bBoardXsize - (bmercBallR*2)) /2
bSidesYsize = bBoardYsize
bSidesZsize = bBoardZsize
bSideLX = bBoardX - ((bSidesXsize/2) + bmercBallR)
bSideRX = bBoardX + (bSidesXsize/2) + bmercBallR
bSidesY = bBoardY
bSidesZ = bBoardZ
bBoardbackZ = bBoardZ - bBoardZsize
bstopR = bglTubeR
bstopX = bBoardX
bstopY = bglTubeY + bglTubeLength
bstopZ = bBoardZ
bmercTubeR = bglTubeR
bmercTubeLength = int(bglTubeLength * .9)
bmercTubeX = bglTubeX
bmercTubeY = bglTubeY
bmercTubeZ = bglTubeZ
btickXsize = bSidesXsize
btickYsize = bBoardYsize * .005
btickZsize = bBoardYsize * .01
btickX = bSideRX
btickY = bSideLX
btickZ = bBoardZ + bBoardZsize / 2
btickstart = bglTubeY + (bmercTubeLength * .05)
btickend = btickstart + (bglTubeLength * .9)
bmercTubestartY = bmercTubeLength * .05
#Appearance
bBoardColor = color.white
bsideColor = color.magenta
bsideOP = 1
bmercColor = color.red
bmercOP = .5
bglTubeColor = color.cyan
bglTubeOP = .2
bstopColor = color.yellow
btickColor = color.white
Shapes Thermometer 1
Boardback = box(size = vector(BoardXsize, BoardYsize, BoardZsize), pos = vector(BoardX, BoardY, BoardbackZ), color = BoardColor)
SideR = box(size = vector(SidesXsize, SidesYsize, SidesZsize), pos = vector(SideRX, SidesY, SidesZ), color = sideColor, opacity = sideOP)
SideL = box(size = vector(SidesXsize, SidesYsize, SidesZsize), pos = vector(SideLX, SidesY, SidesZ), color = sideColor, opacity = sideOP)
mercBall = sphere(radius = mercBallR, pos = vector(mercBallX, mercBallY, mercBallZ), color = mercColor, opacity = mercOP )
glTube = cylinder(radius = glTubeR, axis = vector(0, glTubeLength, 0), pos = vector(glTubeX, glTubeY, glTubeZ), color = glTubeColor, opacity = glTubeOP)
stop = sphere(radius = stopR, pos = vector(stopX, stopY, stopZ), color = stopColor)
mercTube = cylinder(radius = mercTubeR, axis = vector(0, mercTubestartY, 0), pos = vector(mercTubeX, mercTubeY, mercTubeZ), color = mercColor, opacity = mercOP)
for tick in np.linspace(tickstart, tickend, tickNum):
box(size = vector(tickXsize, tickYsize, tickZsize), pos = vector(tickX, tick, tickZ), color = tickColor)
Shapes Thermometer 2
bBoardback = box(size = vector(bBoardXsize, bBoardYsize, bBoardZsize), pos = vector(bBoardX, bBoardY, bBoardbackZ), color = bBoardColor)
bSideR = box(size = vector(bSidesXsize, bSidesYsize, bSidesZsize), pos = vector(bSideRX, bSidesY, bSidesZ), color = bsideColor, opacity = bsideOP)
bSideL = box(size = vector(bSidesXsize, bSidesYsize, bSidesZsize), pos = vector(bSideLX, bSidesY, bSidesZ), color = bsideColor, opacity = bsideOP)
bmercBall = sphere(radius = bmercBallR, pos = vector(bmercBallX, bmercBallY, bmercBallZ), color = bmercColor, opacity = bmercOP )
bglTube = cylinder(radius = bglTubeR, axis = vector(0, bglTubeLength, 0), pos = vector(bglTubeX, bglTubeY, bglTubeZ), color = bglTubeColor, opacity = bglTubeOP)
bstop = sphere(radius = bstopR, pos = vector(bstopX, bstopY, bstopZ), color = bstopColor)
bmercTube = cylinder(radius = bmercTubeR, axis = vector(0, bmercTubestartY, 0), pos = vector(bmercTubeX, bmercTubeY, bmercTubeZ), color = bmercColor, opacity = bmercOP)
for tick in np.linspace(btickstart, btickend, btickNum):
box(size = vector(btickXsize, btickYsize, btickZsize), pos = vector(btickX, tick, btickZ), color = btickColor)

Primary Code
##For Threads##
#Identify arguements
#mercTubeLength, bmercTubeLength ; Already identified.
Thermo1Rate = 3000
Thermo2Rate = 6000
#Set up threads
Thermo1Thread = Thread(target = practiceThermo1, args = (mercTubeLength, Thermo1Rate))
Thermo2Thread = Thread(target = practiceThermo2, args = (bmercTubeLength, Thermo2Rate))
Thermo1Thread.daemon = True
Thermo2Thread.daemon = True

sleep(5) #look at the initial thermometer position.

#Start Threads
Thermo1Thread.start()
Thermo2Thread.start()

while True:
pass

jonathanlanders
Автор

Wishing you all the best for the future. And of course thanks for these videos

Nick-xzqq