Книга: 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.
- How to read
- Chapter 9. How a rule is built
- How it was written
- How to plan an IP filter
- chown
- How to place proxies
- How to use this License for your documents
- 2. How to Apply These Terms to Your New Programs
- 4.3.3. Makefile Targets
- Scaling makes your object darker?
- 1.3. Автоматизация процесса с помощью GNU-утилиты make
- Команды SHOW