Click here to Skip to main content
15,886,919 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more:
I'm working on a program where I need to make spheres. My chosen method is to create an octahedron
https://i.stack.imgur.com/xHpcm.png[^]

and through tessellation shaders, subdividing it and then normalizing the coordinates into an octa sphere (sphere created from tessellating an octahedron). However, my problem is this is only partially working as shown below, and I want a full sphere instead of a 80% sphere. Oh and it's not just when it's in sphere form. This is when I stop normalizing the uvw coordinates of the octahedron

https://i.stack.imgur.com/v1SB0.png[^

https://i.stack.imgur.com/BXmpD.png

Below is my tessellation eval shader (GLSL)

C
#version 450 core

// from control shader
layout(triangles, equal_spacing, cw) in;

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

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

void main()
{
    // get / make the barycentric coordinates of the octahedron
    vec3 u = gl_TessCoord.x * vertex_coord[0];
    vec3 v = gl_TessCoord.y * vertex_coord[1];
    vec3 w = gl_TessCoord.z * vertex_coord[2];
    // normalizing the positions of the triangles allows for every point to be
    // the same distance away from the center, forming a sphere
    vec3 pos = normalize(u + v + w);
    // output patch point position in clip space
    gl_Position = projection * view * model * vec4(pos, 1.0);
}


and my tessellation control shader, also GLSL
C
#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 tessellation
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 step by step
        // 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_1, tess_level_3);
        gl_TessLevelInner[1] = max(tess_level_2, tess_level_1);
    }
}


my vertex shader
C
#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);
    // put the vertices into a different vector
    vert_coord = pos;
}


My octahedron vertices and indices

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

    unsigned int indices[] = {
        // first triangle
        0, 1, 2,
        // second triangle
        3, 4, 5,
        // third triangle
        6, 7, 8,
        // fourth triangle
        9, 10, 11,
        // fifth triangle
        12, 13, 14,
        // sixth triangle
        15, 16, 17,
        // seventh triangle
        18, 19, 20,
        // eighth triangle
        21, 22, 23
    };


And my buffers and draw calls
C
unsigned int vbo, vao, ebo;
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
glGenBuffers(1, &ebo);

glBindVertexArray(vao);

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

// upload index data to gpu
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices) * sizeof(unsigned int), &indices[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);

//
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(2);

// max tessellation points / patches
glPatchParameteri(GL_PATCH_VERTICES, 3);

glBindVertexArray(vao);
glDrawElements(GL_PATCHES, 24, GL_UNSIGNED_INT, 0);


What I have tried:

Scoured the internet for weeks, changed around all shaders, vertices, math, tried this with different shapes such as cubes, icosahedrons, dodecahedrons, UV spheres (spheres generated on the CPU then uploaded to the GPU) and also asked around several different forums, used any and every single computer graphics debugger (like Render Doc), compared my sphere code with at least 50 other code bases, asked professional graphics programmers through DM's and stuff, pretty much anything and everything I tried before this.
Posted
Updated 17-Apr-23 4:30am
v7
Comments
0x01AA 4-Apr-23 12:45pm    
You showed what you got, that's good.
But you do not explain/show what you expect.
Chillzy 4-Apr-23 13:29pm    
Oh ok, forgot about that. What I want is for the ENTIRE sphere to be rendered. Right now, it's only about 80%. I want to have the section that's not being rendered to be drawn with the rest of the sphere, making it a proper sphere (in my case, an octasphere).
[no name] 4-Apr-23 17:34pm    
You went from a wire frame to full on. Maybe step back and make incremental changes so you can observe the behaviour.
Chillzy 4-Apr-23 17:36pm    
Oh no I know about how the behavior is. I just used the wireframe to demonstrate where the error(s) is.
Rick York 4-Apr-23 18:38pm    
I don't have an answer for you but you might find something useful at this guy's site : https://iquilezles.org/

So I went onto a different forum and I asked this question, and somebody helped me solve it. It turns out that the coordinates for the octahedron were wrong. The problematic ones were top-north-east and bottom-south-east. I'll give a list of the new and improved coordinates as well as the output of it.
C
 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
};


https://i.stack.imgur.com/sfoAk.png[^]
 
Share this answer
 
v3
This clearly looks that you missed to draw one part. Most common reasons are:
a) you draw it on the wrong position or
b) ferget to draw it
c) draw with clear color

C++
float vertices[] = {
        //top-north-east
         0.0f, -1.0f,  0.0f, // is the -1.0 correct?
So draw each part of your draw as single output or give them different colors.

Or best identify the part of your code which have to draw the missing part and find the bug.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900