Книга: DirectX 8 Programming Tutorial

How to make a cylinder

How to make a cylinder

Our cylinder will be made up from two triangle fans, one for the top and one for the bottom. The sides of the cylinder will be made up from a triangle strip. Fig 9.1 below shows a diagram of the vertices and polygons for a cylinder. It also includes the normals for the four corners of one segment. To create our cylinder we have not used an index buffer, only a vertex buffer. This is because; although we do have shared vertices (between the sides and the top/bottom faces) we want different normals so the edges around the top and bottom appear sharp.


Fig 9.1

To create the cylinder we need to specify the number of segments. There are 8 segments in the diagram above. The more segments there are, the smoother and rounder the cylinder will appear. We also need to know the height and radius of the cylinder. Once we know the height, radius and number of segments, we can defined the position of our vertices together with their Normal value and texture coordinates. The following code snippet shows how this is done.

bool CCylinder::UpdateVertices() {
 CYLINDER_CUSTOMVERTEX* pVertex;
 WORD wVertexIndex = 0;
 int nCurrentSegment;
 //Lock the vertex buffer
 if (FAILED(m_pVertexBuffer->Lock(0, 0, (BYTE**)&pVertex, 0))) {
  LogError("<li>CCylinder: Unable to lock vertex buffer.");
  return false;
 }
 float rDeltaSegAngle = (2.0f * D3DX_PI / m_nSegments);
 float rSegmentLength = 1.0f / (float)m_nSegments;
 //Create the sides triangle strip
 for (nCurrentSegment = 0; nCurrentSegment <= m_nSegments; nCurrentSegment++) {
  float x0 = m_rRadius * sinf(nCurrentSegment * rDeltaSegAngle);
  float z0 = m_rRadius * cosf(nCurrentSegment * rDeltaSegAngle);
  pVertex->x = x0;
  pVertex->y = 0.0f + (m_rHeight / 2.0f);
  pVertex->z = z0;
  pVertex->nx = x0;
  pVertex->ny = 0.0f;
  pVertex->nz = z0;
  pVertex->tu = 1.0f – (rSegmentLength * (float)nCurrentSegment);
  pVertex->tv = 0.0f;
  pVertex++;
  pVertex->x = x0;
  pVertex->y = 0.0f – (m_rHeight / 2.0f);
  pVertex->z = z0;
  pVertex->nx = x0;
  pVertex->ny = 0.0f;
  pVertex->nz = z0;
  pVertex->tu = 1.0f – (rSegmentLength * (float)nCurrentSegment);
  pVertex->tv = 1.0f;
  pVertex++;
 }
 //Create the top triangle fan: Center
 pVertex->x = 0.0f;
 pVertex->y = 0.0f + (m_rHeight / 2.0f);
 pVertex->z = 0.0f;
 pVertex->nx = 0.0f;
 pVertex->ny = 1.0f;
 pVertex->nz = 0.0f;
 pVertex->tu = 0.5f;
 pVertex->tv = 0.5f;
 pVertex++;
 //Create the top triangle fan: Edges
 for (nCurrentSegment = 0; nCurrentSegment <= m_nSegments; nCurrentSegment++) {
  float x0 = m_rRadius * sinf(nCurrentSegment * rDeltaSegAngle);
  float z0 = m_rRadius * cosf(nCurrentSegment * rDeltaSegAngle);
  pVertex->x = x0;
  pVertex->y = 0.0f + (m_rHeight / 2.0f);
  pVertex->z = z0;
  pVertex->nx = 0.0f;
  pVertex->ny = 1.0f;
  pVertex->nz = 0.0f;
  float tu0 = (0.5f * sinf(nCurrentSegment * rDeltaSegAngle)) + 0.5f;
  float tv0 = (0.5f * cosf(nCurrentSegment * rDeltaSegAngle)) + 0.5f;
  pVertex->tu = tu0;
  pVertex->tv = tv0;
  pVertex++;
 }
 //Create the bottom triangle fan: Center
 pVertex->x = 0.0f;
 pVertex->y = 0.0f – (m_rHeight / 2.0f);
 pVertex->z = 0.0f;
 pVertex->nx = 0.0f;
 pVertex->ny = –1.0f;
 pVertex->nz = 0.0f;
 pVertex->tu = 0.5f;
 pVertex->tv = 0.5f;
 pVertex++;
 //Create the bottom triangle fan: Edges
 for (nCurrentSegment = m_nSegments; nCurrentSegment >= 0; nCurrentSegment--) {
  float x0 = m_rRadius * sinf(nCurrentSegment * rDeltaSegAngle);
  float z0 = m_rRadius * cosf(nCurrentSegment * rDeltaSegAngle);
  pVertex->x = x0;
  pVertex->y = 0.0f – (m_rHeight / 2.0f);
  pVertex->z = z0;
  pVertex->nx = 0.0f;
  pVertex->ny = –1.0f;
  pVertex->nz = 0.0f;
  float tu0 = (0.5f * sinf(nCurrentSegment * rDeltaSegAngle)) + 0.5f;
  float tv0 = (0.5f * cosf(nCurrentSegment * rDeltaSegAngle)) + 0.5f;
  pVertex->tu = tu0;
  pVertex->tv = tv0;
  pVertex++;
 }
 if (FAILED(m_pVertexBuffer->Unlock())) {
  LogError("<li>CCylinder: Unable to unlock vertex buffer.");
  return false;
 }
 return true;
}

So, what's going on here? Well, after locking our vertex buffer (so we can write to it) we calculate the angle for each segment. This is done by dividing the number of radians in a circle (2*PI) by the number of segments, this angle is stored in rDeltaSegAngle for use later when defining the vertices position. We then calculate the length of each segment for use when defining the texture coordinates for the triangle strip (sides). This is done by dividing the length of our texture (1.0) by the number of segments.

Once this is done, we can define the sides of our cylinder. We loop around, once for each segment + 1. In this loop we calculate the x and z position for the current segment and write these values for the top and bottom vertex for that segment. The y value is simply + or – half the height. We use the segment length to calculate the texture coordinates for the current vertex.

Once that is done, we can define the two triangle fans, one for the top and one for the bottom. First we define the centre point for the fan and then we use the same calculations to define the edge vertices of the fan. Once this is complete for the top and bottom fans, the vertex buffer is full and then unlocked ready for rendering.

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


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