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