SOLVED Connecting Camera Focus Distance to Null Object with Python

Hi there. I wonder if anyone would be able to help a not-very-savvy coder figure out a tiny bit of Python code. For this code, I’m trying to import and position a camera into my scene. I then want to connect the 'focus distance' field of the camera to a null object which I have also imported into the scene. I thought it would be as easy as adding some variation of "camera[c4d.CAMERAOBJECT_TARGETOBJECT] = null" into my code, but no amount of tweaking seems to work for this. I feel like I'm missing a step. If anyone knows the answer please let me know. My code can be viewed below.

import c4d
from c4d import gui
# Lighting Stage

def main():
    def tool():
        return c4d.plugins.FindPlugin(doc.GetAction(), c4d.PLUGINTYPE_TOOL)
    def object():
        return doc.GetActiveObject()
    def tag():
        return doc.GetActiveTag()
    def renderdata():
        return doc.GetActiveRenderData()
    def prefs(id):
        return c4d.plugins.FindPlugin(id, c4d.PLUGINTYPE_PREFS)

    c4d.CallCommand(5140) # Create Camera Targeting Null
    object()[c4d.NULLOBJECT_DISPLAY] = 13
    object()[c4d.NULLOBJECT_RADIUS] = 80
    object()[c4d.ID_BASEOBJECT_REL_POSITION,c4d.VECTOR_Y] = 276
    object()[c4d.ID_BASELIST_NAME] = "Camera_Target"

    c4d.CallCommand(5103) # Create Camera with Redshift Tag
    object()[c4d.ID_BASEOBJECT_REL_ROTATION,c4d.VECTOR_X] = 0
    object()[c4d.ID_BASEOBJECT_REL_ROTATION,c4d.VECTOR_Y] = -0.175
    object()[c4d.ID_BASEOBJECT_REL_ROTATION,c4d.VECTOR_Z] = 0
    object()[c4d.ID_BASEOBJECT_REL_POSITION,c4d.VECTOR_X] = 0
    object()[c4d.ID_BASEOBJECT_REL_POSITION,c4d.VECTOR_Y] = 433
    object()[c4d.ID_BASEOBJECT_REL_POSITION,c4d.VECTOR_Z] = -884
    c4d.CallCommand(100004788, 50075) # New Tag
    tag()[c4d.REDSHIFT_POSTEFFECTS_DOF_OVERRIDE] = True
    tag()[c4d.REDSHIFT_POSTEFFECTS_DOF_ENABLED] = True
    tag()[c4d.REDSHIFT_POSTEFFECTS_DOF_RADIUS] = 8.5

    camera[c4d.CAMERAOBJECT_TARGETOBJECT] = null

if __name__=='__main__':
    main()
    c4d.EventAdd()

python.png

Hi,

the problem with your code is that you neither defined the symbol camera nor the symbol null which you used in your code. Script log code is also usually not a very good staring point (I assume this was derived from a script log) . I wrote a little piece of narrative code which roughly does what you want and which you might find helpful.

"""Run this in the script manager with an object in your scene, called
"my_taregt".
"""
import c4d


def main():
    """
    """
    # "doc" is a predefined variable in Script Manager scripts, which
    # points to the currently active document. "BaseDocument.SearchObject"
    # is looking for the first object with the given name in the document.
    # There are better ways to select objects, but this is an easy one and
    # might be sufficient for your case. If you have an object named
    # "my_target" in your scene, the variable "target" will point to it.
    target = doc.SearchObject("my_target")
    # "target" will be "None" if we did not find it, this will just signal
    # that.
    if not target:
        raise IOError("Could not find target object.")

    # We can instantiate an object, a tag, a material or a shader with the
    # type BaseList2D. You have to pass in the ID of the node you want to
    # build. Here we are passing "c4d.Ocamera" to build a camera. Ocamera
    # is just an alias for the integer 5103, which you also used in your
    # CallCommand.
    # But unlike CallCommand constructing an object with the type BaseList2D
    # will give us a symbol under which we can access our object ("camera"
    # here).
    camera = c4d.BaseList2D(c4d.Ocamera)
    # Setting the target is just as easy as you thought, the problem in
    # your code was that you never defined something as "camera".
    camera[c4d.CAMERAOBJECT_TARGETOBJECT] = target
    # Setting the relative position and rotation could be shortened a bit,
    # but your way was totally fine.
    position = c4d.Vector(0, 433, -800)
    rotation = c4d.Vector(0, -0.175, 0)
    camera[c4d.ID_BASEOBJECT_REL_POSITION] = position
    camera[c4d.ID_BASEOBJECT_REL_ROTATION] = rotation
    # There are also two methods of the type BaseObject (our camera is such
    # an BaseObject) which do the same as the attribute access.
    camera.SetRelPos(position)
    camera.SetRelRot(rotation)
    # Since I do not own RedShift, I will just create an target expression
    # on the camera instead. This should look a bit familiar by now.
    tag = c4d.BaseList2D(c4d.Ttargetexpression)
    tag[c4d.TARGETEXPRESSIONTAG_LINK] = target
    # Now we just need to attach our tag to our camera ...
    camera.InsertTag(tag)
    # ... and insert that object into the active document.
    doc.InsertObject(camera)
    # Finally we need to tell Cinema, that we modified something.
    c4d.EventAdd()


if __name__ == "__main__":
    main()

Cheers,
zipit

Hi,

the problem with your code is that you neither defined the symbol camera nor the symbol null which you used in your code. Script log code is also usually not a very good staring point (I assume this was derived from a script log) . I wrote a little piece of narrative code which roughly does what you want and which you might find helpful.

"""Run this in the script manager with an object in your scene, called
"my_taregt".
"""
import c4d


def main():
    """
    """
    # "doc" is a predefined variable in Script Manager scripts, which
    # points to the currently active document. "BaseDocument.SearchObject"
    # is looking for the first object with the given name in the document.
    # There are better ways to select objects, but this is an easy one and
    # might be sufficient for your case. If you have an object named
    # "my_target" in your scene, the variable "target" will point to it.
    target = doc.SearchObject("my_target")
    # "target" will be "None" if we did not find it, this will just signal
    # that.
    if not target:
        raise IOError("Could not find target object.")

    # We can instantiate an object, a tag, a material or a shader with the
    # type BaseList2D. You have to pass in the ID of the node you want to
    # build. Here we are passing "c4d.Ocamera" to build a camera. Ocamera
    # is just an alias for the integer 5103, which you also used in your
    # CallCommand.
    # But unlike CallCommand constructing an object with the type BaseList2D
    # will give us a symbol under which we can access our object ("camera"
    # here).
    camera = c4d.BaseList2D(c4d.Ocamera)
    # Setting the target is just as easy as you thought, the problem in
    # your code was that you never defined something as "camera".
    camera[c4d.CAMERAOBJECT_TARGETOBJECT] = target
    # Setting the relative position and rotation could be shortened a bit,
    # but your way was totally fine.
    position = c4d.Vector(0, 433, -800)
    rotation = c4d.Vector(0, -0.175, 0)
    camera[c4d.ID_BASEOBJECT_REL_POSITION] = position
    camera[c4d.ID_BASEOBJECT_REL_ROTATION] = rotation
    # There are also two methods of the type BaseObject (our camera is such
    # an BaseObject) which do the same as the attribute access.
    camera.SetRelPos(position)
    camera.SetRelRot(rotation)
    # Since I do not own RedShift, I will just create an target expression
    # on the camera instead. This should look a bit familiar by now.
    tag = c4d.BaseList2D(c4d.Ttargetexpression)
    tag[c4d.TARGETEXPRESSIONTAG_LINK] = target
    # Now we just need to attach our tag to our camera ...
    camera.InsertTag(tag)
    # ... and insert that object into the active document.
    doc.InsertObject(camera)
    # Finally we need to tell Cinema, that we modified something.
    c4d.EventAdd()


if __name__ == "__main__":
    main()

Cheers,
zipit

@curripod00 said in Connecting Camera Focus Distance to Null Object with Python:

camera[c4d.CAMERAOBJECT_TARGETOBJECT] = null

This line cannot work because "null" is an undefined variable name (and "camera" actually too). It references nothing.
Instead, you will need to find the actual target null by searching:

camera = doc.SearchObject("Camera")
camera[c4d.CAMERAOBJECT_TARGETOBJECT] = doc.SearchObject("Camera_Target")

(I did not test that, just slapped together from memory.)

This is still not very good code because it assumes that the new camera's name is "Camera" which is not very original and may be duplicate in the scene already. Feel free to call the camera something else by setting the name when you generate the object.

Or instead of searching, you store the objects after generation in a variable. Following code should do it (I didn't test, as I don't have Redshift):

import c4d
from c4d import gui

def main():
    def object():
        return doc.GetActiveObject()
    def tag():
        return doc.GetActiveTag()

    c4d.CallCommand(5140) # Create Camera Targeting Null
    cameraTarget = object()
    cameraTarget[c4d.NULLOBJECT_DISPLAY] = 13
    cameraTarget[c4d.NULLOBJECT_RADIUS] = 80
    cameraTarget[c4d.ID_BASEOBJECT_REL_POSITION,c4d.VECTOR_Y] = 276
    cameraTarget[c4d.ID_BASELIST_NAME] = "Camera_Target"

    c4d.CallCommand(5103) # Create Camera with Redshift Tag
    camera = object()
    camera[c4d.ID_BASEOBJECT_REL_ROTATION,c4d.VECTOR_X] = 0
    camera[c4d.ID_BASEOBJECT_REL_ROTATION,c4d.VECTOR_Y] = -0.175
    camera[c4d.ID_BASEOBJECT_REL_ROTATION,c4d.VECTOR_Z] = 0
    camera[c4d.ID_BASEOBJECT_REL_POSITION,c4d.VECTOR_X] = 0
    camera[c4d.ID_BASEOBJECT_REL_POSITION,c4d.VECTOR_Y] = 433
    camera[c4d.ID_BASEOBJECT_REL_POSITION,c4d.VECTOR_Z] = -884
    c4d.CallCommand(100004788, 50075) # New Tag
    cameratag = tag()
    cameratag[c4d.REDSHIFT_POSTEFFECTS_DOF_OVERRIDE] = True
    cameratag[c4d.REDSHIFT_POSTEFFECTS_DOF_ENABLED] = True
    cameratag[c4d.REDSHIFT_POSTEFFECTS_DOF_RADIUS] = 8.5

    camera[c4d.CAMERAOBJECT_TARGETOBJECT] = cameraTarget

if __name__=='__main__':
    main()
    c4d.EventAdd()

Learn more about Python for C4D scripting:
https://www.patreon.com/cairyn

@zipit okaaaay I get it: you NEVER EVER sleep! 😀

@zipit This is fantastic, thank you for going through and explaining why my code was lacking, I have a better understanding of this process now and my camera focus works perfectly using your method. 👍 👏

@Cairyn Thanks for this fantastic resource, I will definitely use this summer to level up with Python. 👍