Drawing an Interface on top of a 3D Scene

Started by
8 comments, last by 31337 19 years, 7 months ago
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.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.
OpenGL Revolutions http://students.hightechhigh.org/~jjensen/
Advertisement
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.
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
For the love of god, please tell me that you've just omitted your error checking code for brevity, and you don't really assume that all those functions succeed.
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...
Thanks for the help guys. I am most interested in:

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.

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.
OpenGL Revolutions http://students.hightechhigh.org/~jjensen/
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.
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.w        = 1.0;		pVertices.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]
OpenGL Revolutions http://students.hightechhigh.org/~jjensen/
I made it so that it stopped rendering the 3D scene in the background and now it works... why??
OpenGL Revolutions http://students.hightechhigh.org/~jjensen/
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"...
Yah I figured it out, it kinda makes me angry but it was that I had a texture set and wasn't giving it u v coordinates. Doh! Thanks for the help.
OpenGL Revolutions http://students.hightechhigh.org/~jjensen/

This topic is closed to new replies.

Advertisement