Книга: DirectX 8 Programming Tutorial

How to make a sphere

How to make a sphere

Our sphere will be made up from a simple triangle list. We will need to specify the number of rings and segments for the sphere. The more rings and segments there are, the smoother and rounder the sphere will appear. The sphere will be made up using an index and vertex buffer. Fig 9.3 below shows a wireframe screenshot of a sphere. It shows how the sphere is constructed and divided into rings and segments.


Fig 9.3

To create the sphere we can use the following code snippet. The code below has been adapted from a sample by "Laurent" posted on the GameDev.net DirectX forum. To view the post in full go to http://www.gamedev.net/community/forums/topic.asp?topic_id=85779. I would like to thank Laurent for giving me permission to use the code in this tutorial.

bool CSphere::UpdateVertices() {
 //Code adapted from a sample by "Laurent" posted on the GameDev.net DirectX forum
 //http://www.gamedev.net/community/forums/topic.asp?topic_id=85779
 WORD* pIndices;
 SPHERE_CUSTOMVERTEX* pVertex;
 WORD wVertexIndex = 0;
 int nCurrentRing;
 int nCurrentSegment;
 D3DXVECTOR3 vNormal;
 //Lock the vertex buffer
 if (FAILED(m_pVertexBuffer->Lock(0, 0, (BYTE**)&pVertex, 0))) {
  LogError("<li>CSphere: Unable to lock vertex buffer.");
  return false;
 }
 //Lock the index buffer
 if (FAILED(m_pIndexBuffer->Lock(0, m_dwNumOfIndices, (BYTE**)&pIndices, 0))) {
  LogError("<li>CSphere: Unable to lock index buffer.");
  return false;
 }
 //Establish constants used in sphere generation
 FLOAT rDeltaRingAngle = (D3DX_PI / m_nRings);
 FLOAT rDeltaSegAngle = (2.0f * D3DX_PI / m_nSegments);
 //Generate the group of rings for the sphere
 for (nCurrentRing = 0; nCurrentRing < m_nRings + 1; nCurrentRing++) {
  FLOAT r0 = sinf(nCurrentRing * rDeltaRingAngle);
  FLOAT y0 = cosf(nCurrentRing * rDeltaRingAngle);
  //Generate the group of segments for the current ring
  for (nCurrentSegment = 0; nCurrentSegment < m_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 vertex 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->tu = 1.0f – ((FLOAT)nCurrentSegment / (FLOAT)m_nSegments);
   pVertex->tv = (FLOAT)nCurrentRing / (FLOAT)m_nRings;
   pVertex++;
   //Add two indices except for the last ring
   if (nCurrentRing != m_nRings) {
    *pIndices = wVertexIndex;
    pIndices++;
    *pIndices = wVertexIndex + (WORD)(m_nSegments + 1);
    pIndices++;
    wVertexIndex++;
   }
  }
 }
 if (FAILED(m_pIndexBuffer->Unlock())) {
  LogError("<li>CSphere: Unable to unlock index buffer.");
  return false;
 }
 if (FAILED(m_pVertexBuffer->Unlock())) {
  LogError("<li>CSphere: Unable to unlock vertex buffer.");
  return false;
 }
 return true;
}

So what is going on here? Once we have locked the index and vertex buffers we are ready to write to them. We use the same calculation as before to obtain the segment angle and a slight variation to obtain the ring angle. For the ring angle we only need to divide half a circle (PI radians) by the number of rings.

Once we have the ring and segment angles, we simply loop around once for each ring creating the vertices for each segment within that ring. We add an entry into the index buffer each time to create our triangle list. We set the normal values for each vertex to be the normalised position values. The radius of the sphere is always 1. You can use a scaling transformation matrix to increase or decrease the size of the sphere. Once complete, we unlock the vertex and index buffers ready for rendering.

The final scene when rendered will look something like the screenshot below:


Оглавление книги


Генерация: 7.837. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз