Camera Shake [OLD....]

Hey gang. I’m in the process of writing my first Python script, and I was wondering if I could have a little advice. I realize this may have been done already, but I wanted to start with something I thought I would find useful.

Here is what I have so far (not much):


import Blender
from Blender import Object

count = 0
for o in Object.GetSelected():
	count = count + 1
for o in Object.GetSelected():
	if count > 1:
		print "Only one camera please"
		break
	elif o.getType() == 'Camera':
		print "Camera Selected"
		print o.getLocation()
		x, y, z = o.getLocation()
		print "x =", x
		print "y =", y
		print "z =", z
	else:
		print "Camera objects only"
		break

Bear with me here, it’s a n00b script so what I’ve done so far may be the wrong approach. And the print statements are there so I could test it.

So it checks to make sure the object selected is indeed a camera, and if it is continues on with getting the location of the camera.

What I want to know at this point is if I’m doing it “right”. Meaning, the way it’s set up right now the rest of the script would have to be inside that elif statement. Is that a proper technique? Is there a way to get it to move on past the entire for statement but only if a camera is selected? Or is it alright that I have the meat of the script inside the elif statement?

Guess that’s a lot of questions. But I’d greatly appreciate it if someone could let me know whether I’m on the right track or not. I’m trying to find out as much as I can on my own so that I learn more.

Thanks.

keep on going! as long as it works!

am hoping to have the time to suggest ways to make it nice later :slight_smile:

oh well i couldn’t help myself:


allcams = [o for o in Object.GetSelected() if o.type == 'Camera']
try:
    cam = allcams[0] #first cam
except IndexError:
    raise RuntimeError, "please select (at least) one camera"

x, y, z = cam.location 
print "x =", x 
print "y =", y 
print "z =", z 

untested, but you may get some ideas … am not totally sure if all the old getters (like getLocation()) already have attribute/property replacements (like .location) but i think most at least in cvs / upcoming 2.40

~Toni

Thanks for the advice Toni.

I have a new issue though. I can’t for the life of me figure out how to get the script to halt where it is. I’m trying to get it to halt in the if statement if it isn’t just one camera selected.

Wait a minute, I’m a moron. That’s what the raise RuntimeError is for isn’t it? My bad.

I’m having trouble with persistent data. Here’s the setup (from Registry API reference):


def update_Registry():
	d = {}
	d['ShstaFra'] = ShstaFra
	d['ShendFra'] = ShendFra
	d['freq'] = freq
	d['mag'] = mag
	d['taper'] = taper
	Blender.Registry.SetKey('MyScript', d, True)

ShstaFra = 0 #Frame you would like the camera to start shaking
ShendFra = 10 #Frame you would like the camera to stop shaking

freq = 0 #Speed at which the camera shakes
mag = 0 #Maximum amount camera can be repositioned during shake

taper = 0
	
rdict = Registry.GetKey('MyScript', True)
if rdict:
	try:
		ShstaFra = rdict['ShstaFra']
		ShendFra = rdict['ShendFra']
		freq = rdict['freq']
		mag = rdict['mag']
		taper = rdict['taper']
	except: update_Registry()

The variables ShstaFra, ShendFra, freq, mag, and taper will be defined by the user (at least until I figure out how to make a GUI). I setup a script link that is linked to frame changes. I need the script link to access those user defined variables.

However, I’m having very poor luck actually making that happen. Could anyone tell me what lines I need to have in my cam_link script so it can access those variables?

Thanks.

why don’t you just have the variables in the camera shaking script?

~Toni

Alright, I have all the basics done and was going to make a small preview to show off and ran into a problem. Everything works in the 3d views. The camera shake shows up and looks great.

However, when I rendered it, nothing. It was as though I never used the script. Does anyone have any suggestions on this? The script repositions the camera without setting a keyframe, which, like I said, works fine in the 3d views. To get it to show up in render time must I actually set keyframes?

I was hoping to avoid keyframes to make it more usable. For example, let’s say you use the script to apply a camera shake with keyframes. Fine. Then you decide you want the shake to take place later instead. You’d have to go into the IPO editor and delete all the keyframes that the script created before you could reapply it. Which IMO would be rather annoying.

After I make a few more changes I’ll at least post what I have so far in case anyone wants to give it a try. Just no rendering. :stuck_out_tongue:

Alright, here’s what I have so far. Usable, but very limited.

The variables ‘staFra’, ‘endFra’, and ‘mag’ are the only ones that do anything right now. Lot’s of stuff to do yet. :stuck_out_tongue:

Select a camera, and run the script. It’ll tell you if you didn’t have one selected, or if you had more than one object selected and didn’t realize it. Don’t worry, it’ll let you know if it was successful or not. When run, it uses itself as a script link set to FrameChanged. So after you run it once, that’s all you need to worry about.

When playing the animation (only 3d views right now, no renders) if the frame is between staFra and endFra it gets the camera’s location, and gives it a new, random one, based on what value you gave the variable mag. Even a value of 1 creates quite a shake, so keep it small.

Also, if you don’t plan on animating the camera, it’s important to set at least one location keyframe. Try it without and you’ll see why. :wink:

It’s also important to note that as of right now the link has to be deleted manually. So, if you decide to use it on a different camera, or decide to change any of the values (staFra, endFra, mag) remember to delete it (Script Panel) and rerun the script!

I noticed while playing with it that it doesn’t always redraw the 3d windows depending on what Screen you’re using. SCR:2-Model and SCR:3-Material worked for me, but the others didn’t. I have no idea why.

Because of this I may change the script link so that it is an object based one, as opposed to scene. To be honest I don’t know what the pros/cons are of either.

Enough rambling.


import Blender
from Blender import Object
from Blender import Draw
from Blender import Scene
from Blender import Registry
from Blender import Mathutils

def update_Registry():
	#Global Variables
	g = {}
	g["cam"] = cam #DO NOT EDIT
	g["staFra"] = 21 #Frame you would like the camera to start shaking
	g["endFra"] = 51 #Frame you would like the camera to stop shaking
	g["freq"] = 0 #Speed at which camera shakes
	g["mag"] = 1 #Maximum amount (positive or negative) camera can be repositioned during shake. 
				 #Should be a fairly low number, a value of 5 even is overkill. So I'd recommend
				 #a value < 5.
	g["taperLength"] = 0 #Number of frames camera shake will taper
	g["taperAmount"] = 0 #Amount shake will lesson with each frame while tapering
	Blender.Registry.SetKey('cam_shake', g, False)

rdict = Registry.GetKey('cam_shake', False)
if rdict:
	try:
		cam = rdict['cam']
		staFra = rdict['staFra']
		endFra = rdict['endFra']
		freq = rdict['freq']
		mag = rdict['mag']
		taperLength = rdict['taperLength']
		taperAmount = rdict['taperAmount']
	except: update_Registry()

def shake_camera():
	curFra = Blender.Get("curframe")
	if curFra >= staFra and curFra <= endFra:
		#Gets location of each axis of Camera, then uses that location
		#to generate a new, random location
		x, y, z = cam.getLocation()
		#Generating random numbers
		ranNumX = Mathutils.Rand(-mag, mag) + x
		ranNumY = Mathutils.Rand(-mag, mag) + y
		ranNumZ = Mathutils.Rand(-mag, mag) + z
		#Setting new location
		cam.setLocation(ranNumX, ranNumY, ranNumZ)
		Blender.Redraw()
		Scene.GetCurrent()
		
def grab_cam():
	#Grab camera object, store its name.
	#This way after the script is applied to a camera, the camera
	#doesn't actually have to stay selected to affect the camera.
	for o in Object.GetSelected():
		o = o.getName()
		cam = Object.Get(o)
		Draw.PupMenu("Success!%t|Link set.")
		return cam
		
def check_cam():
	#Checks to make sure the object selected is a camera, it not, aborts.
	#Script also aborts if more than one camera is selcted.
	count = 0
	if Object.GetSelected() == []:
		Draw.PupMenu("Error!%t|No cameras selected! Script aborting.")
		Draw.Exit()
		return False
	for o in Object.GetSelected():
		count += 1
	for o in Object.GetSelected():
		if count > 1:
			Draw.PupMenu("Error!%t|Too many objects selected! Script aborting.")
			Draw.Exit()
			return False
		elif o.getType() != 'Camera':
			Draw.PupMenu("Error!%t|Selected object not camera! Script aborting.")
			Draw.Exit()
			return False

#Link this script to the scene with event of framechange	
def plugscript():
	sc = Scene.GetCurrent()
	sc.addScriptLink("camera_shake.py", "FrameChanged")

#Checks to see if the script is already linked to the scene	
def link_check():
	sc = Scene.GetCurrent()
	sc = sc.getScriptLinks("FrameChanged")
	if sc == ['camera_shake.py']:
		return False

#Checks to see if the script link has been set. If it has calls the shake_camera() function.	
if link_check() == False:
	shake_camera()

#Checks to see if the script link has been set. If it hasn't it sets it.
if link_check() != False:
	runFlag = check_cam()
	if runFlag != False:
		cam = grab_cam()
		update_Registry()
		plugscript()
		

After getting an object’s Ipo data is there a way to duplicate it? I’ve looked through both the Object and Ipo API references and didn’t see anything regarding duplicating.

I figured if I had to set keyframes for the shake to show up at render time the least I could do is duplicate the camera’s ipo curve before I altered it. That way you can relink the camera with it’s original ipo curve should you decide you don’t want the one modified by the script.

Thanks.

In the Ipo editor, to the right of the current Ipo name, there is that box labeled with an ‘F’. It’s tooltip reads as ‘Saves this datablock even if it has no users.’ Anyone know if this is accessible through the Python API?

I have been unable to locate anything regarding this or duplicating existing Ipo’s.

Any help would be greatly appreciated. Also, if you knew how to solve my render problem mentioned in the posts above I would be eternally grateful. :stuck_out_tongue:

you don’t need to do anything with IPOs for things to show up at render time. it should be identical with 3d view (i mean regarding object positions, orientations etc.)

are you using the FrameChanged scriptlink or what?

~Toni

Yes, the script is linked to FrameChanged. And when it is previewed in the 3d view everything works. But when I render it’s as though there is no scriptlink. Do Ipo curves take precedence when rendering?

The camera has one keyframe set so that the random location is based off of the keyframe location. If you don’t set a keyframe then the camera slowly moves further and further away from the original location since the new random location would be based off of the old random location. Make any sense?

The script is pasted above. If you’ve time give it a try. Insert a loc keyframe for the camera and apply the script and try rendering it.

Edit: I realize it’d be easy enough to change the script so it stored the location instead of grabbing it every frame. But then the script would only be useful for cameras that weren’t animated.

i’m sorry i dont have the time now.

IPOs should behave similarily in 3d view and in rendering. it is possible that there is a bug in the Python API code related to that. you might wanna test if you get the same behaviour with 2.40alpha1 / current cvs - if so, please report the bug in the tracker.

~Toni

Thanks for the suggestion! Works like a charm with 2.4 Alpha.

Well, it works if the script is setup as an Object link set to FrameChanged as opposed to a Scene link like it’s setup as now.

However, I guarantee that I tried setting it up as an Object link with 2.37 as well. So, it is indeed a bug as you pointed out.

Just tell me how to report it and I will. :wink: I’m unfamiliar with the bug tracker.

Thanks again!

we don’t currently fix bugs in old releases.

so if it works in 2.40alpha, that bug does not exist anymore :slight_smile:

~Toni

My bad. :wink:

Does this script works with 2.41 ? Does it need a python installation to run ?

I have an error when running it on my 2.41 blender without any python installed:

It stops on this line :
sc.addScriptLink(“camera_shake.py”, “FrameChanged”)

with this message in the console :

Traceback (most recent call last):
File “camera-shake.py”, line 101, in ?
File “camera-shake.py”, line 82, in plugscript
AttributeError: no such Blender Text

What a shame ! this script sounded so cool !

Thanks for the interest! This thread is actually for my first attempt at this script.

https://blenderartists.org/forum/viewtopic.php?t=59488&start=30

Go there for a newer version, that is working with 2.41.