Tuesday June 25, 2024
 Home | Contact | Support | XBOX Programming.. More than just a toy... | XBOX Programming.. More than just a toy...
 XBOX Programming.. More than just a toy...

# 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));

//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;

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();

}