Sign in to follow this  
31337

Drawing an Interface on top of a 3D Scene

Recommended Posts

I am trying to render a 3D scene in the background behind an interface of 2D buttons. I also want to be able to hit test the boxes vs the mouse very easily. What is the easiest way to do this? I was thinking that I could just change the projection, viewing, and world matrices after having rendered the perspective scene to fitting an orthographic projection but this doesn't seem to work. For some reason I can't get the second set of stuff to render. Basically my current approach is rendering like this: *Setup perspective cam* *Render perspective background scene* *Setup orthographic cam* *Render orthographic interface scene* Is there anything else I need to do to get this to work? How am I going to hit test the buttons? I'm setting my matricies with this function:
[SOURCE]
D3DXMATRIX mPerspective, mView, mWorld;
	D3DXVECTOR3 vEye, vAt, vUp;

	vEye.x = 0.0;
	vEye.y = 0.0;
	vEye.z = 0.0;

	vAt.x  = 0.0;
	vAt.y  = 0.0;
	vAt.z  = 1.0;

	vUp.x  = 0.0;
	vUp.y  = 1.0;
	vUp.z  = 0.0;

	D3DXMatrixOrthoLH(&mPerspective, 10.0f, 10.0f, 1.0, 10.0);
	CBase::m_pDevice->SetTransform(D3DTS_PROJECTION, &(D3DMATRIX)mPerspective);
	
	D3DXMatrixIdentity(&mWorld);
	CBase::m_pDevice->SetTransform(D3DTS_WORLD, &(D3DMATRIX)mWorld);

	D3DXMatrixLookAtLH(&mView, &vEye, &vAt, &vUp);
	CBase::m_pDevice->SetTransform(D3DTS_VIEW, &(D3DMATRIX)mView);
[/SOURCE]
and I'm trying to render a sample box with this setup code:
[SOURCE]
if(FAILED(CBase::m_pDevice->CreateVertexBuffer(sizeof(TextureVertex_t)*6, D3DCREATE_HARDWARE_VERTEXPROCESSING, 
												   D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1, D3DPOOL_DEFAULT, 
												   &m_pButton, NULL))) {
		return false;
	}
    TextureVertex_t *pVertices;
	if(FAILED(m_pButton->Lock(0, 0, (void **)&pVertices, 0))) {
		return false;
	}
	pVertices[0].x = 0.0f;
	pVertices[0].y = 0.0f;
	pVertices[0].z = 0.0f;
	pVertices[0].u = 0.0f;
	pVertices[0].v = 0.0f;

	pVertices[1].x = BUTTON_SIZEX;
	pVertices[1].y = 0.0f;
	pVertices[1].z = 0.0f;
	pVertices[1].u = 1.0f;
	pVertices[1].v = 0.0f;

	pVertices[2].x = 0.0f;
	pVertices[2].y = BUTTON_SIZEY;
	pVertices[2].z = 0.0f;
	pVertices[2].u = 0.0f;
	pVertices[2].v = 1.0f;

	pVertices[3].x = 0.0f;
	pVertices[3].y = BUTTON_SIZEY;
	pVertices[3].z = 0.0f;
	pVertices[3].u = 0.0f;
	pVertices[3].v = 1.0f;

	pVertices[4].x = BUTTON_SIZEX;
	pVertices[4].y = 0.0f;
	pVertices[4].z = 0.0f;
	pVertices[4].u = 1.0f;
	pVertices[4].v = 0.0f;

	pVertices[5].x = BUTTON_SIZEX;
	pVertices[5].y = BUTTON_SIZEY;
	pVertices[5].z = 0.0f;
	pVertices[5].u = 1.0f;
	pVertices[5].v = 1.0f;

	for(int i=0; i<6; i++) {
		pVertices[i].dDiffuse = D3DCOLOR_ARGB(125, 0, 255, 255);
	}
	if(FAILED(m_pButton->Unlock())) {
		return false;
	}
[/SOURCE]
and then I'm rendering that vertex buffer with this code:
[SOURCE]
//CBase::m_pDevice->SetTexture(0, NULL);
	CBase::m_pDevice->SetStreamSource(0, m_pButton, 0, sizeof(TextureVertex_t));
	CBase::m_pDevice->SetFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
	CBase::m_pDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);
[/SOURCE]
Does it have something to do with me not giving it a texture to put on it? I'm sort of stuck. Thanks for the help in advance.

Share this post


Link to post
Share on other sites
The easiest is to use XYZRHW coordinates for your 2D parts. This makes x and y specified in pixels, z needs to be between 0 and 1, and w should be 1.0f. You can disable Z temporarily to ensure your 2D parts remain on top of everything else, or try using a 0 (or near 0...maybe some cards discard 0 depth) for Z.

To hit test, just get the mouse coord and test vs. your box, since they're both in pixels, it's easy.

Share this post


Link to post
Share on other sites
Quote:
Original post by 31337
I am trying to render a 3D scene in the background behind an interface of 2D buttons. I also want to be able to hit test the boxes vs the mouse very easily. What is the easiest way to do this?


There is code in the latest SDK (9.0c - Summer Update 2004) which does exactly what you want, which is part of the new sample framework.

You can use push buttons, radio buttons, check boxes, edit controls, combo boxes etc.

All hit testing and message handling is done for you.

HTH,
Cambo_frog

Share this post


Link to post
Share on other sites
that's the new gui system isn't it?

anyway, why not use sprites, blit to screen coordinates (with or without alpha). Then to test mouseover use 2d mouse position, to test a click check for mouseover and a click. Simple as that...
In fact, if you don't need transparency, you could use a surface and call a copyrect...

Share this post


Link to post
Share on other sites
Thanks for the help guys. I am most interested in:

[QUOTE]The easiest is to use XYZRHW coordinates for your 2D parts. This makes x and y specified in pixels, z needs to be between 0 and 1, and w should be 1.0f. You can disable Z temporarily to ensure your 2D parts remain on top of everything else, or try using a 0 (or near 0...maybe some cards discard 0 depth) for Z.[/QUOTE]

What do I do for my matrices? Since I'm setting 1.0 to W does that make it so that its already transformed? What exactly are XYZRHW coordinates? Do I use hardware vertex processing for the vertex buffer or software? Thanks for the help.

Share this post


Link to post
Share on other sites
XYZRHW is used for pre-transformed vertices. Not just transformed by world,view,proj, but divided by W and run through the viewport scaling matrix too... which means, they're exact pixel locations. Your world,view,proj matrices should not matter, as the vertex will not be transformed again.

RHW stands for Reciprocal of Homogenous W. I don't pretend to know what that means (except maybe it implies dividing by W).

Use whatever vertex processing you're already using for everything else.

Share this post


Link to post
Share on other sites
Ok so I've tried getting the already transformed polygons to work so that they will appear on top, and I have this major problem. For some reason the polygons pop up for like the first frame and then disappear, and only when I render the buttons for the interface (2D) FIRST, but when I render it second I don't even see anything. What am I doing that's messing this up? I've posted by loading code below for the 2D:

[SOURCE]if(FAILED(CBase::m_pDevice->CreateVertexBuffer(sizeof(ColorVertexW_t)*6, 0,
D3DFVF_XYZRHW | D3DFVF_DIFFUSE, D3DPOOL_DEFAULT, &m_pButton, NULL))) {
return false;
}
ColorVertexW_t *pVertices;
if(FAILED(m_pButton->Lock(0, 0, (void **)&pVertices, 0))) {
return false;
}
pVertices[0].x = 0.0f;
pVertices[0].y = 0.0f;
pVertices[0].z = 0.5f;
//pVertices[0].u = 0.0f;
//pVertices[0].v = 0.0f;

pVertices[1].x = BUTTON_SIZEX;
pVertices[1].y = 0.0f;
pVertices[1].z = 0.5f;
//pVertices[1].u = 1.0f;
//pVertices[1].v = 0.0f;

pVertices[2].x = 0.0f;
pVertices[2].y = BUTTON_SIZEY;
pVertices[2].z = 0.5f;
//pVertices[2].u = 0.0f;
//pVertices[2].v = 1.0f;

pVertices[3].x = 0.0f;
pVertices[3].y = BUTTON_SIZEY;
pVertices[3].z = 0.5f;
//pVertices[3].u = 0.0f;
//pVertices[3].v = 1.0f;

pVertices[4].x = BUTTON_SIZEX;
pVertices[4].y = 0.0f;
pVertices[4].z = 0.5f;
//pVertices[4].u = 1.0f;
//pVertices[4].v = 0.0f;

pVertices[5].x = BUTTON_SIZEX;
pVertices[5].y = BUTTON_SIZEY;
pVertices[5].z = 0.5f;
//pVertices[5].u = 1.0f;
//pVertices[5].v = 1.0f;

for(int i=0; i<6; i++) {
pVertices[i].w = 1.0;
pVertices[i].dDiffuse = D3DCOLOR_XRGB(255, 255, 255);
}
if(FAILED(m_pButton->Unlock())) {
return false;
}
return true;[/SOURCE]


Below this is the drawing code:
[SOURCE]
CBase::m_pDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, true);

CBase::m_pDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
CBase::m_pDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);

CBase::m_pDevice->SetRenderState(D3DRS_ZENABLE, FALSE);
CBase::m_pDevice->SetRenderState(D3DRS_FOGENABLE, (DWORD)false);
//CBase::m_pDevice->SetRenderState(D3DRS_FOGCOLOR, (DWORD)ARGB(255, 0, 0, 0));
//CBase::m_pDevice->SetRenderState(D3DRS_FOGVERTEXMODE, D3DFOG_LINEAR);
//CBase::m_pDevice->SetRenderState(D3DRS_FOGSTART, (*(DWORD *)&fValue));
//fValue = 10.0;
//CBase::m_pDevice->SetRenderState(D3DRS_FOGEND, (*(DWORD *)(&fValue)));

CBase::m_pDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
CBase::m_pDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
//CBase::m_pDevice->SetTexture(0, NULL);
CBase::m_pDevice->SetStreamSource(0, m_pButton, 0, sizeof(ColorVertexW_t));
CBase::m_pDevice->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE);
CBase::m_pDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);
[/SOURCE]

Share this post


Link to post
Share on other sites
Some render state must be getting set that's interfering. Try adding in little sections of the code until it breaks.

Eventually you should be able to narrow down what's causing the problem, at which point you'll probably say "D'oh! Why didn't I think of that sooner"...

Share this post


Link to post
Share on other sites

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