koen
What would be the easiest way to get a camera to screen (NDC) matrix? I would love to have a solution in python, the HDK would work as well.
As I understand it, yes, you can represent the NDC transform as a matrix, but to do anything useful with that matrix, you'll need to work in homogeneous coordinates.
For example, to encode the perspective divide portion (P/P.z) in matrix form, you'd have:
// row-major //
matrix M = 1, 0, 0, 0
0, 1, 0, 0
0, 0, 1, 1
0, 0, 0, 0
When this matrix is used to transform a homogeneous point P, its right-hand column will set Pw to Pz, so when you de-homogenize the resulting P (turn P*M back into Cartesian coords), you'll end up with Pcartesian = {Px/Pw,Py/Pw,Pz/Pw} = {Px/Pw,Py/Pw,1}, which is the perspective divide you want. But without that de-homogenization step the last column is meaningless.
For the actual NDC transform though, you'll need more than just the division by Pz – you'll need to bring in the rest of the camera's viewing parameters into play: focal length, aperture, pixel aspect, etc.
The first step however, is to put all your (homogeneous) P's into camera space (initially all the Pw's will most likely be simply 1, but use the actual attribute just in case). And you can get at the camera transform (let's say some matrix ‘Mcam’) in any number of ways, depending on your context, so I'll assume you can do this. So step 1 is: P = P*Mcam.
Then you'll transform by the NDC matrix, which looks something like this:
float f = focal / aperture;
float a = resy / (resx*aspect);
float b = (far+near) / (far-near);
float c = (2.0*far*near) / (far-near);
Mndc = set( f , 0 , 0 , 0,
0 , f/a , 0 , 0,
0 , 0 , b , -1,
0 , 0 , c , 0 );
That ‘-1’ at Mndc(3,4) could be a +1 depending on your context, and the rest of the variables are the camera's viewing parameters: far/near clipping planes, x/y resolution, etc. Mndc has a “normalized” window of , and all resulting Pw's are set to 1 (or -1 in this case). All that's left now is to put P back to cartesian coords. So, all together:
vector4 Ph = set(P.x,P.y,P.z,P.w);
Ph = Ph*Mcam*Mndc;
vector Pndc = (vector)Ph / Ph.w + {0.5,0.5,0}; // Pndc = NDC version of P
I did a quick mockup in SOPs so you can try it out. View through cam1, which also displays the NDC version in the lower-left corner of the viewport. Then play with cam1's transformation and/or viewing parameters to see how the NDC projection changes. You'll find the above ‘Mndc’ matrix written inside the VOP SOP ‘NDC_0_1’ in the object ‘NDC’.
HTH.