Multiple Objects

Started by
11 comments, last by jollyjeffers 18 years, 10 months ago
I learning through the "Intoruction to 3D game programming with DirectX 9.0" book and have got as far as being learning how to draw a spinning cube. After a bit of messing around I figured out how to use D3DXCreateTeapot() to create a teapot and draw that. I can render both but they both spin together and are in the same position. My question is how do I render objects in different places and how do I make them spin seperate to each other? CAn anyone give me a push in the right direction? this is the code im using to draw and rotate the cube:

float currtime = (float)timeGetTime();
			float timedelta = (currtime - lasttime) * 0.001f;

			D3DXMATRIX Rx, Ry;

			static float y = 0.0f;
			static float x = 0.0f;

			D3DXMatrixRotationX(&Rx, x);

			x += timedelta;

			if(x >= 6.28f)
			{
				x = 0.0f;
			}

			D3DXMatrixRotationY(&Ry, y);

			y += timedelta;

			if(y >= 6.28f)
			{
				y = 0.0f;
			}

			D3DXMATRIX p = Rx * Ry;

			d3ddevice->SetTransform(D3DTS_WORLD, &p);

			d3ddevice->Clear(0, 0, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xffffffff, 1.0f, 0);

			d3ddevice->BeginScene();
			d3ddevice->SetStreamSource(0, VB, 0, sizeof(MyVertex));
			d3ddevice->SetIndices(IB);
			d3ddevice->SetFVF(MyVertex::FVF);
			d3ddevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12);
			d3ddevice->EndScene();

			d3ddevice->Present(0,0,0,0);

			lasttime = currtime;

To render the teapot i just use mesh->DrawSubset(0); Thanks for any help
Advertisement
When using the fixed function vertex pipeline (i.e. not using vertex shaders), all your untransformed (i.e. non D3DFVF_XYZRHW) vertices are affected by 3 matrices: The world, view and projection matrices. The world matrix controls things such as the object size, position and orientation. So in your case, simply do a separate:
d3ddevice->SetTransform(D3DTS_WORLD, &matrix);
..for each object you have.

Are vertices transformed when sent to the vertex buffer, or do they get transformed when they are drawn? I guess it wouldnt really make sense to be transformed when they are drawn, but its good to be sure.
Well, they are in fact transformed just when they need to be drawn. This makes sense, since polygons which fail the frustum check (usually a notable percentage of polygons drawn) do not need to go through the vertex processing pipeline at all.

Thinking of vertex shaders, you could also draw a single vertex buffer with different shaders, if the shader would be applied to the vertex buffer, instead of on-the-fly when drawing takes place, the vertex buffer would be modified each time you call SetStreamSource() or wherever you would intend on putting the transformation stage then - not a good idea if you compare the speed of static and dynamic vertex buffers ;)

-Markus-
Professional C++ and .NET developer trying to break into indie game development.
Follow my progress: http://blog.nuclex-games.com/ or Twitter - Topics: Ogre3D, Blender, game architecture tips & code snippets.
True.

But then how are you supposed to set different transforms for different "world" objects? For instance, if you have 14 rocks, all have different world locations and orientations. How are these applied?
Quote:Original post by Bonehed316
But then how are you supposed to set different transforms for different "world" objects? For instance, if you have 14 rocks, all have different world locations and orientations. How are these applied?

Four options:

1. Multiple draw calls
This is the traditional method; store one rock and 14 matrices. Pair up D3D calls like:

Device->SetStreamSource( ... );Device->SetIndices( ... );//etc...for( int i = 0; i < 14; i++ )    {        Device->SetTransform( D3DTS_WORLD, &rockMatrix );        Device->DrawIndexedPrimitive( ... );    }


2. Extra data
Store 14 copies of similar geometry in your vertex buffer, pre-transformed accordingly. Submit them all as one big draw call.

Not recommended though [smile] - works okay for small sets of static objects, but falls apart when you have large numbers of objects and/or need to update their transformation.

3. Vertex shaders and constants
Some system where you combine #1 and #2 (above) but get the GPU/shader to work out what should be going on. For example, pass various constants/params to the shader so that it can calculate the rotations/translations accordingly.

4. Instancing
A fairly advanced feature available in the latest-and-greatest hardware. Does pretty much exactly what you want in possibly the most efficient possible way. However, support for it isn't really there yet - so i'd class it more of an optimization opportunity than a base-feature.

hth
Jack

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

So you pretty much have to call DIP for every object, and for every texture/render state, I guess.
Quote:Original post by Bonehed316
So you pretty much have to call DIP for every object, and for every texture/render state, I guess.

Yep[attention]

A lot of work done by engine programmers is on algorithms/arrangements/scheduling to reduce the number of state changes and draw calls that are required to render a given scene. Huuuge performance gains are possible [grin]

hth
Jack

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

Ok I have managed to draw them apart using:

d3ddevice->BeginScene();d3ddevice->SetStreamSource(0, VB, 0, sizeof(MyVertex));d3ddevice->SetIndices(IB);d3ddevice->SetFVF(MyVertex::FVF);//CubeD3DXMatrixTranslation(&p, -1.25f, 0.0f, 0.0f);d3ddevice->SetTransform(D3DTS_WORLD, &p);d3ddevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 8, 0, 12);		//TeapotD3DXMatrixTranslation(&p, 1.25f, 0.0f, 0.0f);d3ddevice->SetTransform(D3DTS_WORLD, &p);mesh->DrawSubset(0);d3ddevice->EndScene();


But Im still confused about rotating each of them seperatly using the code in my first post. :S
Well you have two choices. The two rotations can be separate or related. If you just let them spin at the same rate then it's easy:

float currtime = (float)timeGetTime();float timedelta = (currtime - lasttime) * 0.001f;D3DXMATRIX Rx, Ry, Translation;static float y = 0.0f;static float x = 0.0f;D3DXMatrixRotationX(&Rx, x);x += timedelta;if(x >= 2.0f * D3DX_PI)	x = 0.0f;D3DXMatrixRotationY(&Ry, y);y += timedelta;if(y >= 2 * D3DX_PI)	y = 0.0f;D3DXMatrixTranslation(&Translation, 1.5f, 0.0f, 0.0f);D3DXMATRIX p = Rx * Ry * Translation;d3ddevice->SetTransform(D3DTS_WORLD, &p);d3ddevice->DrawPrimitive(...);D3DXMatrixTranslation(&Translation, -1.5f, 0.0f, 0.0f);p = Rx * Ry * Translationd3ddevice->SetTransform(D3DTS_WORLD, &p);mesh->DrawSubset(0);


If you want them to be indepdant of each other I'm afraid it gets a little more complicated. Here's one possiblity:

struct WorldMatrix{	D3DXVECTOR3 position;	float RotationX, RotationY, RotationZ;	D3DXMATRIX GetMatrix()	{		D3DXMATRIX matrix, rx, ry, rz, translation;		while(RotationX >= 2.0f * D3DX_PI) RotationX -= 2.0f * D3DX_PI;		while(RotationY >= 2.0f * D3DX_PI) RotationY -= 2.0f * D3DX_PI;		while(RotationZ >= 2.0f * D3DX_PI) RotationZ -= 2.0f * D3DX_PI;		D3DXMatrixRotationX(&rx, RotationX);		D3DXMatrixRotationX(&ry, RotationY);		D3DXMatrixRotationX(&rz, RotationZ);		D3DXMatrixTranslation(&translation, position.x, position.y, position.z);		matrix = ry * rx * rz * translation;		return matrix;	}};float currtime = (float)timeGetTime();float timedelta = (currtime - lasttime) * 0.001f;static WorldMatrix Teapot;static WorldMatrix Box;Teapot.RotationX += timedelta;Box.RotationX += timedelta;Teapot.RotationY += timedelta;Box.RotationY += timedelta;d3ddevice->SetTransform(D3DTS_WORLD, &Box.GetMatrix());d3ddevice->DrawPrimitive(...);d3ddevice->SetTransform(D3DTS_WORLD, &Teapot.GetMatrix());mesh->DrawSubset(0);


If you don't understand what that second example is doing, post back here and I (or one of many other kind folks) will try to explain.

Hope that helps!

This topic is closed to new replies.

Advertisement