Specular BDRF
parent
ae516a8007
commit
e4587f7c82
Binary file not shown.
|
@ -0,0 +1,111 @@
|
|||
#version 460 core
|
||||
out vec2 FragColor;
|
||||
in vec2 TexCoords;
|
||||
|
||||
|
||||
const float PI = 3.14159265359;
|
||||
|
||||
|
||||
// http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html
|
||||
// efficient VanDerCorpus calculation.
|
||||
float RadicalInverse_VdC(uint bits)
|
||||
{
|
||||
bits = (bits << 16u) | (bits >> 16u);
|
||||
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
|
||||
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
|
||||
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
|
||||
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
|
||||
return float(bits) * 2.3283064365386963e-10; // / 0x100000000
|
||||
}
|
||||
|
||||
vec2 Hammersley(uint i, uint N)
|
||||
{
|
||||
return vec2(float(i)/float(N), RadicalInverse_VdC(i));
|
||||
}
|
||||
|
||||
float GeometrySchlickGGX(float NdotV, float roughness)
|
||||
{
|
||||
float a = roughness;
|
||||
float k = (a * a) / 2.0;
|
||||
|
||||
float nom = NdotV;
|
||||
float denom = NdotV * (1.0 - k) + k;
|
||||
|
||||
return nom / denom;
|
||||
}
|
||||
|
||||
vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness){
|
||||
float a = roughness*roughness;
|
||||
|
||||
float phi = 2.0 * PI * Xi.x;
|
||||
float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y));
|
||||
float sinTheta = sqrt(1.0 - cosTheta*cosTheta);
|
||||
|
||||
// Spherical to cartesian
|
||||
vec3 H;
|
||||
H.x = cos(phi) * sinTheta;
|
||||
H.y = sin(phi) * sinTheta;
|
||||
H.z = cosTheta;
|
||||
|
||||
// tangent space to world sample vector
|
||||
vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
|
||||
vec3 tangent = normalize(cross(up,N));
|
||||
vec3 bitangent = cross(N, tangent);
|
||||
vec3 sampleVec = tangent * H.x + bitangent * H.y + N * H.z;
|
||||
|
||||
return normalize(sampleVec);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
vec2 IntegrateBRDF (float NdotV, float roughness){
|
||||
|
||||
vec3 V;
|
||||
V.x = sqrt(1.0 - NdotV * NdotV);
|
||||
V.y = 0.0;
|
||||
V.z = NdotV;
|
||||
|
||||
float A = 0.0;
|
||||
float B = 0.0;
|
||||
|
||||
vec3 N = vec3(0.0,0.0,1.0);
|
||||
|
||||
const uint SAMPLE_COUNT = 1024u;
|
||||
for(uint i = 0u; i < SAMPLE_COUNT; ++i){
|
||||
vec2 Xi = Hammersley(i, SAMPLE_COUNT);
|
||||
vec3 H = ImportanceSampleGGX(Xi, N, roughness);
|
||||
vec3 L = normalize(2.0 * dot(V, H) * H - V);
|
||||
|
||||
float NdotL = max(L.z, 0.0);
|
||||
float NdotH = max(H.z, 0.0);
|
||||
float VdotH = max(dot(V, H), 0.0);
|
||||
|
||||
if(NdotL > 0.0)
|
||||
{
|
||||
float G = GeometrySmith(N, V, L, roughness);
|
||||
float G_Vis = (G * VdotH) / (NdotH * NdotV);
|
||||
float Fc = pow(1.0 - VdotH, 5.0);
|
||||
|
||||
A += (1.0 - Fc) * G_Vis;
|
||||
B += Fc * G_Vis;
|
||||
}
|
||||
}
|
||||
A /= float(SAMPLE_COUNT);
|
||||
B /= float(SAMPLE_COUNT);
|
||||
return vec2(A, B);
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec2 integratedBRDF = IntegrateBRDF(TexCoords.x, TexCoords.y);
|
||||
FragColor = integratedBRDF;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
#version 460 core
|
||||
layout (location = 0) in vec3 aPos;
|
||||
layout (location = 1) in vec2 aTexCoords;
|
||||
|
||||
out vec2 TexCoords;
|
||||
|
||||
void main(){
|
||||
TexCoords = aTexCoords;
|
||||
gl_Position = vec4(aPos, 1.0);
|
||||
}
|
|
@ -7,7 +7,6 @@ uniform samplerCube environmentMap;
|
|||
|
||||
void main(){
|
||||
vec3 envColor = texture(environmentMap, localPos).rgb;
|
||||
|
||||
envColor = envColor /(envColor + vec3(1.0));
|
||||
envColor = pow(envColor, vec3(1.0/2.2));
|
||||
|
||||
|
|
|
@ -12,9 +12,12 @@ uniform sampler2D metallicMap;
|
|||
uniform sampler2D normalMap;
|
||||
uniform sampler2D roughnessMap;
|
||||
uniform sampler2D aoMap;
|
||||
uniform samplerCube irradianceMap;
|
||||
|
||||
|
||||
uniform samplerCube irradianceMap;
|
||||
uniform samplerCube prefilterMap;
|
||||
uniform sampler2D brdfLUT;
|
||||
|
||||
uniform vec3 lightPositions[4];
|
||||
uniform vec3 lightColors[4];
|
||||
|
||||
|
@ -78,6 +81,8 @@ vec3 getNormalFromNormalMap(){
|
|||
return normalize(TBN * tangentNormal);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void main(){
|
||||
|
||||
vec3 albedo = pow(texture(albedoMap, TexCoords).rgb, vec3(2.2));
|
||||
|
@ -88,7 +93,9 @@ void main(){
|
|||
|
||||
vec3 N = getNormalFromNormalMap();
|
||||
vec3 V = normalize(camPos - WorldPos);
|
||||
|
||||
vec3 R = reflect(-V, N);
|
||||
|
||||
|
||||
vec3 F0 = vec3(0.04);
|
||||
F0 = mix(F0, albedo, metallic);
|
||||
|
||||
|
@ -128,7 +135,15 @@ void main(){
|
|||
kD *= 1.0 - metallic;
|
||||
vec3 irradiance = texture(irradianceMap, N).rgb;
|
||||
vec3 diffuse = irradiance* albedo;
|
||||
vec3 ambient = (kD * diffuse) * ao;
|
||||
|
||||
const float MAX_REFLECTION_LOD = 4.0;
|
||||
vec3 prefilterColor = textureLod(prefilterMap, R, roughness * MAX_REFLECTION_LOD).rgb;
|
||||
vec2 envBRDF = texture(brdfLUT, vec2(max(dot(N,V), 0.0), roughness)).rg;
|
||||
vec3 specular = prefilterColor * (kS * envBRDF.x + envBRDF.y);
|
||||
|
||||
|
||||
|
||||
vec3 ambient = (kD * diffuse + specular) * ao;
|
||||
vec3 color = ambient + Lo;
|
||||
|
||||
// HDR tonemapping
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
#version 460 core
|
||||
out vec4 FragColor;
|
||||
in vec3 localPos;
|
||||
|
||||
uniform samplerCube environmentMap;
|
||||
uniform float roughness;
|
||||
|
||||
const float PI = 3.14159265359;
|
||||
|
||||
vec3 ImportanceSampleGGX(vec2 Xi, vec3 N, float roughness){
|
||||
float a = roughness*roughness;
|
||||
|
||||
float phi = 2.0 * PI * Xi.x;
|
||||
float cosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y));
|
||||
float sinTheta = sqrt(1.0 - cosTheta*cosTheta);
|
||||
|
||||
// Spherical to cartesian
|
||||
vec3 H;
|
||||
H.x = cos(phi) * sinTheta;
|
||||
H.y = sin(phi) * sinTheta;
|
||||
H.z = cosTheta;
|
||||
|
||||
// tangent space to world sample vector
|
||||
vec3 up = abs(N.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0);
|
||||
vec3 tangent = normalize(cross(up,N));
|
||||
vec3 bitangent = cross(N, tangent);
|
||||
vec3 sampleVec = tangent * H.x + bitangent * H.y + N * H.z;
|
||||
|
||||
return normalize(sampleVec);
|
||||
}
|
||||
|
||||
|
||||
// Generate Van Der Corput sequence
|
||||
float RadicalInverse_VdC(uint bits){
|
||||
bits = (bits << 16u) | (bits >> 16u);
|
||||
bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
|
||||
bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
|
||||
bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
|
||||
bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
|
||||
return float(bits) * 2.3283064365386963e-10; // / 0x100000000
|
||||
}
|
||||
|
||||
vec2 Hammersley(uint i, uint N){
|
||||
return vec2(float(i)/float(N), RadicalInverse_VdC(i));
|
||||
}
|
||||
|
||||
void main(){
|
||||
vec3 N = normalize(localPos);
|
||||
vec3 R = N;
|
||||
vec3 V = R;
|
||||
|
||||
const uint SAMPLE_COUNT = 1024u;
|
||||
float totalWeight = 0.0;
|
||||
vec3 prefilteredColor = vec3(0.0);
|
||||
for(uint i = 0u; i < SAMPLE_COUNT; ++i)
|
||||
{
|
||||
vec2 Xi = Hammersley(i, SAMPLE_COUNT);
|
||||
vec3 H = ImportanceSampleGGX(Xi, N, roughness);
|
||||
vec3 L = normalize(2.0 * dot(V,H) * H - V );
|
||||
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
if(NdotL > 0.0){
|
||||
prefilteredColor += texture(environmentMap, L).rgb * NdotL;
|
||||
totalWeight += NdotL;
|
||||
}
|
||||
}
|
||||
|
||||
prefilteredColor = prefilteredColor / totalWeight;
|
||||
|
||||
FragColor = vec4(prefilteredColor, 1.0);
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -119,12 +119,45 @@ void renderCube() {
|
|||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
unsigned int quadVAO = 0;
|
||||
unsigned int quadVBO;
|
||||
void renderQuad()
|
||||
{
|
||||
if (quadVAO == 0)
|
||||
{
|
||||
float quadVertices[] = {
|
||||
// positions // texture Coords
|
||||
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
|
||||
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
|
||||
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
|
||||
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
|
||||
};
|
||||
// setup plane VAO
|
||||
glGenVertexArrays(1, &quadVAO);
|
||||
glGenBuffers(1, &quadVBO);
|
||||
glBindVertexArray(quadVAO);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW);
|
||||
glEnableVertexAttribArray(0);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)0);
|
||||
glEnableVertexAttribArray(1);
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3 * sizeof(float)));
|
||||
}
|
||||
glBindVertexArray(quadVAO);
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
glBindVertexArray(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned int brdfLUTTexture;
|
||||
unsigned int prefilterMap;
|
||||
unsigned int irradianceMap;
|
||||
unsigned int envCubemap;
|
||||
unsigned int envMapVAO;
|
||||
void Renderer::Setup()
|
||||
{
|
||||
glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
|
||||
// Create ScreenVAO
|
||||
glGenVertexArrays(1, &ScreenVAO);
|
||||
glBindVertexArray(ScreenVAO);
|
||||
|
@ -158,11 +191,11 @@ void Renderer::Setup()
|
|||
shaders[static_cast<int>(RenderPass::PBR)].Load("../Shaders/pbr.vs", "../Shaders/pbr.fs");
|
||||
|
||||
|
||||
albedo = TextureFromFile("../Textures/rusted_iron/albedo.png", ".");
|
||||
normal = TextureFromFile("../Textures/rusted_iron/normal.png", ".");
|
||||
metallic = TextureFromFile("../Textures/rusted_iron/metallic.png", ".");
|
||||
roughness = TextureFromFile("../Textures/rusted_iron/roughness.png", ".");
|
||||
ao = TextureFromFile("../Textures/rusted_iron/ao.png",".");
|
||||
albedo = TextureFromFile("../Textures/space-cruiser/albedo.png", ".");
|
||||
normal = TextureFromFile("../Textures/space-cruiser/normal.png", ".");
|
||||
metallic = TextureFromFile("../Textures/space-cruiser/metallic.png", ".");
|
||||
roughness = TextureFromFile("../Textures/space-cruiser/roughness.png", ".");
|
||||
ao = TextureFromFile("../Textures/space-cruiser/ao.png",".");
|
||||
|
||||
|
||||
// Create the skybox from an HDR equirectangular environment map
|
||||
|
@ -199,7 +232,7 @@ void Renderer::Setup()
|
|||
auto eqShader = Shader();
|
||||
eqShader.Load("../Shaders/HDRMap.vs", "../Shaders/HDRMap.fs");
|
||||
|
||||
auto hdrTexture = LoadIBL("../Textures/photostudio.hdr");
|
||||
auto hdrTexture = LoadIBL("../Textures/night_2k.hdr");
|
||||
|
||||
eqShader.use();
|
||||
eqShader.setInt("equirectangularMap", 0);
|
||||
|
@ -319,6 +352,71 @@ void Renderer::Setup()
|
|||
|
||||
glBindVertexArray(0);
|
||||
|
||||
glGenTextures(1, &prefilterMap);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, prefilterMap);
|
||||
for (unsigned int i = 0; i < 6; ++i) {
|
||||
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, 128, 128, 0, GL_RGB, GL_FLOAT, nullptr);
|
||||
}
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
|
||||
|
||||
auto prefilterShader = Shader();
|
||||
prefilterShader.Load("../Shaders/skybox2.vs", "../Shaders/prefilter.fs");
|
||||
prefilterShader.setInt("environmentMap", 0);
|
||||
prefilterShader.setMat4("projection", captureProjection);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, envCubemap);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, captureFBO);
|
||||
unsigned int maxMipLevels = 5;
|
||||
for (unsigned int mip = 0; mip < maxMipLevels; ++mip) {
|
||||
unsigned int mipWidth = 128 * std::pow(0.5, mip);
|
||||
unsigned int mipHeight = 128 * std::pow(0.5, mip);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, captureRBO);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, mipWidth, mipHeight);
|
||||
glViewport(0, 0, mipWidth, mipHeight);
|
||||
|
||||
float roughness = (float)mip / (float)(maxMipLevels - 1);
|
||||
prefilterShader.setFloat("roughness", roughness);
|
||||
for (unsigned int i = 0; i < 6; ++i) {
|
||||
prefilterShader.setMat4("view", captureViews[i]);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, prefilterMap, mip);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
renderCube();
|
||||
}
|
||||
}
|
||||
|
||||
glGenTextures(1, &brdfLUTTexture);
|
||||
|
||||
// Pre-allocate enough memory for the LUT texture
|
||||
glBindTexture(GL_TEXTURE_2D, brdfLUTTexture);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RG16F, 512, 512, 0, GL_RG, GL_FLOAT, 0);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, captureFBO);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, captureRBO);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, 512, 512);
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, brdfLUTTexture, 0);
|
||||
|
||||
glViewport(0, 0, 512, 512);
|
||||
auto brdfShader = Shader();
|
||||
brdfShader.Load("../Shaders/BRDFIntegration.vs", "../Shaders/BRDFIntegration.fs");
|
||||
|
||||
brdfShader.use();
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
renderQuad();
|
||||
|
||||
glViewport(0, 0, 800, 600); // reset viewport
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -540,6 +638,9 @@ void Renderer::Render(Scene& scene)
|
|||
shader.setInt("roughnessMap", 3);
|
||||
shader.setInt("aoMap", 4);
|
||||
shader.setInt("irradianceMap", 5);
|
||||
shader.setInt("prefilterMap", 6);
|
||||
shader.setInt("brdfLUT", 7);
|
||||
|
||||
|
||||
shader.setMat4("projection", projection);
|
||||
view = scene.MainCamera.GetViewMatrix();
|
||||
|
@ -564,6 +665,12 @@ void Renderer::Render(Scene& scene)
|
|||
glActiveTexture(GL_TEXTURE5);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, irradianceMap);
|
||||
|
||||
glActiveTexture(GL_TEXTURE6);
|
||||
glBindTexture(GL_TEXTURE_CUBE_MAP, prefilterMap);
|
||||
|
||||
glActiveTexture(GL_TEXTURE7);
|
||||
glBindTexture(GL_TEXTURE_2D, brdfLUTTexture);
|
||||
|
||||
|
||||
// Render Spheres
|
||||
model = glm::mat4(1.0f);
|
||||
|
@ -626,16 +733,10 @@ void Renderer::Render(Scene& scene)
|
|||
entity.Draw(OutlineShader);
|
||||
}
|
||||
|
||||
glStencilFunc(GL_ALWAYS, 1, 0xFF);
|
||||
glStencilMask(0xFF);
|
||||
glStencilFunc(GL_ALWAYS, 1, 0xFF);
|
||||
glStencilMask(0xFF);
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
// 4. draw result to screen
|
||||
|
|
Loading…
Reference in New Issue