问题
this is the code I use to create and draw an ellipsoid with OpenGL with shader
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);
while this is the code that I use to render it:
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);
It seems to work but I have some issue. Looking the image it is possible to see some vertex in the wrong position. I think that is something related to the indicies but I'm not sure. I have notice that depends by the number of stacks or slices that I use
UPDATE:
I take into account the suggestion of @Rabbid76 and this is the result. No more degenerated vertex and triangles in the rendering. However the rendering is not equal to the one of @Rabbid76 there is like a rotation of the vertex.
FINAL:
This is the creation vertex and indices code:
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);
This is the rendering one:
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);
回答1:
You have confused phi
and theta
. theta
is the angle of the points around the circumference of a slice in range [0, 2*PI]. phi
is the angle of the points form the south to the north in range [-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) );
}
}
The number of points of a slice (around the circumference) is noPerSlice = slices + 1
. The first index of a point of a quad is start_i = (i * noPerSlice) + j
, where i
is the index of the stack and j
the index around the slice. Create slices
quads around the circumference and stacks
slices form the south to the north:
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 );
}
}
回答2:
i think
slices*stacks+slices
should be
slices*stacks+stacks
the +stacks is for the extra quads from the duplicate vertex in every stack
although this fixes the number of indices, you still have degenerate triangles along the duplicate vertices where theta equals zero
来源:https://stackoverflow.com/questions/60686457/issue-in-drawing-ellipsoid-with-opengl