Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware API
      • ZBrush Python API
      • ZBrush GoZ API
      • Code Examples on Github
    • Forum
    • Downloads
    • Support
      • Support Procedures
      • Registered Developer Program
      • Plugin IDs
      • Contact Us
    • Categories
      • Overview
      • News & Information
      • Cinema 4D SDK Support
      • Cineware SDK Support
      • ZBrush 4D SDK Support
      • Bugs
      • General Talk
    • Recent
    • Tags
    • Users
    • Register
    • Login

    Programmatically created Redshift Lights in an Object Plugin converts lights into Null-Objekts without an function after making Objekt-Plugin editable

    Scheduled Pinned Locked Moved Cinema 4D SDK
    2026202520242023pythonwindows
    5 Posts 2 Posters 27 Views 2 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • ThomasBT Online
      ThomasB
      last edited by ThomasB

      Sorry first, I am not sure if this is the right place to post this. The Redshift forum was apparently not the right place. 🙄

      I don't know if this behavior is intentional or unavoidable, but there is a problem with Redshift lights in my opinion.

      Situation:
      When you create a Redshift light and press 'C', it converts it into a standard Cinema 4D light—or, if generated programmatically, into a useless Null object.
      It is programmatically impossible to generate a light (e.g., within an object plugin). When the object plugin is made "Editable"—for instance, to get the geometry—all Redshift lights are converted into Null objects and lose their functionality. Unlike the standard behavior, they aren't even converted into Cinema 4D lights.

      Steps:

      • The plugin loads a virtual scene containing prepared scene elements and lights.
      • It returns in a container all the needed elements
      • When the plugin is made "Editable" to recieve the geometry, all Redshift lights are converted into Null objects.
        ➡️ result: Light functionality is lost.

      Visual Examples:
      Plugin creates a building for night view:

      • as long as the plugin is running lights are working
        bug_redshift.jpg

      • a light in code looks like this in a virtual temp_doc:
        bug_redshift_light_in_code.jpg

      • after converting the plugin into geometry (c to make it editable) it converts the lights into this:
        bug_redshift_light_afterconversion.jpg

      Plugin Example:
      Here is a trivial plugin example which basically loads a scene and returns an element with a light.
      The scene structure of the document looks like that. The plugin returns the base element
      bug_house_stucture.jpg

      After making the plugin editabel the light_flurescent is converted into a null object, and not even a Cinema 4D light remains.
      Ideally, of course, the Redshift light would be fully preserved. That makes sense if you want to render with Redshift.

      It uses a temporary Plugin ID
      Download Plugin

      I don't need to explain the code in detail here; an element is simply returned in the GetVirtualObjects method:

          def GetVirtualObjects(self, op: BaseObject, hh: object) -> Optional[BaseObject]:
      
              cdirty = False
              for child in op.GetChildren():
      
                  cdirty = child.CheckCache(hh) or child.IsDirty(c4d.DIRTYFLAGS_DATA)
                  if cdirty:
      
                      break
      
              dirty = op.CheckCache(hh) or op.IsDirty(c4d.DIRTYFLAGS_DATA | c4d.DIRTYFLAGS_ALL) or cdirty
              if not dirty:
                  return op.GetCache(hh)
      
      
              if self._temp_doc:
                  container = c4d.BaseObject(c4d.Onull)
      
                  base: c4d.BaseObject = self._temp_doc.GetFirstObject().GetDown().GetClone()
                  base.InsertUnder(container)
      
                  return container
              else:
                  return None
      

      Cheers
      T.B.

      Thanks,
      T.B

      ferdinandF 1 Reply Last reply Reply Quote 0
      • ferdinandF Offline
        ferdinand @ThomasB
        last edited by ferdinand

        Hello @ThomasB,

        I am sorry that you had a bad experience in the RS forum. Can you show me the actual code where you add the RS light object in code? Because I see no Orslight in your snippet? Or when you load an asset, share that asset? When I do a quick test with a Python generator object, this works fine for me.

        Cheers,
        Ferdinand

        PS: The plugin link you shared only contains an encrypted plugin (pypv) which not only makes it harder for me to get to the source code, I also cannot run such plugin on company hardware before I cracked it and can reasonably say that it does not contain dangerous code. Could you please share an unencrypted version?

        MAXON SDK Specialist
        developers.maxon.net

        ThomasBT 1 Reply Last reply Reply Quote 0
        • ThomasBT Online
          ThomasB @ferdinand
          last edited by ThomasB

          @ferdinand

          Okay, thank you Ferdinand for your reply.
          Okay, that's strange—it works in your video.

          I don't think the issue lies with my code; it simply loads a Cinema 4D scene in which the objects are already prepared.

          But here is the unprotected plugin.
          As previously mentioned, this is just a simple, simplified plugin to demonstrate that the problem behaves exactly as described above when using "Make Editable."
          Download unprotected plugin

          and the code if this helps out:

          from typing import Optional
          
          import c4d
          from c4d import plugins, bitmaps, BaseObject
          import os
          
          
          PLUGIN_ID = 1000200
          
          
          def load_house():
          
              house_path = os.path.join(path, "res", "models", "build_1.c4d")
              doc = None
              if os.path.exists(house_path):
                  doc = c4d.documents.LoadDocument(house_path, c4d.SCENEFILTER_OBJECTS | c4d.SCENEFILTER_MATERIALS)
          
              return doc
          
          
          
          
          class RedshiftLightsTest(plugins.ObjectData):
          
              def __init__(self):
                  self.SetOptimizeCache(True)
          
                  self._temp_doc = load_house()
          
              def Init(self, op, isCloneInit):
          
          
                  return True
          
              
          
              def GetVirtualObjects(self, op: BaseObject, hh: object) -> Optional[BaseObject]:
          
                  cdirty = False
                  for child in op.GetChildren():
          
                      cdirty = child.CheckCache(hh) or child.IsDirty(c4d.DIRTYFLAGS_DATA)
                      if cdirty:
          
                          break
          
                  dirty = op.CheckCache(hh) or op.IsDirty(c4d.DIRTYFLAGS_DATA | c4d.DIRTYFLAGS_ALL) or cdirty
                  if not dirty:
                      return op.GetCache(hh)
          
          
                  if self._temp_doc:
                      container = c4d.BaseObject(c4d.Onull)
          
                      base: c4d.BaseObject = self._temp_doc.GetFirstObject().GetDown().GetClone()
                      base.InsertUnder(container)
          
                      return container
                  else:
                      return None
          
              def GetDDescription(self, op, description, flags):
                  if not description.LoadDescription(op.GetType()):
          
                      return False
          
                  single_id = description.GetSingleDescID()
                  
          
                  return False, (flags | c4d.DESCFLAGS_DESC_LOADED)            
          
             
          
              def GetDEnabling(self, op, did, t_data, flags, itemdesc):        
          
                  return True
          
          
          if __name__ == "__main__":
              path, file = os.path.split(__file__)
              file = "icon.tif"
              new_path = os.path.join(path, "res", file)
              bitmap = bitmaps.BaseBitmap()
              bitmap.InitWith(new_path)
              plugins.RegisterObjectPlugin(id=PLUGIN_ID, str="redshift_lights_test", g=RedshiftLightsTest, description="redshift_lights_test", icon=bitmap,
                                           info=c4d.OBJECT_GENERATOR)
          
          

          Thanks,
          T.B

          1 Reply Last reply Reply Quote 0
          • ferdinandF Offline
            ferdinand
            last edited by ferdinand

            Hey @ThomasB,

            I do not think that this is an API issue. I do not meant with that that I will not help you, as this still happens in the context of a plugin, I say this simply to classify the issue.

            When I try to manually open your build_1.c4d file, it loads in 2026.2.0 but when I then press C on that light in question, I get exactly the output you report. And I cannot really explain why as this is just a normal rectangle shape area light (well, I sort of can, see below 😄 ).

            26b330be-2ffb-4079-94bd-e35821b41c29-image.png

            The plot however thickens when I try to open the file with 2026.3.1:

            3f42e837-826c-4145-87ae-9436d31c51f2-image.png

            This file seems to be somehow corrupted. After some poking around I manged to create this build_2.c4d which loads in 2026.3. But the light still did not work correctly. I then created a new RS light instance and copied over the whole data container via Get/SetData, which again resulted in a broken light. Only when I manually recreated the light by manually copying values, I ended up with a valid light. Which then also revealed that this light should have a much different light representation in the VP.

            Your light:

            8bb73cb1-8cf6-4851-9001-83dff031795e-image.png

            The manual copy:

            31f028b3-6054-4078-b9c0-82f04b49b7a9-image.png

            I.e., you seem to have there a fundamentally corrupted scene and especially light objects. The fact that I could reproduce this with a fresh light instance and a Get/SetData copy indicates this the data container of the light is corrupted. We could now start comparing the data containers of your light and the manually created one, to dive deeper, but I think I stop here for now. Did you programmatically modify this scene? Because your plugin only seems to load it. The question is now if you have more scenes like this. Otherwise I would just use my fixed scene (which also contains the fixed light) and move one.

            Cheers,
            Ferdinand

            PS: Okay, now I see it, the actual scene in much more complex.

            When you want to dig deeper yourself, a great tool to debug this would be mxutils.GetContainerTreeString. You can just dump both containers and then either visually compare them or use a diff tool. Or you use mxutils.GetParameterTreeString directly on the light objects.

            MAXON SDK Specialist
            developers.maxon.net

            ThomasBT 1 Reply Last reply Reply Quote 0
            • ThomasBT Online
              ThomasB @ferdinand
              last edited by ThomasB

              @ferdinand
              thank you for your time Ferdinand. We all really appreciate your work. Without you, there would be only half as many plugins for Cinema 4D.

              Oh man, I'm sorry about the corrupted scene.

              Did you programmatically modify this scene? Because your plugin only seems to load it.

              The Road to a Corrupted File

              • Since I prefer modeling in R23, I did my modeling work there and saved the scene in R23.
              • Then I opened it in the latest version, 2026.3.1.
              • It notified me that it needed to modify the Cinema 4D scene and that it might no longer work with older versions of Cinema 4D.
              • Then, I just saved over it normally using 2026.3.1. That version runs on the MRD license.
              • I just wanted to make sure it was saved using the latest version.
                ➡️Apparently, it didn't correctly convert the scene to the new Redshift core. I'll compare the two versions later using mxutils. For now, everything looks normal in the new scene.

              I didn't modify the scene via code.
              Otherwise, the only other explanation I can think of for the corrupted file structure is the ZIP compression or a temporary license problem, between R23 and the MRD License. R23 runs on a Commercial License, Redshift runs on MRD.

              New scene:
              However, I’ve now created and saved a completely new scene—exclusively in 2026.3.1—and uploaded it as a new plugin. The file cannot be corrupt at this stage. Using the mxutils methods reveals no issues.

              Result:
              However, the result is the same. Something seems to struggle with the conversion process during the "Make Editable" when those lights originate from a loaded virtual document.
              So, if I create the area light directly via code as you did and then press "C", then it works, it appears in the scene as a standard Redshift Area Light. But you simply can't generate everything via code, so I need the ability to take things from pre-made scenes.

              Important:
              I’ve gone a step further and implemented a button that simply extracts the light from the virtual document—or rather, the container—and inserts it into the scene. Oddly enough, the light is inserted correctly into the active document this way.
              The user could bring the lights into the scene before pressing "C"—that would be a workaround.
              However, the problem with "Make Editable" still persists.

              Download New Plugin Version

              I wish you a relaxing weekend. As a Maxon SDK specialist, your head must be spinning quite often.
              Cheers

              Thanks,
              T.B

              1 Reply Last reply Reply Quote 0
              • First post
                Last post