diff --git a/include/InitShader.h b/include/InitShader.h index f7450a7..83cf92c 100644 --- a/include/InitShader.h +++ b/include/InitShader.h @@ -6,6 +6,7 @@ GLuint InitShader( const char* computeShaderFile); GLuint InitShader( const char* vertexShaderFile, const char* fragmentShaderFile ); GLuint InitShader( const char* vertexShaderFile, const char* geometryShader, const char* fragmentShaderFile ); +GLuint InitShader( const char* vShaderFile, const char* tcShader, const char* teShader, const char* fShaderFile ); #endif \ No newline at end of file diff --git a/shaders/fragment.glsl b/shaders/fragment.glsl index fdf2154..6717873 100644 --- a/shaders/fragment.glsl +++ b/shaders/fragment.glsl @@ -33,6 +33,8 @@ in VertexData vec3 nw; //world-space normal vector } inData; //block is named 'inData' +in vec3 frag_position; + out vec4 frag_color; //the output color for this fragment void main(void) @@ -56,6 +58,6 @@ void main(void) // vec4 specular_term = atten*ks*Ls*pow(max(0.0, dot(rw, vw)), shininess); // fragcolor = ambient_term + diffuse_term + specular_term; - frag_color = vec4(0.45f, 0.82f, 0.52f, 1.0f); + frag_color = vec4(frag_position, 1.0f); } diff --git a/shaders/tessellation_ctrl.glsl b/shaders/tessellation_ctrl.glsl new file mode 100644 index 0000000..5aca5ac --- /dev/null +++ b/shaders/tessellation_ctrl.glsl @@ -0,0 +1,19 @@ +#version 430 + +layout(vertices = 4) out; // Define the number of control points per patch (e.g., 4 for a quad) + +void main() +{ + // Pass through control points to the tessellation evaluation shader + gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; + + // Set the tessellation levels (outer and inner) + if (gl_InvocationID == 0) { + gl_TessLevelOuter[0] = 5.0; // Level of tessellation along one edge + gl_TessLevelOuter[1] = 5.0; // Level of tessellation along another edge + gl_TessLevelOuter[2] = 5.0; // Level of tessellation along the other edge + gl_TessLevelOuter[3] = 5.0; // Level of tessellation along the other edge + gl_TessLevelInner[0] = 5.0; // Level of tessellation for the inner part + gl_TessLevelInner[1] = 5.0; // Level of tessellation for the inner part + } +} diff --git a/shaders/tessellation_eval.glsl b/shaders/tessellation_eval.glsl new file mode 100644 index 0000000..f964490 --- /dev/null +++ b/shaders/tessellation_eval.glsl @@ -0,0 +1,17 @@ +#version 430 + +layout(quads, equal_spacing, ccw) in; // Define the type of patch (e.g., quads) + +out vec3 frag_position; // Ensure this matches the input in fragment.glsl + +void main() +{ + // Interpolate the position using the barycentric coordinates from tessellation + vec3 pos = mix(mix(gl_in[0].gl_Position.xyz, gl_in[1].gl_Position.xyz, gl_TessCoord.x), + mix(gl_in[3].gl_Position.xyz, gl_in[2].gl_Position.xyz, gl_TessCoord.x), + gl_TessCoord.y); + + frag_position = pos; + + gl_Position = vec4(pos, 1.0); +} diff --git a/shaders/vertex.glsl b/shaders/vertex.glsl index 74905dd..a8a00ee 100644 --- a/shaders/vertex.glsl +++ b/shaders/vertex.glsl @@ -1,30 +1,41 @@ -#version 430 -layout(location = 0) uniform mat4 M; -layout(location = 1) uniform float time; +#version 430 -layout(std140, binding = 0) uniform SceneUniforms -{ - mat4 PV; //camera projection * view matrix - vec4 eye_w; //world-space eye position -}; - -layout(location = 0) in vec3 pos_attrib; //this variable holds the position of mesh vertices +layout(location = 0) in vec3 pos_attrib; layout(location = 1) in vec2 tex_coord_attrib; layout(location = 2) in vec3 normal_attrib; -out VertexData -{ - vec2 tex_coord; - vec3 pw; //world-space vertex position - vec3 nw; //world-space normal vector -} outData; +void main() { + gl_Position = vec4(pos_attrib, 1.0); +} -void main(void) -{ - gl_Position = PV*M*vec4(pos_attrib, 1.0); //transform vertices and send result into pipeline + +// #version 400 core +// layout(location = 0) uniform mat4 M; +// layout(location = 1) uniform float time; + +// layout(std140, binding = 0) uniform SceneUniforms +// { +// mat4 PV; //camera projection * view matrix +// vec4 eye_w; //world-space eye position +// }; + +// layout(location = 0) in vec3 pos_attrib; //this variable holds the position of mesh vertices +// layout(location = 1) in vec2 tex_coord_attrib; +// layout(location = 2) in vec3 normal_attrib; + +// out VertexData +// { +// vec2 tex_coord; +// vec3 pw; //world-space vertex position +// vec3 nw; //world-space normal vector +// } outData; + +// void main(void) +// { +// gl_Position = PV*M*vec4(pos_attrib, 1.0); //transform vertices and send result into pipeline - //Use dot notation to access members of the interface block - outData.tex_coord = tex_coord_attrib; //send tex_coord to fragment shader - outData.pw = vec3(M*vec4(pos_attrib, 1.0)); //world-space vertex position - outData.nw = vec3(M*vec4(normal_attrib, 0.0)); //world-space normal vector -} \ No newline at end of file +// //Use dot notation to access members of the interface block +// outData.tex_coord = tex_coord_attrib; //send tex_coord to fragment shader +// outData.pw = vec3(M*vec4(pos_attrib, 1.0)); //world-space vertex position +// outData.nw = vec3(M*vec4(normal_attrib, 0.0)); //world-space normal vector +// } \ No newline at end of file diff --git a/source/InitShader.cpp b/source/InitShader.cpp index 83e42d1..9194613 100644 --- a/source/InitShader.cpp +++ b/source/InitShader.cpp @@ -269,3 +269,72 @@ GLuint InitShader(const char* vShaderFile, const char* gShaderFile, const char* return program; } + +GLuint InitShader( const char* vShaderFile, const char* tcShader, const char* teShader, const char* fShaderFile ) +{ + bool error = false; + struct Shader + { + const char* filename; + GLenum type; + std::string source; + } shaders[4] = + { + { vShaderFile, GL_VERTEX_SHADER, "" }, + { tcShader, GL_TESS_CONTROL_SHADER, "" }, + { teShader, GL_TESS_EVALUATION_SHADER, "" }, + { fShaderFile, GL_FRAGMENT_SHADER, "" } + }; + + GLuint program = glCreateProgram(); + + for ( int i = 0; i < 4; ++i ) + { + Shader& s = shaders[i]; + s.source = readShaderSource(s.filename); + if ( shaders[i].source.length() == 0 ) + { + std::cerr << "Failed to read " << s.filename << std::endl; + error = true; + } + + GLuint shader = glCreateShader( s.type ); + const char *c_str = s.source.c_str(); + glShaderSource(shader, 1, (const GLchar**)&c_str, NULL); + glCompileShader( shader ); + + GLint compiled; + glGetShaderiv( shader, GL_COMPILE_STATUS, &compiled ); + if ( !compiled ) + { + std::cerr << s.filename << " failed to compile:" << std::endl; + printShaderCompileError(shader); + error = true; + } + + glAttachShader( program, shader ); + } + + /* link and error check */ + glLinkProgram(program); + + GLint linked; + glGetProgramiv( program, GL_LINK_STATUS, &linked ); + if ( !linked ) + { + std::cerr << "Shader program failed to link" << std::endl; + printProgramLinkError(program); + + error = true; + } + + if(error == true) + { + return -1; + } + + /* use program object */ + glUseProgram(program); + + return program; +} \ No newline at end of file diff --git a/source/scene.cpp b/source/scene.cpp index 0298408..50221e4 100644 --- a/source/scene.cpp +++ b/source/scene.cpp @@ -25,6 +25,8 @@ namespace { const std::string kVertexShaderPath = "shaders/vertex.glsl"; +const std::string kTessellationCtrlPath = "shaders/tessellation_ctrl.glsl"; +const std::string kTessellationEvalPath = "shaders/tessellation_eval.glsl"; const std::string kFragmentShaderPath = "shaders/fragment.glsl"; const std::string kQuadVertexPath = "shaders/quad_vertex.glsl"; @@ -57,7 +59,9 @@ Scene::~Scene() { void Scene::Init() { glewInit(); - glEnable(GL_DEPTH_TEST); + // GL_DEPTH_TEST causes artifacts in meshes made up of multiple triangles + // disabling for now + //glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); fbo_.Init(window_width, window_height); @@ -74,21 +78,28 @@ void Scene::Init() { // Currently creates a test triangle and initializes its buffers void Scene::InitBuffers() { - GLuint vbo; - float vertices[] = { - -0.5f, -0.5f, 0.0f, - 0.5f, -0.5f, 0.0f, - 0.0f, 0.5f, 0.0f + GLuint patch_vbo; + // Quad vertices in 3D space + float patchVertices[] = { + -0.5f, -0.5f, 0.0f, // Bottom-left + 0.5f, -0.5f, 0.0f, // Bottom-right + 0.5f, 0.5f, 0.0f, // Top-right + -0.5f, 0.5f, 0.0f // Top-left + }; - glGenBuffers(1, &vbo); - glBindBuffer(GL_ARRAY_BUFFER, vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - glGenVertexArrays(1, &vao_); + glGenBuffers(1, &patch_vbo); glBindVertexArray(vao_); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); + + glBindBuffer(GL_ARRAY_BUFFER, patch_vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(patchVertices), &patchVertices, GL_STATIC_DRAW); + + // Position attribute glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); + + glBindVertexArray(0); } void Scene::InitQuadBuffers() { @@ -121,7 +132,7 @@ void Scene::InitQuadBuffers() { // Allows for runtime shader updates void Scene::ReloadShader() { - GLuint new_shader = InitShader(kVertexShaderPath.c_str(), kFragmentShaderPath.c_str()); + GLuint new_shader = InitShader(kVertexShaderPath.c_str(), kTessellationCtrlPath.c_str(), kTessellationEvalPath.c_str(), kFragmentShaderPath.c_str()); if (new_shader == -1) { DEBUG_BREAK(); glClearColor(1.0f, 0.0f, 1.0f, 0.0f); @@ -141,6 +152,8 @@ void Scene::Display(GLFWwindow* window) { glUseProgram(shader_program_); + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + view_matrix_ = glm::lookAt(glm::vec3(Uniforms::SceneData.eye_w), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f)); Uniforms::SceneData.PV = projection_matrix_ * view_matrix_; // Projection-View matrix Uniforms::BufferSceneData(); @@ -149,7 +162,10 @@ void Scene::Display(GLFWwindow* window) { glUniformMatrix4fv(Uniforms::UniformLocs::M, 1, false, glm::value_ptr(model_matrix)); glBindVertexArray(vao_); - glDrawArrays(GL_TRIANGLES, 0, 3); + glPatchParameteri(GL_PATCH_VERTICES, 4); + glDrawArrays(GL_PATCHES, 0, 4); + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); fbo_.Unbind();