0

I have a direct3d environment in a MFC window and i would like to draw the coordinate system axes in the corner of the screen, as any 3d software has. I thought this would be no problem, but issues occurred when i started moving the camera around. I need the object to appear to be in the same spot, no matter how i pan, zoom or rotate the camera.

But it seems that i'm doing something wrong, and i was hoping someone could point me on the right direction, since the object i'm drawing is not scaled accordingly when i zoom, but it works perfect when panning or rotating.

I have also put up a youtube video to show you the symptoms: http://www.youtube.com/watch?v=gwM0m8nbLts&feature=youtu.be

This is my code for drawing the object:

    void CDEMView::DrawSomeBox()
{
// Define the needed matrices - object world, view and project 
D3DXMATRIX matObjectWorld;
    D3DXMatrixIdentity (&matObjectWorld);   // object world matrix
D3DXMATRIX matView;             
    D3DXMatrixIdentity (&matView);      // view matrix
D3DXMATRIX matProjection;   
    D3DXMatrixIdentity (&matProjection);    // projection matrix

// Get the needed matrices
_device->GetTransform(D3DTS_VIEW, &matView);
_device->GetTransform(D3DTS_PROJECTION, &matProjection);

// Get the viewport
D3DVIEWPORT9 viewport;
_device->GetViewport(&viewport);

// Get the center point of the object       
D3DXVECTOR3* p_centerPoint = BoxCenterVector; // this is from an external variable

// Get the point on the creen that is the screen projection of the object
D3DXVECTOR3 projectPoint;
D3DXVec3Project(&projectPoint, p_centerPoint ,&viewport, &matProjection, &matView, &matObjectWorld);

// choose the screen point where the object is to be drawn, relative to the Viewport's dimensions
D3DXVECTOR3 screenPoint;
screenPoint.x = 0.1*viewport.Width; // x position (horizontal) is 10% of the width of the screen (0% is left, 100% is right)
screenPoint.y = 0.9*viewport.Height;    // y position (vertical) is 90% of the height of the screen (0% is top, 100% is bottom)
screenPoint.z = projectPoint.z;     // 1-projectPoint.z*60/(-zoom);

//transform the screen position to a world position
D3DXVECTOR3 worldPoint;
D3DXVec3Unproject( &worldPoint, &screenPoint, &viewport, &matProjection, &matView, &matObjectWorld );

// now define how much to translate the box in order to get it to the point we want it to be (WorldPoint)
float transX, transY, transZ;
transX = worldPoint.x;
transY = worldPoint.y;
transZ = worldPoint.z;

// define a mesh to store the object into and create the object
ID3DXMesh* _SomeBox;
float boxSize = 2.0f;
D3DXCreateBox(_device,boxSize,boxSize,boxSize,&_SomeBox,NULL);

// define a material and set its color
D3DMATERIAL9 mat;

// Set the RGBA for diffuse reflection.
mat.Diffuse.r = 255;
mat.Diffuse.g = 0;
mat.Diffuse.b = 0;
mat.Diffuse.a = 0.5;

_device->SetMaterial(&mat);
_device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME); // D3DFILL_SOLID

// apply the translation matrix
D3DXMatrixTranslation(&matObjectWorld, transX, transY, transZ);
_device->SetTransform(D3DTS_WORLD, &matObjectWorld);

// draw the object
_SomeBox->DrawSubset(0);
// release the mesh
_SomeBox->Release();
}

2 Answers2

0

I haven't looked closely at your code to try and find the issue but I'd suggest you might want to take a slightly different approach which would avoid the need for trying to compensate for the camera movement. Instead of trying to position your coordinate axes as an object positioned in the same world space as your scene, change your viewport to the region where you want to display your coordinate axes and render them in a virtual scene with a fixed camera and a world matrix that's your main scene's camera view matrix without the translation component.

This way you don't even have to worry about your camera's zoom, you're just directly displaying how your view matrix rotation affects the world axes. This approach also has the advantage that you can avoid any issues with your axes interacting with your scene. You can clear the z-buffer of the viewport where you render your axes before drawing them and they will be like a separate layer that doesn't interact with your main scene. You could also achieve the same affect by rendering the axes to an off screen render target texture and displaying that as a quad in your main scene but for this case that would be more work without much obvious benefit.

mattnewport
  • 12,751
  • 2
  • 30
  • 38
  • hi! thanks for the reply. i have little knowledge of both programming in general and directx in particular. therefore i don't understand what a "virtual scene" is and how it can be done. I too had an idea to create another smaller viewport and draw the axes there but i had much trouble with that and abandoned the idea. could you perhaps point me to a place where i could study multiple viewports usage on the same window (i use MFC). Thanks again! – user2415320 May 24 '13 at 20:54
  • Virtual scene isn't an official term, it was just my term for the approach described. There's not much to using a smaller viewport, you just need to call SetViewport with the coordinates you want to render to and then you'll probably want to call Clear to clear the z buffer before rendering. Any rendering you do now you've set the viewport will happen to that subregion of the screen. – mattnewport May 25 '13 at 00:11
  • Great! I'll give it a go. I've also tried that a few days back but i think now i understand what went wrong. I'll keep you posted. – user2415320 May 25 '13 at 07:52
  • Ok... i've tried using multiple viewports, but i couldn't get it to just apply the rotation on the smaller viewport and not the translation and zoom. Sooo.. i think i'll settle with the old school way of doing things (working hard not smart) and i'll show you what i've achieved in a video i've uploaded: http://www.youtube.com/watch?v=OGbfLzj6Dvs That was accomplished by compensating the size of the object with the zoom and rotation of the view matrix. Not elegant, but works. :) Thanks for the help! – user2415320 May 25 '13 at 09:12
0

One thing you could do, albeit a bit overkill, is to first draw the rotating object with no translation but only rotation orthogonally into a texture. See this link.

This way no matter how far the object is, it will be the same size. Once you have your texture, simply do one of two things: Render a quad to the screen in the top left corner with no 3d transformations, or use the sprite interface provided with DirectX to render the texture. Using the sprite interface will essentially do the same thing as using a 2D quad but it may be a bit easier, and from my experience, its pretty fast. Good luck!

Joseph Pla
  • 1,561
  • 1
  • 10
  • 21