New script: Adjust lens without loosing the view

In Blender, adjusting the camera lens means that you have to reposition the camera in order to see what you saw before changing the lens.
This can be very time consuming for someone trying to adjust the perfect lens while maintaining the same view.

The following script will automatically reposition the camera while adjusting the lens, attempting to keep the view as it was before.

Here is a video showing the difference. (Google quality, sorry)
http://video.google.com/videoplay?docid=8738353078901968452

 
#!BPY
"""
Name: 'Camera Lens'
Blender: 242
Group: 'Object'
Tooltip: 'Adjusts the camera lens while maintaining the view'
"""
 
import Blender
from Blender import Mathutils
from Blender.Mathutils import *
 
lensSlider = 0
oldLens = 0
cam = Blender.Scene.GetCurrent().getActiveObject()
if cam.getType() != 'Camera':
 Blender.Draw.PupBlock("Error", ["No camera selected"]) 
 #exit 
def draw(): 
 global cam
 global lensSlider
 global oldLens
 
 Blender.BGL.glClear(Blender.BGL.GL_COLOR_BUFFER_BIT) 
 oldLens = cam.getData().getLens()
 lensSlider = Blender.Draw.Slider('Lens: ', 1, 20, 20, 200, 20, oldLens,1.0, 250.0, 1,'Specify the lens of the camera')
 
 
def event(evt,val):  
 if evt == Blender.Draw.ESCKEY: 
  Blender.Draw.Exit()   
  return                 
def button(evt): 
 global cam
 global lensSlider
 global oldLens  
 newLens = lensSlider.val
 
 difference = newLens - oldLens
 
 distance = difference * 0.15625 
 
 LocalTranslation = TranslationMatrix(Vector(0,0,distance))
 LocalTranslation *= cam.getMatrix()
 cam.setMatrix(LocalTranslation)
 
 cam.getData().setLens(newLens)
 Blender.Window.Redraw() 
 
Blender.Draw.Register(draw,event,button)
 

I like it!

this is very useful. thanks!

Oh that is awesome! That should be intergrated into Blender

Nice tool!! thanks…BlackBlender for sharing…

The functionality that the script offers is nice.

There are minor problems in the implementation though. It can crash Blender due to
Blender.Window.Redraw() in def button(evt):

While you handle a button you are not allowed to draw!

Take a look at http://wiki.blenderpython.org/ for good examples.

When am I meant to redraw? (It is done like this in the wikibook) http://en.wikibooks.org/wiki/Blender_3D:_Noob_to_Pro/Advanced_Tutorials/Python_Scripting/Creating_a_GUI_for_your_script

Besides, the script isn’t perfect yet. I’m still looking for a clean way to abort a script immediately. Currently, if the selected object is not a camera, the script will display an error but continue until it crashes:

 
if cam.getType() != 'Camera':
Blender.Draw.PupBlock("Error", ["No camera selected"]) 
#exit

This would be great if it was animatable - it could be used for dolly zooms.

Here is my alteration of your code that doesn’t crash. I’m not a python programmer, I just like to play with it :slight_smile: You are warned, so If your comp explodes, don’t blame me :slight_smile:


#!BPY
"""
Name: 'Camera Lens'
Blender: 242
Group: 'Object'
Tooltip: 'Adjusts the camera lens while maintaining the view'
"""
 
import Blender
from Blender import Mathutils
from Blender.Mathutils import *
 
lensSlider = 0
oldLens = 0

# I've added this def
#-----------------------------------------------------------------------------
def getCam():
 cam = Blender.Scene.GetCurrent().getActiveObject()
 if cam.getType() != 'Camera':
  Blender.Draw.PupBlock("Error", ["No camera selected"])
  Blender.Draw.Exit()
  return False
 return cam
#-----------------------------------------------------------------------------

def draw(): 
 global cam
 global lensSlider
 global oldLens
 
 Blender.BGL.glClear(Blender.BGL.GL_COLOR_BUFFER_BIT) 
 
#and changed these lines
#-----------------------------------------------------------------------------
 cam = getCam()
 if cam:
  oldLens = cam.getData().getLens()
  lensSlider = Blender.Draw.Slider('Lens: ', 1, 20, 20, 200, 20, oldLens,1.0, 250.0, 1,'Specify the lens of the camera')
#-----------------------------------------------------------------------------
   
def event(evt,val):  
 if evt == Blender.Draw.ESCKEY: 
  Blender.Draw.Exit()   
  return                 
def button(evt): 
 global cam
 global lensSlider
 global oldLens  
 newLens = lensSlider.val
 
 difference = newLens - oldLens
 
 distance = difference * 0.15625 
 
 LocalTranslation = TranslationMatrix(Vector(0,0,distance))
 LocalTranslation *= cam.getMatrix()
 cam.setMatrix(LocalTranslation)
 
 cam.getData().setLens(newLens)
 Blender.Window.Redraw() 
 
Blender.Draw.Register(draw,event,button)

blackblender: What I was trying to say was that if you move
Blender.Window.Redraw() after Blender.Draw.Register(draw,event,button) it does not crash anymore as you don’t draw in event. (That’s forbidden.)

I tested this and it worked without errors.

I appreciate your efforts and did not mean to be unconstructive.

By the way you can find a nice way to add an exit button to your script at http://wiki.blenderpython.org/index.php/BPyIntro/Fruitsalad_script_walkthrough .

Keep on coding!

I have played little more with this and I have realized that instead of Window.Redraw() you should use Draw.Redraw(). That way script actually does what it is designed for. And there’s no “atempt to free busy buttonblock” messages… Here’s your complete code with mine alterations.


#!BPY
"""
Name: 'Camera Lens'
Blender: 242
Group: 'Object'
Tooltip: 'Adjusts the camera lens while maintaining the view'
"""
 
import Blender
from Blender import Mathutils
from Blender.Mathutils import *
 
lensSlider = 0
oldLens = 0

# I've added this def
#-----------------------------------------------------------------------------
def GetCam():
 cam = Blender.Scene.GetCurrent().getActiveObject()
 if cam.getType() != 'Camera':
  Blender.Draw.PupBlock("Error", ["No camera selected"])
  Blender.Draw.Exit()
  return False
 return cam
#-----------------------------------------------------------------------------

def draw():
 global cam
 global lensSlider
 global oldLens
 
 Blender.BGL.glClear(Blender.BGL.GL_COLOR_BUFFER_BIT)
 
# And changed these lines
#-----------------------------------------------------------------------------
 cam = GetCam()
 if cam:
  oldLens = cam.getData().getLens()
  lensSlider = Blender.Draw.Slider('Lens: ', 1, 20, 20, 200, 20, oldLens,1.0, 250.0, 1,'Specify the lens of the camera')
#-----------------------------------------------------------------------------
   
def event(evt,val):  
 if evt == Blender.Draw.ESCKEY:
  Blender.Draw.Exit()  
  return                
def button(evt):
 global cam
 global lensSlider
 global oldLens  
 newLens = lensSlider.val
 
 difference = newLens - oldLens
 
 distance = difference * 0.15625
 
 LocalTranslation = TranslationMatrix(Vector(0,0,distance))
 LocalTranslation *= cam.getMatrix()
 cam.setMatrix(LocalTranslation)
 
 cam.getData().setLens(newLens)

# Instead of Window.Redraw() use Draw.Redraw()
#-----------------------------------------------------------------------------
 Blender.Draw.Redraw()
#-----------------------------------------------------------------------------

Blender.Draw.Register(draw,event,button)