Maxon Developers Maxon Developers
    • Documentation
      • Cinema 4D Python API
      • Cinema 4D C++ API
      • Cineware 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
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Phong Tag with ObjectData

    Cinema 4D SDK
    python
    4
    6
    963
    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.
    • ?
      A Former User
      last edited by

      Hello,
      I'm trying to get a Phong tag to work with my ObjectData plugin similar to the Phong tags assigned to primitive Polygon Objects such as Sphere & Cube.

      Using the py-rounded_tube_r13.pyp as reference, I'm currently calling a function from ObjectData.GetVirtualObjects that sets the Phong with BaseObject.SetPhong. In my ObjectData I'm creating a Phong tag in my overridden NodeData.Init function. The Phong Tag is not having any effect unless I make the Object Editable. I've tried removing the SetPhong call, but it doesn't make a difference.

      How can I get the Phong tag to have an effect on my ObjectData object?

      Thank you!

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

        Hi,

        could you show us an example for your code not working? On R23 SetPhong seems to work properly, when tested from a Python generator object.

        import c4d
        
        def main():
            """
            """
            node = c4d.BaseList2D(c4d.Osphere)
            if op[c4d.ID_USERDATA, 1]:
                node.SetPhong(True, True, 3.14159 * .125)
            return node
        

        smooth_sphere.c4d

        Cheers,
        zipit

        MAXON SDK Specialist
        developers.maxon.net

        1 Reply Last reply Reply Quote 0
        • r_giganteR
          r_gigante
          last edited by

          hi @blastframe, usually the BaseObject::SetPhong() is not called in ObjectData::GetVirtualObjects() but rather in NodeData::Message() when the message intercepted is MSG_MENUPREPARE.

          Something like

          if type == c4d.MSG_MENUPREPARE:
              node.SetPhong(True, True, c4d.utils.DegToRad(40.0))
          

          Cheers, R

          ? 1 Reply Last reply Reply Quote 0
          • ?
            A Former User @r_gigante
            last edited by A Former User

            Hi @r_gigante & @zipit,
            Thank you both for your replies. I am still experiencing the issue, unfortunately. I can set the Phong angle manually, but I want to set (or override) my object's Phong angle with a tag. As can be seen in this image, the Phong tag is at 91⁰.
            bc6daa42-e84a-4c99-a033-7414e135dec7-image.png

            It should look like this. (side note: when the object is made editable, it creates a Phong tag with the angle set with SetPhong and deletes the previous one):
            057fc233-14ec-4270-a677-5596801181af-image.png

            @zipit
            My issue is not with setting the Phong. My issue is that I cannot surface the Phong tag to the user as is done with the Cinema 4D Primitives. Here is a code example that shows how the Phong tag I'm creating does not associate with the object's Phong tag until it is made editable.

            import os
            import math
            import sys
            import c4d
            from c4d import utils
            
            PLUGIN_ID = 1234569
            
            class PhongDemoObject(c4d.plugins.ObjectData):
                size = 100
            
                def __init__(self, *args):
                    super(PhongDemoObject, self).__init__(*args)
                    self.SetOptimizeCache(True)
            
                def Init(self, op):
                    tag = op.MakeTag(c4d.Tphong)
                    tag[c4d.PHONGTAG_PHONG_ANGLELIMIT] = True
                    tag[c4d.PHONGTAG_PHONG_ANGLE] = c4d.utils.DegToRad(91.0)
                    tag[c4d.PHONGTAG_PHONG_USEEDGES] = False
                    c4d.EventAdd()
            
                    return True
            
                def GetVirtualObjects(self, op, hierarchyhelp):
                    ret = self.CreateMyObject()
                    if ret is None:
                        return None
                    ret.SetName(op.GetName())
                    return ret
            
                def CreateMyObject(self):
                    node = c4d.PolygonObject(8, 6)
            
                    node.SetPoint(0, c4d.Vector(-self.size,-self.size,-self.size))
                    node.SetPoint(1, c4d.Vector(-self.size,self.size,-self.size))
                    node.SetPoint(2, c4d.Vector(self.size,-self.size,-self.size))
                    node.SetPoint(3, c4d.Vector(self.size,self.size,-self.size))
                    node.SetPoint(4, c4d.Vector(self.size,-self.size,self.size))
                    node.SetPoint(5, c4d.Vector(self.size,self.size,self.size))
                    node.SetPoint(6, c4d.Vector(-self.size,-self.size,self.size))
                    node.SetPoint(7, c4d.Vector(-self.size,self.size,self.size))
            
                    node.SetPolygon(0, c4d.CPolygon(3,1,7,5))
                    node.SetPolygon(1, c4d.CPolygon(3,5,4,2))
                    node.SetPolygon(2, c4d.CPolygon(4,6,0,2))
                    node.SetPolygon(3, c4d.CPolygon(6,7,1,0))
                    node.SetPolygon(4, c4d.CPolygon(0,1,3,2))
                    node.SetPolygon(5, c4d.CPolygon(4,5,7,6))
            
                    node.SetPhong(True, True, c4d.utils.DegToRad(40.0))
            
                    node.Message(c4d.MSG_UPDATE)
                    return node
            
            """
                #this throws an error:
                #AttributeError: 'function' object has no attribute 'im_func'
                def Message(self, node, type, data):
                    if type == c4d.MSG_MENUPREPARE:
                        node.SetPhong(True, True, c4d.utils.DegToRad(40.0))
                        return True
            """
            
            if __name__ == "__main__":
                c4d.plugins.RegisterObjectPlugin(id=PLUGIN_ID,
                                                 str="PhongDemoObject",
                                                 g=PhongDemoObject,
                                                 description="phongdemoobject",
                                                 icon=None,
                                                 info=c4d.OBJECT_GENERATOR )
            
            

            I got some errors without including the res folder, so I've uploaded it if you wish to demo it on your machine:
            Phong Demo Object.zip

            @r_gigante
            I am calling BaseObject::SetPhong() as it is done in the example: py-rounded_tube_r13.pyp. In that file, the method that sets the Node's points & then the Phong (GenerateLathe) is called from ObjectData::GetVirtualObjects().

            Using the code below threw this error AttributeError: 'function' object has no attribute 'im_func':

                def Message(self, node, type, data):
                    if type == c4d.MSG_MENUPREPARE:
                        node.SetPhong(True, True, c4d.utils.DegToRad(40.0))
            

            Am I doing this incorrectly?

            Thanks again.

            1 Reply Last reply Reply Quote 0
            • M
              m_adam
              last edited by m_adam

              Hi @blastframe I think you get the concept wrong, Generator doesn't have a "proper" Phong tag, or at least the Phong tag you apply to it has no real meaning since Phong is not a hierarchical tag(like Texture is), but it affects only the current object and a generator don't have any Polygon Information.
              With that's said this Phong tag on the generator is very useful because it let you expose parameter to the user in a meaningful manner, so the Generator can know for each Polygon Object it will generate, it can basically Retrieve a clone of this Phong and apply the same value. But the generator still has the liberty to not do it.

              So the proper workflow is

              • Create a Tag in the MSG_MENUPREPARE so you expose to the user a UI to control the Phong shading.
              • Attach a Clone of this Tag to all PolygonObject you generate within your Generator.

              So this gives us code like that:

              import os
              import math
              import sys
              import c4d
              from c4d import utils
              
              PLUGIN_ID = 1234569
              
              
              class PhongDemoObject(c4d.plugins.ObjectData):
                  size = 100
              
                  def __init__(self, *args):
                      super(PhongDemoObject, self).__init__(*args)
                      self.SetOptimizeCache(True)
              
                  def GetVirtualObjects(self, op, hierarchyhelp):
                      ret = self.CreateMyObject(op)
                      if ret is None:
                          return None
              
                      ret.SetName(op.GetName())
                      return ret
              
                  def CreateMyObject(self, node):
                      newObj = c4d.PolygonObject(8, 6)
              
                      newObj.SetPoint(0, c4d.Vector(-self.size,-self.size,-self.size))
                      newObj.SetPoint(1, c4d.Vector(-self.size,self.size,-self.size))
                      newObj.SetPoint(2, c4d.Vector(self.size,-self.size,-self.size))
                      newObj.SetPoint(3, c4d.Vector(self.size,self.size,-self.size))
                      newObj.SetPoint(4, c4d.Vector(self.size,-self.size,self.size))
                      newObj.SetPoint(5, c4d.Vector(self.size,self.size,self.size))
                      newObj.SetPoint(6, c4d.Vector(-self.size,-self.size,self.size))
                      newObj.SetPoint(7, c4d.Vector(-self.size,self.size,self.size))
              
                      newObj.SetPolygon(0, c4d.CPolygon(3, 1, 7, 5))
                      newObj.SetPolygon(1, c4d.CPolygon(3, 5, 4, 2))
                      newObj.SetPolygon(2, c4d.CPolygon(4, 6, 0, 2))
                      newObj.SetPolygon(3, c4d.CPolygon(6, 7, 1, 0))
                      newObj.SetPolygon(4, c4d.CPolygon(0, 1, 3, 2))
                      newObj.SetPolygon(5, c4d.CPolygon(4, 5, 7, 6))
              
                      # If the generator already have a PhongTag, jsut clone it otherwise define it a 92° phong shading
                      phongTag = node.GetTag(c4d.Tphong)
                      if phongTag is not None:
                          newTag = phongTag.GetClone(c4d.COPYFLAGS_NONE)
                          newObj.InsertTag(newTag)  # Add the cloned tag to the new Polygon Object present only in the cache
                      else:
                          newObj.SetPhong(True, True, c4d.utils.DegToRad(92.0))
              
                      newObj.Message(c4d.MSG_UPDATE)
                      return newObj
              
                  def Message(self, node, type, data):
                      # On the creation of the Object, via the Menu create a Phong tag on the generator
                      # c4d.BaseList2D(1234569) will not trigger it
                      if type == c4d.MSG_MENUPREPARE:
                          # Create a phong tag and set the default value to 92° (so we see the phong shading)
                          node.SetPhong(True, True, c4d.utils.DegToRad(92.0))
                      return True
              
              
              if __name__ == "__main__":
                  c4d.plugins.RegisterObjectPlugin(id=PLUGIN_ID,
                                                   str="phongdemoobject",
                                                   g=PhongDemoObject,
                                                   description="phongdemoobject",
                                                   icon=None,
                                                   info=c4d.OBJECT_GENERATOR )
              

              Regarding your issue about AttributeError: 'function' object has no attribute 'im_func': As written in the doc of NodeData.Message you are supposed to return a bool. (I agree the code sample is a bit weird because it doesn't show the return statement, I will fix it)

              I've opened a BugReport since the error could be more explicit I will look at it but I guess this is a leftover of Python2.7 since im_func is removed in Python3.

              If you have any questions, please let me know,
              Cheers,
              Maxime.

              MAXON SDK Specialist

              Development Blog, MAXON Registered Developer

              1 Reply Last reply Reply Quote 1
              • ?
                A Former User
                last edited by A Former User

                It's working! 😄 Thank you @zipit , @r_gigante , & @m_adam ! Have an excellent weekend.

                A note for future readers
                One issue with my demo code is I wasn't passing the op from GetVirtualObjects to the CreateMyObject method. @m_adam created a new object (newObj) and only calls GetTag on the op (variable name: node).

                phongTag = node.GetTag(c4d.Tphong)
                
                1 Reply Last reply Reply Quote 0
                • First post
                  Last post