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. 👍


Log in to reply