Global pos to camera view
-
On 01/03/2018 at 11:46, xxxxxxxx wrote:
How i can convert global coordinates of object in relation to specific camera view?
I've managed to create a Python Generator which returns quad polygon with points linked to top-left, top-right, bottom-right and bottom-left coordinates of camera-view:import c4d,math # Cam Quad Maker def fov(fv) : #get FoV-point return math.tan(fv*.5) def main() : op[c4d.ID_BASEOBJECT_ABS_POSITION] = c4d.Vector(0) op[c4d.ID_BASEOBJECT_ABS_ROTATION] = c4d.Vector(0) op[c4d.ID_BASEOBJECT_ABS_SCALE] = c4d.Vector(1) cam=op[c4d.ID_USERDATA,1] #Link-field for Camera if(not cam)or(cam.GetType()!=c4d.Ocamera) : return None cMat=cam.GetMg() #camera-matrix cZ=cam[c4d.CAMERAOBJECT_TARGETDISTANCE] #z-distance cvH=fov(cam[c4d.CAMERAOBJECT_FOV])*cZ #view-Horz cvV=fov(cam[c4d.CAMERAOBJECT_FOV_VERTICAL])*cZ #view-Vert qd=c4d.BaseObject(c4d.Opolygon) pts=[c4d.Vector(0,0,0)]*4 pts[0]=c4d.Vector(-cvH,-cvV,cZ)*cMat #topLeft pts[1]=c4d.Vector(cvH,-cvV,cZ)*cMat #topRight pts[2]=c4d.Vector(cvH,cvV,cZ)*cMat #botRight pts[3]=c4d.Vector(-cvH,cvV,cZ)*cMat #botLeft qd.ResizeObject(4,1) qd.SetAllPoints(pts) qd.SetPolygon(0,c4d.CPolygon(0,1,2,3)) return qd
Now i want to convert another object's coordinates relatively to this quad so in resulting coords:
- X will be 0 if object exactly on the left edge, 1 if on the right, <0 if out of view on the left and >0 if on the right
- Y will be same as X but relative vertically
- Z will be 0 if object exactly on the plane formed by the quad points, <0 if it's farther and >0 if closer to camera
But i don't sure what to do next When i multiply obj.GetMg().off by pts[0] for example (TopLeft point of view) i get some garbage values, it's definitely not what i wanned lol
And cuz i have pretty crappy knowledge of trigonometry i'm kinda stuck now =\ -
On 01/03/2018 at 14:35, xxxxxxxx wrote:
Well, i found a way to do what i wanted:
import c4d,math # Object Pos related to CamView def fov(fv) : #get FoV-point return math.tan(fv*.5) def main() : cam=op[c4d.ID_USERDATA,1] #Link-field for Camera if(not cam)or(cam.GetType()!=c4d.Ocamera) : return None obj=op[c4d.ID_USERDATA,2] #Link-field for Object if(not obj) : return None cMat=cam.GetMg() #camera-matrix cZ=cam[c4d.CAMERAOBJECT_TARGETDISTANCE] #z-distance cvH=fov(cam[c4d.CAMERAOBJECT_FOV])*cZ #view-Horz cvV=fov(cam[c4d.CAMERAOBJECT_FOV_VERTICAL])*cZ #view-Vert bd=doc.GetActiveBaseDraw() bd.InitializeView(doc, cam, True) oMat=obj.GetMg() #object-matrix v=bd.WC(oMat.off) #World2Camera v[0]=(v[0]+cvH)/cvH*.5 v[1]=1-(v[1]+cvV)/cvV*.5 v[2]=(cZ-v[2])/cZ op[c4d.ID_USERDATA,3]=str(v) #Output coords into string-field return None
But if anyone who's not THAT retarded in 3D math as i am will provide code to do the same without BaseView.WC() via basic matrix/vector equations i will absolutely appreciate it.
-
On 02/03/2018 at 11:02, xxxxxxxx wrote:
Hi Markus, thanks for writing us.
With regard to your request, consider that using the BaseView::WS() and BaseView::GetSafeFrame() are the easiest and fastest way to deliver a world-to-screen representation of the space which, in my opinion, fits better with what you're looking for.
Slightly modifying the code it should look like:
import c4d # Object Pos related to CamView def main() : cam = op[c4d.ID_USERDATA,1] #Link-field for Camera if(not cam)or(cam.GetType()!=c4d.Ocamera) : return None obj = op[c4d.ID_USERDATA,2] #Link-field for Object if(not obj) : return None cZ = cam[c4d.CAMERAOBJECT_TARGETDISTANCE] #z-distance bd = doc.GetActiveBaseDraw() objPos = obj.GetMg().off #object global position v = bd.WS(objPos) #World2Screen sf = bd.GetSafeFrame() #SafeFrame v[0] = (v[0] - sf["cl"])/(sf["cr"]-sf["cl"]) v[1] = (v[1] - sf["ct"])/(sf["cb"]-sf["ct"]) v[2] = (cZ-v[2])/cZ op[c4d.ID_USERDATA,3]=str(v) #Output coords into string-field return None
Best, Riccardo