使用 OpenGL 绘制椭圆体时出现问题
Issue in drawing ellipsoid with OpenGL
这是我使用带有着色器的 OpenGL 创建和绘制椭圆体的代码
const float _2pi = 2.0f * M_PI;
std::vector<glm::vec3> positions;
std::vector<glm::vec3> normals;
std::vector<glm::vec2> textureCoords;
for(int i = 0; i <= stacks; ++i) {
// V texture coordinate
float V = i / (float)stacks;
float phi = V * M_PI;
for( int j = 0; j <= slices; ++j) {
// U texture coordinate
float U = j / (float)slices;
float theta = U * _2pi;
float X = a * cos(theta) * cos(phi);
float Y = b * cos(theta) * sin(phi);
float Z = c * sin(theta);
positions.push_back( glm::vec3( X, Y, Z) );
normals.push_back( glm::vec3(X, Y, Z) );
textureCoords.push_back( glm::vec2(U, V) );
}
}
// Now generate the index buffer
std::vector<GLuint> indicies;
for(int i=0; i <slices*stacks+slices; ++i) {
indicies.push_back(i);
indicies.push_back(i + slices + 1);
indicies.push_back(i + slices);
indicies.push_back(i + slices + 1);
indicies.push_back(i);
indicies.push_back(i + 1);
}
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(4, vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, positions.size() * sizeof(glm::vec3), positions.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), normals.data(), GL_STATIC_DRAW);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_TRUE, 0, nullptr);
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, vbo[2]);
glBufferData(GL_ARRAY_BUFFER, textureCoords.size() * sizeof(glm::vec2), textureCoords.data(), GL_STATIC_DRAW);
glVertexAttribPointer(8, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(8);
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, vbo[3]);
glBufferData( GL_ELEMENT_ARRAY_BUFFER, indicies.size() * sizeof(GLuint), indicies.data(), GL_STATIC_DRAW);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
虽然这是我用来呈现它的代码:
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
if(style == glObject::STYLE::WIREFRAME) glDrawElements(GL_LINES, (slices * stacks + slices) * 6, GL_UNSIGNED_INT, nullptr);
if(style == glObject::STYLE::SOLID) glDrawElements(GL_TRIANGLES, (slices * stacks + slices) * 6, GL_UNSIGNED_INT, nullptr);
glBindVertexArray(0);
它似乎有效,但我遇到了一些问题。
查看图像可能会在错误的位置看到一些顶点。
我认为这与指标有关,但我不确定。
我注意到这取决于我使用的堆栈或切片的数量
更新:
我考虑了@Rabbid76 的建议,结果是这样的。
渲染中不再有退化的顶点和三角形。
但是渲染不等于@Rabbid76 的渲染,就像顶点旋转一样。
决赛:
这是创建顶点和索引代码:
std::vector<glm::vec3> positions;
std::vector<glm::vec3> normals;
std::vector<glm::vec2> textureCoords;
for(int i = 0; i <= stacks; ++i) {
// V texture coordinate.
float V = i / (float)stacks;
float phi = V * M_PI;
for( int j = 0; j <= slices; ++j) {
// U texture coordinate.
float U = j / (float)slices;
float theta = U * 2.0f * M_PI;
float X = cos(theta) * sin(phi);
float Y = cos(phi);
float Z = sin(theta) * sin(phi);
positions.push_back( glm::vec3( X, Y, Z) * radius );
normals.push_back( glm::vec3(X, Y, Z) );
textureCoords.push_back( glm::vec2(U, V) );
}
}
// Now generate the index buffer
std::vector<GLuint> indicies;
int noPerSlice = slices + 1;
for(int i=0; i < stacks; ++i) {
for (int j=0; j < slices; ++j) {
int start_i = (i * noPerSlice) + j;
indicies.push_back( start_i );
indicies.push_back( start_i + noPerSlice + 1 );
indicies.push_back( start_i + noPerSlice );
indicies.push_back( start_i + noPerSlice + 1 );
indicies.push_back( start_i );
indicies.push_back( start_i + 1 );
}
}
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(4, vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, positions.size() * sizeof(glm::vec3), positions.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), normals.data(), GL_STATIC_DRAW);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_TRUE, 0, nullptr);
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, vbo[2]);
glBufferData(GL_ARRAY_BUFFER, textureCoords.size() * sizeof(glm::vec2), textureCoords.data(), GL_STATIC_DRAW);
glVertexAttribPointer(8, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(8);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[3]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicies.size() * sizeof(GLuint), indicies.data(), GL_STATIC_DRAW);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
这是渲染图:
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
if(style == glObject::STYLE::WIREFRAME) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
if(style == glObject::STYLE::SOLID) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDrawElements(GL_TRIANGLES, (slices * stacks + slices) * 6, GL_UNSIGNED_INT, nullptr);
glBindVertexArray(0);
您混淆了 phi
和 theta
。 theta
是 [0, 2*PI] 范围内切片圆周上的点的角度。 phi
是范围内从南到北的点的角度 [-PI, PI]:
for (int i = 0; i <= stacks; ++i) {
// V texture coordinate
float V = i / (float)stacks;
float phi = V * M_PI - M_PI/2.0;
for ( int j = 0; j <= slices; ++j) {
// U texture coordinate
float U = j / (float)slices;
float theta = U * _2pi;
float X = a * cos(phi) * cos(theta);
float Y = b * cos(phi) * sin(theta);
float Z = c * sin(phi);
positions.push_back( glm::vec3( X, Y, Z) );
normals.push_back( glm::vec3(X, Y, Z) );
textureCoords.push_back( glm::vec2(U, V) );
}
}
一个切片(围绕圆周)的点数是noPerSlice = slices + 1
。四边形点的第一个索引是 start_i = (i * noPerSlice) + j
,其中 i
是堆栈的索引,j
是切片周围的索引。围绕圆周创建 slices
个四边形,stacks
个切片从南到北:
int noPerSlice = slices + 1;
for(int i=0; i < stacks; ++i) {
for (int j = 0; j < slices; ++j) {
int start_i = (i * noPerSlice) + j;
indicies.push_back( start_i );
indicies.push_back( start_i + noPerSlice + 1 );
indicies.push_back( start_i + noPerSlice );
indicies.push_back( start_i + noPerSlice + 1 );
indicies.push_back( start_i );
indicies.push_back( start_i + 1 );
}
}
我觉得
slices*stacks+slices
应该是
slices*stacks+stacks
+stacks 用于每个堆栈中重复顶点的额外四边形
虽然这修复了索引的数量,但沿着重复的顶点仍然有退化的三角形,其中 theta 等于零
这是我使用带有着色器的 OpenGL 创建和绘制椭圆体的代码
const float _2pi = 2.0f * M_PI;
std::vector<glm::vec3> positions;
std::vector<glm::vec3> normals;
std::vector<glm::vec2> textureCoords;
for(int i = 0; i <= stacks; ++i) {
// V texture coordinate
float V = i / (float)stacks;
float phi = V * M_PI;
for( int j = 0; j <= slices; ++j) {
// U texture coordinate
float U = j / (float)slices;
float theta = U * _2pi;
float X = a * cos(theta) * cos(phi);
float Y = b * cos(theta) * sin(phi);
float Z = c * sin(theta);
positions.push_back( glm::vec3( X, Y, Z) );
normals.push_back( glm::vec3(X, Y, Z) );
textureCoords.push_back( glm::vec2(U, V) );
}
}
// Now generate the index buffer
std::vector<GLuint> indicies;
for(int i=0; i <slices*stacks+slices; ++i) {
indicies.push_back(i);
indicies.push_back(i + slices + 1);
indicies.push_back(i + slices);
indicies.push_back(i + slices + 1);
indicies.push_back(i);
indicies.push_back(i + 1);
}
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(4, vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, positions.size() * sizeof(glm::vec3), positions.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), normals.data(), GL_STATIC_DRAW);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_TRUE, 0, nullptr);
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, vbo[2]);
glBufferData(GL_ARRAY_BUFFER, textureCoords.size() * sizeof(glm::vec2), textureCoords.data(), GL_STATIC_DRAW);
glVertexAttribPointer(8, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(8);
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, vbo[3]);
glBufferData( GL_ELEMENT_ARRAY_BUFFER, indicies.size() * sizeof(GLuint), indicies.data(), GL_STATIC_DRAW);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
虽然这是我用来呈现它的代码:
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
if(style == glObject::STYLE::WIREFRAME) glDrawElements(GL_LINES, (slices * stacks + slices) * 6, GL_UNSIGNED_INT, nullptr);
if(style == glObject::STYLE::SOLID) glDrawElements(GL_TRIANGLES, (slices * stacks + slices) * 6, GL_UNSIGNED_INT, nullptr);
glBindVertexArray(0);
它似乎有效,但我遇到了一些问题。 查看图像可能会在错误的位置看到一些顶点。 我认为这与指标有关,但我不确定。 我注意到这取决于我使用的堆栈或切片的数量
更新:
我考虑了@Rabbid76 的建议,结果是这样的。 渲染中不再有退化的顶点和三角形。 但是渲染不等于@Rabbid76 的渲染,就像顶点旋转一样。
决赛:
这是创建顶点和索引代码:
std::vector<glm::vec3> positions;
std::vector<glm::vec3> normals;
std::vector<glm::vec2> textureCoords;
for(int i = 0; i <= stacks; ++i) {
// V texture coordinate.
float V = i / (float)stacks;
float phi = V * M_PI;
for( int j = 0; j <= slices; ++j) {
// U texture coordinate.
float U = j / (float)slices;
float theta = U * 2.0f * M_PI;
float X = cos(theta) * sin(phi);
float Y = cos(phi);
float Z = sin(theta) * sin(phi);
positions.push_back( glm::vec3( X, Y, Z) * radius );
normals.push_back( glm::vec3(X, Y, Z) );
textureCoords.push_back( glm::vec2(U, V) );
}
}
// Now generate the index buffer
std::vector<GLuint> indicies;
int noPerSlice = slices + 1;
for(int i=0; i < stacks; ++i) {
for (int j=0; j < slices; ++j) {
int start_i = (i * noPerSlice) + j;
indicies.push_back( start_i );
indicies.push_back( start_i + noPerSlice + 1 );
indicies.push_back( start_i + noPerSlice );
indicies.push_back( start_i + noPerSlice + 1 );
indicies.push_back( start_i );
indicies.push_back( start_i + 1 );
}
}
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(4, vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER, positions.size() * sizeof(glm::vec3), positions.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), normals.data(), GL_STATIC_DRAW);
glVertexAttribPointer(2, 3, GL_FLOAT, GL_TRUE, 0, nullptr);
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, vbo[2]);
glBufferData(GL_ARRAY_BUFFER, textureCoords.size() * sizeof(glm::vec2), textureCoords.data(), GL_STATIC_DRAW);
glVertexAttribPointer(8, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(8);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[3]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indicies.size() * sizeof(GLuint), indicies.data(), GL_STATIC_DRAW);
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
这是渲染图:
glBindVertexArray(vao);
glEnableVertexAttribArray(0);
if(style == glObject::STYLE::WIREFRAME) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
if(style == glObject::STYLE::SOLID) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glDrawElements(GL_TRIANGLES, (slices * stacks + slices) * 6, GL_UNSIGNED_INT, nullptr);
glBindVertexArray(0);
您混淆了 phi
和 theta
。 theta
是 [0, 2*PI] 范围内切片圆周上的点的角度。 phi
是范围内从南到北的点的角度 [-PI, PI]:
for (int i = 0; i <= stacks; ++i) {
// V texture coordinate
float V = i / (float)stacks;
float phi = V * M_PI - M_PI/2.0;
for ( int j = 0; j <= slices; ++j) {
// U texture coordinate
float U = j / (float)slices;
float theta = U * _2pi;
float X = a * cos(phi) * cos(theta);
float Y = b * cos(phi) * sin(theta);
float Z = c * sin(phi);
positions.push_back( glm::vec3( X, Y, Z) );
normals.push_back( glm::vec3(X, Y, Z) );
textureCoords.push_back( glm::vec2(U, V) );
}
}
一个切片(围绕圆周)的点数是noPerSlice = slices + 1
。四边形点的第一个索引是 start_i = (i * noPerSlice) + j
,其中 i
是堆栈的索引,j
是切片周围的索引。围绕圆周创建 slices
个四边形,stacks
个切片从南到北:
int noPerSlice = slices + 1;
for(int i=0; i < stacks; ++i) {
for (int j = 0; j < slices; ++j) {
int start_i = (i * noPerSlice) + j;
indicies.push_back( start_i );
indicies.push_back( start_i + noPerSlice + 1 );
indicies.push_back( start_i + noPerSlice );
indicies.push_back( start_i + noPerSlice + 1 );
indicies.push_back( start_i );
indicies.push_back( start_i + 1 );
}
}
我觉得
slices*stacks+slices
应该是
slices*stacks+stacks
+stacks 用于每个堆栈中重复顶点的额外四边形
虽然这修复了索引的数量,但沿着重复的顶点仍然有退化的三角形,其中 theta 等于零