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
    • Register
    • Login

    Convert 3D space to 2D Space

    PYTHON Development
    0
    6
    984
    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 04/07/2018 at 03:36, xxxxxxxx wrote:

      Hey Everyone,

      Just wanted to know if anyone can point me in the right direction.

      Im looking to convert a 3D (world) space, point co-ordinate into a 2D camera space co-ordinate.

      Is this possible with the python SDK?

      Any info or a nudge in the right direction is much appreciated!

      Cheers,

      Cerac

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

        On 04/07/2018 at 12:22, xxxxxxxx wrote:

        Check out the BaseView class
        BaseView::WC() or BaseView::WC_V() is what you most likely are looking for.

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

          On 05/07/2018 at 02:12, xxxxxxxx wrote:

          Hi Ceracticus,

          As Daniel already pointed you BaseView.WC and BaseView.WC_V is the way to go.

          Additionally, I would like to point you to the C++ manual which can give you some valuable information even for python.

          Cheers,
          Maxime

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

            On 05/07/2018 at 09:53, xxxxxxxx wrote:

            Hey Both,

            thanks so much for your suggestions, massively helpful.

            Managed to get 90% of the way with looking up other examples on this site, plus your feedback which is really great.

            What im essentially doing is rebuilding the interactive render region crop function out of guides (converted from world to screen space) then plugging these values into the active render setting.

            Ive got everything working as expected - apart from when a camera has film offset. I know i can access this data which is great.

            [c4d.CAMERAOBJECT_FILM_OFFSET_Y]``` [c4d.CAMERAOBJECT_FILM_OFFSET_X]`

            Does anyone know what the best way of taking this into account whilst running my code?

              
            def main() :  
                
              
              rd = doc.GetActiveRenderData()  
              rd_w = rd[c4d.RDATA_XRES_VIRTUAL]  
              rd_h = rd[c4d.RDATA_YRES_VIRTUAL]  
              bd = doc.GetActiveBaseDraw()       # Get current view  
              sf = bd.GetSafeFrame() #SafeFrame  
              
              obj = op.GetObject()               # Get Null  
              cam = obj[c4d.ID_USERDATA,2]       # Get Camera  
              top = obj[c4d.ID_USERDATA,3]       # GetGuideObjects  
              bottom = obj[c4d.ID_USERDATA,7]  
              left = obj[c4d.ID_USERDATA,8]  
              right = obj[c4d.ID_USERDATA,9]  
              switch = obj[c4d.ID_USERDATA,4]           # Get Switch  
              cZ = cam[c4d.CAMERAOBJECT_TARGETDISTANCE] #z-distance  
              
              if switch:  
              
                  # +-------------------------- TOP IRR  
                
                  topPos = top.GetMg().off #top global position  
                  top_v = bd.WS(topPos) #World2Screen  
                
                
                  top_v[0] = (top_v[0] - sf["cl"])/(sf["cr"]-sf["cl"])  
                  top_v[1] = (top_v[1] - sf["ct"])/(sf["cb"]-sf["ct"])  
                  top_v[2] = (cZ-top_v[2])/cZ  
              
                  top_pos = top_v[1] #Gets Y pos from vector  
              
                  # Rangemap the result to IRR space  
                  irrTop_min = c4d.utils.RangeMap(top_pos, 0, 1, 0, rd_h, True)  
                  irrTop_max = 0  
                
                  # If its over halfway - reverse it  
                  if irrTop_min >= (rd_h/2) :  
                      irrTop_max = c4d.utils.RangeMap(irrTop_min, rd_h, rd_h/2, 0, rd_h/2,True)   
                      rd[c4d.RDATA_RENDERREGION_TOP] = int(irrTop_max)  
                    
                  else:  
                      pass
            

            Thanks again!

            Cerac

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

              On 09/07/2018 at 07:09, xxxxxxxx wrote:

              Hi Ceracticus,

              Actually, WS already take care of the film offset, so you just have to do something like that.

                  rd = doc.GetActiveRenderData()
                  rd_w = rd[c4d.RDATA_XRES_VIRTUAL]
                  rd_h = rd[c4d.RDATA_YRES_VIRTUAL]
                  
                  bd = doc.GetActiveBaseDraw()
                  viewX = bd.GetFrame()["cr"]
                  viewY = bd.GetFrame()["cb"]
                  sf = bd.GetSafeFrame() #SafeFrame
                  cam = bd.GetSceneCamera(doc)
                
                  top = doc.GetFirstObject().GetMg().off
                  bot = doc.GetFirstObject().GetNext().GetMg().off
                  left = doc.GetFirstObject().GetNext().GetNext().GetMg().off
                  right = doc.GetFirstObject().GetNext().GetNext().GetNext().GetMg().off
                
              	# Get pixels counts between top obj and the frame, then scale this pixel count according to the ratio between viewport size and render size.
                  top_p = max(0, bd.WS(top).y - sf["ct"]) * rd_h / viewY 
                  bot_p = max(0, sf["cb"] - bd.WS(bot).y) * rd_h / viewY
                  left_p = max(0, bd.WS(left).x - sf["cl"]) * rd_w / viewX
                  right_p = max(0, sf["cr"] - bd.WS(right).x) * rd_w / viewX
                  
                  rd[c4d.RDATA_RENDERREGION_TOP] = int(top_p)
                  rd[c4d.RDATA_RENDERREGION_BOTTOM] = int(bot_p)
                  rd[c4d.RDATA_RENDERREGION_LEFT] = int(left_p)
                  rd[c4d.RDATA_RENDERREGION_RIGHT] = int(right_p)
                  
                  c4d.EventAdd()
              

              On a side topic, please use [ code] [ /code] to insert code in your post, it increases the readability of them.

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

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

                On 11/07/2018 at 01:05, xxxxxxxx wrote:

                Thanks Maxime,

                i got there in the end, my solution was far less elegant than yours though, so thank you for spending the time to look through my code, i can certainly learn lots from your approach.

                Apologies also for my scrappy code - there was parts in there that made no sense whatsoever so kudos for managing to read through that.

                I'll post my solution below for reference but anyone who references this thread should definitely go with Maximes above suggestion.

                def screenCalc(guide, cZ, bd, sf, rd_w, rd_h) :  
                        
                        
                  gPos = guide.GetMg().off  # get global position of guide  
                  convertPos = bd.WS(gPos)  # convert world to screen space  
                  
                        
                  # Perform safe zone maths  
                  convertPos[0] = (convertPos[0] - sf["cl"])/(sf["cr"]-sf["cl"])  
                  convertPos[1] = (convertPos[1] - sf["ct"])/(sf["cb"]-sf["ct"])  
                  convertPos[2] = (cZ - convertPos[2])/cZ    
                        
                  gV1 = convertPos[0]  # get x from vector  
                  gV2 = convertPos[1]  # get y from vector  
                  
                        
                  # Remaps vector values to screenspace values, aswell as inverts  
                  g_Xpos = c4d.utils.RangeMap(gV1, 0, 1, 0, rd_w, True)  
                  INVg_Xpos = c4d.utils.RangeMap(gV1, 1, 0, 0, rd_w, True)  
                    
                  g_Ypos = c4d.utils.RangeMap(gV2, 0, 1, 0, rd_h, True)  
                  INVg_Ypos = c4d.utils.RangeMap(gV2, 1, 0, 0, rd_h, True)  
                    
                  # Loads final values into a list and returns it  
                  pos = [int(g_Xpos), int(INVg_Xpos), int(g_Ypos), int(INVg_Ypos)]  
                        
                  return pos  
                  
                  
                def main() :  
                    
                  # +------- GET DOCUMENT DATA --------#  
                    
                  bd = doc.GetActiveBaseDraw()                 # Get current view  
                  rd = doc.GetActiveRenderData()               # Get Render Setting  
                  rd_w = rd[c4d.RDATA_XRES_VIRTUAL]            # Get X resolution  
                  rd_h = rd[c4d.RDATA_YRES_VIRTUAL]            # Get Y resolution  
                  sf = bd.GetSafeFrame()                       # Get SafeFrame dims  
                    
                  # +------- GET CUSTOM DATA --------#  
                  obj = op.GetObject()                         # Get Null  
                  cam = obj[c4d.ID_USERDATA,2]                 # Get Camera  
                  top = obj[c4d.ID_USERDATA,3]                 # GetGuideObjects  
                  bottom = obj[c4d.ID_USERDATA,7]              # --------------  
                  left = obj[c4d.ID_USERDATA,8]                # --------------  
                  right = obj[c4d.ID_USERDATA,9]               # --------------  
                  switch = obj[c4d.ID_USERDATA,4]              # Get Switch  
                  cZ = cam[c4d.CAMERAOBJECT_TARGETDISTANCE]    # Get z-distance  
                  
                  # If tag is activated  
                    
                  if switch:  
                        
                      # Use function to grab data  
                      try:     
                          topPos = screenCalc(top, cZ, bd, sf, rd_w, rd_h)  
                          bottomPos = screenCalc(bottom, cZ, bd, sf, rd_w, rd_h)  
                          leftPos = screenCalc(left, cZ, bd, sf, rd_w, rd_h)  
                          rightPos = screenCalc(right, cZ, bd, sf, rd_w, rd_h)  
                            
                          # SET RENDER DATA  
                          rd[c4d.RDATA_RENDERREGION_TOP] = topPos[2]  
                          rd[c4d.RDATA_RENDERREGION_BOTTOM] = bottomPos[3]  
                          rd[c4d.RDATA_RENDERREGION_LEFT] = leftPos[0]  
                          rd[c4d.RDATA_RENDERREGION_RIGHT] = rightPos[1]  
                  
                          doc.SetActiveRenderData(rd)  
                          c4d.EventAdd()  
                        
                      except ZeroDivisionError:  
                          pass  
                  else:  
                      pass  
                
                

                Thanks again,

                Cerac

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