Plugin Cafe Homepage
Forum Home Forum Home > Plugin Cafe > PYTHON Development
  New Posts New Posts
  FAQ FAQ  Forum Search   Register Register  Login Login

Convert 3D space to 2D Space

 Post Reply Post Reply
Author
Message
Ceracticus View Drop Down
Member
Member


Joined: 2017 Mar 29
Location: Cardiff, UK
Online Status: Offline
Posts: 11
Post Options Post Options   Quote Ceracticus Quote  Post ReplyReply Direct Link To This Post Topic: Convert 3D space to 2D Space
    Posted: 2018 Jul 04 at 3:36am
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
Back to Top
C4DS View Drop Down
Member
Member


Joined: 2015 Dec 01
Online Status: Offline
Posts: 233
Post Options Post Options   Quote C4DS Quote  Post ReplyReply Direct Link To This Post Posted: 2018 Jul 04 at 12:22pm
Check out the BaseView class
BaseView::WC() or BaseView::WC_V() is what you most likely are looking for.

Back to Top
MaximeA View Drop Down
Forum Moderator
Forum Moderator

Forum Moderator

Joined: 2018 Jan 04
Location: France - Nantes
Online Status: Online
Posts: 88
Post Options Post Options   Quote MaximeA Quote  Post ReplyReply Direct Link To This Post Posted: 2018 Jul 05 at 2:12am
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
MAXON
SDK Specialist
Back to Top
Ceracticus View Drop Down
Member
Member


Joined: 2017 Mar 29
Location: Cardiff, UK
Online Status: Offline
Posts: 11
Post Options Post Options   Quote Ceracticus Quote  Post ReplyReply Direct Link To This Post Posted: 2018 Jul 05 at 9:53am
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




Edited by MaximeA - 2018 Jul 09 at 7:10am
Back to Top
MaximeA View Drop Down
Forum Moderator
Forum Moderator

Forum Moderator

Joined: 2018 Jan 04
Location: France - Nantes
Online Status: Online
Posts: 88
Post Options Post Options   Quote MaximeA Quote  Post ReplyReply Direct Link To This Post Posted: 2018 Jul 09 at 7:09am
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


Edited by MaximeA - 2018 Jul 09 at 7:09am
MAXON
SDK Specialist
Back to Top
Ceracticus View Drop Down
Member
Member


Joined: 2017 Mar 29
Location: Cardiff, UK
Online Status: Offline
Posts: 11
Post Options Post Options   Quote Ceracticus Quote  Post ReplyReply Direct Link To This Post Posted: 2018 Jul 11 at 1:05am
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


Edited by Ceracticus - 2018 Jul 11 at 1:11am
Back to Top
 Post Reply Post Reply

Forum Jump Forum Permissions View Drop Down

Bulletin Board Software by Web Wiz Forums® version 9.61 [Free Express Edition]
Copyright ©2001-2009 Web Wiz

This page was generated in 0.156 seconds.