Jump to content
  • Advertisement
Sign in to follow this  
Kram

D3DXVec3Unproject Problems

This topic is 3767 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have asked questions about the D3DXVec3Unproject method before, but that was embedded into another thread so I think Ill ask the question in a fresh thread. I am trying to make a very simple, rotating cube move to a position in 3d-space from a users mouse click. I can do 90% of this, but when I try to convert the users mouse click into 3D-space, I get strange values (or at least I think they are strange). I have placed a cube at and around the -3 to +3 vertex positions in 3D space. Then I setup the camera, etc... and I can see the cube in the middle of the black screen. Then when I click the mouse, I call a self-defined method called
SetupLocalMousePoints(IDirect3DDevice9* p_d3dDevice)

The method is defined as:
D3DXVECTOR3* GameEntity::SetupLocalMousePoints(IDirect3DDevice9
* p_d3dDevice)
{
	if (m_mousePoint)
	{
		D3DXVECTOR3 result;
		D3DXVECTOR3 screenPoint;
		D3DVIEWPORT9 viewport;
		D3DXMATRIX matProjection;
		D3DXMATRIX matView;
		D3DXMATRIX matWorld;

		screenPoint.x = m_mousePoint->x;
		screenPoint.y = m_mousePoint->y;
		screenPoint.z = 0.0f;
		m_mousePoint = 0;

		p_d3dDevice->GetViewport(&viewport);
		p_d3dDevice->GetTransform( D3DTS_PROJECTION, &matProjection );
		p_d3dDevice->GetTransform( D3DTS_VIEW, &matView );
		p_d3dDevice->GetTransform( D3DTS_WORLD, &matWorld );

		//transform the mouse clicked location
		D3DXVec3Unproject( &result, &screenPoint, &viewport, &matProjection, &matView, &matWorld );
		return &result;
	}
	return NULL;
}

m_mousePoint is a private class member variable:
POINTS* m_mousePoint

The rest should be pretty obvious. Now, the issue is when I click in the TOP RIGHT corner of the screen, I am getting. X: -23, Y:8 and Z:0.44 (ish). Why on earth would X be a negative number??? I am having real trouble here and would appreciate any help at all! Thanks Mark

Share this post


Link to post
Share on other sites
Advertisement
Because what you're doing is dangerous. Your compiler should generate a warning about this - you're returning a pointer to a local variable.

When your function exits, your result variable goes out of scope, and is destroyed. Your pointer now points to rubbish, because the thing it was pointing to is now gone. To solve this, either return by value, or have an extra parameter in your function like this:

void GameEntity::SetupLocalMousePoints(IDirect3DDevice9* p_d3dDevice, D3DXVECTOR3& return)
{
/*...*/

D3DXVec3Unproject(&return, &screenPoint, &viewport, &matProjection, &matView, &matWorld);

/*...*/
}

Share this post


Link to post
Share on other sites
Quote:
Original post by Sc4Freak
Because what you're doing is dangerous. Your compiler should generate a warning about this - you're returning a pointer to a local variable.

When your function exits, your result variable goes out of scope, and is destroyed. Your pointer now points to rubbish, because the thing it was pointing to is now gone. To solve this, either return by value, or have an extra parameter in your function like this:
...


Well thats a good point. I got so caught up in the 3D stuff that I forgot about basic c++...

But anyways, my breakpoints were actually set in that method, so the values that I was checking were the correct ones, but still wrong.

Any more thoughts on the issue here?

Thanks
Mark

P.S. I am happy to attach the project to this thread, or email it, or whatever, to anyone who wants it :)

Share this post


Link to post
Share on other sites
The usual suspects:

Are you mayhaps using a pure device?
In that case the GetTransform and GetViewport calls will fail. You should check the result codes from them.

It might be a good idea to store the matrices and viewport when you set them anyway to save the getter calls.

Share this post


Link to post
Share on other sites
Quote:
Original post by Endurion
The usual suspects:

Are you mayhaps using a pure device?
In that case the GetTransform and GetViewport calls will fail. You should check the result codes from them.

It might be a good idea to store the matrices and viewport when you set them anyway to save the getter calls.


Thanks,

the Getters are all working ok, I have just checked them and they all return S_OK. It seems that maybe I am getting the correct values, but maybe my view is all wrong.

Below is my render method that I use:


void GameEntity::Render(IDirect3DDevice9* p_d3dDevice)
{
// select which vertex format we are using
p_d3dDevice->SetFVF(CUSTOMFVF);

// set the view transform
D3DXMATRIX matView; // the view transform matrix
D3DXMatrixLookAtLH(&matView,
&D3DXVECTOR3 (0.0f, 8.0f, 25.0f), // the camera position
&D3DXVECTOR3 (0.0f, 0.0f, 0.0f), // the look-at position
&D3DXVECTOR3 (0.0f, 1.0f, 0.0f)); // the up direction
p_d3dDevice->SetTransform(D3DTS_VIEW, &matView);

// set the world transform
static float index = 0.0f; index += 0.03f; // an ever-increasing float value
D3DXMATRIX matRotateY; // a matrix to store the rotation
D3DXMatrixRotationY(&matRotateY, index); // the rotation matrix

// set the projection transform
D3DXMATRIX matProjection; // the projection transform matrix
D3DXMatrixPerspectiveFovLH(&matProjection,
D3DXToRadian(45), // the horizontal field of view
640.0f / 480.0f, // aspect ratio
1.0f, // the near view-plane
100.0f); // the far view-plane

p_d3dDevice->SetTransform(D3DTS_PROJECTION, &matProjection);

//convert clicked positions into 3D space positions if user has
//clicked the mouse...
this->SetupLocalMousePoints(p_d3dDevice, &m_xOffset, &m_yOffset);

//Remember...Scaling, Translation, Rotation

//translate the X and Y of needed
D3DXMATRIX matTranslate;
D3DXMatrixTranslation(&matTranslate, m_xOffset, m_yOffset, m_zOffset);

//ALWAYS, Rotate before Translate
p_d3dDevice->SetTransform(D3DTS_WORLD, &(matRotateY * matTranslate)); // set the world transform

// select the vertex buffer to display
p_d3dDevice->SetStreamSource(0, this->GetVertexBuffer(), 0, sizeof(CUSTOMVERTEX));

// set the texture
p_d3dDevice->SetTexture(0, m_triangleTexture);

// draw the textured square
p_d3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
p_d3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 4, 2);
p_d3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 8, 2);
p_d3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 12, 2);
p_d3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 16, 2);
p_d3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 20, 2);
}



and the SetupLocalMousePoints method (yes it is different than the original post, as I am simply try new things :))


void GameEntity::SetupLocalMousePoints(IDirect3DDevice9* p_d3dDevice, float* m_xOffset, float* m_yOffset)
{
if (m_mousePoint)
{
D3DXVECTOR3 screenPoint;
D3DVIEWPORT9 viewport;
D3DXMATRIX matProjection;
D3DXMATRIX matView;
D3DXMATRIX matWorld;
D3DXVECTOR3 screenVector;

screenPoint.x = m_mousePoint->x;
screenPoint.y = m_mousePoint->y;
screenPoint.z = 0.0f;

HRESULT viewportRes = p_d3dDevice->GetViewport(&viewport);
HRESULT projRes = p_d3dDevice->GetTransform( D3DTS_PROJECTION, &matProjection );
HRESULT viewRes = p_d3dDevice->GetTransform( D3DTS_VIEW, &matView );
HRESULT worldRes = p_d3dDevice->GetTransform( D3DTS_WORLD, &matWorld );

//transform the mouse clicked location
D3DXVec3Unproject( &screenVector, &screenPoint, &viewport, &matProjection, &matView, &matWorld );

*m_xOffset = screenVector.x;
*m_yOffset = screenVector.y;
m_mousePoint = 0;
}
}



Mark

Share this post


Link to post
Share on other sites
You're setting the world transform after the call to SetupLocalMousePoints, that might end up using an old world transform matrix.

Also, with one Unproject call with z=0 you get the 3d coordinate on the near plane. You should do two Unproject calls, one with z=0, one with z=1.

Use the resulting line to do intersection tests on your cube.

Share this post


Link to post
Share on other sites
Quote:
Original post by Endurion
You're setting the world transform after the call to SetupLocalMousePoints, that might end up using an old world transform matrix.

Also, with one Unproject call with z=0 you get the 3d coordinate on the near plane. You should do two Unproject calls, one with z=0, one with z=1.

Use the resulting line to do intersection tests on your cube.


Yes, I thought that is what I would have to do, setup the X and Y transformation, which is what SetupLocalMousePoints does, then call the D3DTS_WORLD transformation with the altered X and Y offsets. Isn't that be the way it should be done?

If I did it afterwards, the translation of the X, Y and Z values would be done too late wouldn't they? Although, the next time the Render() method is called, they will be altered correctly, but surely that shouldn't matter, should it??

Also, what is the reasoning behind needing to do the z=0 and z=1 calls?

Thanks for the help!
Mark

Share this post


Link to post
Share on other sites
Think about why you're making the Unproject call.

What you see on the screen is a 2D projection of objects in a world-space volume that's a truncated pyramid. A point on the 2D screen is the projection of a line in world space. In screen-space the points on that line are ( mouseX, mouseY, some-Z-value ).

Looking down from the top:

+----------------*--+ far plane ( z=1 )
\ / /
\...........[/]./
\ / /
\ / /
+------*--+ near plane ( z=0 )

Your mouse point on the screen is the line between the two asterisks in world space. The place you want to place the cube is somewhere on that line at some z value between 0 ( the near plane ) and 1 ( the far plane ).

You have to decide where on that line, what z value in screen-space, you want the cube to be. Use that z-value in the Unproject call to get the world-space position.

One way to determine that screen-space z-value is to choose the plane (
  ......  
in the diagram above ) where you want the cube to be. Pick a point (any point) in world-space in that plane. If you want to move the cube within the same plane all the time, you can use the point at the center of the cube in world-space. Use a Project call to get the screen-space Z-value for that plane and use that Z-value in your Unproject call with your mouse points.

Share this post


Link to post
Share on other sites
Ok so correct me if I am wrong, but you are saying that I need to setup the Z value because the line that moves back through the 3D space projection, is NOT a strait line, rather, it moves away as a diagonal line. So at different values of Z will give different values of X and Y?

I think Im getting you.

Therefor, if you want to keep the cube on the SAME Z plane, you need to get the current Z position of the center of the cube and use that in the Unproject call.

Correct?

If so, could I please ask you to help me GET the Z corrds from the D3DXVec3Project call? If it converts a Vector from 3D space into screen space, Im not too sure on the best way of getting that Vector...

Thanks so much for the help, I appreciate it greatly.

Share this post


Link to post
Share on other sites
Yep. The line "behind" the mouse point is a diagonal line (it is straight, by the way ) and the world-space x,y,z values vary along the screen-space line as the screen-space z-value changes.

For the project call, use a world-space D3DXVECTOR3 at the center of your cube. Then use the pOut z-value from the Project call in your Unproject pIn vector.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!