pyConstraint - Distance to Scale

Hi,

just a quicky script to try out and learn a bit about pyconstraints.

The idea came from watching one of those helicopter combat movies. In some shoots you see the scene through the “hightech” helmets of the pilots. The HUD display there draws a virtual rectangle around a moving target with a distance indicator above.

I wanted to be able to let the distance of the camera to an object scale such an indicator automatically. Here is what i came up with. In the options of the script you can define which axis to scale, the distance range which should affect a also editable scale range for the owner. You can also invert the scale behavior with a button.

Just copy the code into a text area in blender and chose a name which can then be used in the constraints -> script field.

Dunno if it’s useful for someone but just want to share it here.
Have fun with it
Efelon


#BPYCONSTRAINT
'''
    Description:
    Constraint which uses the distance of target1 to target2 to translate it to
    the scale of the constraint owner. Distance and Scale limits can be set using the Options button.
    Author:
    Efelon
'''

import Blender
from Blender import Draw
from Blender import Mathutils
import math

'''
 This variable specifies the number of targets 
 that this constraint can use
'''
NUM_TARGETS = 2


'''
 This function is called to evaluate the constraint
    obmatrix:        (Matrix) copy of owner's 'ownerspace' matrix
    targetmatrices:    (List) list of copies of the 'targetspace' matrices of the targets (where applicable)
    idprop:            (IDProperties) wrapped data referring to this 
                    constraint instance's idproperties
'''
def doConstraint(obmatrix, targetmatrices, idprop):
    # Separate the Scale matrix
    obLoc = obmatrix.translationPart()    # Location
    obRot = obmatrix.toEuler()            # Rotation
    obSca = obmatrix.scalePart()        # Scale

    
    # Define user-settable parameters
    # Must also be defined in getSettings().
    if not idprop.has_key('X_Axis'): idprop['X_Axis'] = 1
    if not idprop.has_key('Y_Axis'): idprop['Y_Axis'] = 0
    if not idprop.has_key('Z_Axis'): idprop['Z_Axis'] = 0
    if not idprop.has_key('min_dist'): idprop['min_dist'] = 0.0
    if not idprop.has_key('max_dist'): idprop['max_dist'] = 10.0
    if not idprop.has_key('min_sca'): idprop['min_sca'] = 0.5
    if not idprop.has_key('max_sca'): idprop['max_sca'] = 4.0
    if not idprop.has_key('invert'): idprop['invert'] = 0
    
    # Calculate the Distance between given Targets
    target1loc = targetmatrices[0].translationPart()
    target2loc = targetmatrices[1].translationPart()
    distance = target2loc - target1loc
    
    # Calculate the distance and scale range
    range_distance = idprop['max_dist'] - idprop['min_dist']
    range_change = idprop['max_sca'] - idprop['min_sca']
    
    #Cut the influence range
    if idprop['invert'] == 1:
        if distance.length <= idprop['min_dist']:
            change = idprop['max_sca']
        elif distance.length >= idprop['max_dist']:
            change = idprop['min_sca']
        else:
            #Calculate the change factor
            change = idprop['max_sca']-(range_change*((distance.length-idprop['min_dist'])/range_distance))
    else:
        if distance.length <= idprop['min_dist']:
            change = idprop['min_sca']
        elif distance.length >= idprop['max_dist']:
            change = idprop['max_sca']
        else:
            #Calculate the change factor
            change = idprop['min_sca']+(range_change*((distance.length-idprop['min_dist'])/range_distance))
    
    #apply the change to the choosen axis
    if idprop['X_Axis'] == 1:
        obSca[0] *= change
    if idprop['Y_Axis'] == 1:
        obSca[1] *= change
    if idprop['Z_Axis'] == 1:
        obSca[2] *= change
        
    # Convert back into a matrix for loc, scale, rotation,
    mtxloc = Mathutils.TranslationMatrix(obLoc)
    mtxrot = obRot.toMatrix().resize4x4()
    mtxsca = Mathutils.Matrix([obSca[0],0,0,0], [0,obSca[1],0,0], [0,0,obSca[2],0], [0,0,0,1])
    
    # Recombine the separate elements into a transform matrix.
    outputmatrix = mtxsca * mtxrot * mtxloc

    # Return the new matrix.
    return outputmatrix



'''
 This function manipulates the matrix of a target prior to sending it to doConstraint()
    target_object:                    wrapped data, representing the target object
    subtarget_bone:                    wrapped data, representing the subtarget pose-bone/vertex-group (where applicable)
    target_matrix:                    (Matrix) the transformation matrix of the target
    id_properties_of_constraint:    (IDProperties) wrapped idproperties
'''
def doTarget(target_object, subtarget_bone, target_matrix, id_properties_of_constraint):
    return target_matrix


'''
 This function draws a pupblock that lets the user set
 the values of custom settings the constraint defines.
 This function is called when the user presses the settings button.
    idprop:    (IDProperties) wrapped data referring to this 
            constraint instance's idproperties
'''
def getSettings(idprop):
    # Define user-settable parameters.
    # Must also be defined in getSettings().
    if not idprop.has_key('X_Axis'): idprop['X_Axis'] = 1
    if not idprop.has_key('Y_Axis'): idprop['Y_Axis'] = 0
    if not idprop.has_key('Z_Axis'): idprop['Z_Axis'] = 0
    if not idprop.has_key('min_dist'): idprop['min_dist'] = 0.0
    if not idprop.has_key('max_dist'): idprop['max_dist'] = 10.0
    if not idprop.has_key('min_sca'): idprop['min_sca'] = 0.5
    if not idprop.has_key('max_sca'): idprop['max_sca'] = 4.0
    if not idprop.has_key('invert'): idprop['invert'] = 0
    
    # create temporary vars for interface 
    X_Axis = Draw.Create(idprop['X_Axis'])
    Y_Axis = Draw.Create(idprop['Y_Axis'])
    Z_Axis = Draw.Create(idprop['Z_Axis'])
    min_dist = Draw.Create(idprop['min_dist'])
    max_dist = Draw.Create(idprop['max_dist'])
    min_sca = Draw.Create(idprop['min_sca'])
    max_sca = Draw.Create(idprop['max_sca'])
    invert = Draw.Create(idprop['invert'])

    # define and draw pupblock
    block = []
    block.append("Axis to Scale: ")
    block.append(("X", X_Axis, "Axis should scale"))
    block.append(("Y", Y_Axis, "Y"))
    block.append(("Z", Z_Axis, "Z"))
    block.append("Distance Range: ")
    block.append(("Min", min_dist, 0.0000001, 1000.0, "Min. Distance."))
    block.append(("Max", max_dist, 0.0000001, 1000.0, "Max. Distance."))
    block.append("")
    block.append("Scale Range: ")
    block.append(("Min", min_sca, 0.0000001, 1000.0, "Min. Scale."))
    block.append(("Max", max_sca, 0.0000001, 1000.0, "Max. Scale."))
    block.append("Invert scale direction")
    block.append(("Invert", invert, "invert scale min <-> max"))

    retval = Draw.PupBlock("Distance to Scale Transformation", block)
    
    # update id-property values after user changes settings
    if (retval):
        idprop['X_Axis']= X_Axis.val
        idprop['Y_Axis']= Y_Axis.val
        idprop['Z_Axis']= Z_Axis.val
        idprop['min_dist']= min_dist.val
        idprop['max_dist']= max_dist.val
        idprop['min_sca']= min_sca.val
        idprop['max_sca']= max_sca.val
        idprop['invert']= invert.val

P.S.: First target can be of course the owner itself or an other object as well.

Hi Efelon, it sounds very useful.
I tried your script, with a simple scene of two cubes. I wasn’t sure, how to use it exactly.It’s the distance of camera as target 2 to target 1 or do you mean the distance of camera (no matter which target is set) to the constraint’s owner? Should I set some special settings or are there some ways to refresh it?
Might I ask you to post a sample scene (and if I might be allowed - in an impertinent manner - to ask for a modified version for translation (and rotation), in addition or replaced scaling properties)?
Thank you!