Unsure how to create a background

Started by
16 comments, last by MasterWorks 16 years, 2 months ago
Hi, i'm currently unsure of how to go about doing my background in Direct3D 9. I'm making a small game (simple point and click e.g monkey island) that will have a 2D Texture as the background, with a few 3D models in the foreground. The only way I know on how to do this is to create a geometric quad, however I'm struggling to get the 'perfect' lookat camera angle to work (there are either gaps between the window edge and the quad or part of the quad is cut off from viewing). I'm not very familiar with sprites, as the book that I'm learning from only ever talks about the 3d stuff, plus I think I've read somewhere that its best to use quads anyway. How should I go about do this, and if using a quad is the best idea, how do I get the view right? Thanks in advance
Advertisement
From your description you really want to be rendering your background in 2D rather than as a billboard/imposter.

It is perfectly normal to mix rendering like this, so just because you have some 3D elements doesn't mean everything must be 3D (although, strictly speaking its more "2D in 3D" as you still have a depth axis [smile]).

Use of ID3DXSprite is a nice and simple way of doing things, but manually creating a full-screen "transformed and lit quad" (aka 'TL Quad') is easy enough. Look up the D3DFVF_XYZRHW or POSITIONT vertex data formats.

hth
Jack

<hr align="left" width="25%" />
Jack Hoxley <small>[</small><small> Forum FAQ | Revised FAQ | MVP Profile | Developer Journal ]</small>

This is how I've been doing this sort of thing.

d3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);IDirect3DSurface9* backBuffer = NULL;d3dDevice->GetBackBuffer(0,0,D3DBACKBUFFER_TYPE_MONO,&backBuffer);// IDirect3DSurface9* background; // Initialized outside the render loop!d3dDevice->UpdateSurface(background,NULL,backBuffer,NULL);d3dDevice->BeginScene();// ... rest of render loop ...


No idea of the performance of this method compared to ID3DXSprite or a textured quad.
Whilst not as terrible as messing with the raw backbuffer data, I'd suspect that your code is not as efficient as a full-screen TL quad. Then again, if you're not stressing out the GPU and performance isn't an issue it is a neat and elegant solution to the problem [smile]

Jack

<hr align="left" width="25%" />
Jack Hoxley <small>[</small><small> Forum FAQ | Revised FAQ | MVP Profile | Developer Journal ]</small>

I've followed this websites advise http://nexe.gamedev.net/directKnowledge/default.asp?p=2D%20In%20Direct3D , and created the follow (bear in mind i'm using vertex elements in preparation for when I implement shaders)

struct VertPosTexRhw{	VertPosTexRhw(float x, float y, float z, float RHW			   float u, float v)		: p(x,y,z), t0(u,v), rhw(RHW) {}	D3DXVECTOR3 p;	float	rhw;	D3DXVECTOR2 t0;	static LPDIRECT3DVERTEXDECLARATION9 Decl;};...D3DVERTEXELEMENT9 VertPosTexRhwElements[] =	{		{0, 0,  D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},		{0, 12, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},		{0, 20,	D3DDECLTYPE_FLOAT1, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITIONT, 1},		D3DDECL_END()	};	device->CreateVertexDeclaration(VertPosTexRhwElements, &VertPosTexRhw::Decl);


and for creating the quad i've done:

void gfxBackground::BuildVertexBuffer(LPDIRECT3DDEVICE9 device){	device->CreateVertexBuffer(4*sizeof(VertPosTexRhw), // Number of vertices * Custom Vertex		D3DUSAGE_WRITEONLY, 0, D3DPOOL_MANAGED, &m_vb, 0);	VertPosTexRhw *v = 0;	m_vb->Lock(0, 0, (void**)&v, 0);	v[0] = VertPosTexRhw(-1.0f,  1.0f,  1.0f,  1.0f,  0.0f,  0.0f);	v[1] = VertPosTexRhw( 1.0f,  1.0f,  1.0f,  1.0f,  0.0f,  1.0f);	v[2] = VertPosTexRhw( 1.0f, -1.0f,  1.0f,  1.0f,  1.0f,  1.0f);	v[3] = VertPosTexRhw(-1.0f, -1.0f,  1.0f,  1.0f,  1.0f,  0.0f);	m_vb->Unlock();}...void gfxBackground::BuildIndexBuffer(LPDIRECT3DDEVICE9 device){	device->CreateIndexBuffer(2*3*sizeof(WORD), // Number of triangles * 3 * sizeof		D3DUSAGE_WRITEONLY,	D3DFMT_INDEX16, D3DPOOL_MANAGED, &m_ib, 0);	WORD *i = 0;	m_ib->Lock(0, 0, (void**)&i, 0);	i[0] = 0; i[1] = 1; i[2] = 2;	i[3] = 0; i[4] = 2; i[5] = 3;	m_ib->Unlock();}...void gfxBackground::Display(LPDIRECT3DDEVICE9 device, const D3DMATERIAL9* mtrl, LPDIRECT3DTEXTURE9 tex){	device->SetTexture(0, tex);	device->SetMaterial(mtrl);	device->SetStreamSource(0, m_vb, 0, sizeof(VertPosTexRhw));	device->SetIndices(m_ib);	device->SetVertexDeclaration(VertPosTexRhw::Decl);	// Draw the background	device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 4, 0, 2);	// TRIANGLELIST, 0, 0, How many vertices, 0, How many triangles}


But the quad doesn't show now? Am I miss using the rhw thing
Quote:Original post by jollyjeffers
Whilst not as terrible as messing with the raw backbuffer data, I'd suspect that your code is not as efficient as a full-screen TL quad. Then again, if you're not stressing out the GPU and performance isn't an issue it is a neat and elegant solution to the problem [smile]

Jack


I built a simple application to test your suspicion and found that using ID3DXSprite in place of an UpdateSurface call like I had above was about 8% faster in my test case (1024x768 windowed, no other geometry). Good to know.

I think this type of problem comes up a lot because people don't realize how general-purpose Direct3D is. When I was learning D3D coming from a 2D game background I didn't realize the full flexibility you have to render things both '2D' and '3D' in the same frame. You're free to build up the frame buffer(s) with all kinds of pixels coming from different textures, vertex formats, models, whatever. It's totally up to you how to paint the blank canvas that you're given at the start of each frame. Whatever you render first (like a huge sprite or textured quad) will be in the background; don't worry about making sure it fits into your 'world' with the correct units, alignment, and all that garbage.
So what is more popular/effecient to use for a background, a sprite or this TL Quads I can't get the hang of
As my understanding of Direct3D and ID3DXSprite goes, sprites are actually textured, lit quads. They just come wrapped in a handy interface to handle the complex bits for you.
Ok, well I tried to get the POSITIONT stuff to work but either nothing shows up on screen or it just acts as a normal quad.

I've now implemented a sprite correctly, but I'm still struggling on how I get it to fit the window properly?

This topic is closed to new replies.

Advertisement