jimbo, your code looks ok to me.
jimbo wrote:
// project
Matrix4f screenMat = projMat * camViewMat * nodeMat;
// why not?: Matrix4f screenMat = nodeMat * camViewMat * projMat;
Vectors are multiplied from the right side, so the order
projMat * camViewMat * nodeMat [* vector] is correct (nodeMat is applied to vector first, then viewMat and finally the projection).
jimbo wrote:
float y = -screenMat.x[13] / w; // why negative?
The origin of the overlay coordinate system is the upper left corner and the positive y axis points to the bottom of the screen. Usually, in maths you would have the positive y axis pointing to the top of the screen. However, I find the other convention more intuitive to work with when creating screen elements (since you read from top to bottom).
Here is a IMHO slightly clearer version of your code that I would propose to add to the wiki snippets later:
Code:
// Get camera view matrix
const float *camTrans;
h3dGetNodeTransMats( _cam, 0x0, &camTrans );
Matrix4f viewMat( Matrix4f( camTrans ).inverted() );
// Get camera projection matrix
float camProj[16];
h3dGetCameraProjMat( _cam, camProj );
Matrix4f projMat( camProj );
// Loop over all model nodes
int cnt = h3dFindNodes( H3DRootNode, "", H3DNodeTypes::Model );
for( int i = 0; i < cnt; ++i )
{
// Get node name
H3DNode node = h3dGetNodeFindResult( i );
const char *name = h3dGetNodeParamStr( node, H3DNodeParams::NameStr );
// Get node position
const float *nodeTrans;
h3dGetNodeTransMats( node, 0, &nodeTrans );
Vec4f pos( nodeTrans[12], nodeTrans[13], nodeTrans[14], 1 );
// Project
pos = projMat * viewMat * pos;
float x = pos.x / pos.w;
float y = pos.y / pos.w;
// Transform to overlay coordinates
x = x * 0.5f + 0.5f;
y = -y * 0.5f + 0.5f;
// Show text (avoid back-projection)
if( pos.w > 0 ) h3dutShowText( name, x, y, 0.02f, 1.0f, 1.0f, 1.0f, _fontMatRes, 0 );
}