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
    • Unread
    • Recent
    • Tags
    • Users
    • Login

    Modifiying the normal-tag

    PYTHON Development
    0
    15
    2.2k
    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.
    • H
      Helper
      last edited by

      On 17/03/2014 at 01:49, xxxxxxxx wrote:

      I was afraid something with byte-reading and -writing would be inevitable.
      Thank you so much for you code, I'll try to wrap my head around it.
      I still don't get why the "SetAllHighlevelData()" funtction does not work as expected. At least it should accept the data you read using the "GetAllHighlevelData()" function.

      1 Reply Last reply Reply Quote 0
      • H
        Helper
        last edited by

        On 17/03/2014 at 11:53, xxxxxxxx wrote:

        Isn't the normal tag a read-only tag?
        I've always thought it was.

        -ScottA

        1 Reply Last reply Reply Quote 0
        • H
          Helper
          last edited by

          On 17/03/2014 at 15:04, xxxxxxxx wrote:

          I had exactly the same problem as hgcafe, as I wanted to set the normals with the "HighLevelData" functions which did not work at all (in Python). After some searching I found a C++ version of a similar code and tried to understand how the normals are stored. The main issue is to understand that a float value has to be converted to a 2byte signed integer. The normal vector has to be normalized, for each component a mapping between -1.0 ... 1.0 to -32000 ... 32000 has to be calculated. As the normaltag is a variabletag, the lowlevel functions

            
              VariableTag.GetLowlevelDataAddressW()   
              VariableTag.GetLowlevelDataAddressR()   
          

          can be used to get and set the bytes of a byte sequence. But be careful with that...

          1 Reply Last reply Reply Quote 0
          • H
            Helper
            last edited by

            On 17/03/2014 at 17:29, xxxxxxxx wrote:

            I'm having some trouble using your custom set_normals() method.
            It's throwing a type error.
            Any idea why? Am I using it wrong?

            import c4d  
            def float2bytes(f) :  
              int_value = int(math.fabs(f * 32000.0))  
              high_byte = int(int_value / 256)  
              low_byte = int_value - 256 * high_byte  
              
              if f < 0:  
                  high_byte = 255-high_byte  
                  low_byte = 255-low_byte  
              
              return (low_byte,high_byte)  
              
              
            def set_normals(normal_tag,polygon,normal_a,normal_b,normal_c,normal_d) :  
              normal_list = [normal_a,normal_b,normal_c,normal_d]  
              normal_buffer = normal_tag.GetLowlevelDataAddressW()  
              vector_size = 6  
              component_size = 2  
              
              for v in range(0,4) :  
                  normal = normal_list[v]  
              
                  for c in range(0,3) :  
                      low_byte, high_byte = float2bytes(normal[c]) #<--- TypeError: int is unscriptable  
              
                      normal_buffer[normal_tag.GetDataSize()*polygon+v*vector_size+c*component_size+0] = chr(low_byte)  
                      normal_buffer[normal_tag.GetDataSize()*polygon+v*vector_size+c*component_size+1] = chr(high_byte)  
              
            def main() :  
                
              obj = doc.GetActiveObject()  
              normalTag = obj.GetFirstTag() #Assuming the normal tag is the first tag  
              polys = obj.GetAllPolygons()  
              
              #Change the normals for the first polygon in the normal tag  
              set_normals(normalTag, polys[0], polys[0].a, polys[0].b, polys[0].c, polys[0].d)  
              
            if __name__=='__main__':  
              main()
            

            -ScottA

            1 Reply Last reply Reply Quote 0
            • H
              Helper
              last edited by

              On 18/03/2014 at 01:57, xxxxxxxx wrote:

              Just to add something here, the function "SetAllHighlevelData()" works and you can set normals, just only some of them.
              Let's say we have only polygon, according to the documentation there should be 12 integers to set (for each of the 4 vectors 3 values (x,y,z)). Reading the normals using the "GetAllHighlevelData()" function you get an integer array with the length of 12 as expected. Trying to set the normals using this array throws the error I mentioned before. When you only set an array with the length of 1 the function works (but isn't useful at all, because you can only set the x-value of the first vector).
              If you have 2 polygons, you are able to set an array with the length of 2, 3 polygons -> array with the length of 3, and so on. Maybe there is a trick to this, I don't know. But in fact you can set normals using this mehtod, only not the way you'd expect.
              Also a funny thing: "GetAllHighlevelData()" seems to scramble the order of the normals if you have more than one polygon. I don't think this is intended. Anyway it's easier to get just the normals using the "CreatePhongNormals()"-function.
              I'll give reverend's approach a try as soon as I have time.
              Phil

              1 Reply Last reply Reply Quote 0
              • H
                Helper
                last edited by

                On 18/03/2014 at 02:16, xxxxxxxx wrote:

                sorry, I did not explain how to call my functions...
                and thanks hgcafe for pointing out what works with the highlevel functions.
                I made the implementation similar to the uvwtag.SetSlow() function (for the parameters to use), so setting the normals for points a,b,c,d of polygon 0 to the "up" vector (0,1,0) would be:

                  
                        normal_a = c4d.Vector(0.0,1.0,0.0)   
                        normal_b = c4d.Vector(0.0,1.0,0.0)   
                        normal_c = c4d.Vector(0.0,1.0,0.0)   
                        normal_d = c4d.Vector(0.0,1.0,0.0)   
                        set_normals(normal_tag,0,normal_a,normal_b,normal_c,normal_d)   
                

                so set_normals expects a normal tag as 1st parameter, a polygon index number (int) as the 2nd parameter and the 4 normalized normal vectors.
                Unfortunately there is no SetSlow() for a normal tag...

                1 Reply Last reply Reply Quote 0
                • H
                  Helper
                  last edited by

                  On 18/03/2014 at 08:40, xxxxxxxx wrote:

                  Hmm. Nope.
                  That just changes the error to this: TypeError: 'c4d.Vector' object is unsubscriptable

                  -ScottA

                  1 Reply Last reply Reply Quote 0
                  • H
                    Helper
                    last edited by

                    On 18/03/2014 at 10:35, xxxxxxxx wrote:

                    hmm, which version of Cinema4D do you use?
                    iterating over Vector components was introduced in R14.014.
                    see the current Python SDK.

                      
                    Vector.__getitem__(self, key)   
                      
                        New in version R14.014.   
                      
                        Gets X, Y and Z components by index.   
                      
                      
                    Note: The Vector objects does not support item deletion. For instance by calling del(v[0]).   
                    Parameters:        
                      
                        key (int) – The component index.   
                        value (float) – The new vector component.   
                      
                    Raises IndexError:   
                            
                      
                    If the index key is out of range : 0<=key<2.   
                    

                    if you have a previous version you might to have to change the code...

                    1 Reply Last reply Reply Quote 0
                    • H
                      Helper
                      last edited by

                      On 18/03/2014 at 10:42, xxxxxxxx wrote:

                      maybe its another problem...
                      in your code you wrote:

                        
                          polys = obj.GetAllPolygons()   
                        
                          #Change the normals for the first polygon in the normal tag   
                          set_normals(normalTag, polys[0], polys[0].a, polys[0].b, polys[0].c, polys[0].d)   
                      

                      but polys is a list of CPolygons and therefore polys[0].a etc is an int and not a c4d.Vector.
                      You need to support c4d.Vector's for normal_a (and so on) as in my example call.

                      1 Reply Last reply Reply Quote 0
                      • H
                        Helper
                        last edited by

                        On 18/03/2014 at 12:05, xxxxxxxx wrote:

                        I'm using R13.
                        I'll keep trying to figure it out.
                        You've posted enough code that I should be able to figure it out eventually. It's just going to take me some time and effort to re-write it so it works for me.

                        Thanks a lot for the help and the code.
                        -ScottA

                        1 Reply Last reply Reply Quote 0
                        • H
                          Helper
                          last edited by

                          On 18/03/2014 at 13:07, xxxxxxxx wrote:

                          I think a modification like this should be enough to try it out:

                            
                                  component = [normal.x,normal.y,normal.z]   
                                  for c in range(0,3) :   
                                      low_byte, high_byte = float2bytes(component[c])   
                          
                          1 Reply Last reply Reply Quote 0
                          • H
                            Helper
                            last edited by

                            On 18/03/2014 at 14:43, xxxxxxxx wrote:

                            Yes. That fixed it.
                            Thanks a lot for the extra effort.🍺

                            I'll post my complete working script code so that way people can at least have something that works that they can cut and paste into their script manager to start off with.

                            import c4d  
                            import math  
                              
                            def float2bytes(f) :  
                              int_value = int(math.fabs(f * 32000.0))  
                              high_byte = int(int_value / 256)  
                              low_byte = int_value - 256 * high_byte  
                              
                              if f < 0:  
                                  high_byte = 255-high_byte  
                                  low_byte = 255-low_byte  
                              
                              return (low_byte,high_byte)  
                              
                              
                            def set_normals(normal_tag,polygon,normal_a,normal_b,normal_c,normal_d) :  
                              
                              normal_list = [normal_a, normal_b, normal_c, normal_d]  
                              normal_buffer = normal_tag.GetLowlevelDataAddressW()  
                              vector_size = 6  
                              component_size = 2  
                              
                              for v in range(0,4) :  
                                  normal = normal_list[v]  
                                  component = [normal.x, normal.y, normal.z]  
                              
                                  for c in range(0,3) :  
                                      low_byte, high_byte = float2bytes(component[c])  
                              
                                      normal_buffer[normal_tag.GetDataSize()*polygon+v*vector_size+c*component_size+0] = chr(low_byte)  
                                      normal_buffer[normal_tag.GetDataSize()*polygon+v*vector_size+c*component_size+1] = chr(high_byte)  
                              
                              
                            def main() :  
                                
                              obj = doc.GetActiveObject()  
                              normal_tag = obj.GetFirstTag() #Assuming the normal tag is the first tag  
                              
                              #These four variabls will be used to change the normal values of a polygon  
                              normal_a = c4d.Vector(0.0,1.0,0.0)  
                              normal_b = c4d.Vector(0.0,1.0,0.0)  
                              normal_c = c4d.Vector(0.0,1.0,0.0)  
                              normal_d = c4d.Vector(0.0,1.0,0.0)  
                              
                              #Set the first polygon normals in the normals tag using the above values  
                              set_normals(normal_tag, 0, normal_a, normal_b, normal_c, normal_d)  
                                
                              obj.Message(c4d.MSG_UPDATE)  
                              c4d.EventAdd()  
                              
                            if __name__=='__main__':  
                              main()
                            

                            -ScottA

                            1 Reply Last reply Reply Quote 0
                            • H
                              Helper
                              last edited by

                              On 19/03/2014 at 03:03, xxxxxxxx wrote:

                              Hey guys. Thank you very much for your replies and input.
                              I had time to test reverend's approach and it works. Really cool. Now editing the phong-normals should be a breeze.
                              Phil

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