diff --git a/data/shaders/geometry.glsl b/data/shaders/geometry.glsl new file mode 100644 index 0000000..593f9eb --- /dev/null +++ b/data/shaders/geometry.glsl @@ -0,0 +1,33 @@ +#version 330 core +layout (triangles) in; +layout (triangle_strip) out; + +in vec2 gtexCoord[]; +in vec3 gnormCoord[]; +in vec3 gWorldPos[]; + +out vec2 texCoord; +out vec3 normCoord; +out vec3 WorldPos; + +void main() +{ + gl_Position = gl_in[0].gl_Position; + texCoord = gtexCoord[0]; + normCoord = gnormCoord[0]; + WorldPos = gWorldPos[0]; + EmitVertex(); + + gl_Position = gl_in[1].gl_Position; + texCoord = gtexCoord[1]; + normCoord = gnormCoord[1]; + WorldPos = gWorldPos[1]; + EmitVertex(); + + gl_Position = gl_in[2].gl_Position; + texCoord = gtexCoord[2]; + normCoord = gnormCoord[2]; + WorldPos = gWorldPos[2]; + EmitVertex(); + EndPrimitive(); +}; diff --git a/data/shaders/pbrFragment.glsl b/data/shaders/pbrFragment.glsl index 2fef9bd..914e6f9 100644 --- a/data/shaders/pbrFragment.glsl +++ b/data/shaders/pbrFragment.glsl @@ -1,10 +1,10 @@ #version 330 core out vec4 FragColor; -in vec2 ourTexCoord; -in vec3 ourNormCoord; +in vec2 texCoord; +in vec3 normCoord; in vec3 WorldPos; -in mat4 TBN; +//in mat4 TBN; // TODO: make temporary hard coded world/camera pos dynamic //uniform vec3 WorldPos ; @@ -34,48 +34,48 @@ const float PI = 3.14159265359; vec3 fresnelSchlick(float cosTheta, vec3 F0) { - return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0); + return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0); } float DistributionGGX(vec3 N, vec3 H, float roughness) { - float a = roughness*roughness; - float a2 = a*a; - float NdotH = max(dot(N, H), 0.0); - float NdotH2 = NdotH*NdotH; + float a = roughness*roughness; + float a2 = a*a; + float NdotH = max(dot(N, H), 0.0); + float NdotH2 = NdotH*NdotH; - float num = a2; - float denom = (NdotH2 * (a2 - 1.0) + 1.0); - denom = PI * denom * denom; + float num = a2; + float denom = (NdotH2 * (a2 - 1.0) + 1.0); + denom = PI * denom * denom; - return num / denom; + return num / denom; } float GeometrySchlickGGX(float NdotV, float roughness) { - float r = (roughness + 1.0); - float k = (r*r) / 8.0; + float r = (roughness + 1.0); + float k = (r*r) / 8.0; - float num = NdotV; - float denom = NdotV * (1.0 - k) + k; + float num = NdotV; + float denom = NdotV * (1.0 - k) + k; - return num / denom; + return num / denom; } float GeometrySmith(vec3 N, vec3 V, vec3 L, float roughness) { - float NdotV = max(dot(N, V), 0.0); - float NdotL = max(dot(N, L), 0.0); - float ggx2 = GeometrySchlickGGX(NdotV, roughness); - float ggx1 = GeometrySchlickGGX(NdotL, roughness); + float NdotV = max(dot(N, V), 0.0); + float NdotL = max(dot(N, L), 0.0); + float ggx2 = GeometrySchlickGGX(NdotV, roughness); + float ggx1 = GeometrySchlickGGX(NdotL, roughness); - return ggx1 * ggx2; + return ggx1 * ggx2; } vec3 normal(){ // load and invert normal - vec3 normal = normalize(texture(texture_normal1, ourTexCoord).rgb * 2.0 - 1.0); + vec3 normal = normalize(texture(texture_normal1, texCoord).rgb * 2.0 - 1.0); - normal = (TBN * vec4(normal, 1.0)).xyz; + //normal = (TBN * vec4(normal, 1.0)).xyz; //TODO: Make the normal vector match the matrix of the rest of the model by //actually calculating the TBN @@ -92,7 +92,7 @@ vec3 PBR(vec3 albedo, float roughness, float metallic, float ao) //vec3 lightColor = vec3(1.0, 1.0, 1.0) - sin(tick / 90); vec3 lightColor = vec3(13.47, 11.31, 10.79); - vec3 N = normalize(ourNormCoord); + vec3 N = normalize(normCoord); vec3 V = normalize(CameraPos - WorldPos); N = (N + normal()) / 2; //N = normal(); For seeing if normal map tracks with light. @@ -136,12 +136,12 @@ vec3 PBR(vec3 albedo, float roughness, float metallic, float ao) void main() { vec3 albedo; - albedo.r = pow(texture(texture_diffuse1, ourTexCoord).r, 2.2); - albedo.g = pow(texture(texture_diffuse1, ourTexCoord).g, 2.2); - albedo.b = pow(texture(texture_diffuse1, ourTexCoord).b, 2.2); - float roughness = texture(texture_rma1, ourTexCoord).r; - float metallic = texture(texture_rma1, ourTexCoord).g; - float ao = texture(texture_rma1, ourTexCoord).b; + albedo.r = pow(texture(texture_diffuse1, texCoord).r, 2.2); + albedo.g = pow(texture(texture_diffuse1, texCoord).g, 2.2); + albedo.b = pow(texture(texture_diffuse1, texCoord).b, 2.2); + float roughness = texture(texture_rma1, texCoord).r; + float metallic = texture(texture_rma1, texCoord).g; + float ao = texture(texture_rma1, texCoord).b; FragColor = vec4(PBR(albedo, roughness, metallic, ao), 1.0); } diff --git a/data/shaders/pbrVertex.glsl b/data/shaders/pbrVertex.glsl index 2a166cf..5b9ccf0 100644 --- a/data/shaders/pbrVertex.glsl +++ b/data/shaders/pbrVertex.glsl @@ -6,23 +6,20 @@ layout (location = 2) in vec2 aTexCoord; uniform mat4 MVP; uniform mat4 Model; -out vec2 ourTexCoord; -out vec3 ourNormCoord; +out vec2 gtexCoord; +out vec3 gnormCoord; //Pbr -out vec3 WorldPos; +out vec3 gWorldPos; //Normals -out mat4 TBN; void main() { gl_Position = MVP * Model * vec4(aPos, 1.0); - ourNormCoord = aNormal; - ourTexCoord = aTexCoord; - - TBN = Model; + gnormCoord = aNormal; + gtexCoord = aTexCoord; // Calculate position of fragment - WorldPos = vec3(Model * vec4(aPos, 1.0)); + gWorldPos = vec3(Model * vec4(aPos, 1.0)); }; diff --git a/src/ShaderLoader.cpp b/src/ShaderLoader.cpp index 7f8935f..19486f3 100644 --- a/src/ShaderLoader.cpp +++ b/src/ShaderLoader.cpp @@ -1,37 +1,54 @@ #include "ShaderLoader.h" #include -ShaderLoader::ShaderLoader(const char *vertexPath, const char *fragmentPath) { +// This function always expects vertex and fragment shaders, if a geometry +// shader is present then it will also compile in that boi too. +// TODO: Make this code more readable and reduce the number of if statements. +void ShaderLoader::loadShader(const char *vertexPath, const char *fragmentPath, + const char *geometryPath) { std::string vertexCode; std::string fragmentCode; + std::string geometryCode; std::ifstream vShaderFile; std::ifstream fShaderFile; + std::ifstream gShaderFile; vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); + if (geometryPath != nullptr) + gShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); try { // Open Files vShaderFile.open(vertexPath); fShaderFile.open(fragmentPath); - std::stringstream vShaderStream, fShaderStream; + if (geometryPath != nullptr) + gShaderFile.open(geometryPath); + std::stringstream vShaderStream, fShaderStream, gShaderStream; // read file's buffer contents into streams vShaderStream << vShaderFile.rdbuf(); fShaderStream << fShaderFile.rdbuf(); + if (geometryPath != nullptr) + gShaderStream << gShaderFile.rdbuf(); // close file handlers vShaderFile.close(); fShaderFile.close(); + if (geometryPath != nullptr) + gShaderFile.close(); // convert stream into string vertexCode = vShaderStream.str(); fragmentCode = fShaderStream.str(); + if (geometryPath != nullptr) + geometryCode = gShaderStream.str(); } catch (std::string e) { error.crash("Failed to read shaderfiles", e); } const char *vShaderCode = vertexCode.c_str(); const char *fShaderCode = fragmentCode.c_str(); + const char *gShaderCode = geometryCode.c_str(); // Compile shaders - unsigned int vertex, fragment; + unsigned int vertex, fragment, geometry; int success; char infoLog[512]; @@ -60,10 +77,25 @@ ShaderLoader::ShaderLoader(const char *vertexPath, const char *fragmentPath) { error.crash("Fragment shader compilation failed", infoLog); } + // create geometry shader + if (geometryPath != nullptr) { + geometry = glCreateShader(GL_GEOMETRY_SHADER); + // compile fragment shader + glShaderSource(geometry, 1, &gShaderCode, NULL); + glCompileShader(geometry); + // https://learnopengl.com/Getting-started/Hello-Triangle + glGetShaderiv(geometry, GL_COMPILE_STATUS, &success); + if (!success) { + glGetShaderInfoLog(geometry, 512, NULL, infoLog); + error.crash("Geometry shader compilation failed", infoLog); + } + } // shader Program ID = glCreateProgram(); glAttachShader(ID, vertex); glAttachShader(ID, fragment); + if (geometryPath != nullptr) + glAttachShader(ID, geometry); glLinkProgram(ID); // print linking errors if any glGetProgramiv(ID, GL_LINK_STATUS, &success); @@ -76,6 +108,16 @@ ShaderLoader::ShaderLoader(const char *vertexPath, const char *fragmentPath) { // necessary glDeleteShader(vertex); glDeleteShader(fragment); + glDeleteShader(geometry); +} + +ShaderLoader::ShaderLoader(const char *vertexPath, const char *fragmentPath, + const char *geometryPath) { + this->loadShader(vertexPath, fragmentPath, geometryPath); +} + +ShaderLoader::ShaderLoader(const char *vertexPath, const char *fragmentPath) { + this->loadShader(vertexPath, fragmentPath, nullptr); } void ShaderLoader::use() { glUseProgram(ID); } diff --git a/src/ShaderLoader.h b/src/ShaderLoader.h index dc92c42..996116f 100644 --- a/src/ShaderLoader.h +++ b/src/ShaderLoader.h @@ -16,9 +16,14 @@ private: unsigned int ID; Error error = Error("ShaderLoader"); + void loadShader(const char *vertexPath, const char *fragmentPath, + const char *geometryPath); + public: // constructor builds shader ShaderLoader(const char *vertexPath, const char *fragmentPath); + ShaderLoader(const char *vertexPath, const char *fragmentPath, + const char *geometryPath); // use the shader void use(); diff --git a/src/main.cpp b/src/main.cpp index f043b20..83ca4ff 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -71,7 +71,8 @@ int main(int argc, char **argv) { SDL_Event input; ShaderLoader shader(ROOT_DIR "data/shaders/pbrVertex.glsl", - ROOT_DIR "data/shaders/pbrFragment.glsl"); + ROOT_DIR "data/shaders/pbrFragment.glsl", + ROOT_DIR "data/shaders/geometry.glsl"); // Model backpack(std::string(ROOT_DIR) + // std::string("data/models/backpack/backpack.obj"));