Added geometry shader to pipeline so I can calculate normal data on the GPU

This commit is contained in:
Warwick 2022-07-27 14:30:24 +01:00
parent 532382b1f9
commit 5b1aba34df
6 changed files with 122 additions and 44 deletions

View file

@ -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();
};

View file

@ -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);
}

View file

@ -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));
};

View file

@ -1,37 +1,54 @@
#include "ShaderLoader.h"
#include <iostream>
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); }

View file

@ -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();

View file

@ -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"));