Horde3D

Next-Generation Graphics Engine
It is currently 29.04.2024, 13:17

All times are UTC + 1 hour




Post new topic Reply to topic  [ 4 posts ] 
Author Message
PostPosted: 24.01.2010, 10:31 
Offline

Joined: 10.04.2008, 09:13
Posts: 86
I would like to render the node names in the scene like billboards, so I've written a function to convert the object transformations to the screen. It seems to work but I'm not sure if this is correct:

Code:
void Application::renderNodeNames() {

// get view transformation
   const float* camTrans = 0;
   h3dGetNodeTransMats(_cam, 0, &camTrans);   
   Matrix4f camViewMat(Matrix4f(camTrans).inverted());

// get projection
   float projection[16];
   h3dGetCameraProjMat( _cam, projection );       
   Matrix4f projMat(projection);

   int cnt = h3dFindNodes(H3DRootNode, "", H3DNodeTypes::Undefined);
   for(int i = 0; i < cnt; i++) {
      int node = h3dGetNodeFindResult(i);

// get node name
      const char *name = h3dGetNodeParamStr(node, H3DNodeParams::NameStr);

// get node transform
      const float* nodeTrans = 0;
      h3dGetNodeTransMats(node, 0, &nodeTrans);   
      Matrix4f nodeMat( nodeTrans );

// project
      Matrix4f screenMat = projMat * camViewMat * nodeMat;
      //   why not?: Matrix4f screenMat = nodeMat * camViewMat * projMat;

// to 2D
      float w = screenMat.x[15];
      float x = screenMat.x[12] / w;
      float y = -screenMat.x[13] / w; // why negative?
      float z = screenMat.x[14];

// to screen (overlay coordinates)
      x= (x*0.5f) + 0.5f;
      y = (y*0.5f) + 0.5f;

      if(z > 0)
         h3dutShowText(name, x, y, 0.02f, 1.0f, 1.0f, 1.0f, _fontMatRes, 0);

      //      printf("pos: %f %f %f\n",x,y,z);
   }
}


Top
 Profile  
Reply with quote  
PostPosted: 24.01.2010, 17:40 
Offline
Engine Developer

Joined: 10.09.2006, 15:52
Posts: 1217
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 );
}


Top
 Profile  
Reply with quote  
PostPosted: 24.01.2010, 19:50 
Offline

Joined: 10.04.2008, 09:13
Posts: 86
Thanks for your help, looks nice and clean. For larger scenes I've added a bit of depth to the texts:
Code:

...

 y = -y * 0.5f + 0.5f;

float maxFontSize = 0.02f;
float minFontSize = 0.005f;

// Scale font a bit with z pos
 float fontSize = 0.2f / pos.z;

// Show text (avoid back-projection)
if( pos.w > 0 && fontSize >= minFontSize ) {
     if( fontSize >= maxFontSize ) fontSize = maxFontSize;
     h3dutShowText( name, x, y, fontSize, 1.0f, 1.0f, 1.0f, _fontMatRes, 0 );
}


Top
 Profile  
Reply with quote  
PostPosted: 27.01.2010, 22:35 
Offline
Engine Developer

Joined: 10.09.2006, 15:52
Posts: 1217
jimbo wrote:
For larger scenes I've added a bit of depth to the texts

Good idea :)


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 4 posts ] 

All times are UTC + 1 hour


Who is online

Users browsing this forum: No registered users and 14 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Group