Read "Computer Graphics Programming (Using OpenGL and C++)" 10 - Drawing a Circle

build a ring

First draw a circle on the xy plane, with the origin as the center and the outer diameter as the radius. (It can be seen as translating a point from the origin along the x-axis direction by the length of the outer diameter, and then rotating it around the Z-axis to get the circle. ), and then translate the circle along the x-axis direction by the distance of the inner diameter. As shown in the left picture above, it is the cross section of the ring, thus obtaining the first component of the ring.

Rotate each vertex of this circle along the Y axis once again to get a ring. As shown in the picture on the right above, they are different torus formed during the rotation of the circle around the Y-axis.

When building these vertices, texture coordinates and normal vectors are calculated for each vertex. A vector tangent to the torus surface (called a tangent vector) is additionally generated for each vertex.

After the vertices are created, all vertices are traversed ring by ring and for each vertex two triangles are generated. The six index table entries for the two triangles are generated in a similar way to the previous sphere.

Our strategy for selecting texture coordinates for the remaining rings is to arrange them so that the S-axis of the texture image surrounds half of the horizontal perimeter of the torus, and then repeat for the other half. When we rotate around the Y-axis to generate the ring, we specify a variable ring that starts at 1 and increases to the specified precision (again called "prec"). We then set the S texture coordinate value to ring*2.0/prec so that S ranges between 0.0 and 2.0, and then subtract 1.0 whenever the texture coordinate is greater than 1.0. The motivation for this approach is to avoid excessive "stretching" of the texture image in the horizontal direction. Conversely, if we really want the texture to stretch completely around the torus, we simply remove the "*2.0" multiplier from the texture coordinate calculation.

OpenGL indexing is used here and we need to load the index itself into the VBO. Specify the type of the VBO as GL_ELEMENT_ARRAY_BUFFER (this tells OpenGL that the VBO contains an index).

This replaces the glDrawArrays() call with a glDrawElements() call, which tells OpenGL to use the index VBO to find the vertices to draw. We also enable VBOs containing indexes using glBindBuffer(), specifying which VBO contains the index and is of type GL_ELEMENT_ARRAY_BUFFER.

The prec variable has a similar effect to that of a sphere, with similar calculations of the number of vertices and indexes.

Two tangent vectors (sTangent and tTangent, although often called "tangent" and "bitangent") are calculated, and their cross product forms the normal vector.

code show as below:

Torus

1 #pragma once
  2 #include <vector>
  3 #include <glm\glm.hpp>
  4 #include <cmath>
  5 class Torus
  6 {
  7 private:
  8     int numVertices;
  9     int numIndices;
 10     int prec;
 11     float inner;
 12     float outer;
 13     std::vector<int> indices;
 14     std::vector<glm::vec3> vertices;
 15     std::vector<glm::vec2> texCoords;
 16     std::vector<glm::vec3> normals;
 17     std::vector<glm::vec3> sTangents;
 18     std::vector<glm::vec3> tTangents;
 19     void init();
 20     float toRadians(float degrees);
 21 
 22 public:
 23     Torus();
 24     Torus(float innerRadius, float outerRadius, int prec);
 25     ~Torus();
 26     int getNumVertices();
 27     int getNumIndices();
 28     std::vector<int> getIndices();
 29     std::vector<glm::vec3> getVertices();
 30     std::vector<glm::vec2> getTexCoords();
 31     std::vector<glm::vec3> getNormals();
 32     std::vector<glm::vec3> getStangents();
 33     std::vector<glm::vec3> getTtangents();
 34 };
 35 
 36 #include "Torus.h"
 37 #include <iostream>
 38 using namespace std;
 39 #include "glm/gtc/matrix_transform.hpp"
 40 void Torus::init()
 41 {
 42     numVertices = (prec + 1) * (prec + 1);
 43     numIndices = prec * prec * 6;
 44     for (int i = 0; i < numVertices; i++)
 45     {
 46         vertices.push_back(glm::vec3());
 47         texCoords.push_back(glm::vec2());
 48         normals.push_back(glm::vec3());
 49         sTangents.push_back(glm::vec3());
 50         tTangents.push_back(glm::vec3());
 51     }
 52     for (int i = 0; i < numIndices; i++)
 53     {
 54         indices.push_back(0);
 55     }
 56 
 57     // 计算第一个环
 58     for (int i = 0; i < prec + 1; i++)
 59     {
 60         float amt = toRadians(i * 360.0f / prec);
 61         // 绕原点旋转点,形成环,然后将它们向外移动
 62         glm::mat4 rMat = glm::rotate(glm::mat4(1.0f), amt, glm::vec3(0.0f, 0.0f, 1.0f));
 63         glm::vec3 initPos(rMat * glm::vec4(outer, 0.0f, 0.0f, 1.0f));
 64         vertices[i] = glm::vec3(initPos + glm::vec3(inner, 0.0f, 0.0f));
 65 
 66         // 为环上的每个顶点计算纹理坐标
 67         texCoords[i] = glm::vec2(0.0f, ((float)i / (float)prec));
 68 
 69         // 计算切向量和法向量,第一个切向量是绕Z轴旋转的Y轴
 70         rMat = glm::rotate(glm::mat4(1.0f), amt, glm::vec3(0.0f, 0.0f, 1.0f));
 71         tTangents[i] = glm::vec3(rMat * glm::vec4(0.0f, -1.0f, 0.0f, 1.0f));
 72         sTangents[i] = glm::vec3(glm::vec3(0.0f, 0.0f, -1.0f));
 73         // 第二个切向量是-Z轴
 74         normals[i] = glm::cross(tTangents[i], sTangents[i]);
 75         // 它们的叉乘积就是法向量
 76 
 77         // 绕Y轴旋转最初的那个环,形成其他的环
 78         for (int ring = 1; ring < prec + 1; ring++)
 79         {
 80             for (int vert = 0; vert < prec + 1; vert++)
 81             {
 82                 // 绕Y轴旋转最初那个环的顶点坐标
 83                 float amt = (float)(toRadians(ring * 360.0f / prec));
 84                 glm::mat4 rMat = glm::rotate(glm::mat4(1.0f), amt, glm::vec3(0.0f, 1.0f, 0.0f));
 85                 vertices[ring * (prec + 1) + i] = glm::vec3(rMat * glm::vec4(vertices[i], 1.0f));
 86 
 87                 // 计算新环顶点的纹理坐标
 88                 texCoords[ring * (prec + 1) + vert] = 
 89                     glm::vec2((float)ring/** 2.0f*//(float)prec, texCoords[vert].t);
 90                 if (texCoords[ring * (prec + 1) + i].s > 1.0)
 91                 {
 92                     texCoords[ring * (prec + 1) + i].s -= 1.0f;
 93                 }
 94 
 95                 // 绕Y轴旋转切向量和副切向量
 96                 rMat = glm::rotate(glm::mat4(1.0f), amt, glm::vec3(0.0f, 1.0f, 0.0f));
 97                 sTangents[ring * (prec + 1) + i] = glm::vec3(rMat * glm::vec4(sTangents[i], 1.0f));
 98                 rMat = glm::rotate(glm::mat4(1.0f), amt, glm::vec3(0.0f, 1.0f, 0.0f));
 99                 tTangents[ring * (prec + 1) + i] = glm::vec3(rMat * glm::vec4(tTangents[i], 1.0f));
100 
101                 // 绕Y轴旋转法向量
102                 rMat = glm::rotate(glm::mat4(1.0f), amt, glm::vec3(0.0f, 1.0f, 0.0f));
103                 normals[ring * (prec + 1) + i] = glm::vec3(rMat * glm::vec4(normals[i], 1.0f));
104             }
105         }
106     }
107     // 按照逐个顶点的两个三角形,计算三角形索引
108     for (int ring = 0; ring < prec; ring++)
109     {
110         for (int vert = 0; vert < prec; vert++)
111         {
112             indices[((ring * prec + vert) * 2) * 3 + 0] = ring * (prec + 1) + vert;
113             indices[((ring * prec + vert) * 2) * 3 + 1] = (ring + 1) * (prec + 1) + vert;
114             indices[((ring * prec + vert) * 2) * 3 + 2] = ring * (prec + 1) + vert + 1;
115             indices[((ring * prec + vert) * 2 + 1) * 3 + 0] = ring * (prec + 1) + vert + 1;
116             indices[((ring * prec + vert) * 2 + 1) * 3 + 1] = (ring + 1) * (prec + 1) + vert;
117             indices[((ring * prec + vert) * 2 + 1) * 3 + 2] = (ring + 1) * (prec + 1) + vert + 1;
118         }
119     }
120 }
121 
122 float Torus::toRadians(float degrees)
123 {
124     return (degrees * 2.0f * 3.14159f) / 360.0f;
125 }
126 
127 Torus::Torus()
128 {
129     prec = 48;
130     inner = 0.5f;
131     outer = 0.2f;
132     init();
133 }
134 
135 Torus::Torus(float innerRadius, float outerRadius, int precIn)
136 {
137     prec = precIn;
138     inner = innerRadius;
139     outer = outerRadius;
140     init();
141 }
142 
143 Torus::~Torus()
144 {
145 }
146 
147 int Torus::getNumVertices()
148 {
149     return numVertices;
150 }
151 
152 int Torus::getNumIndices()
153 {
154     return numIndices;
155 }
156 
157 std::vector<int> Torus::getIndices()
158 {
159     return indices;
160 }
161 
162 std::vector<glm::vec3> Torus::getVertices()
163 {
164     return vertices;
165 }
166 
167 std::vector<glm::vec2> Torus::getTexCoords()
168 {
169     return texCoords;
170 }
171 
172 std::vector<glm::vec3> Torus::getNormals()
173 {
174     return normals;
175 }
176 
177 std::vector<glm::vec3> Torus::getStangents()
178 {
179     return sTangents;
180 }
181 
182 std::vector<glm::vec3> Torus::getTtangents()
183 {
184     return tTangents;
185 }

main.cpp

 1 ...
 2 #include "Torus.h"
 3 ...
 4 Torus myTorus(0.5f, 0.2f, 48);
 5 ...
 6 void setupVertices(void)
 7 {    
 8     std::vector<int> ind = myTorus.getIndices();         //索引
 9     std::vector<glm::vec3> vert = myTorus.getVertices(); //顶点
10     std::vector<glm::vec2> tex = myTorus.getTexCoords(); //纹理
11     std::vector<glm::vec3> norm = myTorus.getNormals();  //法向量
12 
13     std::vector<float> pvalues;   //顶点位置
14     vector<float> tvalues;        //纹理坐标
15     vector<float> nvalues;        //法向量
16 
17     int numVertices = myTorus.getNumVertices();
18     for (int i = 0; i < numVertices; i++)
19     {
20         pvalues.push_back((vert[i]).x);
21         pvalues.push_back((vert[i]).y);
22         pvalues.push_back((vert[i]).z);
23 
24         tvalues.push_back((tex[i]).s);
25         tvalues.push_back((tex[i]).t);
26 
27         nvalues.push_back((norm[i]).x);
28         nvalues.push_back((norm[i]).y);
29         nvalues.push_back((norm[i]).z);
30     }
31 
32     glGenVertexArrays(1, vao); // 创建一个vao,并返回它的整数型ID存进数组vao中
33     glBindVertexArray(vao[0]); // 激活vao
34     glGenBuffers(numVBOs, vbo);// 创建4个vbo,并返回它们的整数型ID存进数组vbo中
35 
36     // 把顶点放入缓冲区 #0
37     glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); 
38     glBufferData(GL_ARRAY_BUFFER, pvalues.size() * 4, &pvalues[0], GL_STATIC_DRAW); 
39     // 把纹理坐标放入缓冲区 #1
40     glBindBuffer(GL_ARRAY_BUFFER, vbo[1]); 
41     glBufferData(GL_ARRAY_BUFFER, tvalues.size() * 4, &tvalues[0], GL_STATIC_DRAW); 
42     // 把法向量放入缓冲区 #2
43     glBindBuffer(GL_ARRAY_BUFFER, vbo[2]);
44     glBufferData(GL_ARRAY_BUFFER, nvalues.size() * 4, &nvalues[0], GL_STATIC_DRAW);
45     // 把索引放入缓冲区 #3
46     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[3]);
47     glBufferData(GL_ELEMENT_ARRAY_BUFFER, ind.size() * 4, &ind[0], GL_STATIC_DRAW);
48 }
49 ...
50 void display(GLFWwindow* window, double currentTime)
51 {
52     ...
53     
54     glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[3]);
55     glDrawElements(GL_TRIANGLES, myTorus.getNumIndices(), GL_UNSIGNED_INT, 0);
56 }

The effect is as shown in the figure:

Guess you like

Origin blog.csdn.net/ttod/article/details/135346477