Skip to main content
GameDev.net gamedev.net
🔒 Locked

[Solved] Determining object height on screen

Started by Kalten Feb 2, 2010 at 7:22 PM 10 replies 1.7k views
Original Post
Kalten
Kalten
Guys, I'm looking into obtaining a rendered object's height once it has been transformed and rendered on the screen, the purpose of which is to place a label floating above the character's head. The object is stored within an ID3DXAnimationController using a series of bones and meshes. When attempting to use a bounding box to obtain the object height, I've expectedly obtained the model's height in the object space, which is several thousand units high, not the ~40 or so pixels that I need on the screen. I've attempted to use _22 within the material matrix assuming this to be the Max Y value for the object to be rendered to the screen... possibly a misunderstanding as to how the matrix works. I'm sure the solution is simple and related to my lack of experience, though i'm stumped. Note: using C++ and DX9.0 at this point. My object position to screen position code:

D3DXVECTOR3 ObjPosToScreenPos(D3DXMATRIX matProj, D3DXMATRIX matView, int type){

	D3DXMATRIX identityMatrix;
	
	D3DXMatrixIdentity(&identityMatrix);
	
	D3DXMATRIX mat = identityMatrix * matView * matProj;

	D3DXVECTOR4 trans;



	if (type == 0)
	{
		D3DXVec3Transform(&trans, &pos, &mat);		
	}
	else if (type == 1) // for words...
	{
		D3DXVECTOR3 tempPos = D3DXVECTOR3(pos.x,pos.y+(mat._22),pos.z); //guessing numbers...
 
		D3DXVec3Transform(&trans, &tempPos, &mat);
	}
	
	if(trans.z >= 0) //if the translated Z depth is less than 0 then we have an object behind the camera.
	{
		D3DXVECTOR3 result = D3DXVECTOR3(((trans.x / trans.w) + 1) * (SCREEN_WIDTH/2),((1 - (trans.y / trans.w)) * (SCREEN_HEIGHT /2)), 0);
		return result;
	}else{
		return D3DXVECTOR3(-1,-1,-1);
	}
}



[Edited by - Kalten on February 14, 2010 7:07:42 PM]
MJP
MJP
Once you've got the bounding box min and max values, transform the max by the model's root world matrix. This will put the max in world space. Then transform the max by your view * projection matrix and divide Y by W. This will give you a value of the range [-1, 1] where -1 is the bottom of the screen and 1 is the top.
Buckeye
Buckeye
It appears you have the position. If you have the bounding box, and you're willing to except some error due to animation and perspective, you can project the top of the bounding box. Is D3DXVec3Project() available in dx8?

I don't know how you have the animation implemented, but another possibility (if it's important enough) is to add a boneframe to the top of the head in the model and get it's animated position and project that position.

EDIT: looks like MJP's got it.
Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly. You don't forget how to play when you grow old; you grow old when you forget how to play.
Kalten
Kalten
I think MJP's solution is one that works but i'm trying to figure out how to implement it... bit rusty atm :(

I've got boundingBox.max which is a D3DXVECTOR3 representation of the maximum of the bounding box's corner. So text should render on one corner of the model's space.

I've got a function GetWM() which returns the object's world matrix as a D3DXMATRIX.

i've tried:
D3DXVec3Transform(&trans,&boundingBox.max,&GetWM());
which gives a value that looks like it belongs to the model object, doesnt move relative to view matrix, so looks good.

Attempted to then translate this directly against the view*proj matricies with:
D3DXVec4Transform(&trans,&trans, &mat);

then created the result vector by:
D3DXVECTOR3 result = D3DXVECTOR3((trans.x/trans.w),(trans.y/trans.w),(trans.z/trans.w));

numbers from that seem to be far too large and i think i've done something wrong or dont understand something :S

Object's GetWM();
D3DXMATRIX MOBILE::GetWM(){	D3DXMATRIX p, r, s;	D3DXMatrixTranslation(&p, pos.x, pos.y, pos.z);	D3DXMatrixRotationYawPitchRoll(&r, rot.x, rot.y, rot.z);	D3DXMatrixScaling(&s, sca.x, sca.y, sca.z);	D3DXMATRIX world = s * r * p;	return world;}


[Edited by - Kalten on February 2, 2010 10:29:40 PM]
Buckeye
Buckeye
In your posted code, you have mat = identity*view*proj.

Did you change that to mat = view*proj?

Also, as mentioned above, can you use D3DXVec3Project()?
Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly. You don't forget how to play when you grow old; you grow old when you forget how to play.
Kalten
Kalten
I do have access to Vec3Project, i'm actually using DX9... i appear to have typo'd in my opening post, sorry guys.

Following is the changes made to the function:
D3DXVECTOR3 ObjPosToScreenPos(D3DXMATRIX matProj, D3DXMATRIX matView){	//Setup identity matrix	D3DXMATRIX identityMatrix;	D3DXMatrixIdentity(&identityMatrix);	//matView in this case = Camera's View Matrix	//matProj in this case = Camera's Projection Matrix	D3DXMATRIX mat = matView * matProj;		D3DXVECTOR4 trans;	D3DXVec3Transform(&trans, &boundingBox.max, &GetWM()); //Translate bounding box against object's world matrix.	D3DXVec4Transform(&trans, &trans, &mat); //Translate previous translation against View*Proj matrix.		D3DXVECTOR3 result = D3DXVECTOR3((trans.x/trans.w),(trans.y/trans.w),(trans.z/trans.w));	//debug output for tracking label location		debug.Print("Label Location: ");	debug << (trans.x / trans.w) << "," << (trans.y / trans.w) << "," << (trans.z / trans.w);	debug.Endl(1);	return result;}
Kalten
Kalten
still stuck on this... anyone else got any other ideas?
Buckeye
Buckeye
Quote:
still stuck on this

You don't mention what problem you're having, just that you changed your code.

Without info, I'd just make a guess that you don't set trans.w=1.0f between the D3DXVec3Transform and D3DXVec4Transform calls.

If you're still having problems after that, you might try (as mentioned a couple times above) using D3DXVec3Project with one of the world bounding box vertices.
Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly. You don't forget how to play when you grow old; you grow old when you forget how to play.
Kalten
Kalten
sorry let me expand then...

this currently draws the label in the top left hand corner of the screen...

The X,Y,Z values for the text are similar to the following:

2.66742,4.29452,0.989695
or
6.00648,-11.1048,1.02755

these dont look right...

[edit]

D3DXVec3Project(&objScreenPos,&g_mobile[selectedObject].GetPos(),&vp,&camera.GetProjectionMatrix(),&camera.GetViewMatrix(),&matWorld);

used instead of the function defined previously produces a label at a set point in the world and it doesnt move with the model or anything. :S

thinking i messed something up (prolly did)

D3DXVec3Project(&objScreenPos,&g_mobile[selectedObject].GetPos(),&vp,&camera.GetProjectionMatrix(),&camera.GetViewMatrix(),&g_mobile[selectedObject].GetWM());

Produces a label that skates next to the model but at a velocity greater than the model, IE if i move the model to the left the position of the lable moves 2x the distance.

[Edited by - Kalten on February 8, 2010 10:13:07 PM]
Buckeye
Buckeye
Assuming that the viewport, projection and view matrices are correct, the problem must be with the world matrix.

As a test case, you should be able to use an identity matrix for world* and ensure it follows your axes origin correctly (assuming your axes origin is visible in your camera view).

*Alternately, pick a point in your world you know is in the camera view and set world to D3DXMatrixTranslation(&world, point.x, point.y, point.z).
Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly. You don't forget how to play when you grow old; you grow old when you forget how to play.
Kalten
Kalten
Buckeye,

Thanks a lot for the help...

Found what the issue was, it appears that i was hitting a barrier when using out of date or scope values for the boundingBox's max value.

It appears that dispite the bounding box being calculated in the same pass as the drawing of it's object to screen that the values were being corrupted... giving some stupid large number instead of the value that i was hoping for.

The path i was travelling by not using the D3DXVec3Project would achieve the same result, though not as simply and when tested i was happy to see that it did indeed work... though i've now simplified with the Project function.

In the end identifying the location reads simply as:
D3DXVec3Project(&objScreenPos,&g_mobile[selectedObject].CalcBoundingBox().max,&vp,&camera.GetProjectionMatrix(),&camera.GetViewMatrix(),&g_mobile[selectedObject].GetWM());


With the mobile's CalcBoundingBox function reading:
BBOX MOBILE::CalcBoundingBox(){	LPD3DXMESH tempMesh;	BBOX tempBox; //STRUCT BBOX{ D3DXVECTOR3 min, max;};)	tempMesh = animMeshes[animMeshID]->GetCurrentMesh(NULL);	BYTE* v = 0;	tempMesh->LockVertexBuffer(0, (void**)&v);	if(FAILED(D3DXComputeBoundingBox((LPD3DXVECTOR3) v, tempMesh->GetNumVertices(),D3DXGetFVFVertexSize(tempMesh->GetFVF()), &tempBox.min, &tempBox.max)))	{		debug.Print("WARNING: Bounding Box failed.");		tempBox = BBOX(D3DXVECTOR3(0,0,0),D3DXVECTOR3(0,0,0));	}		float heightAdjust = tempBox.max.y - tempBox.min.y;	D3DXMATRIX p, r, s;	D3DXMatrixTranslation(&p, pos.x, pos.y + heightAdjust/2, pos.z);	D3DXMatrixRotationYawPitchRoll(&r, rot.x, rot.y, rot.z);	D3DXMatrixScaling(&s, sca.x, sca.y, sca.z);	D3DXMATRIX world = s * r * p;	m_pDevice->SetTransform(D3DTS_WORLD, &world);	tempMesh->UnlockVertexBuffer();	tempMesh = NULL;	return tempBox;}


so my draw text to screen ends up as:
D3DXVec3Project(&objScreenPos,&g_mobile[selectedObject].CalcBoundingBox().max,&vp,&camera.GetProjectionMatrix(),&camera.GetViewMatrix(),&g_mobile[selectedObject].GetWM());if (objScreenPos != D3DXVECTOR3(-1,-1,-1)){	RECT rc = {(long)objScreenPos.x, (long)objScreenPos.y, 0,0}; //TODO - change drawing of text from screen pos to object's world pos.	g_pFont->DrawText(NULL, g_mobile[selectedObject].GetName(), -1, &rc, DT_LEFT| DT_TOP | DT_NOCLIP, D3DCOLOR_ARGB(255,0,255,0));}


Any feed back on these would be greatly appreciated...



[Edited by - Kalten on March 8, 2010 10:53:28 PM]
Kalten
Kalten
Another update,

How i'd fixed it didnt work completely, when i went back i found that it worked in some cases and in others it didnt... (no issues with objects that are static, moving had issues.)

It came down to a fundamental understanding of what D3DXVec3Project does...

Parameter 1 for the function is the origin of the projection
Parameter 2 for the function is the vector by which you want to project it in world space.

EG.
If you want to project something directly up in the Y axis, you project it by a vector of {0,x,0}.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.