Added geometry shader to pipeline so I can calculate normal data on the GPU
This commit is contained in:
parent
532382b1f9
commit
5b1aba34df
6 changed files with 122 additions and 44 deletions
33
data/shaders/geometry.glsl
Normal file
33
data/shaders/geometry.glsl
Normal 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();
|
||||
};
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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); }
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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"));
|
||||
|
|
|
|||
Loading…
Reference in a new issue