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

    Plane by Python Generator

    Cinema 4D SDK
    python
    5
    18
    3.3k
    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.
    • FlavioDinizF
      FlavioDiniz @indexofrefraction
      last edited by FlavioDiniz

      @indexofrefraction I was experimenting this exactly right now!
      I'm sure it's not done in the most optimized way, but it does return a beautiful quad polygon, here is:

      import c4d
      
      def main():
      
          poly = c4d.PolygonObject(4,1)
      
      
          a = c4d.CPolygon(0,1,2,3)
      
      
          poly.SetPolygon(0,a)
          poly.SetPoint(0, c4d.Vector(0,0,0))
          poly.SetPoint(1, c4d.Vector(50,0,0))
          poly.SetPoint(3, c4d.Vector(0,0,-50))
          poly.SetPoint(2, c4d.Vector(50,0,-50))
      
      
          return poly
      

      edit: this is just for generating a polygon, I don't know how to make parametric subdivisions on it.

      1 Reply Last reply Reply Quote 0
      • indexofrefractionI
        indexofrefraction
        last edited by indexofrefraction

        thanks Flavio !

        with this i came that far...
        it works, but hogs down c4d very fast! (12 subdivisons are already causing a huge lag)
        also writing back to the userdata causes an indefinite loop 😕

        what i need is are planes of 5000 to 10000m with subdivisions of 15 to 17,
        which would result in segment sizes of 7.5 to 15cm [ 500000 / (2^15) = ~15 ]

        is there a way to

        • only update the plane if a parameter changes?
        • update the userdata with the calculated segment size without causing the loop?
        • get the already created plane and to not create/subdivide it again, if the parameters have not changed?
          (not to re-create on refreshes of nothing changed)

        Python Generator
        UserData 1 : Size (Float)
        UserData 3 : Subdivision (Integer)
        UserData 5 : Segment Size (Static String)

        import c4d
        
        def main():
            w = op[c4d.ID_USERDATA,1] # just one dimension
            s = op[c4d.ID_USERDATA,3] # subdivision
            # op[c4d.ID_USERDATA,5] = str(w / pow(2, s)) # feedback causes indefinite loop :-/
        
            p = c4d.PolygonObject(4,1)
            p.SetPolygon(0, c4d.CPolygon(3,2,1,0))
            p.SetPoint(0, c4d.Vector(-w/2, 0, -w/2))
            p.SetPoint(1, c4d.Vector(w/2, 0, -w/2))
            p.SetPoint(2, c4d.Vector(w/2, 0, w/2))
            p.SetPoint(3, c4d.Vector(-w/2, 0, w/2))
        
            bc = c4d.BaseContainer()
            bc[c4d.MDATA_SUBDIVIDE_SUB] = s 
        
            c4d.utils.SendModelingCommand(c4d.MCOMMAND_SUBDIVIDE,
                [p], c4d.MODELINGCOMMANDMODE_ALL, bc, doc)
        
            #c4d.EventAdd() # is it needed here?
            #print "done"
        
            return p
        
        1 Reply Last reply Reply Quote 0
        • CairynC
          Cairyn
          last edited by

          Just food for thought:
          I once had the same desire to create landscapes in optimum resolution, but I came to realize that it is necessary to create a dynamic subdivision that reserves the higher resolutions for spots close to the camera. The numbers just accumulate too fast:

          Subdivision of 15 means
          2^15 = 32768 segments in either direction, which amounts to
          32768^2 = 1,073,741,824 polygons (one gigapoly 😁).
          Almost the same number of points is needed to define these polygons
          (strictly one row and one line more, so 32769^2 = 1,073,807,361).
          Each point is a vector from three floats, which is eight bytes each, resulting in a payload of roundabout 8GB for storing the points alone. Each polygon refers to four points which requires an index of four bytes at least (too lazy to look up the type now), which is another 16GB.

          Thus, your plane has a memory footprint of 24GB for (2^15)^2 segments (for 2^17 it's 16 times more, or 384GB). A well equipped machine may still be able to work with that, but it's not practical, and causes inavoidable lags and most likely swapping. Not having a special datatype underlying, C4D may need to copy that data for rendering, too...

          1 Reply Last reply Reply Quote 0
          • indexofrefractionI
            indexofrefraction
            last edited by

            @ Cairyn

            i know that this hogs down c4d at some point.
            that is exactly why i want a dynamically adjustable object, not a fixed subdivided polygon object
            like this i can test the size/subdivision my machine can handle

            of course it would be even better to have a plane with a polygon-resolution-fall off
            but one step at the time 🙂

            for now it would be interesting why c4d lags that fast...
            i suppose there is something not good in this code,...

            1 Reply Last reply Reply Quote 0
            • ManuelM
              Manuel
              last edited by Manuel

              Hello,

              mmm Ocean 😄

              as @Cairyn mention, this way is really too "brute force"
              If on top of that you want to add a deformer to simulate the ocean, you are going to kill your computer.

              You should search how you can build a mesh taking into account the screen/camera space. There's no point into having that kind of details km away from the camera. (I'm sure you are already aware of that)

              You should try to build your own geometry instead of using the modeling command subdivide.

              other ideas :

              you don't want to go with a plugins because of the render farm but remember that you can still export the animated mesh with alembic. Of course that will create a huge file, but will reduce the render time.

              You can also have a "light" grid using one of the Ocean deformer that are available out there and use a displacement map (you can have some feedback of that on the viewport with the viewport tessellation).

              This is really shot depending also.

              Cheers
              Manuel

              MAXON SDK Specialist

              MAXON Registered Developer

              1 Reply Last reply Reply Quote 1
              • indexofrefractionI
                indexofrefraction
                last edited by indexofrefraction

                hm.. ok...

                i guess what would be best is an adaptive plane....

                • outer size, ie 5km
                • center size, ie 500m
                • outer segment size, 10m
                • center segment size, 10cm
                • falloff type (linear/exponential/...)

                i still wonder if the code above is good,
                or if it hogs down because of event loops

                1 Reply Last reply Reply Quote 0
                • ManuelM
                  Manuel
                  last edited by

                  hello,

                  The generator is already caching your object. That what "optimize cache" checkbox is for, you don't have to deal with CheckDirty and things like that.
                  If the generator see nothing different, it will send the cache. If you change a parameter, it will rebuild the object (execute the code, update the cache etc)

                  Try to pick a simple plane and launch the subdivide command by hand, you will see that after some, the command will start to be slow. Go step by step, start with one single polygon, and subdivide by 1, after 16 777 216 polygons, you will see the command take some times to go to 67 108 864 poly.

                  Cinema 4D should start to show that he's not happy. And it's not a generator.

                  Your code doesn't loop or anything, you are just asking for too much.

                  Cheers
                  Manuel

                  MAXON SDK Specialist

                  MAXON Registered Developer

                  1 Reply Last reply Reply Quote 0
                  • FlavioDinizF
                    FlavioDiniz
                    last edited by FlavioDiniz

                    @indexofrefraction I know this is not what you've asked, but it might help you:
                    Redshift does have a method of subdivision called screen space adaptive, which make more subdivisions on polygons that are close to the camera and less to those that are far from the camera. So it relatively lightweight because it happen only at render time and still bring good results.
                    alt text

                    1 Reply Last reply Reply Quote 0
                    • indexofrefractionI
                      indexofrefraction
                      last edited by indexofrefraction

                      thank you guys,

                      im intrigued to make something like this as a Python Generator

                      • starting in the center
                      • generate a square of x square polygons
                      • then at some point double the polygon size
                      • generate x borders with the new polygon size
                      • etc etc

                      not such an easy algorithm, tough

                      ... isnt there a built in solution for something like that?
                      adaptive / falloff subdivision ....

                      1 Reply Last reply Reply Quote 0
                      • ManuelM
                        Manuel
                        last edited by Manuel

                        hello,

                        There's no such a function as we can tell in the sdk.

                        There's not one single solution for your problem. As it's for Ocean Simulation your problem is more 2D than 3D. You need to build a plan.

                        You can create points in your space and use a 2D Delaunay triangulation, that could work.
                        You can create a 2D grid on screen space and project that grid into world space.

                        I don't know witch one works and witch one could be the fastest.

                        a very naive way to go is this one but maybe that will help you to try to find formula and start somewhere.

                        import c4d
                        #Welcome to the world of Python
                        
                        
                        def main():
                            # Width
                            l = 5000
                            # Height
                            L = 5000
                        
                            # Segments per lengh
                            lSegments = 20
                            LSegments = 10
                        
                            # Space beetween points
                            lSpace = l /(lSegments - 1)
                            LSpace = L /(LSegments - 1)
                        
                            # halfPoint
                            lhalfSegment = lSegments * 0.5
                        
                            # Creates points
                            points = []
                            for z in xrange(LSegments):
                                for x in xrange (lSegments):
                                    p = c4d.Vector(0.0)
                                    # This is where you can change the formula to change point position
                                    p.x = lSpace * ( x - lhalfSegment) 
                                    p.z = LSpace * z
                                    points.append(p)
                        
                            # Creates the polygon
                            pol = c4d.BaseObject(c4d.Opolygon)
                        
                            # Points number and polyCount
                            ptCnt = lSegments * LSegments
                            polyCnt =  (lSegments - 1 )* (LSegments - 1)
                        
                            # Resize Object
                            pol.ResizeObject(ptCnt, polyCnt)
                        
                            # Updates points position
                            pol.SetAllPoints(points)
                            polyIndex = 0
                            
                            # Creates CPolygon structure for each polygon (points ID for each polygon)
                            for x in xrange(lSegments - 1):
                                for y in xrange (LSegments - 1):
                                    xmove = x + y * lSegments
                                    ymove =  x + y * lSegments + lSegments
                                    cpol = c4d.CPolygon( xmove ,ymove ,ymove + 1 ,xmove + 1 )    
                                    pol.SetPolygon(polyIndex , cpol)
                                    polyIndex += 1
                            # Updates the polygon object
                            pol.Message(c4d.MSG_UPDATE)    
                        
                            # Done
                            return pol
                        
                        

                        Cheers
                        Manuel

                        MAXON SDK Specialist

                        MAXON Registered Developer

                        1 Reply Last reply Reply Quote 0
                        • indexofrefractionI
                          indexofrefraction
                          last edited by indexofrefraction

                          thank you manuel,

                          atm i'm going another way...

                          1. make a plane with a low subdivision
                          2. select polygons with a distance from the center
                          3. subdivide
                            repeat at 2. with lower distance
                            etc...

                          i guess this is probably faster anyway
                          (compared to setting up all points manually)

                          ps.
                          adjacent polygons are not sharing the same points in your code, right?
                          this is the tricky thing with setting up a plane, i guess .)

                          ManuelM 1 Reply Last reply Reply Quote 0
                          • ManuelM
                            Manuel @indexofrefraction
                            last edited by Manuel

                            hello,

                            yea you can try this way also, but selecting polygons closer to camera will take some time because there will be more and more polygons. But that can do the trick.

                            @indexofrefraction said in Plane by Python Generator:

                            adjacent polygons are not sharing the same points in your code, right?
                            this is the tricky thing with setting up a plane, i guess .)

                            Of course they are. But there's no UVs.

                            Cheers
                            Manuel

                            MAXON SDK Specialist

                            MAXON Registered Developer

                            1 Reply Last reply Reply Quote 0
                            • indexofrefractionI
                              indexofrefraction
                              last edited by indexofrefraction

                              still working on it, it looks very promising...

                              generating the geometry seems to work fast enough, but...

                              • adding a phong tag to the python generator has no effect
                                the solution for this is here:
                                https://developers.maxon.net/forum/topic/10383/13881_python-generator--phong-tag/2

                              • but would it be possible to get UVs for such a plane?
                                c4d.utils.GenerateUVW() ? TempUVHandle ?

                              EDIT:
                              similar to the phong tag solution i tried to add an uvw tag to the generators cache object with:

                                  uvw = c4d.BaseTag(c4d.Tuvw)
                                  polygon.InsertTag(uvw)
                              

                              now, if i convert the generator to polygons I get:

                              A problem with this project has been detected:
                              Object "OceanPlane" - Tag 5671 not in sync.
                              Please save and contact MAXON Support
                              with a description of the last used commands, actions or plugins.

                              the object then has an uv tag, tough,
                              but mapping does not work, yet.

                              any tips to get working uv coordinates on such a plane object?

                              1 Reply Last reply Reply Quote 0
                              • ManuelM
                                Manuel
                                last edited by Manuel

                                hello,

                                I've updated my code, there were some bugs with type and things like that.
                                Also added the phong tag and a way to create a UVW tag in the most easiest way i found.

                                import c4d
                                #Welcome to the world of Python
                                
                                
                                def main():
                                    # Width
                                    l = 500
                                    # Height
                                    L = 500
                                
                                    # Segments per lengh
                                    lSegments = 500
                                    LSegments = 500
                                
                                    # Space beetween points
                                    lSpace = l /(lSegments - 1.0)
                                    LSpace = L /(LSegments - 1.0)
                                
                                    # halfPoint
                                    lhalf = l * 0.5
                                
                                    # Creates points
                                    points = []
                                    for z in xrange(LSegments):
                                        for x in xrange (lSegments):
                                            p = c4d.Vector(0.0)
                                            # This is where you can change the formula to change point position
                                            p.x = lSpace * x - lhalf
                                            p.z = LSpace * z
                                            points.append(p)
                                
                                    # Creates the polygon
                                    pol = c4d.BaseObject(c4d.Opolygon)
                                
                                    # Points number and polyCount
                                    ptCnt = lSegments * LSegments
                                    polyCnt =  (lSegments - 1 )* (LSegments - 1)
                                
                                    # Resize Object
                                    pol.ResizeObject(ptCnt, polyCnt)
                                
                                    # Updates points position
                                    pol.SetAllPoints(points)
                                    polyIndex = 0
                                
                                    # Creates CPolygon structure for each polygon (points ID for each polygon)
                                    for x in xrange(lSegments - 1):
                                        for y in xrange (LSegments - 1):
                                            xmove = x + y * lSegments
                                            ymove =  x + y * lSegments + lSegments
                                            cpol = c4d.CPolygon( xmove ,ymove ,ymove + 1 ,xmove + 1 )
                                            pol.SetPolygon(polyIndex , cpol)
                                            polyIndex += 1
                                
                                    # Adds a phong tag (copy from generator or create a new one)
                                    # Checks for phong tag on python generator
                                    phong = op.GetTag(c4d.Tphong)
                                    if phong is None:
                                        # Creates one, if non-existent (careful with such operations, make sure, the tag is only created once)
                                        phong = op.MakeTag(c4d.Tphong)
                                    if phong is not None:
                                        pol.InsertTag(phong.GetClone()) # important to insert a clone of the original phong tag
                                
                                
                                
                                    # Creates a new texture tag
                                    matTag = c4d.BaseTag(c4d.Ttexture)
                                    pol.InsertTag(matTag)
                                
                                    # Changes the settings of that texture tag to cubic
                                    matTag[c4d.TEXTURETAG_PROJECTION] = c4d.TEXTURETAG_PROJECTION_CUBIC
                                    matTag[c4d.TEXTURETAG_POSITION] =c4d.Vector(0 , 0, L * 0.5  )
                                    matTag[c4d.TEXTURETAG_SIZE,c4d.VECTOR_X] = l * 0.5
                                    matTag[c4d.TEXTURETAG_SIZE,c4d.VECTOR_Z] = L * 0.5
                                
                                    # Generates uvwCoordinates from the texture tag
                                    uvwTag = c4d.utils.GenerateUVW(pol, pol.GetMg(), matTag, pol.GetMg())
                                    # Inserts the uvwtag
                                    pol.InsertTag(uvwTag)
                                
                                    # Removes the TEXTURE tag so we can add one on the generator.
                                    matTag.Remove()
                                
                                    # Updates the polygon object
                                    pol.Message(c4d.MSG_UPDATE)
                                
                                    return pol
                                

                                Cheers
                                Manuel

                                MAXON SDK Specialist

                                MAXON Registered Developer

                                1 Reply Last reply Reply Quote 0
                                • indexofrefractionI
                                  indexofrefraction
                                  last edited by indexofrefraction

                                  Hey thanks ALOT, Manuel !

                                  i'm creating the plane in a different way,
                                  because i double the polygon sizes with distance
                                  still, i must check your code for learning!

                                  the phong & material tag solution is gold 🙂

                                  EDIT:
                                  all works like a charm, now 🙂
                                  topic solved!

                                  1 Reply Last reply Reply Quote 0
                                  • ManuelM
                                    Manuel
                                    last edited by

                                    hiya,

                                    Feel free to share your code (if you want of course) as it could help other people.

                                    If you think your question is solved, please change the states of this thread to solved.

                                    Cheers
                                    Manuel

                                    MAXON SDK Specialist

                                    MAXON Registered Developer

                                    1 Reply Last reply Reply Quote 1
                                    • M
                                      mp5gosu
                                      last edited by

                                      Yes, I'd like to see it of course. Maybe you can share it via Github so others can for and contribute to it. 🙂

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