How To Draw A Cylinder In Opengl
OpenGL Cylinder, Prism & Pipe
Related Topics: OpenGL Sphere
Download: cylinder.aught, cylinderShader.cipher, pipe.zip
- Cylinder & Prism
- Case: Drawing Cylinder
- Pipe (Tube)
- Instance: Extrude Piping Along Path
- Example: WebGL Cylinder (Interactive Demo)
This page describes how to generate a cylinder geometry using C++ and how to depict information technology in OpenGL.
Cylinder & Prism
The definition of a cylinder is a 3D closed surface that has two parallel circular bases at the ends and continued by a curved surface (side). Similarly, a prism is a 3D closed surface that has 2 parallel polygonal bases connected by apartment surfaces.
Since we cannot draw a perfect circular base of operations and curved side of the cylinder, we only sample a limited corporeality of points by dividing the base by sectors (slices). Therefore, it is technically constructing a prism past connecting these sampled points together. As the number of samples increases, the geometry is closer to a cylinder.
Triangular Prism (3)
Rectangluar Prism (iv)
Octagonal Prism (8)
Hexadecagonal Prism (16)
A vertex coordinate on a cylinder
Suppose a cylinder is centered at the origin and its radius is r and the height is h. An capricious point (x, y, z) on the cylinder can be computed from the equation of circumvolve with the respective sector angle θ.
The range of sector angles is from 0 to 360 degrees. The sector angle for each step can be calculated by the following;
The following C++ lawmaking generates all vertices of the cylinder with the given base radius, acme and the number of sectors (slices). It also creates other vertex attributes; surface normals and texture coordinates.
In order to reduce multiple computations of sine and cosine, we compute the vertices of a unit circumvolve on XY plane only once, and so re-apply these points multiple times by scaling with the base of operations radius. These are also used for the normal vectors of the side faces of the cylinder.
// generate a unit of measurement circle on XY-plane std::vector<bladder> Cylinder::getUnitCircleVertices() { const bladder PI = 3.1415926f; float sectorStep = 2 * PI / sectorCount; float sectorAngle; // radian std::vector<float> unitCircleVertices; for(int i = 0; i <= sectorCount; ++i) { sectorAngle = i * sectorStep; unitCircleVertices.push_back(cos(sectorAngle)); // x unitCircleVertices.push_back(sin(sectorAngle)); // y unitCircleVertices.push_back(0); // z } return unitCircleVertices; } ... // generate vertices for a cylinder void Cylinder::buildVerticesSmooth() { // articulate retentivity of prev arrays std::vector<float>().swap(vertices); std::vector<float>().swap(normals); std::vector<bladder>().swap(texCoords); // get unit of measurement circle vectors on XY-aeroplane std::vector<bladder> unitVertices = getUnitCircleVertices(); // put side vertices to arrays for(int i = 0; i < two; ++i) { float h = -meridian / two.0f + i * height; // z value; -h/2 to h/ii bladder t = i.0f - i; // vertical tex coord; 1 to 0 for(int j = 0, k = 0; j <= sectorCount; ++j, g += 3) { float ux = unitVertices[k]; float uy = unitVertices[k+1]; bladder uz = unitVertices[thou+ii]; // position vector vertices.push_back(ux * radius); // vx vertices.push_back(uy * radius); // vy vertices.push_back(h); // vz // normal vector normals.push_back(ux); // nx normals.push_back(uy); // ny normals.push_back(uz); // nz // texture coordinate texCoords.push_back((float)j / sectorCount); // s texCoords.push_back(t); // t } } // the starting alphabetize for the base of operations/superlative surface //Annotation: it is used for generating indices later int baseCenterIndex = (int)vertices.size() / 3; int topCenterIndex = baseCenterIndex + sectorCount + 1; // include center vertex // put base of operations and top vertices to arrays for(int i = 0; i < 2; ++i) { float h = -height / 2.0f + i * top; // z value; -h/2 to h/2 float nz = -ane + i * 2; // z value of normal; -1 to 1 // eye point vertices.push_back(0); vertices.push_back(0); vertices.push_back(h); normals.push_back(0); normals.push_back(0); normals.push_back(nz); texCoords.push_back(0.5f); texCoords.push_back(0.5f); for(int j = 0, k = 0; j < sectorCount; ++j, grand += three) { float ux = unitVertices[k]; float uy = unitVertices[k+one]; // position vector vertices.push_back(ux * radius); // vx vertices.push_back(uy * radius); // vy vertices.push_back(h); // vz // normal vector normals.push_back(0); // nx normals.push_back(0); // ny normals.push_back(nz); // nz // texture coordinate texCoords.push_back(-ux * 0.5f + 0.5f); // s texCoords.push_back(-uy * 0.5f + 0.5f); // t } } }
Cylinders with different base/tiptop radii and stack count
This C++ class provides buildVerticesSmooth() and buildVerticesFlat() functions depending on surface smoothness. The constructor also takes additional parameters to construct various shapes of a cylinder, similar to OpenGL gluCylinder() function.
The parameters of the cylinder class are;
- the base radius (float)
- the acme radius (bladder)
- the height (float)
- the number of sectors (int)
- the number of stacks (int)
- smoothness (bool)
For case, if the base radius is 0, it becomes a cone shape. For more details, please refer to Cylinder.cpp class.
In order to draw the surface of a cylinder in OpenGL, you must triangulate adjacent vertices counterclockwise to form polygons. Each sector on the side surface requires two triangles. The total number of triangles for the side is two × sectorCount. And the number of triangles for the base of operations or top surface is the same as the number of sectors. (Yous may use GL_TRIANGLE_FAN for the base/top instead of GL_TRIANGLES.)
The code snippet to generate all the triangles of a cylinder may look similar;
// generate CCW index list of cylinder triangles std::vector<int> indices; int k1 = 0; // 1st vertex alphabetize at base int k2 = sectorCount + ane; // 1st vertex index at top // indices for the side surface for(int i = 0; i < sectorCount; ++i, ++k1, ++k2) { // 2 triangles per sector // k1 => k1+ane => k2 indices.push_back(k1); indices.push_back(k1 + 1); indices.push_back(k2); // k2 => k1+1 => k2+1 indices.push_back(k2); indices.push_back(k1 + 1); indices.push_back(k2 + 1); } // indices for the base surface //NOTE: baseCenterIndex and topCenterIndices are pre-computed during vertex generation // please see the previous code snippet for(int i = 0, k = baseCenterIndex + 1; i < sectorCount; ++i, ++k) { if(i < sectorCount - one) { indices.push_back(baseCenterIndex); indices.push_back(chiliad + ane); indices.push_back(k); } else // last triangle { indices.push_back(baseCenterIndex); indices.push_back(baseCenterIndex + ane); indices.push_back(chiliad); } } // indices for the top surface for(int i = 0, 1000 = topCenterIndex + 1; i < sectorCount; ++i, ++k) { if(i < sectorCount - i) { indices.push_back(topCenterIndex); indices.push_back(thou); indices.push_back(k + ane); } else // last triangle { indices.push_back(topCenterIndex); indices.push_back(k); indices.push_back(topCenterIndex + i); } }
Example: Cartoon Cylinder
Download: cylinder.zip, cylinderShader.zip (Updated: 2020-03-14)
This example constructs cylinders with 36 sectors and 8 stacks, only with unlike shadings; flat, shine or textured. With the default constructor (without arguments), it generates a cylinder with base/superlative radius = 1, elevation = 2, sectors = 36 and stacks = one. You could likewise laissez passer the custom parameters to the constructor, similar to gluCylinder(). Press the space key to change the number of sectors and stacks of the cylinders.
Cylinder.cpp class provides pre-defined drawing functions using OpenGL VertexArray; draw(), drawWithLines(), drawLines(), drawSide(), drawBase() and drawTop().
// create a cylinder with base radius=i, top radius=two, elevation=3, // summit=4, sectors=five, stacks=6, smooth=true Cylinder cylinder(ane, ii, 3, 4, 5, six, true); // can modify parameters later cylinder.setBaseRadius(1.5f); cylinder.setTopRadius(2.5f); cylinder.setHeight(3.5f); cylinder.setSectorCount(36); cylinder.setStackCount(8); cylinder.setSmooth(false); ... // draw cylinder using vertexarray cylinder.draw(); // draw surface only cylinder.drawWithLines(); // describe surface and lines cylinder.drawSide(); // draw side only cylinder.drawTop(); // describe meridian but cylinder.drawBase(); // depict botton only
This C++ class also provides getVertices(), getIndices(), getInterleavedVertices(), etc. in gild to access the vertex data in GLSL. The following lawmaking draws a cylinder with interleaved vertex information using VBO and GLSL. Or, download cylinderShader.zippo for more details.
// create a cylinder with default params; // radii=ane, peak=1, sectors=36, stacks=ane, shine=true Cylinder cylinder; // copy interleaved vertex data (5/N/T) to VBO GLuint vboId; glGenBuffers(1, &vboId); glBindBuffer(GL_ARRAY_BUFFER, vboId); // for vertex data glBufferData(GL_ARRAY_BUFFER, // target cylinder.getInterleavedVertexSize(), // data size, # of bytes cylinder.getInterleavedVertices(), // ptr to vertex data GL_STATIC_DRAW); // usage // copy index data to VBO GLuint iboId; glGenBuffers(one, &iboId); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboId); // for index data glBufferData(GL_ELEMENT_ARRAY_BUFFER, // target cylinder.getIndexSize(), // data size, # of bytes cylinder.getIndices(), // ptr to index data GL_STATIC_DRAW); // usage ... // bind VBOs glBindBuffer(GL_ARRAY_BUFFER, vboId); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboId); // activate attrib arrays glEnableVertexAttribArray(attribVertex); glEnableVertexAttribArray(attribNormal); glEnableVertexAttribArray(attribTexCoord); // set attrib arrays with stride and showtime int stride = cylinder.getInterleavedStride(); // should exist 32 bytes glVertexAttribPointer(attribVertex, three, GL_FLOAT, false, stride, (void*)0); glVertexAttribPointer(attribNormal, 3, GL_FLOAT, simulated, stride, (void*)(sizeof(bladder)*3)); glVertexAttribPointer(attribTexCoord, 2, GL_FLOAT, faux, stride, (void*)(sizeof(float)*half dozen)); // depict a cylinder with VBO glDrawElements(GL_TRIANGLES, // primitive blazon cylinder.getIndexCount(), // # of indices GL_UNSIGNED_INT, // data type (void*)0); // offset to indices // conciliate attrib arrays glDisableVertexAttribArray(attribVertex); glDisableVertexAttribArray(attribNormal); glDisableVertexAttribArray(attribTexCoord); // unbind VBOs glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
Pipage (Tube)
Extruding a pipage along a path Q1-Q2-Qiii
Cross-section view of extruding a pipe
P'1 is the intersection betoken on a plane and a line passing P1
A common application is drawing a pipe, which is extruding a contour forth a given path. Suppose the path is Qi-Q2-Qthree, and a point of the contour is P1. To discover the next point, P'one, we demand to project Pane onto the plane at the Q2 with the normal, , where 2 path lines Qi-Q2 and Qtwo-Q3 are met.
Projecting P1 to P'1 is actually finding the intersection of the point where a line and a plane are met. See the cross-department view (the right-side image in a higher place). The line equation is , which is passing P1 with the direction vector
.
And, the plane equation can be computed by the normal vector and the indicate on the airplane Q2 (ten2, y2, z2);
And, the normal vector is computed past adding and
together;
Finding the intersection point P'1 is solving the linear system of the airplane and line;
Yous tin discover the solution of the linear system here. Or, see the detail C++ implementation in Pipe::projectContour() of Pipe.cpp and Plane.cpp.
std::vector<Vector3> Piping::projectContour(int fromIndex, int toIndex) { Vector3 v1, v2, normal, point; Line line; // discover direction vectors; v1 and v2 v1 = path[toIndex] - path[fromIndex]; if(toIndex == (int)path.size()-ane) v2 = v1; else v2 = path[toIndex + i] - path[toIndex]; // normal vector of plane at toIndex normal = v1 + v2; // define plane equation at toIndex with normal and point Plane airplane(normal, path[toIndex]); // project each vertex of contour to the plane std::vector<Vector3>& fromContour = contours[fromIndex]; std::vector<Vector3> toContour; int count = (int)fromContour.size(); for(int i = 0; i < count; ++i) { line.fix(v1, fromContour[i]); // define line with management and point point = airplane.intersect(line); // find the intersection point toContour.push_back(point); } // return the projected vertices of contour at toIndex render toContour; }
Instance: Extruding Pipe along Path
This example is drawing a pipe extruding a round contour following a screw path. Printing D key to switch the rendering modes.
Download: pipe.zip
A pipe tin can exist constructed with a pre-defined path (a sequence of points), or you can add the adjacent betoken of the path if needed using Pipe::addPathPoint().
The shape of the contour is not necessarily a circumvolve. You can provide an arbitrary shape of a profile.
To draw the surface of the pipe, use Pipage::getContour() and Pipe::getNormal() to become the vertices and normals at a given path bespeak. Then, draw triangles between 2 contours using GL_TRIANGLE_STRIP.
Example: WebGL Cylinder (Interactive Demo)
It is a JavaScript implementation of Cylinder class, Cylinder.js, and rendering it with WebGL. Drag the sliders to change the parameters of the cylinder. The fullscreen version is available here.
The following JavaScript lawmaking is to create and to render a cylinder object.
// create a cylinder with six params: baseR, topR, height, sectors, stacks, polish allow cylinder = new Cylinder(1, two, three, iv, 5, imitation); ... // change params of cylinder later cylinder.setBaseRadius(1); cylinder.setTopRadius(2); cylinder.setHeight(3); cylinder.setSectorCount(4); cylinder.setStackCount(v); cylinder.setSmooth(true); ... // describe a cylinder with interleaved mode gl.bindBuffer(gl.ARRAY_BUFFER, cylinder.vboVertex); gl.vertexAttribPointer(gl.program.attribPosition, three, gl.Bladder, fake, cylinder.stride, 0); gl.vertexAttribPointer(gl.program.attribNormal, 3, gl.Bladder, fake, cylinder.stride, 12); gl.vertexAttribPointer(gl.program.attribTexCoord0, 2, gl.Bladder, false, cylinder.stride, 24); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cylinder.vboIndex); gl.drawElements(gl.TRIANGLES, cylinder.getIndexCount(), gl.UNSIGNED_SHORT, 0); ...
Source: http://www.songho.ca/opengl/gl_cylinder.html
Posted by: schellfromen.blogspot.com
0 Response to "How To Draw A Cylinder In Opengl"
Post a Comment