修复了计算BrdfLut的错误

dev-VirtualTexture
wuyize 2023-02-13 23:14:45 +08:00
parent 2a78bb4be8
commit ef88c4a39e
8 changed files with 156 additions and 132 deletions

View File

@ -110,7 +110,7 @@ vec2 IntegrateBRDF(float NdotV, float roughness)
void main() void main()
{ {
uvec2 pixelLocation = gl_GlobalInvocationID.xy; uvec2 pixelLocation = gl_GlobalInvocationID.xy;
vec2 texCoords = vec2(pixelLocation)/vec2(imageSize(brdfLUT)); vec2 texCoords = (vec2(pixelLocation)+vec2(0.5))/vec2(imageSize(brdfLUT));
vec2 integratedBRDF = IntegrateBRDF(texCoords.x, texCoords.y); vec2 integratedBRDF = IntegrateBRDF(texCoords.x, texCoords.y);
imageStore(brdfLUT, ivec2(pixelLocation), vec4(integratedBRDF,0,0)); imageStore(brdfLUT, ivec2(pixelLocation), vec4(integratedBRDF,0,0));
} }

View File

@ -36,7 +36,6 @@ vec3 getNormalFromMap()
void main() void main()
{ {
//gBaseColor = vec4(1,0,0,1);
gBaseColor = texture(texture_basecolor, TexCoords); gBaseColor = texture(texture_basecolor, TexCoords);
if(gBaseColor.a<0.4) if(gBaseColor.a<0.4)
discard; discard;

View File

@ -1,133 +1,25 @@
#version 330 core #version 450 core
layout (location = 0) out vec4 gBaseColor;
layout (location = 1) out vec3 gNormal;
layout (location = 2) out vec3 gPosition;
layout (location = 3) out vec2 gMetallicRoughness;
layout (location = 4) out uint gPaintingIndex;
uniform sampler2D texture_basecolor;
uniform sampler2D texture_metallic_roughness;
uniform sampler2D texture_normal;
out vec4 FragColor;
in vec2 TexCoords; in vec2 TexCoords;
in vec3 WorldPos; in vec3 WorldPos;
in vec3 Normal; in vec3 Normal;
// lights // material parameters
uniform vec3 lightPositions[4]; uniform vec3 albedo;
uniform vec3 lightColors[4]; uniform float metallic;
uniform float roughness;
uniform vec3 camPos;
const float PI = 3.14159265359;
vec3 getNormalFromMap()
{
vec3 tangentNormal = texture(texture_normal, TexCoords).xyz * 2.0 - 1.0;
vec3 Q1 = dFdx(WorldPos);
vec3 Q2 = dFdy(WorldPos);
vec2 st1 = dFdx(TexCoords);
vec2 st2 = dFdy(TexCoords);
vec3 N = normalize(Normal);
vec3 T = normalize(Q1*st2.t - Q2*st1.t);
vec3 B = -normalize(cross(N, T));
mat3 TBN = mat3(T, B, N);
return normalize(TBN * tangentNormal);
}
// ----------------------------------------------------------------------------
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 nom = a2;
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
denom = PI * denom * denom;
return nom / denom;
}
// ----------------------------------------------------------------------------
float GeometrySchlickGGX(float NdotV, float roughness)
{
float r = (roughness + 1.0);
float k = (r*r) / 8.0;
float nom = NdotV;
float denom = NdotV * (1.0 - k) + k;
return nom / 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;
}
// ----------------------------------------------------------------------------
vec3 fresnelSchlick(float cosTheta, vec3 F0)
{
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
}
void main() void main()
{ {
vec4 baseColor = texture(texture_basecolor, TexCoords); gBaseColor = vec4(albedo, 1);
if(baseColor.a<0.4) gPosition = WorldPos;
discard; gNormal = normalize(Normal);
gMetallicRoughness = vec2(metallic,roughness);
vec3 albedo = pow(baseColor.rgb, vec3(2.2)); gPaintingIndex = 0;
float metallic = texture(texture_metallic_roughness, TexCoords).b;
float roughness = texture(texture_metallic_roughness, TexCoords).g;
vec3 N = getNormalFromMap();
vec3 V = normalize(camPos - WorldPos);
vec3 F0 = vec3(0.04);
F0 = mix(F0, albedo, metallic);
// reflectance equation
vec3 Lo = vec3(0.0);
for(int i = 0; i < 1; ++i)
{
// calculate per-light radiance
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;
// cook-torrance brdf
float NDF = DistributionGGX(N, H, roughness);
float G = GeometrySmith(N, V, L, roughness);
vec3 F = fresnelSchlick(max(dot(H, V), 0.0), F0);
F = clamp(F,vec3(0),vec3(1));
vec3 kS = F;
vec3 kD = vec3(1.0) - kS;
kD *= 1.0 - metallic;
vec3 nominator = NDF * G * F;
float denominator = 4.0 * max(dot(N, V), 0.0) * max(dot(N, L), 0.0) + 0.001;
vec3 specular = nominator / denominator;
// add to outgoing radiance Lo
float NdotL = max(dot(N, L), 0.0);
Lo += (kD * albedo / PI + specular) * radiance * NdotL;
}
vec3 ambient = vec3(0.03) * albedo;
vec3 color = ambient + Lo;
color = color / (color + vec3(1.0));
color = pow(color, vec3(1.0/2.2));
FragColor = vec4(color, 1.0);
} }

View File

@ -78,7 +78,7 @@ vec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness)
vec3 ambientLighting(vec3 N, vec3 V, vec3 F0, vec3 albedo, float metallic, float roughness, float ao) vec3 ambientLighting(vec3 N, vec3 V, vec3 F0, vec3 albedo, float metallic, float roughness, float ao)
{ {
// ambient lighting (we now use IBL as the ambient term) // ambient lighting (we now use IBL as the ambient term)
vec3 F = fresnelSchlickRoughness(max(dot(N, V), 0.0), F0, roughness); vec3 F = fresnelSchlickRoughness(clamp(dot(N, V),0.,1.), F0, roughness);
vec3 kS = F; vec3 kS = F;
vec3 kD = 1.0 - kS; vec3 kD = 1.0 - kS;
@ -91,7 +91,7 @@ vec3 ambientLighting(vec3 N, vec3 V, vec3 F0, vec3 albedo,float metallic, float
const float MAX_REFLECTION_LOD = 4.0; const float MAX_REFLECTION_LOD = 4.0;
vec3 R = reflect(-V, N); vec3 R = reflect(-V, N);
vec3 prefilteredColor = textureLod(prefilterMap, R, roughness * MAX_REFLECTION_LOD).rgb; vec3 prefilteredColor = textureLod(prefilterMap, R, roughness * MAX_REFLECTION_LOD).rgb;
vec2 brdf = texture(brdfLUT, vec2(max(dot(N, V), 0.0), roughness)).rg; vec2 brdf = texture(brdfLUT, vec2(clamp(dot(N, V),0.,1.), roughness)).rg;
vec3 specular = prefilteredColor * (F * brdf.x + brdf.y); vec3 specular = prefilteredColor * (F * brdf.x + brdf.y);
return (kD * diffuse + specular) * ao; return (kD * diffuse + specular) * ao;
@ -200,7 +200,7 @@ void main()
imageStore(gBaseColor, pixelLocation, vec4(0)); imageStore(gBaseColor, pixelLocation, vec4(0));
return; return;
} }
normal = normalize(normal);
vec3 V = normalize(camPos - worldPos); vec3 V = normalize(camPos - worldPos);

View File

@ -2,6 +2,7 @@
#include <QOpenGLShaderProgram> #include <QOpenGLShaderProgram>
#include <QDebug> #include <QDebug>
#include <array> #include <array>
#include <glm/glm.hpp>
#define STB_IMAGE_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h> #include <stb_image.h>
@ -77,6 +78,101 @@ void Renderer::IblUtils::renderCube(QOpenGLFunctions_4_5_Core* glFunc)
glFunc->glBindVertexArray(0); glFunc->glBindVertexArray(0);
} }
void Renderer::IblUtils::renderSphere(QOpenGLFunctions_4_5_Core* glFunc)
{
static unsigned int sphereVAO = 0;
static unsigned int indexCount;
if (sphereVAO == 0)
{
glFunc->glGenVertexArrays(1, &sphereVAO);
unsigned int vbo, ebo;
glFunc->glGenBuffers(1, &vbo);
glFunc->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);
}
}
glFunc->glBindVertexArray(sphereVAO);
glFunc->glBindBuffer(GL_ARRAY_BUFFER, vbo);
glFunc->glBufferData(GL_ARRAY_BUFFER, data.size() * sizeof(float), &data[0], GL_STATIC_DRAW);
glFunc->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glFunc->glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), &indices[0], GL_STATIC_DRAW);
unsigned int stride = (3 + 2 + 3) * sizeof(float);
glFunc->glEnableVertexAttribArray(0);
glFunc->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, (void*)0);
glFunc->glEnableVertexAttribArray(1);
glFunc->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, stride, (void*)(3 * sizeof(float)));
glFunc->glEnableVertexAttribArray(2);
glFunc->glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, stride, (void*)(6 * sizeof(float)));
}
glFunc->glBindVertexArray(sphereVAO);
glFunc->glDrawElements(GL_TRIANGLE_STRIP, indexCount, GL_UNSIGNED_INT, 0);
}
std::tuple<GLuint, GLuint, GLuint, GLuint> Renderer::IblUtils::precomputeCubemaps(QOpenGLFunctions_4_5_Core* glFunc) std::tuple<GLuint, GLuint, GLuint, GLuint> Renderer::IblUtils::precomputeCubemaps(QOpenGLFunctions_4_5_Core* glFunc)
{ {
// pbr: setup framebuffer // pbr: setup framebuffer

View File

@ -8,10 +8,13 @@ namespace Renderer
public: public:
static constexpr int cubemapSize = 1024; static constexpr int cubemapSize = 1024;
static void renderCube(QOpenGLFunctions_4_5_Core* glFunc); static void renderCube(QOpenGLFunctions_4_5_Core* glFunc);
static void renderSphere(QOpenGLFunctions_4_5_Core* glFunc);
/** /**
* @brief * @brief
* @return GLuint envCubemap * @return GLuint envCubemap
* @return GLuint irradianceMap * @return GLuint irradianceMap
* @return GLuint prefilterMap
* @return GLuint brdfLut
*/ */
static std::tuple<GLuint, GLuint, GLuint, GLuint> precomputeCubemaps(QOpenGLFunctions_4_5_Core* glFunc); static std::tuple<GLuint, GLuint, GLuint, GLuint> precomputeCubemaps(QOpenGLFunctions_4_5_Core* glFunc);
private: private:

View File

@ -121,6 +121,14 @@ void RendererGLWidget::initializeGL()
if (!shadowProgramPtr->link()) if (!shadowProgramPtr->link())
qDebug() << "ERROR:" << shadowProgramPtr->log(); qDebug() << "ERROR:" << shadowProgramPtr->log();
plainProgramPtr = new QOpenGLShaderProgram;
if (!plainProgramPtr->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/shader.vert"))
qDebug() << "ERROR:" << plainProgramPtr->log();
if (!plainProgramPtr->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/Shaders/shader.frag"))
qDebug() << "ERROR:" << plainProgramPtr->log();
if (!plainProgramPtr->link())
qDebug() << "ERROR:" << plainProgramPtr->log();
modelProgramPtr = new QOpenGLShaderProgram; modelProgramPtr = new QOpenGLShaderProgram;
if (!modelProgramPtr->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/model.vert")) if (!modelProgramPtr->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/model.vert"))
qDebug() << "ERROR:" << modelProgramPtr->log(); qDebug() << "ERROR:" << modelProgramPtr->log();
@ -303,6 +311,31 @@ void RendererGLWidget::paintGL()
if (model != nullptr) if (model != nullptr)
model->draw(); model->draw();
plainProgramPtr->bind();
plainProgramPtr->setUniformValue("projection", projection);
plainProgramPtr->setUniformValue("view", view);
plainProgramPtr->setUniformValue("albedo", 0.5f, 0.5f, 0.5f);
QMatrix4x4 model;
int nrRows = 7, nrColumns = 7;
float spacing = 2.5;
for (int row = 0; row < nrRows; ++row)
{
plainProgramPtr->setUniformValue("metallic", (float)row / (float)nrRows);
for (int col = 0; col < nrColumns; ++col)
{
plainProgramPtr->setUniformValue("roughness", glm::clamp((float)col / (float)nrColumns, 0.05f, 1.0f));
model.setToIdentity();
model.scale(10);
model.translate(QVector3D((float)(col - (nrColumns / 2)) * spacing,
(float)(row - (nrRows / 2)) * spacing+20,
-2.0f));
plainProgramPtr->setUniformValue("model", model);
IblUtils::renderSphere(glFunc);
}
}
plainProgramPtr->release();
fboPtr->release(); fboPtr->release();
} }

View File

@ -51,6 +51,7 @@ namespace Renderer
float exposure = 0.8; float exposure = 0.8;
QOpenGLShaderProgram* shadowProgramPtr = nullptr; QOpenGLShaderProgram* shadowProgramPtr = nullptr;
QOpenGLShaderProgram* plainProgramPtr = nullptr;
QOpenGLShaderProgram* modelProgramPtr = nullptr; QOpenGLShaderProgram* modelProgramPtr = nullptr;
QOpenGLShaderProgram* paintingProgramPtr = nullptr; QOpenGLShaderProgram* paintingProgramPtr = nullptr;
QOpenGLShaderProgram* paintingCompProgramPtr = nullptr; QOpenGLShaderProgram* paintingCompProgramPtr = nullptr;