Prt6b - More than just a shape - a rotating shape...Cool
Author: bkenwright@xbdev.net
To take the sphere to a higher level, I've added some complex stuff which I'm
wondering if I should have .... I've added a light, so that our sphere is
illuminated - put those normals to good use. Also I've added a matrix to
rotate our world.... its a lot of code.... and its messy... but still ... this
piece of code will be a cool in the future when we make it explode....
Now before you go running away screaming...take a deep breadth....that's
it...now stay calm...its not that bad ...
//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
DrawSphereTriangleList()
{
UINT
D3DFVF_CUSTOMVERTEX = (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_DIFFUSE);
struct CUSTOMVERTEX
{
FLOAT x, y, z;
FLOAT nx, ny, nz;
DWORD colour;
};
int nRings = 4;
int nSegments = 4;
DWORD
dwNumOfVertices = (nRings + 1) * (nSegments + 1);
DWORD
dwNumOfPolygons = dwNumOfVertices * 3;
LPDIRECT3DVERTEXBUFFER8 pVertexBuffer = NULL;
//CUSTOMVERTEX pVertex[dwNumOfVertices*3];
CUSTOMVERTEX pVertex[25*3] = {0};
D3DXVECTOR3 vNormal;
int nCurrentRing = 0;
//Setup some angles
float rDeltaRingAngle = (D3DX_PI / nRings);
float rDeltaSegAngle = (2.0f * D3DX_PI /
nSegments);
//PART-1- Read in all the vertices that make up the
shape
//Generate the group of rings for the sphere
for(nCurrentRing = 0; nCurrentRing < nRings
+1; nCurrentRing++)
{
float r0 = sinf(nCurrentRing * rDeltaRingAngle);
float y0 = cosf(nCurrentRing * rDeltaRingAngle);
//OOooo Generate 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
int i = nCurrentRing *
nSegments + nCurrentSegment;
pVertex[i].x = x0;
pVertex[i].y = y0;
pVertex[i].z = z0;
pVertex[i].nx = vNormal.x;
pVertex[i].ny = vNormal.y;
pVertex[i].nz = vNormal.z;
pVertex[i].colour = 0xff00ff00;
}
}
//PART-2- Arrange them in list order
//This part puts all of our lovely vertices into a nice tidy order of
triangles.
//CUSTOMVERTEX pVertexList[dwNumOfVertices*3];
CUSTOMVERTEX pVertexList[50*3] = {0};
int index = 0;
for(nCurrentRing = 0; nCurrentRing < nRings
+1; nCurrentRing++)
{
for(int
nCurrentSegment=0; nCurrentSegment < nSegments + 1; nCurrentSegment++)
{
if(nCurrentRing != nRings)
{
//These few lines specify
the triangles into the pVertexList, as
//above we have just
generated the vertices for the sphere, but they
//arnt aranged in an order
of triangles, e.g. the first three points
//make up a triangle, the
next three points make up a second triangle
//etc. These lines within
the loop take the points and generate
//a list of triangles which
we can draw using D3DPT_TRIANGLELIST
int i = nCurrentRing
* nSegments;
pVertexList[index].x = pVertex[i+nCurrentSegment].x;
pVertexList[index].y = pVertex[i+nCurrentSegment].y;
pVertexList[index].z = pVertex[i+nCurrentSegment].z;
pVertexList[index].nx = pVertex[i+nCurrentSegment].nx;
pVertexList[index].ny = pVertex[i+nCurrentSegment].ny;
pVertexList[ index].nz = pVertex[i+nCurrentSegment].nz;
pVertexList[index].colour =
pVertex[i+nCurrentSegment].colour;
index++;
///////////////////////////////////////////////////////////////
pVertexList[index].x = pVertex[i+nCurrentSegment +
nSegments].x;
pVertexList[index].y = pVertex[i+nCurrentSegment +
nSegments].y;
pVertexList[index].z = pVertex[i+nCurrentSegment +
nSegments].z;
pVertexList[index].nx = pVertex[i+nCurrentSegment +
nSegments].nx;
pVertexList[index].ny = pVertex[i+nCurrentSegment +
nSegments].ny;
pVertexList[index].nz = pVertex[i+nCurrentSegment +
nSegments].nz;
pVertexList[index].colour = pVertex[i+nCurrentSegment
+ nSegments].colour;
index++;
//////////////////////////////////////////////////////////////
pVertexList[index].x = pVertex[i+nCurrentSegment
+1].x;
pVertexList[index].y = pVertex[i+nCurrentSegment
+1].y;
pVertexList[index].z = pVertex[i+nCurrentSegment
+1].z;
pVertexList[index].nx = pVertex[i+nCurrentSegment
+1].nx;
pVertexList[index].ny = pVertex[i+nCurrentSegment
+1].ny;
pVertexList[index].nz = pVertex[i+nCurrentSegment
+1].nz;
pVertexList[index].colour =
pVertex[i+nCurrentSegment+1].colour;
index++;
/////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////
pVertexList[index].x = pVertex[i+nCurrentSegment+
nSegments].x;
pVertexList[index].y = pVertex[i+nCurrentSegment+
nSegments].y;
pVertexList[index].z = pVertex[i+nCurrentSegment+
nSegments].z;
pVertexList[index].nx = pVertex[i+nCurrentSegment+
nSegments].nx;
pVertexList[index].ny = pVertex[i+nCurrentSegment+
nSegments].ny;
pVertexList[ index].nz = pVertex[i+nCurrentSegment+
nSegments].nz;
pVertexList[index].colour = pVertex[i+nCurrentSegment+
nSegments].colour;
index++;
///////////////////////////////////////////////////////////////
pVertexList[index].x = pVertex[i+nCurrentSegment +
nSegments+ 1].x;
pVertexList[index].y = pVertex[i+nCurrentSegment +
nSegments+ 1].y;
pVertexList[index].z = pVertex[i+nCurrentSegment +
nSegments+ 1].z;
pVertexList[index].nx = pVertex[i+nCurrentSegment +
nSegments+ 1].nx;
pVertexList[index].ny = pVertex[i+nCurrentSegment +
nSegments+ 1].ny;
pVertexList[index].nz = pVertex[i+nCurrentSegment +
nSegments+ 1].nz;
pVertexList[index].colour = pVertex[i+nCurrentSegment
+ nSegments].colour;
index++;
//////////////////////////////////////////////////////////////
pVertexList[index].x = pVertex[i+nCurrentSegment
+1].x;
pVertexList[index].y = pVertex[i+nCurrentSegment
+1].y;
pVertexList[index].z = pVertex[i+nCurrentSegment
+1].z;
pVertexList[index].nx = pVertex[i+nCurrentSegment
+1].nx;
pVertexList[index].ny = pVertex[i+nCurrentSegment
+1].ny;
pVertexList[index].nz = pVertex[i+nCurrentSegment
+1].nz;
pVertexList[index].colour =
pVertex[i+nCurrentSegment+1].colour;
index++;
}
}
}
g_pD3DDevice->CreateVertexBuffer(index * sizeof(CUSTOMVERTEX),
0, D3DFVF_CUSTOMVERTEX,
D3DPOOL_DEFAULT, &pVertexBuffer);
VOID*
pV;
pVertexBuffer->Lock(0,0, (BYTE**)&pV, 0);
memcpy(pV, pVertexList, sizeof(CUSTOMVERTEX)*index);
pVertexBuffer->Unlock();
g_pD3DDevice->SetStreamSource(0, pVertexBuffer,
sizeof(CUSTOMVERTEX));
g_pD3DDevice->SetVertexShader(D3DFVF_CUSTOMVERTEX);
g_pD3DDevice->DrawPrimitive(D3DPT_TRIANGLELIST, 0, index/3);//dwNumOfPolygons
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
Now to make the sphere cooler....and not to make the whole tutorial to
complex, I added a couple of functions to add light to the sphere.
//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
setlight()
{
//Set a light up?
D3DLIGHT8 d3dLight;
//Initialize the light structure.
ZeroMemory(&d3dLight, sizeof(D3DLIGHT8));
//Set up a white point light at (0, 0, -10).
d3dLight.Type = D3DLIGHT_POINT;
d3dLight.Diffuse.r = 1.0f;
d3dLight.Diffuse.g = 1.0f;
d3dLight.Diffuse.b = 1.0f;
d3dLight.Ambient.r = 0.0f;
d3dLight.Ambient.g = 0.0f;
d3dLight.Ambient.b = 0.0f;
d3dLight.Specular.r = 0.0f;
d3dLight.Specular.g = 0.0f;
d3dLight.Specular.b = 0.0f;
d3dLight.Position.x = 0.0f;
d3dLight.Position.y = 10.0f;//2
d3dLight.Position.z = -10.0f;
d3dLight.Attenuation0 = 1.0f;
d3dLight.Attenuation1 = 0.0f;
d3dLight.Attenuation2 = 0.0f;
d3dLight.Range = 100.0f;
g_pD3DDevice->SetLight(0, &d3dLight);
g_pD3DDevice->LightEnable(0,TRUE);
//Turn on lighting
g_pD3DDevice->SetRenderState(D3DRS_LIGHTING, TRUE);
g_pD3DDevice->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_XRGB(5,100,32));
}
void
setmaterial()
{
D3DMATERIAL8 matMaterial;
D3DCOLORVALUE rgbaDiffuse= {1.0, 1.0, 1.0, 0.0};
D3DCOLORVALUE rgbaAmbient = {1.0, 1.0, 1.0, 0.0};
D3DCOLORVALUE rgbaSpecular = {0.0, 0.0, 0.0, 0.0};
D3DCOLORVALUE rgbaEmissive = {0.0, 0.0, 0.0, 0.0};
matMaterial.Diffuse = rgbaDiffuse;
matMaterial.Ambient = rgbaAmbient;
matMaterial.Specular = rgbaSpecular;
matMaterial.Emissive = rgbaEmissive;
matMaterial.Power = 100.0f;
g_pD3DDevice->SetMaterial(&matMaterial);
}
//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
The DirectX Initilisation and De-Initilisation functions.
//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, TRUE);
//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 the entry point...the point where it all starts.
//Application entry point
void
__cdecl main()
{
InitialiseD3D();
setlight();
setmaterial();
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
//Okay this all may seem scary for
someone new to matrix's but these few lines
//of code rotate our sphere so
that we can make sure its round :)
D3DXMATRIX matWorld;
D3DXMATRIX trans_matrix; //Our
translation matrix
D3DXMATRIX y_rot_matrix;
static
float y_rot=0;
y_rot-=0.001f;
//Set up the rotation matrix for
the triangle
D3DXMatrixRotationY(&y_rot_matrix,y_rot);
//Set up the translation matrix
(move it over to the left a bit)
D3DXMatrixTranslation(&trans_matrix,-1.0,0.0f,0.0f);
//Combine out matrices
D3DXMatrixMultiply(&matWorld,&y_rot_matrix,&trans_matrix);
//Set our World Matrix
g_pD3DDevice->SetTransform(D3DTS_WORLD,&matWorld );
//NEW NEW NEW NEW NEW NEW NEW NEW
NEW NEW NEW NEW NEW NEW NEW NEW NEW NEW
DrawSphereTriangleList();
//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();
}
Now if you go through the code slowly, you'll find the only code you need to
know is the DrawSphereTriangleList() function...which of corse is a beauty to
try and understand in one go. But most of the other code is for effect -
e.g. I've added a few lines in the main() function which rotates our world...so
our lovely sphere is rotated slowly.
|