banner



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.

triangluar prism
Triangular Prism (3)

rectangular prism
Rectangluar Prism (iv)

octagonal prism
Octagonal Prism (8)

hexadecagonal prism
Hexadecagonal Prism (16)

finding a point on a cylinder
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 θ.

formula to find a point on a cylinder

The range of sector angles is from 0 to 360 degrees. The sector angle for each step can be calculated by the following;
step angle per sector

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 stack counts and base/top radii
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;

  1. the base radius (float)
  2. the acme radius (bladder)
  3. the height (float)
  4. the number of sectors (int)
  5. the number of stacks (int)
  6. 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

example of drawing 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)

pipe along path
Extruding a pipage along a path Q1-Q2-Qiii

projecting a point to a plane in cross-section view
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, normal vector, 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 line equation, which is passing P1 with the direction vector direction vector.

And, the plane equation can be computed by the normal vector normal vector and the indicate on the airplane Q2 (ten2, y2, z2);
plane equation
And, the normal vector is computed past adding and together;
normal vector of plane

Finding the intersection point P'1 is solving the linear system of the airplane and line;
linear system of plane 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

exampleof pipe

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

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel