thewoz
thewoz

Reputation: 562

Issue in drawing ellipsoid with OpenGL

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

enter image description here

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.

enter image description here enter image description here

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);

Upvotes: 1

Views: 1139

Answers (2)

phry
phry

Reputation: 84

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

Upvotes: 0

Rabbid76
Rabbid76

Reputation: 210928

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 );
    }
}

Upvotes: 3

Related Questions