Using VBOs to draw a cylinder with selectable faces

You can’t directly render an OBJ-like structure without using a vertex shader. With the fixed-function pipeline, you have to expand the data so that each distinct position+normal pair corresponds to a distinct entry in the attribute arrays (all of which must have the same size).

If two vertices have the same position and normal, they can be a single vertex. If any attribute differs, they need to be distinct vertices.

For loading OBJ files, you typically maintain an associative array (e.g. std::unordered_map in C++) where the key is a triple of position/normal/texcoord indices and the value is an OpenGL vertex index. When reading faces, each “face vertex” (triple of indices) is looked up in the associative array. If an entry is found, the OpenGL vertex index is used. Otherwise, a new OpenGL vertex is created using the position/normal/texcoord data corresponding to the three indices and the new vertex is added to the associative array.

Hi I revise the code the make it more general

    void ConstructCylinder(uint32_t N, float r, glm::vec3 start, glm::vec3 end) {

        std::vector<TexturedVertex_new> vertices(4 * N + 2);
        std::vector<std::uint32_t> indices(12 * N);


        vertices[4 * N + 0].position = start; // top centre
        vertices[4 * N + 1].position = end; // bottom centre

        glm::vec3 top_normal = glm::normalize(start - end);
        glm::vec3 bottom_normal = -top_normal;

        vertices[4 * N + 0].normal = top_normal; // top centre
        vertices[4 * N + 1].normal = bottom_normal; // bottom centre

        // main normal direction (axis of cylinder)
        glm::vec3 normal = glm::normalize(end - start);
        glm::vec3 tangent = Maths::ComputeOrthogonalVector(normal);
        glm::vec3 biTangent = glm::normalize(glm::cross(normal, tangent));


        for (int i = 0; i < N; i++) {
            float angle = i * 2 * Maths::M_PI / N;
            
            float nx = cos(angle);
            float ny = sin(angle);
            
            // current tangent direction offset 
            glm::vec3 offset = nx * tangent + ny * biTangent; 

            vertices[2 * i + 0].position = vertices[2 * N + i].position = start + r * offset;
            vertices[2 * i + 1].position = vertices[3 * N + i].position = end + r * offset;

            vertices[2 * i + 0].normal = offset;
            vertices[2 * i + 1].normal = offset;
            vertices[2 * N + i].normal = top_normal;
            vertices[3 * N + i].normal = bottom_normal;


            int j = (i + 1) % N; // index of next face
            // outer faces
            // lower-right triangle
            indices[6 * i + 0] = 2 * j + 0; // lower-right
            indices[6 * i + 1] = 2 * j + 1; // upper-right
            indices[6 * i + 2] = 2 * i + 0; // lower-left
            // upper-left triangle
            indices[6 * i + 3] = 2 * j + 1; // upper-right
            indices[6 * i + 4] = 2 * i + 1; // upper-left
            indices[6 * i + 5] = 2 * i + 0; // lower-left
            // bottom face
            indices[6 * N + 3 * i + 1] = 2 * N + j;
            indices[6 * N + 3 * i + 0] = 2 * N + i;
            indices[6 * N + 3 * i + 2] = 4 * N + 0; // centre
            // top face
            indices[9 * N + 3 * i + 0] = 3 * N + i;
            indices[9 * N + 3 * i + 1] = 3 * N + j;
            indices[9 * N + 3 * i + 2] = 4 * N + 1; // centre
        }

        meshFilter = std::make_shared<Mesh_new>(std::move(Mesh_new{vertices, std::vector<SkinnedVertex_new>{}, indices}));
    }