Sign in to follow this  

Width and height of orthogonal projection does not work correctly

This topic is 3563 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

(EDIT: Changed the subject to a more appropiate one) Hi experts! :) I'm working on my own GUI (Yes, yes, I know, there are lots of them, but i'm doing it to get some experience with D3D) and I got it working with pre-transformed vertices. (I think that's the right terminology - Vertices that have the FVF_XYZRHW component) But I realized it limited me in several ways, so I wanted to make it with orthogonal projection instead. But I'm having problems with it. I use the function D3DMatrixOrthoOffCenterLH to decide the size of the 'view'. I create it like this:
D3DXMatrixOrthoOffCenterLH(&m_projectionMatrix, 0.0f, 800.0f, 0.0f, 600.0f, 1.0f, 100.0f);
I set the minimum X to 0 and maximum X to 800. If I create a quad and positions it at 0,0 it appears in the bottom left corner. That's great. But when I translate it in X to 400, it goes off screen. And this is the part I don't get. I just created my orthogonal projection matrix with a width of 800, so why does my quad leave the screen at 400? As you can see on the width and height, I tried to map 1 unit to 1 pixel. How should I go about doing this? Is it even possible? I probably should mention that my view matrix is the identity matrix. As I'm not sure where the problem lies, I'm not sure what code to post. And I don't want to spam you guys. But if it can be of any help, I'll gladly post source code. I really appreciate any help given! Thanks in advance! [Edited by - rene_g on March 6, 2008 5:49:31 AM]

Share this post


Link to post
Share on other sites
That looks fine to me at first glance. Do you get the same effect moving in Y? Do you know approximately where the edge of your screen seems to be? I have almost identical code in my engine which works fine...

Share this post


Link to post
Share on other sites
Yes, the effect is the same in Y.

My quad (With dimensions 50x50) leaves horizontally when X >= 400 and leaves vertically at the top when Y >= 300

400 is half the width I set, and 300 is half the height. Hmm.

Could it be a renderstate I've sat?

Share this post


Link to post
Share on other sites
Quote:
Original post by rene_g
Yes, the effect is the same in Y.

My quad (With dimensions 50x50) leaves horizontally when X >= 400 and leaves vertically at the top when Y >= 300

400 is half the width I set, and 300 is half the height. Hmm.

Could it be a renderstate I've sat?
Hmm, I'm sure I've seen that bug before, but I can't remember what causes it :/

The only render state that should affect it would be the world matrix, if you have some scale in there.

Share this post


Link to post
Share on other sites
I'm not scaling anywhere in my code.

Am I calculating the translation matrix incorrectly then? Here's how I do it:

D3DXMatrixTranslation(&m_transform, m_entity.GetPositionX(), m_entity.GetPositionY(), 5.0f); // Save the translation in the transform matrix
// Just when I'm about to draw the quad I call this
SetTransform(D3DTS_WORLD, &m_transform);


Am I setting the transformation in a wrong way?

For completeness sake, here is the code of how I prepare the projection and view matrix:

D3DXMatrixIdentity(&m_viewMatrix);
D3DXMatrixOrthoOffCenterLH(&m_projectionMatrix, 0.0f, 800.0f, 0.0f, 600.0f, 1.0f, 100.0f);
m_device->SetTransform(D3DTS_VIEW, &m_viewMatrix);
m_device->SetTransform(D3DTS_PROJECTION, &m_projectionMatrix);


And here is which renderstates I use:

Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
Device->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
Device->SetRenderState(D3DRS_LIGHTING, false);
Device->SetRenderState(D3DRS_NORMALIZENORMALS, true);
Device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);


I've tried googling for an answer, but I can't find any useful information on orthogonal projection in Direct3D.

I really hope somone is able to help me with this!

Thanks for your help so far Evil Steve. :-)

Share this post


Link to post
Share on other sites
I've tried using D3DXMatrixOthoLH instead of D3DXMatrixOrthoOffCenterLH, but it gives the same result. (Although 0,0 is now at the center of the screen)

The problem remains the same even if I change the size of the orthogonal projection, to fx. 100 x 100. Then the quad leaves the screen at 100 / 2 / 2 = 25. (Remember that 0,0 is now at the center of the screen)

I've tried searching and searching, and I've found some that do orthogonal projection, but I do it the same way. (Well, so it seems, but there must be something wrong somewhere...)

The orthogonal projection don't care about the viewport, right?

Or the actual pixel size of the window?

Or the pixel size I sat in the present parameters when creating my device?

When I run my program through PIX, the coordinates on my quad is exactly as I set them in the code, so there's no transformation going on 'that I've forgot'.

This is so weird! 8-|

Share this post


Link to post
Share on other sites
Previously, I wasn't setting it to anything, but in my struggle to figure out what I've done wrong, I'm setting it now, like this:

D3DVIEWPORT9 viewport = { 0, 0, 800, 600, 0.0f, 1.0f };
Device->SetViewport(&viewport);


Here is how I create the device, set the matrices and renderstates:

D3DPRESENT_PARAMETERS pp;
pp.BackBufferWidth = ClientRect.right - ClientRect.left;
pp.BackBufferHeight = ClientRect.bottom - ClientRect.top;
pp.BackBufferFormat = D3DFMT_A8R8G8B8;
pp.BackBufferCount = 1;
pp.MultiSampleType = D3DMULTISAMPLE_NONE;
pp.MultiSampleQuality = 0;
pp.SwapEffect = D3DSWAPEFFECT_DISCARD;
pp.hDeviceWindow = Handle;
pp.Windowed = true;
pp.EnableAutoDepthStencil = true;
pp.AutoDepthStencilFormat = D3DFMT_D24S8;
pp.Flags = 0;
pp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
pp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
HRESULT hr = d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, Handle, VertexProcessing, &pp, &Device);

D3DVIEWPORT9 viewport = { 0, 0, 800, 600, 0.0f, 1.0f };
Device->SetViewport(&viewport);

D3DXVECTOR3 position(0.0f, 15.0f, -0.001f);
D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
D3DXMATRIX view;
D3DXMatrixLookAtLH(&view, &position, &target, &up);

Device->SetTransform(D3DTS_VIEW, &view);

D3DXMATRIX proj;
Device->SetTransform(D3DTS_PROJECTION, &proj);

D3DXMATRIX world;
D3DXMatrixIdentity(&world);
Device->SetTransform(D3DTS_WORLD, &world);

Device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
Device->SetRenderState(D3DRS_SHADEMODE, D3DSHADE_GOURAUD);
Device->SetRenderState(D3DRS_LIGHTING, false);
Device->SetRenderState(D3DRS_NORMALIZENORMALS, true);
Device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);





Here is some of the code to create my window:

WindowClass.style = CS_HREDRAW | CS_VREDRAW;
WindowClass.lpfnWndProc = pWindowProc;
WindowClass.cbClsExtra = 0;
WindowClass.cbWndExtra = 0;
WindowClass.hInstance = Instance;
WindowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WindowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WindowClass.hbrBackground = NULL;
WindowClass.lpszMenuName = NULL;
WindowClass.lpszClassName = L"D3D_FW Window";

Windowstyle = WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX;
ExWindowstyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;

WindowRect.right = 800;
WindowRect.bottom = 600;

// Elsewhere in my code...

if (!RegisterClass(&WindowClass))
return false;
if (!AdjustWindowRectEx(&WindowRect, Windowstyle, false, ExWindowstyle))
return false;
Handle = CreateWindowEx(ExWindowstyle,
WindowClass.lpszClassName,
WindowCaption, Windowstyle,
CreatePosX,
CreatePosY,
WindowRect.right - WindowRect.left,
WindowRect.bottom - WindowRect.top,
Parent,
NULL,
Instance,
NULL);





As you see, I create a matrix projection when creating my device. However, when I'm about to render my gui elements, this following function is called, which change the projection matrix:


void GuiManager::Draw()
{
D3DXMATRIX oldViewMatrix, oldProjectionMatrix;
m_device->GetTransform(D3DTS_VIEW, &oldViewMatrix);
m_device->GetTransform(D3DTS_PROJECTION, &oldProjectionMatrix);

m_device->SetTransform(D3DTS_VIEW, &m_viewMatrix);
m_device->SetTransform(D3DTS_PROJECTION, &m_projectionMatrix);

if (HasChildren())
{
list<Entity*>::reverse_iterator runner;
Entity * child;
for (runner = m_entities.rbegin(); runner != m_entities.rend(); ++runner)
{
child = *runner;
child->Draw();
}
}

m_device->SetTransform(D3DTS_VIEW, &oldViewMatrix);
m_device->SetTransform(D3DTS_PROJECTION, &oldProjectionMatrix);
}



And I set m_viewMatrix and m_projectionMatrix in my GuiManager constructor, like this:

D3DXMatrixIdentity(&m_viewMatrix);
//D3DXMatrixOrthoOffCenterLH(&m_projectionMatrix, 0.0f, 800.0f, 0.0f, 600.0f, 1.0f, 100.0f);
D3DXMatrixOrthoLH(&m_projectionMatrix, 100.0f, 100.0f, 1.0f, 100.0f);


The line I've commented out is the one I started out with, but as I've continued to try different things to figure out what's going wrong, I've tried with the normal ortho matrix, but the result is the same.

Thanks for your time, I really appreciate it!

Share this post


Link to post
Share on other sites
I'm not sure if the following has any effect on your problem, rene_g, but there are some inconsistencies in the way you setup your window.

The info on AdjustWindowRectEx states that you cannot use the WS_OVERLAPPED style. I think you need to either set a different style or use AdjustWindowRect/CreateWindow rather than AdjustWindowRectEx/CreateWindowEx.

By any chance, are you trying to set a full screen window?

Share this post


Link to post
Share on other sites
I'm totally stuck with this...

I've compressed the entire solution and uploaded it here: <LINK REMOVED - SEE NEXT POST>

If anyone has the time, I would be really grateful if they would look over my source code and see if they can find the problem.

The zipped package is 18 kb, so it's really quick to download. The solution file is for Visual C++ 2005.

The points of interest are:
Window.h / Window.cpp -> A helper class, to create and initialize a win32 window
D3D_Window.h / D3D_Window.cpp -> A helper class, inheriting from Window, providing Direct3D support for the window.
GuiManager.cpp -> Here is the call to D3DXMatrixOrthoLH, in the constructor.
TestWindow.cpp -> This is where I'm setting the position and dimensions of the quad. (In the WindowController constructor, near the bottom of the source file)

I would truly love any sort of input on the source code, in this regard.

Best regards
René

[Edited by - rene_g on March 10, 2008 10:34:09 AM]

Share this post


Link to post
Share on other sites
FINALLY! I figured it out! Oh, the joy! The satisfaction!

Anyway, the problem was with the code where I created my quad. I used the position of my quad class to create the vertices 'in position' so to speak. However, before drawing it to the screen, I also moved it with the world transform matrix. So in essence, when I sat the position of my quad, it actually doubled the horizontal and vertical position.

So it was actually just a silly error. I can't believe it took me so long to figure it out. I was so convinced the error had to have something to do with a renderstate, or an incorrect world transform matrix, that I didn't think of the creation of the quad to be the problem.

I found the error by comparing a working sample I downloaded and changing that to use orthogonal projection. The result was as expected: It worked just as it should. So after studying the differences, it suddenly just hit me: Maybe I was double transforming my vertices, and there it was.

But thanks alot for your suggestions and comments! I appreciate it. :-)

Best regards
René

Share this post


Link to post
Share on other sites

This topic is 3563 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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this