I'm working on a program where I need to draw spheres. The method I'm using is creating an octahedron
And using tessellation shaders to subdivide it into a sphere, however there is a patch of the sphere that is not being rendered, and I don't know what's causing it. Keep in mind, this is the same when I stop normalizing the UVW coordinates through the evaluation shader
Here is my tessellation evaluation shader
#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);
}
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 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] = tess_level_1;
gl_TessLevelInner[1] = tess_level_2;
}
}
Here is my vertex shader
#version 450 core
// position of the object
layout (location = 0) in vec3 pos;
layout (location = 1) in vec3 vert;
// 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 = vert;
}
And finally, here are my octahedron vertices and buffers and draw call
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
};
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);
// max tessellation points / patches
glPatchParameteri(GL_PATCH_VERTICES, 3);
glDrawElements(GL_PATCHES, 24, GL_UNSIGNED_INT, 0);
As a bonus, if it's helpful, this is where the tutorial where I adapted my code from. The guy making it uses an icosahedron, which did not work when I tried it https://prideout.net/blog/old/blog/index.html@p=48.html
GL_ELEMENT_ARRAY_BUFFER
withglDrawArrays
command instead ofglDrawElements
. Are there 3 vertices in your vertices list per block? have you tried to disable cullingglDisable(GL_CULL_FACE);
? maybe one of the patches is oriented the wrong way $\endgroup$