Having trouble rendering entire sphere

Started by
8 comments, last by Chillzy 1 year ago

I'm working on a program where I have to draw spheres. My chosen method of doing so is to create an octa sphere. How that's done is I start by creating an octahedron

Octahedron, rendered in wireframe mode.

And then from there, I, through tessellation shaders, subdivide the octahedron, at which point you could see the problem forming

Tessellated octahedron with one patch missing, rendered in wireframe mode.

And finally, normalize the UVW coordinates of the octahedron, to form an octa-sphere, which is just a sphere that was created from a tessellated octahedron

Normalizing the coordinates of the octahedron creates this sphere, with that same patch missing that was missing from the subdivided octahedron

As you can (hopefully) see, starting from octahedron subdivision, a patch of the shape stopped rendering, and I don't know why, I haven't been able to figure this out and it's been over 2 months of me having this problem. Below is my source code.

Here is my tessellation evaluation shader

#version 450 core

// determines what type of tessellation to do
layout(triangles, equal_spacing, cw) in;

// input from control shader
in vec3 vertex_coord[];
// output vec
out vec3 vert;

// allows for object transformations
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;

void main()
{
    // gets barycentric coordinates from the triangles
    vec3 u = gl_TessCoord.x * vertex_coord[0];
    vec3 v = gl_TessCoord.y * vertex_coord[1];
    vec3 w = gl_TessCoord.z * vertex_coord[2];
    // makes every triangle an equal distance from the center (that's how spheres are formed)
    vec3 pos = normalize(u + v + w);

    // output tessellated shape
    gl_Position = projection * view * model * vec4(pos, 1.0);
}

And here is my tessellation control shader

#version 450 core

// specify control points per output per patch
// control size of input and output arrays
layout(vertices=3) out;
// input from vertex shader
in vec3 vert_coord[];
// output to evaluation shader
out vec3 vertex_coord[];

// for dynamic LOD (level of detail)
uniform mat4 view;
uniform mat4 model;

void main()
{
    // pass attributes through
    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
    vertex_coord[gl_InvocationID] = vert_coord[gl_InvocationID];

    // control tessellation
    if(gl_InvocationID==0)
    {
        // dynamic LOD (from the learnopengl.com website)
        // first: define rendering constants to control tessellation
        const float MIN_TESS_LEVEL = 4;
        const float MAX_TESS_LEVEL = 64;
        const float MIN_DISTANCE = 20;
        const float MAX_DISTANCE = 800;
        // second: transform each vertex into each eye
        vec4 eye_space_pos_1 = view * model * gl_in[0].gl_Position;
        vec4 eye_space_pos_2 = view * model * gl_in[1].gl_Position;
        vec4 eye_space_pos_3 = view * model * gl_in[2].gl_Position;
        // third: distance from camera scaled between 0 and 1
        float distance_1 = clamp((abs(eye_space_pos_1.z)-MIN_DISTANCE)/(MAX_DISTANCE-MIN_DISTANCE), 0.0, 1.0);
        float distance_2 = clamp((abs(eye_space_pos_2.z)-MIN_DISTANCE)/(MAX_DISTANCE-MIN_DISTANCE), 0.0, 1.0);
        float distance_3 = clamp((abs(eye_space_pos_3.z)-MIN_DISTANCE)/(MAX_DISTANCE-MIN_DISTANCE), 0.0, 1.0);
        // fourth: interpolate edge tessellation level based on closer vertex
        float tess_level_1 = mix(MAX_TESS_LEVEL, MIN_TESS_LEVEL, min(distance_3, distance_1));
        float tess_level_2 = mix(MAX_TESS_LEVEL, MIN_TESS_LEVEL, min(distance_1, distance_2));
        float tess_level_3 = mix(MAX_TESS_LEVEL, MIN_TESS_LEVEL, min(distance_2, distance_1));
        // fifth: set the corresponding outer tessellation levels
        gl_TessLevelOuter[0] = tess_level_1;
        gl_TessLevelOuter[1] = tess_level_2;
        gl_TessLevelOuter[2] = tess_level_3;
        // sixth: set the inner tessellation levels
        gl_TessLevelInner[0] = max(tess_level_2, tess_level_1);
        gl_TessLevelInner[1] = max(tess_level_1, tess_level_3);
    }
}

Finally, here's my vertex shader

#version 450 core

// position of the object
layout (location = 0) in vec3 pos;

// vertices to make the sphere
out vec3 vert_coord;

void main()
{
    // position object
    gl_Position = vec4(pos, 1.0f);
    vert_coord = pos;
}

Here are the vertices / coordinates of my octahedron

    float vertices[] = {
        //top-north-east
         0.0f, -1.0f,  0.0f,
         0.0f,  0.0f,  1.0f,
         1.0f,  0.0f,  0.0f,

        //top-north-west
         0.0f,  1.0f,  0.0f,
        -1.0f,  0.0f,  0.0f,
         0.0f,  0.0f,  1.0f,

        //top-south-west
         0.0f,  1.0f,  0.0f,
         0.0f,  0.0f, -1.0f,
        -1.0f,  0.0f,  0.0f,

        //top-south-east
         0.0f, -1.0f,  0.0f,
         1.0f,  0.0f,  0.0f,
         0.0f,  0.0f, -1.0f,

        //bottom-north-east
         0.0f, -1.0f,  0.0f,
         1.0f,  0.0f,  0.0f,
         0.0f,  0.0f,  1.0f,

        //bottom-north-west
         0.0f, -1.0f,  0.0f,
         0.0f,  0.0f,  1.0f,
        -1.0f,  0.0f,  0.0f,

        //bottom-south-west
         0.0f, -1.0f,  0.0f,
        -1.0f,  0.0f,  0.0f,
         0.0f,  0.0f, -1.0f,

        //bottom-south-east
         0.0f, 1.0f,  0.0f,
         0.0f,  0.0f, -1.0f,
         1.0f,  0.0f,  0.0f
};

Here is my vbo and vao, and also where I upload some data to the GPU

    unsigned int vbo, vao;
    glGenVertexArrays(1, &vao);
    glGenBuffers(1, &vbo);

    glBindVertexArray(vao);

    // upload vertex data to gpu
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vertices) * sizeof(double), &vertices[0], GL_STATIC_DRAW);

    // position attribute
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
    glEnableVertexAttribArray(0);

    // normal attribute
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)(3 * sizeof(float)));
    glEnableVertexAttribArray(1);

    // amount of tessellation to do per triangle
    glPatchParameteri(GL_PATCH_VERTICES, 3);

Last but not least, my OpenGL draw call

        glBindVertexArray(vao);
        glDrawArrays(GL_PATCHES, 0, 24);

If you want the full source code, here's the link you could use to download it (the libraries needed are CGLM, GLFW, and GLEW, and the IDE used is Code::Blocks)

Download Program From Here:

None

Advertisement

Are you by chance rendering with backface culling enabled? It might be that you just need to reorder the vertices on the missing face to make it point the right way.

@Aressera Already tried that and it didn't change anything

None

Your octahedron mesh has a duplicate face. I copied your vertex array and turned it into an OBJ mesh file and opened it in Meshlab.

The face labeled “top north east” has wrong the 0th vertex. It was obvious something was wrong when not all of the “top” faces shared a vertex. Your vertex labeled “bottom-south-east” is actually the top, your labels are wrong.

You spent 2 months on this and didn't think to check the input data?

@Aressera Wait really? That was the problem this whole time? Oh well let me try this for myself and see if the solution works. Also if the top-north-east is wrong, then what is it?

None

@Aressera Alright so if I have two duplicate vertices, meaning that top north east is wrong, then what are the correct vertices?

None

I already told you where the problem is, it's up to you to fix it for yourself. Debugging and troubleshooting is a valuable skill to learn.

@Aressera Thanks for the help, I figured it out just now

None

For future viewers, this is how my sphere looks like now, also, here are the correct coordinates

    float vertices[] = {
        //top-north-east
         0.0f, 1.0f,  0.0f,
         0.0f,  0.0f,  1.0f,
         1.0f,  0.0f,  0.0f,

        //top-north-west
         0.0f,  1.0f,  0.0f,
        -1.0f,  0.0f,  0.0f,
         0.0f,  0.0f,  1.0f,

        //top-south-west
         0.0f,  1.0f,  0.0f,
         0.0f,  0.0f, -1.0f,
        -1.0f,  0.0f,  0.0f,

        //top-south-east
         0.0f, -1.0f,  0.0f,
         1.0f,  0.0f,  0.0f,
         0.0f,  0.0f, -1.0f,

        //bottom-north-east
         0.0f, -1.0f,  0.0f,
         1.0f,  0.0f,  0.0f,
         0.0f,  0.0f,  1.0f,

        //bottom-north-west
         0.0f, -1.0f,  0.0f,
         0.0f,  0.0f,  1.0f,
        -1.0f,  0.0f,  0.0f,

        //bottom-south-west
         0.0f, -1.0f,  0.0f,
        -1.0f,  0.0f,  0.0f,
         0.0f,  0.0f, -1.0f,

        //bottom-south-east
         0.0f, 1.0f,  0.0f,
         0.0f,  0.0f, -1.0f,
         1.0f,  0.0f,  0.0f
};

Full Octa-sphere!

None

This topic is closed to new replies.

Advertisement