Выбрать главу

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.

How to make a cone

Our cone will be made up from one triangle fan for the bottom and a triangle list for the sides. As for the cylinder above, we need to specify the number of segments, the height and the radius for our cone. Fig 9.2 below shows how the cone will be made up; there are 8 segments in this cone. The red arrows show the normals for one segment of this cone. To create the cone, we will use an index buffer and a vertex buffer. We will store the triangles for the sides in the index buffer and use the vertex buffer to store the vertices for the side triangles and the base triangle fan. This is so that we get the correct shading around the cone and a sharp edge between the sides and base.

Fig 9.2

To create the cone 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 cone will appear. We also need to know the height and radius of the cone. 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.