FIrst step in Physically based rendering
This commit is contained in:
parent
4cba6ad37e
commit
7627df0fa0
106
Shaders/pbr.fs
Normal file
106
Shaders/pbr.fs
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
#version 460 core
|
||||||
|
|
||||||
|
out vec4 FragColor;
|
||||||
|
in vec2 TexCoords;
|
||||||
|
in vec3 WorldPos;
|
||||||
|
in vec3 Normal;
|
||||||
|
|
||||||
|
uniform vec3 camPos;
|
||||||
|
|
||||||
|
uniform vec3 albedo;
|
||||||
|
uniform float metallic;
|
||||||
|
uniform float roughness;
|
||||||
|
uniform float ao;
|
||||||
|
|
||||||
|
uniform vec3 lightPositions[4];
|
||||||
|
uniform vec3 lightColors[4];
|
||||||
|
|
||||||
|
const float PI = 3.14159265359;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ratio Refraction vs Reflection (F function)
|
||||||
|
vec3 fresnelSchlick (float cosTheta, vec3 F0)
|
||||||
|
{
|
||||||
|
return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate Normal distribution (D function)
|
||||||
|
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 num = a2;
|
||||||
|
float denom = (NdotH2 * ( a2 - 1.0) + 1.0);
|
||||||
|
denom = PI * denom * denom;
|
||||||
|
return num / denom;
|
||||||
|
}
|
||||||
|
|
||||||
|
// G function
|
||||||
|
float GeometrySchlickGGX(float NdotV, float roughness){
|
||||||
|
float r = (roughness + 1.0);
|
||||||
|
float k = (r*r) / 8.0;
|
||||||
|
|
||||||
|
float num = NdotV;
|
||||||
|
float denom = NdotV * (1.0 - k) + k;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
return ggx1 * ggx2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main(){
|
||||||
|
vec3 N = normalize(Normal);
|
||||||
|
vec3 V = normalize(camPos - WorldPos);
|
||||||
|
|
||||||
|
vec3 F0 = vec3(0.04);
|
||||||
|
F0 = mix(F0, albedo, metallic);
|
||||||
|
|
||||||
|
// Calculate the light contributions of each light source
|
||||||
|
vec3 Lo = vec3(0.0);
|
||||||
|
for( int i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
vec3 L = normalize(lightPositions[i] - WorldPos);
|
||||||
|
vec3 H = normalize(V + L);
|
||||||
|
float distance = length(lightPositions[i] - WorldPos);
|
||||||
|
float attenuation = 1.0/ (distance*distance);
|
||||||
|
vec3 radiance = lightColors[i] * attenuation;
|
||||||
|
|
||||||
|
float NDF = DistributionGGX(N,H, roughness);
|
||||||
|
float G = GeometrySmith(N,V,L, roughness);
|
||||||
|
vec3 F = fresnelSchlick(max(dot(H,V), 0.0), F0);
|
||||||
|
|
||||||
|
vec3 kS = F;
|
||||||
|
vec3 kD = vec3(1.0) - kS;
|
||||||
|
kD *= 1.0 - metallic;
|
||||||
|
|
||||||
|
|
||||||
|
vec3 numerator = NDF * G * F;
|
||||||
|
float denominator = 4.0 * max(dot(N,V), 0.0) * max(dot(N, L), 0.0) + 0.0001;
|
||||||
|
vec3 specular = numerator /denominator;
|
||||||
|
|
||||||
|
|
||||||
|
float NdotL = max(dot(N,L), 0.0);
|
||||||
|
Lo += (kD * albedo / PI + specular) * radiance * NdotL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the ambient term and add it
|
||||||
|
vec3 ambient = vec3(0.03) * albedo * ao;
|
||||||
|
vec3 color = ambient + Lo;
|
||||||
|
|
||||||
|
// Gamma correct the result
|
||||||
|
color = color / (color + vec3(1.0));
|
||||||
|
color = pow(color, vec3(1.0/2.2));
|
||||||
|
|
||||||
|
FragColor = vec4(color, 1.0);
|
||||||
|
}
|
22
Shaders/pbr.vs
Normal file
22
Shaders/pbr.vs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#version 460 core
|
||||||
|
layout (location = 0) in vec3 aPos;
|
||||||
|
layout (location = 1) in vec3 aNormal;
|
||||||
|
layout (location = 2) in vec2 aTexCoords;
|
||||||
|
|
||||||
|
out vec2 TexCoords;
|
||||||
|
out vec3 WorldPos;
|
||||||
|
out vec3 Normal;
|
||||||
|
|
||||||
|
uniform mat4 projection;
|
||||||
|
uniform mat4 view;
|
||||||
|
uniform mat4 model;
|
||||||
|
uniform mat3 normalMatrix;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
TexCoords = aTexCoords;
|
||||||
|
WorldPos = vec3(model * vec4(aPos, 1.0));
|
||||||
|
Normal = normalMatrix * aNormal;
|
||||||
|
|
||||||
|
gl_Position = projection * view * vec4(WorldPos, 1.0);
|
||||||
|
}
|
@ -111,6 +111,11 @@ void Shader::setMat4(const std::string &name, glm::mat4 value)const{
|
|||||||
glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &value[0][0] );
|
glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &value[0][0] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Shader::setMat3(const std::string& name, glm::mat3 value) const
|
||||||
|
{
|
||||||
|
glUniformMatrix3fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &value[0][0]);
|
||||||
|
}
|
||||||
|
|
||||||
void Shader::setVec3(const std::string &name, glm::vec3 value)const{
|
void Shader::setVec3(const std::string &name, glm::vec3 value)const{
|
||||||
glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value.x);
|
glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value.x);
|
||||||
}
|
}
|
@ -22,6 +22,7 @@ class Shader
|
|||||||
void setInt(const std::string &name, int value)const;
|
void setInt(const std::string &name, int value)const;
|
||||||
void setFloat(const std::string &name, float value)const;
|
void setFloat(const std::string &name, float value)const;
|
||||||
void setMat4(const std::string &name, glm::mat4 value)const;
|
void setMat4(const std::string &name, glm::mat4 value)const;
|
||||||
|
void setMat3(const std::string& name, glm::mat3 value)const;
|
||||||
void setVec3(const std::string &name, glm::vec3 value) const ;
|
void setVec3(const std::string &name, glm::vec3 value) const ;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -14,11 +14,29 @@ static enum class RenderPass {
|
|||||||
NONE = 0,
|
NONE = 0,
|
||||||
SKYBOX,
|
SKYBOX,
|
||||||
DEFAULT,
|
DEFAULT,
|
||||||
|
PBR
|
||||||
};
|
};
|
||||||
const int num_passes = static_cast<int>(RenderPass::DEFAULT) ;
|
const int num_passes = static_cast<int>(RenderPass::DEFAULT) ;
|
||||||
|
|
||||||
Texture* colourAttachment;
|
Texture* colourAttachment;
|
||||||
|
glm::vec3 lightPositions[] = {
|
||||||
|
glm::vec3(-10.0f, 10.0f, 10.0f),
|
||||||
|
glm::vec3(10.0f, 10.0f, 10.0f),
|
||||||
|
|
||||||
|
glm::vec3(-10.0f, -10.0f, 10.0f),
|
||||||
|
glm::vec3(10.0f, -10.0f, 10.0f)
|
||||||
|
};
|
||||||
|
|
||||||
|
glm::vec3 lightColors[] = {
|
||||||
|
glm::vec3(300.0f, 300.0f, 300.0f),
|
||||||
|
glm::vec3(300.0f, 300.0f, 300.0f),
|
||||||
|
glm::vec3(300.0f, 300.0f, 300.0f),
|
||||||
|
glm::vec3(300.0f, 300.0f, 300.0f)
|
||||||
|
};
|
||||||
|
|
||||||
|
int nrRows = 7;
|
||||||
|
int nrColumns = 7;
|
||||||
|
float spacing = 2.5;
|
||||||
|
|
||||||
void Renderer::Setup()
|
void Renderer::Setup()
|
||||||
{
|
{
|
||||||
@ -49,6 +67,8 @@ void Renderer::Setup()
|
|||||||
shaders[static_cast<int>(RenderPass::SKYBOX)].Load("../Shaders/skybox.vs", "../Shaders/Cubemap.fs");
|
shaders[static_cast<int>(RenderPass::SKYBOX)].Load("../Shaders/skybox.vs", "../Shaders/Cubemap.fs");
|
||||||
shaders[static_cast<int>(RenderPass::DEFAULT)] = Shader();
|
shaders[static_cast<int>(RenderPass::DEFAULT)] = Shader();
|
||||||
shaders[static_cast<int>(RenderPass::DEFAULT)].Load("../Shaders/shader.vs", "../Shaders/shader.fs");
|
shaders[static_cast<int>(RenderPass::DEFAULT)].Load("../Shaders/shader.vs", "../Shaders/shader.fs");
|
||||||
|
shaders[static_cast<int>(RenderPass::PBR)] = Shader();
|
||||||
|
shaders[static_cast<int>(RenderPass::PBR)].Load("../Shaders/pbr.vs", "../Shaders/pbr.fs");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,10 +114,107 @@ void Renderer::resize(int width, int height ) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int sphereVAO = 0;
|
||||||
|
unsigned int indexCount;
|
||||||
|
void renderSphere() {
|
||||||
|
if (sphereVAO == 0) {
|
||||||
|
glGenVertexArrays(1, &sphereVAO);
|
||||||
|
|
||||||
|
unsigned int vbo, ebo;
|
||||||
|
glGenBuffers(1, &vbo);
|
||||||
|
glGenBuffers(1, &ebo);
|
||||||
|
|
||||||
|
std::vector<glm::vec3> positions;
|
||||||
|
std::vector<glm::vec2> uv;
|
||||||
|
std::vector<glm::vec3> normals;
|
||||||
|
std::vector<unsigned int> indices;
|
||||||
|
|
||||||
|
const unsigned int X_SEGMENTS = 64;
|
||||||
|
const unsigned int Y_SEGMENTS = 64;
|
||||||
|
const float PI = 3.14159265359f;
|
||||||
|
for (unsigned int x = 0; x <= X_SEGMENTS; ++x) {
|
||||||
|
for (unsigned int y = 0; y <= Y_SEGMENTS; ++y) {
|
||||||
|
float xSegment = (float)x / (float)X_SEGMENTS;
|
||||||
|
float ySegment = (float)y / (float)Y_SEGMENTS;
|
||||||
|
float xPos = std::cos(xSegment * 2.0f * PI) * std::sin(ySegment * PI);
|
||||||
|
float yPos = std::cos(ySegment * PI);
|
||||||
|
float zPos = std::sin(xSegment * 2.0f * PI) * std::sin(ySegment * PI);
|
||||||
|
|
||||||
|
positions.push_back(glm::vec3(xPos, yPos, zPos));
|
||||||
|
uv.push_back(glm::vec2(xSegment, ySegment));
|
||||||
|
normals.push_back(glm::vec3(xPos, yPos, zPos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool oddRow = false;
|
||||||
|
for (unsigned int y = 0; y < Y_SEGMENTS; ++y)
|
||||||
|
{
|
||||||
|
if (!oddRow) // even rows: y == 0, y == 2; and so on
|
||||||
|
{
|
||||||
|
for (unsigned int x = 0; x <= X_SEGMENTS; ++x)
|
||||||
|
{
|
||||||
|
indices.push_back(y * (X_SEGMENTS + 1) + x);
|
||||||
|
indices.push_back((y + 1) * (X_SEGMENTS + 1) + x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int x = X_SEGMENTS; x >= 0; --x)
|
||||||
|
{
|
||||||
|
indices.push_back((y + 1) * (X_SEGMENTS + 1) + x);
|
||||||
|
indices.push_back(y * (X_SEGMENTS + 1) + x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
oddRow = !oddRow;
|
||||||
|
}
|
||||||
|
indexCount = static_cast<unsigned int>(indices.size());
|
||||||
|
|
||||||
|
std::vector<float> data;
|
||||||
|
for (unsigned int i = 0; i < positions.size(); ++i)
|
||||||
|
{
|
||||||
|
data.push_back(positions[i].x);
|
||||||
|
data.push_back(positions[i].y);
|
||||||
|
data.push_back(positions[i].z);
|
||||||
|
if (normals.size() > 0)
|
||||||
|
{
|
||||||
|
data.push_back(normals[i].x);
|
||||||
|
data.push_back(normals[i].y);
|
||||||
|
data.push_back(normals[i].z);
|
||||||
|
}
|
||||||
|
if (uv.size() > 0)
|
||||||
|
{
|
||||||
|
data.push_back(uv[i].x);
|
||||||
|
data.push_back(uv[i].y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
glBindVertexArray(sphereVAO);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(float), &data[0], GL_STATIC_DRAW);
|
||||||
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);
|
||||||
|
unsigned int stride = (3 + 2 + 3) * sizeof(float);
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, (void*)0);
|
||||||
|
glEnableVertexAttribArray(1);
|
||||||
|
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, stride, (void*)(3 * sizeof(float)));
|
||||||
|
glEnableVertexAttribArray(2);
|
||||||
|
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, stride, (void*)(6 * sizeof(float)));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindVertexArray(sphereVAO);
|
||||||
|
glDrawElements(GL_TRIANGLE_STRIP, indexCount, GL_UNSIGNED_INT, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Renderer::Render(Scene& scene)
|
void Renderer::Render(Scene& scene)
|
||||||
{
|
{
|
||||||
static RenderPass currentPass = RenderPass::SKYBOX;
|
|
||||||
|
|
||||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
|
||||||
|
|
||||||
@ -105,7 +222,7 @@ void Renderer::Render(Scene& scene)
|
|||||||
auto view = scene.MainCamera.GetViewMatrix();
|
auto view = scene.MainCamera.GetViewMatrix();
|
||||||
auto model = glm::mat4(1.0f);
|
auto model = glm::mat4(1.0f);
|
||||||
|
|
||||||
std::cout << "SKYBOX PASS!" << std::endl;
|
// Skybox
|
||||||
glDepthMask(GL_FALSE);
|
glDepthMask(GL_FALSE);
|
||||||
Shader shader = shaders.at(static_cast<int>(RenderPass::SKYBOX));
|
Shader shader = shaders.at(static_cast<int>(RenderPass::SKYBOX));
|
||||||
|
|
||||||
@ -124,7 +241,7 @@ void Renderer::Render(Scene& scene)
|
|||||||
glDepthMask(GL_TRUE);
|
glDepthMask(GL_TRUE);
|
||||||
|
|
||||||
|
|
||||||
std::cout << "DEFAULT PASS!" << std::endl;
|
// Phong lighting
|
||||||
shader = shaders.at(static_cast<int>(RenderPass::DEFAULT));
|
shader = shaders.at(static_cast<int>(RenderPass::DEFAULT));
|
||||||
|
|
||||||
shader.use();
|
shader.use();
|
||||||
@ -135,7 +252,7 @@ void Renderer::Render(Scene& scene)
|
|||||||
scene.skybox.Bind();
|
scene.skybox.Bind();
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
|
||||||
|
model = glm::translate(model, glm::vec3(20.0f, 0.0f, 0.0f));
|
||||||
shader.setMat4("model", model);
|
shader.setMat4("model", model);
|
||||||
shader.setMat4("view", view);
|
shader.setMat4("view", view);
|
||||||
shader.setMat4("projection", projection);
|
shader.setMat4("projection", projection);
|
||||||
@ -143,6 +260,59 @@ void Renderer::Render(Scene& scene)
|
|||||||
entity.Draw(shader);
|
entity.Draw(shader);
|
||||||
}
|
}
|
||||||
scene.skybox.Unbind();
|
scene.skybox.Unbind();
|
||||||
|
|
||||||
|
|
||||||
|
// PBR
|
||||||
|
shader = shaders.at(static_cast<int>(RenderPass::PBR));
|
||||||
|
|
||||||
|
shader.use();
|
||||||
|
shader.setVec3("albedo", glm::vec3(0.5f, 0.0f, 0.0f));
|
||||||
|
shader.setFloat("ao", 1.0f);
|
||||||
|
shader.setMat4("projection", projection);
|
||||||
|
view = scene.MainCamera.GetViewMatrix();
|
||||||
|
shader.setMat4("view", view);
|
||||||
|
shader.setVec3("camPos", scene.MainCamera.Position);
|
||||||
|
|
||||||
|
model = glm::mat4(1.0f);
|
||||||
|
for (int row = 0; row < nrRows; ++row) {
|
||||||
|
shader.setFloat("metallic", (float)row / (float)nrRows);
|
||||||
|
for (int col = 0; col < nrColumns; ++col) {
|
||||||
|
|
||||||
|
shader.setFloat("roughness", glm::clamp((float)col / (float)nrColumns, 0.05f, 1.0f));
|
||||||
|
|
||||||
|
model = glm::mat4(1.0f);
|
||||||
|
model = glm::translate(model, glm::vec3(
|
||||||
|
(col - (nrColumns / 2)) * spacing,
|
||||||
|
(row - (nrRows / 2)) * spacing,
|
||||||
|
0.0f
|
||||||
|
));
|
||||||
|
|
||||||
|
shader.setMat4("model", model);
|
||||||
|
shader.setMat3("normalMatrix", glm::transpose(glm::inverse(glm::mat3(model))));
|
||||||
|
renderSphere();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render light source
|
||||||
|
for (unsigned int i = 0; i < sizeof(lightPositions) / sizeof(lightPositions[0]); ++i) {
|
||||||
|
glm::vec3 newPos = lightPositions[i] + glm::vec3(sin(glfwGetTime() * 5.0) * 5.0, 0.0, 0.0);
|
||||||
|
newPos = lightPositions[i];
|
||||||
|
shader.setVec3("lightPositions[" + std::to_string(i)+"]", newPos);
|
||||||
|
shader.setVec3("lightColors[" + std::to_string(i) + "]", lightColors[i]);
|
||||||
|
|
||||||
|
model = glm::mat4(1.0f);
|
||||||
|
model = glm::translate(model, newPos);
|
||||||
|
model = glm::scale(model, glm::vec3(0.5f));
|
||||||
|
shader.setMat4("model", model);
|
||||||
|
shader.setMat3("normalMatrix", glm::transpose(glm::inverse(glm::mat3(model))));
|
||||||
|
|
||||||
|
renderSphere();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Shader OutlineShader;
|
Shader OutlineShader;
|
||||||
|
@ -53,6 +53,8 @@ public:
|
|||||||
scene.MainCamera = Camera(glm::vec3(0.0f, 0.0f, 8.0f));
|
scene.MainCamera = Camera(glm::vec3(0.0f, 0.0f, 8.0f));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
std::vector<std::string> faces = {
|
std::vector<std::string> faces = {
|
||||||
"../Textures/skybox/right.jpg",
|
"../Textures/skybox/right.jpg",
|
||||||
"../Textures/skybox/left.jpg",
|
"../Textures/skybox/left.jpg",
|
||||||
@ -67,7 +69,8 @@ public:
|
|||||||
renderer.resize(WIDTH, HEIGHT);
|
renderer.resize(WIDTH, HEIGHT);
|
||||||
renderer.Setup();
|
renderer.Setup();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
//glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||||
while(!window.shouldClose())
|
while(!window.shouldClose())
|
||||||
|
Loading…
Reference in New Issue
Block a user