Prt6a - Sphere "AKA Ball"
Author: bkenwright@xbdev.net
Squares, and cubes and other small shapes, this tutorial will give you a feel
of how shapes can be generated using algorithms. I don't know if you've
used such packages as 3D Studio Max and Maya or even MilkShape - but these
packages allow you to draw 3D shapes in your scene, specify there width, there
complexity etc. These are generated as I'll show you now.
Not before you even think of looking at this code, I'd go and grab 4 or 5
cups of coffee....its a scary beast... once you grasp it though you'll be using
a it a lot in the future for cool effects in your games. You could
represent bullets etc using the sphere..
Now where going in, hold on tight, and don't stick your arms out......
This is it!...The magic function.... of course its not optimised or anything,
but you could copy and paste this into any project and....tadaaa...a sphere
would be born on your screen.
//NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW
//NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW
void
DrawSphere()
{
UINT
D3DFVF_CUSTOMVERTEX = (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_DIFFUSE);
struct CUSTOMVERTEX
{
FLOAT x, y, z; //Vertex position
FLOAT nx, ny, nz; //Direction the vertex is
facing(normal)
DWORD colour; //The vertex colour.
};
//These two variables determine the quality of our
sphere, try changing them,
//if you put a large number in them you'll get a
very details sphere...made
//up of very small triangles.
int nRings = 15;
int nSegments = 12;
DWORD
dwNumOfVertices = (nRings + 1) * (nSegments + 1);
DWORD
dwNumOfIndices = 2 * nRings * (nSegments + 1);
LPDIRECT3DVERTEXBUFFER8 pVertexBuffer = NULL;
IDirect3DIndexBuffer8* pIndexBuffer = NULL;
g_pD3DDevice->CreateVertexBuffer(dwNumOfVertices *
sizeof(CUSTOMVERTEX),
0,
D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT, &pVertexBuffer);
g_pD3DDevice->CreateIndexBuffer(dwNumOfIndices *
sizeof(WORD),
0,
D3DFMT_INDEX16, D3DPOOL_MANAGED,
&pIndexBuffer);
WORD
*pIndices;
CUSTOMVERTEX *pVertex;
pVertexBuffer->Lock(0,0, (BYTE**)&pVertex, 0);
pIndexBuffer->Lock(0,dwNumOfIndices, (BYTE**)&pIndices, 0);
WORD
wVertexIndex = 0;
D3DXVECTOR3 vNormal;
//Setup some angles
float rDeltaRingAngle = (D3DX_PI / nRings);
float rDeltaSegAngle = (2.0f * D3DX_PI /
nSegments);
float red = 0.0f, green = 1.0f, blue = 0.0f;
//Generate the group of rings for the sphere
for(int
nCurrentRing = 0; nCurrentRing < nRings + 1; nCurrentRing++)
{
float r0 = sinf(nCurrentRing * rDeltaRingAngle);
float y0 = cosf(nCurrentRing * rDeltaRingAngle);
//OOooo Gerneate the group of segments for the
current ring
for(int
nCurrentSegment=0; nCurrentSegment < nSegments + 1; nCurrentSegment++)
{
float x0 = r0 *
sinf(nCurrentSegment * rDeltaSegAngle);
float z0 = r0 *
cosf(nCurrentSegment * rDeltaSegAngle);
vNormal.x = x0;
vNormal.y = y0;
vNormal.z = z0;
D3DXVec3Normalize(&vNormal, &vNormal);
//Add one vector to the strip
which makes up the sphere
pVertex->x = x0;
pVertex->y = y0;
pVertex->z = z0;
pVertex->nx = vNormal.x;
pVertex->ny = vNormal.y;
pVertex->nz = vNormal.z;
pVertex->colour = D3DXCOLOR(red, green, blue, 1.0f);
red += 0.02f;
blue += 0.01f;
green -= 0.015f;
//You could set all the vertices
the same colour, but to add a some different colours
//I'll add a variable that changes
//pVertex->colour = 0xff00ff00;
/*
//Alternatively you could set texture coordinates e.g:
pVertex->tu = 1.0f - ( (float)nCurrentSegment / (float)nSegments
);
pVertex->tv = (float)nCurrent / (float)nRings;
*/
pVertex++;
//Add two indices except for the last
ring
if(nCurrentRing != nRings)
{
*pIndices = wVertexIndex;
pIndices++;
*pIndices = wVertexIndex + (WORD)(nSegments + 1);
pIndices++;
wVertexIndex++;
}
}
}
pIndexBuffer->Unlock();
pVertexBuffer->Unlock();
g_pD3DDevice->SetStreamSource(0, pVertexBuffer,
sizeof(CUSTOMVERTEX));
g_pD3DDevice->SetVertexShader(D3DFVF_CUSTOMVERTEX);
//Select the index buffer
g_pD3DDevice->SetIndices(pIndexBuffer, 0);
DWORD
dwNumOfPolygons = dwNumOfIndices - 2;
//Render the polygons from the index buffer
//Note ~ That you can change D3DPT_LINESTRIP to
D3DPT_TRIANGLESTRIP to see the
//coloured in - by using the linestrip we see the
sphere as a mesh.
g_pD3DDevice->DrawIndexedPrimitive(D3DPT_LINESTRIP, 0, dwNumOfVertices, 0,
dwNumOfPolygons);
pIndexBuffer->Release();
pVertexBuffer->Release();
}
//NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW
//NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW
Well there's other parts of the code .... I added a little bit of matrix's in
part 2, so make sure you see the differences in this and the next part....itsso
that you could see the sphere rotate - matrixes are scares...even to me.. which
is why later I promise a tutorial on them. ABC to Matrices at a screen
near you soon.
//Main header file for the XDK
#include
<xtl.h>
LPDIRECT3D8
g_pD3D = NULL; // DirectX
Object
LPDIRECT3DDEVICE8 g_pD3DDevice = NULL; //
Screen Object
void
InitialiseD3D()
{
g_pD3D
= Direct3DCreate8(D3D_SDK_VERSION);
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.BackBufferWidth = 640;
d3dpp.BackBufferHeight = 480;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferCount = 1;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
g_pD3D->CreateDevice(0, D3DDEVTYPE_HAL, NULL,
D3DCREATE_HARDWARE_VERTEXPROCESSING,
&d3dpp, &g_pD3DDevice);
//NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW
NEW NEW NEW NEW NEW NEW
g_pD3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
//Turn on z-buffering
g_pD3DDevice->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);
//Turn off culling - so we can see the back of the
sphere :)
g_pD3DDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
}
void
CleanUp()
{
g_pD3DDevice->Release();
g_pD3D->Release();
}
And finally our entry point. Now if you look carefully you'll notice a
few new lines... don't be scared.... all these do is put a camera in the
picture. Well originally we where set in a fixed position, e.g. at 0,0,0
looking into the screen. With these few lines of code we can look anywhere
we want... up, down ... we can even write it so that if we move our game pad the
camera moves and we can go walking around our 3D world. Of course all
thats there at the moment is a sphere....but one day...it will be more.
//Application entry point
void
__cdecl main()
{
InitialiseD3D();
while(true)
{
//Clear the backbuffer to black
g_pD3DDevice->Clear(0, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,
D3DCOLOR_XRGB(0, 0, 255), 1.0f, 0);
//Begin the scene
g_pD3DDevice->BeginScene();
//NEW NEW NEW NEW NEW NEW NEW NEW
NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW
//NEW NEW NEW NEW NEW NEW NEW NEW
NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW
//camera
D3DXMATRIX view_matrix, matProj;
D3DXMatrixLookAtLH(&view_matrix,&D3DXVECTOR3( 0.0f,
0.0f,-5.0f ),
&D3DXVECTOR3( 0.0f, 0.0f, 0.0f ),
&D3DXVECTOR3( 0.0f, 1.0f, 0.0f ));
g_pD3DDevice->SetTransform(D3DTS_VIEW,&view_matrix);
D3DXMatrixPerspectiveFovLH(&matProj,
//Result Matrix
D3DX_PI/4,//Field of
View, in radians. (PI/4) is typical
((float)600 / (float)400),
//Aspect ratio
1.0f, //Near view
plane
1000.0f ); // Far view
plane
g_pD3DDevice->SetTransform( D3DTS_PROJECTION, &matProj );
//end camera
//NEW NEW NEW NEW NEW NEW NEW NEW
NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW
DrawSphere();
//End the scene
g_pD3DDevice->EndScene();
//Filp the back and front buffers so that whatever
has been rendered on the back buffer
//will now be visible on screen (front buffer).
g_pD3DDevice->Present(NULL, NULL, NULL, NULL);
}
CleanUp();
}
|