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

    Converting 3D Points to Screen Space X&Y

    PYTHON Development
    0
    9
    1.4k
    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 28/07/2018 at 16:27, xxxxxxxx wrote:

      Hello,
      I'm trying to get the X&Y pixel coordinates of my polygon plane's vertices (as well as their depth). The output dimensions are 4096x2160 pixels (attached). These are the plane's 3D vectors followed by the pixel coordinates I'm looking to get:

      # Top Left Corner: (-200,200,0) -> 1493,505
      # Top Right Corner: (200,200,0) -> 2458,471
      # Bottom Left Corner: (-200,-200,0) -> 1524,1712
      # Bottom Right Corner: (200,-200,0) -> 2438,1509
      

      How can I do this in Python? I've tried to use BaseDraw's WC, WC_V, WS, CS methods, but I'm not sure what to do with their results as they are not in pixels.

      WC: Vector(-174.873, 181.224, 1288.966) # Top Left Corner
      WC then CS: Vector(472.901, 423.506, 1288.966) # Top Left Corner
      WS: Vector(472.901, 423.506, 1288.966) # Top Left Corner
      WC_V: Vector(-163.448, 174.118, -151.55) # Top Left Corner
      CS: Vector(-25959351, -25959394, 0),Vector(25960649, -25959394, 0),Vector(25960649, 25960606, 0),Vector(-25959351, 25960606, 0) # All four vertices
      

      Thank you.

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

        On 30/07/2018 at 08:32, xxxxxxxx wrote:

        Hi blastframe, welcome to our community and thanks for writing here.

        With regard to your question, there are a couple of point missing:

        1. what's the context? Rendering or Viewport?
        2. The output dimensions you're reporting is the size of the rendered image or is it the size of the viewport?

        As a rule of thumb, in case you're evaluating the viewport in a rendering context it's recommended to use BaseDocument::GetRenderBaseDraw() whilst if in viewport feel free to use BaseDocument::GetActiveBaseDraw().

        Aside fro this also note that the origin of the screen space is the top/left corner - where the "Perspective" label is - and ends on the bottom/right  - where the "Grid spacing" label is.

        A brief test in viewport provides the correct results with this code

        def main() :  
          if not doc or not op:  
              return  
            
          activeBD = doc.GetActiveBaseDraw()  
          if not activeBD:  
              return  
            
          points =  op.GetAllPoints()  
          if not points:  
              return  
            
          for point in points:  
              print "point: [",point,"] / [", activeBD.WS(point),"]"  
            
        if __name__=='__main__':  
          main()  
        
        

        Hoping it helps, give best.

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

          On 02/08/2018 at 08:41, xxxxxxxx wrote:

          Hi Riccardo,
          Thank you again for the reply. To answer your questions:

          1. the context is Rendering.
          2. The output dimensions are the size of the rendered image

          I used the code you provided with GetRenderBaseDraw(). It still is giving me numbers that do not equate to the X & Y coordinates in pixels. For example, if the rendered image is 1920x1080 and I have a point at 0,200,-200, the pixel coordinates in the image are 657 x 144. The script's output is:

          point: [ Vector(0, 200, -200) ] / [ Vector(443.885, 338.496, 880.435) ]
          

          If I use the Camera to screen conversion method, I get closer, but the Y is a crazy value:

              for point in points:
                  print "point: [",point,"] / [", activeBD.CS(point, True),"]"
          

          Output:

          point: [ Vector(0, 200, -200) ] / [ Vector(649, -25959394, -500000000) ]
          

          Can you help me get the values that I'm seeking? Thanks again!

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

            On 03/08/2018 at 06:23, xxxxxxxx wrote:

            Hi Blastframe thanks for following up.

            I've prepared the following script hoping it works nicely for you.

            def main() :  
              # check for doc being valid  
              if not doc:  
                  return  
                
              # retrieve the BaseDraw of the view set to "Use as Render View"  
              renderBD = doc.GetRenderBaseDraw()  
              if not renderBD:  
                  return  
                
              # retrieve the safe-frame information  
              renderSafeFrame = renderBD.GetSafeFrame()  
              renderSafeFrameRes = (renderSafeFrame['cr'] - renderSafeFrame['cl'], renderSafeFrame['cb'] - renderSafeFrame['ct'])  
                
                
              # retrieve active RenderData  
              rData = doc.GetActiveRenderData()  
              if not rData:  
                  return  
                
              # get render data  
              rDataBC = rData.GetDataInstance()  
              if not rDataBC:  
                  return   
                
              # store frame resolution  
              frameRes = (rDataBC.GetInt32(c4d.RDATA_XRES), rDataBC.GetInt32(c4d.RDATA_YRES))  
              
                
              # check there's a valid active object  
              if not op or not op.IsInstanceOf(c4d.Opolygon) :  
                  return      
                
              # get the points or return instance it's not valid  
              points =  op.GetAllPoints()  
              if not points:  
                  return  
                
              # loop through points  
              for point in points:  
                  # transform point from World to Screen  
                  pointToScreen = renderBD.WS(point)  
                  # notify about points outside the render frame  
                  if pointToScreen.x > renderSafeFrame['cr'] or pointToScreen.x < renderSafeFrame['cl']:  
                      print " -- x-coordinate out of frame area --- "  
                  if pointToScreen.y > renderSafeFrame['cb'] or pointToScreen.y < renderSafeFrame['ct']:  
                      print " -- y-coordinate out of frame area --- "  
                  # compensate the x/y offset              
                  pointsR_XY = (pointToScreen.x - renderSafeFrame['cl'], pointToScreen.y -renderSafeFrame['ct'])          
                  # scale with regard of the final frame size  
                  pointsR_XY_2 = (pointsR_XY[0] * frameRes[0] / renderSafeFrameRes[0], pointsR_XY[1] * frameRes[1] / renderSafeFrameRes[1])  
                  # just print  
                  print "point: [", point ,"] / [", pointsR_XY_2, "]"  
            
            

            Let me know if something is unclear or wrong.
            Cheers, Riccardo

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

              On 03/08/2018 at 07:33, xxxxxxxx wrote:

              WOW! You did it, Riccardo! Thank you very much 😄 I'm very impressed and grateful.

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

                On 03/08/2018 at 07:57, xxxxxxxx wrote:

                My apologies, I do have one follow-up question. I see the line with # notify about points outside the render frame

                How could I tell if the point is being obscured by other geometry? Would this be

                renderBD.TestPointZ(point)
                

                ?

                When I use this with the plane highlighted in green, it returns False for two of the points which are visible.

                point: [ Vector(0, 200, -200) ] / [ (576.2718396467545, 166.23981331428323) ]
                Visible: False
                  
                point: [ Vector(0, -200, -200) ] / [ (589.7969294792699, 878.0441715337967) ]
                Visible: False
                  
                point: [ Vector(0, 200, 200) ] / [ (1066.6762020149142, 205.85938605460527) ]
                Visible: True
                  
                point: [ Vector(0, -200, 200) ] / [ (1063.7210058999553, 771.3600524945704) ]
                Visible: True
                

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

                  On 06/08/2018 at 00:23, xxxxxxxx wrote:

                  Hi Blastframe, thanks for following up.

                  With regard to your last question, consider that the point being passed to the BaseView::TestPointZ() needs to be expressed in camera space and not in world space. Then I warmly suggest to use BaseView::WC() before passing your point to the TestPointZ function.

                  Best, Riccardo

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

                    On 06/08/2018 at 12:09, xxxxxxxx wrote:

                    Originally posted by xxxxxxxx

                    Hi Blastframe, thanks for following up.

                    With regard to your last question, consider that the point being passed to the BaseView::TestPointZ()needs to be expressed in camera space and not in world space. Then I warmly suggest to use BaseView::WC() before passing your point to the TestPointZ function.

                    Best, Riccardo

                    Hi Riccardo,
                    Thank you for all of your help with my issue. Per your advice, I tried converting to camera space, but the results for all points were still true, even if they were blocked by self geometry or another object.

                            pointToCS = renderBD.WC(point)
                            print renderBD.TestPointZ(pointToCS)
                    

                    Maybe this is not what TestPointZ is checking? I am wanting to skip vertices that are not visible. Thank you.

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

                      On 07/08/2018 at 03:05, xxxxxxxx wrote:

                      Hi Blastframe, thanks for following up.

                      With regard to your last post, I need to apologize cause I provided a misleading information being myself confused by the documentation. Actually the BaseView::TestPointZ() verify if a given point is within the camera near/far clipping range and not if the point is occluded by any other object.

                      In your case instead, you should think about a more complex design where each of your point is tested against any other geometry found in the scene by using a GeRayCollider()[URL-REMOVED] and then evaluate the result according to the intersection distance.

                      Unfortunately there's no other turn-key solution to achieve your desired functionality.

                      Best,  Riccardo


                      [URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.

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