实现PCF Shadow Map

dev-VirtualTexture
wuyize 2022-08-18 13:22:45 +08:00
parent 762fb474e5
commit 0efd3b1dbc
18 changed files with 408 additions and 123 deletions

View File

@ -106,6 +106,8 @@
<None Include="Shaders\final.vert" />
<None Include="Shaders\model.frag" />
<None Include="Shaders\model.vert" />
<None Include="Shaders\model_shadow.frag" />
<None Include="Shaders\model_shadow.vert" />
<None Include="Shaders\painting.comp" />
<None Include="Shaders\painting.frag" />
<None Include="Shaders\painting.vert" />

View File

@ -98,6 +98,12 @@
<None Include="Shaders\painting.comp">
<Filter>Resource Files\Shaders</Filter>
</None>
<None Include="Shaders\model_shadow.frag">
<Filter>Resource Files\Shaders</Filter>
</None>
<None Include="Shaders\model_shadow.vert">
<Filter>Resource Files\Shaders</Filter>
</None>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Camera.h">

View File

@ -3,5 +3,6 @@ class Drawable
{
public:
virtual void draw() = 0;
virtual void drawShadow() = 0;
};

View File

@ -10,5 +10,7 @@
<file>Shaders/painting.frag</file>
<file>Shaders/painting.vert</file>
<file>Shaders/painting.comp</file>
<file>Shaders/model_shadow.frag</file>
<file>Shaders/model_shadow.vert</file>
</qresource>
</RCC>

View File

@ -1,8 +1,9 @@
#include "Mesh.h"
Mesh::Mesh(QOpenGLFunctions_4_5_Compatibility* glFunc, QOpenGLShaderProgram* shaderProgram, aiMatrix4x4 model)
Mesh::Mesh(QOpenGLFunctions_4_5_Compatibility* glFunc, QOpenGLShaderProgram* shaderProgram, QOpenGLShaderProgram* shadowProgram, aiMatrix4x4 model)
: glFunc(glFunc)
, shaderProgram(shaderProgram)
, shadowProgram(shadowProgram)
, VBO(QOpenGLBuffer::VertexBuffer)
, EBO(QOpenGLBuffer::IndexBuffer)
, model((float*)&model)
@ -26,8 +27,6 @@ void Mesh::draw()
for (unsigned int i = 0; i < textures.size(); i++)
{
glFunc->glActiveTexture(GL_TEXTURE0 + i); // 在绑定之前激活相应的纹理单元
textures[i]->texture.bind();
//qDebug() << name + number;
shaderProgram->setUniformValue(textures[i]->type.toStdString().c_str(), i);
@ -40,6 +39,30 @@ void Mesh::draw()
shaderProgram->release();
}
void Mesh::drawShadow()
{
shadowProgram->bind();
unsigned int diffuseNr = 1;
unsigned int specularNr = 1;
unsigned int normalNr = 1;
unsigned int heightNr = 1;
for (unsigned int i = 0; i < textures.size(); i++)
{
glFunc->glActiveTexture(GL_TEXTURE0 + i); // 在绑定之前激活相应的纹理单元
textures[i]->texture.bind();
//qDebug() << name + number;
shadowProgram->setUniformValue(textures[i]->type.toStdString().c_str(), i);
}
// 绘制网格
QOpenGLVertexArrayObject::Binder bind(&VAO);
shadowProgram->setUniformValue("model", model);
glFunc->glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
shadowProgram->release();
}
void Mesh::setupMesh()
{
shaderProgram->bind();

View File

@ -16,45 +16,46 @@
struct Vertex
{
QVector3D Position;
QVector3D Normal;
QVector2D TexCoords;
QVector3D Tangent;
QVector3D Bitangent;
QVector3D Position;
QVector3D Normal;
QVector2D TexCoords;
QVector3D Tangent;
QVector3D Bitangent;
};
struct Texture
{
QOpenGLTexture texture;
QString type;
QString path;
Texture() :texture(QOpenGLTexture::Target2D) {
texture.create();
texture.setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);
texture.setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);
texture.setMinMagFilters(QOpenGLTexture::LinearMipMapLinear, QOpenGLTexture::Linear);
}
QOpenGLTexture texture;
QString type;
QString path;
Texture() :texture(QOpenGLTexture::Target2D) {
texture.create();
texture.setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::Repeat);
texture.setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::Repeat);
texture.setMinMagFilters(QOpenGLTexture::LinearMipMapLinear, QOpenGLTexture::Linear);
}
};
class Mesh : public Drawable
{
public:
/* 网格数据 */
QVector<Vertex> vertices; //顶点数据
QVector<unsigned int> indices; //索引数组
QVector<Texture*> textures; //纹理数据
QMatrix4x4 model; //模型矩阵
QOpenGLFunctions_4_5_Compatibility* glFunc; //opengl函数入口
QOpenGLShaderProgram* shaderProgram; //着色器程序
/* 网格数据 */
QVector<Vertex> vertices; //顶点数据
QVector<unsigned int> indices; //索引数组
QVector<Texture*> textures; //纹理数据
QMatrix4x4 model; //模型矩阵
QOpenGLFunctions_4_5_Compatibility* glFunc; //opengl函数入口
QOpenGLShaderProgram* shaderProgram, * shadowProgram; //着色器程序
/* 函数 */
Mesh(QOpenGLFunctions_4_5_Compatibility* glFunc, QOpenGLShaderProgram* shaderProgram, aiMatrix4x4 model);
void draw() override;
void setupMesh();
/* 函数 */
Mesh(QOpenGLFunctions_4_5_Compatibility* glFunc, QOpenGLShaderProgram* shaderProgram, QOpenGLShaderProgram* shadowProgram, aiMatrix4x4 model);
void draw() override;
void drawShadow() override;
void setupMesh();
private:
/* 渲染数据 */
QOpenGLVertexArrayObject VAO;
QOpenGLBuffer VBO, EBO;
/* 渲染数据 */
QOpenGLVertexArrayObject VAO;
QOpenGLBuffer VBO, EBO;
};

View File

@ -30,11 +30,12 @@ Model::Model(QString path, QOpenGLContext* context, QOpenGLShaderProgram* shader
processNode(scene->mRootNode, scene);
}
Model::Model(QString path, QOpenGLContext* context, QOpenGLShaderProgram* shaderProgram, QOpenGLShaderProgram* paintingProgram, PaintingHelper* paintingHelper)
Model::Model(QString path, QOpenGLContext* context, QOpenGLShaderProgram* shaderProgram, QOpenGLShaderProgram* paintingProgram, QOpenGLShaderProgram* shadowProgram, PaintingHelper* paintingHelper)
: context(context)
, glFunc(context->versionFunctions<QOpenGLFunctions_4_5_Compatibility>())
, shaderProgram(shaderProgram)
, paintingProgram(paintingProgram)
, shadowProgram(shadowProgram)
, paintingHelper(paintingHelper)
, directory(path)
{
@ -71,6 +72,13 @@ void Model::draw() {
}
}
void Model::drawShadow() {
//shaderProgram->bind();
for (Drawable* mesh : meshes) {
mesh->drawShadow();
}
}
void Model::destroy()
{
context->doneCurrent();
@ -109,7 +117,7 @@ Drawable* Model::processMesh(aiMesh* mesh, const aiScene* scene, aiMatrix4x4 mod
{
qDebug() << str.C_Str() << "Replaced";
// 初始化网格
PaintingMesh* m_mesh = new PaintingMesh(glFunc, paintingProgram, model);
PaintingMesh* m_mesh = new PaintingMesh(glFunc, paintingProgram, shadowProgram, model);
// 遍历网格的每个顶点
for (unsigned int i = 0; i < mesh->mNumVertices; i++)
{
@ -258,7 +266,7 @@ Drawable* Model::processMesh(aiMesh* mesh, const aiScene* scene, aiMatrix4x4 mod
else
{
// 初始化网格
Mesh* m_mesh = new Mesh(glFunc, shaderProgram, model);
Mesh* m_mesh = new Mesh(glFunc, shaderProgram, shadowProgram, model);
// 遍历网格的每个顶点
for (unsigned int i = 0; i < mesh->mNumVertices; i++)
{

View File

@ -9,9 +9,10 @@ class Model
{
public:
void draw();
void drawShadow();
void destroy();
static Model* createModel(QString path, QOpenGLContext* context, QOpenGLShaderProgram* shaderProgram);
Model(QString path, QOpenGLContext* context, QOpenGLShaderProgram* shaderProgram, QOpenGLShaderProgram* paintingProgram, PaintingHelper* paintingHelper);
Model(QString path, QOpenGLContext* context, QOpenGLShaderProgram* shaderProgram, QOpenGLShaderProgram* paintingProgram, QOpenGLShaderProgram* shadowProgram, PaintingHelper* paintingHelper);
private:
Model(QString path, QOpenGLContext* context, QOpenGLShaderProgram* shaderProgram);
@ -20,6 +21,7 @@ private:
QOpenGLFunctions_4_5_Compatibility* glFunc;
QOpenGLShaderProgram* shaderProgram = nullptr;
QOpenGLShaderProgram* paintingProgram = nullptr; //彩绘着色器程序
QOpenGLShaderProgram* shadowProgram = nullptr;
PaintingHelper* paintingHelper = nullptr;
/* 模型数据 */

View File

@ -1,8 +1,9 @@
#include "PaintingMesh.h"
PaintingMesh::PaintingMesh(QOpenGLFunctions_4_5_Compatibility* glFunc, QOpenGLShaderProgram* shaderProgram, aiMatrix4x4 model)
PaintingMesh::PaintingMesh(QOpenGLFunctions_4_5_Compatibility* glFunc, QOpenGLShaderProgram* shaderProgram, QOpenGLShaderProgram* shadowProgram, aiMatrix4x4 model)
: glFunc(glFunc)
, shaderProgram(shaderProgram)
, shadowProgram(shadowProgram)
, VBO(QOpenGLBuffer::VertexBuffer)
, EBO(QOpenGLBuffer::IndexBuffer)
, model((float*)&model)
@ -10,14 +11,21 @@ PaintingMesh::PaintingMesh(QOpenGLFunctions_4_5_Compatibility* glFunc, QOpenGLSh
}
void PaintingMesh::draw()
{
shaderProgram->bind();
QOpenGLVertexArrayObject::Binder bind(&VAO);
shaderProgram->setUniformValue("model", model);
glFunc->glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
glFunc->glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
shaderProgram->release();
}
void PaintingMesh::drawShadow()
{
shadowProgram->bind();
QOpenGLVertexArrayObject::Binder bind(&VAO);
shadowProgram->setUniformValue("model", model);
glFunc->glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
shadowProgram->release();
}
void PaintingMesh::setupMesh()
{
shaderProgram->bind();

View File

@ -32,11 +32,12 @@ public:
QVector<unsigned int> indices; //索引数组
QMatrix4x4 model; //模型矩阵
QOpenGLFunctions_4_5_Compatibility* glFunc; //opengl函数入口
QOpenGLShaderProgram* shaderProgram; //着色器程序
QOpenGLShaderProgram* shaderProgram, * shadowProgram; //着色器程序
GLuint paintingIndex;
/* 函数 */
PaintingMesh(QOpenGLFunctions_4_5_Compatibility* glFunc, QOpenGLShaderProgram* shaderProgram, aiMatrix4x4 model);
PaintingMesh(QOpenGLFunctions_4_5_Compatibility* glFunc, QOpenGLShaderProgram* shaderProgram, QOpenGLShaderProgram* shadowProgram, aiMatrix4x4 model);
void draw() override;
void drawShadow() override;
void setupMesh();
private:

View File

@ -49,6 +49,14 @@ void RendererWidget::initializeGL()
glEnable(GL_DEPTH_TEST);
glClearColor(0, 0, 0, 1);
shadowProgramPtr = new QOpenGLShaderProgram;
if (!shadowProgramPtr->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/model_shadow.vert"))
qDebug() << "ERROR:" << shadowProgramPtr->log();
if (!shadowProgramPtr->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/Shaders/model_shadow.frag"))
qDebug() << "ERROR:" << shadowProgramPtr->log();
if (!shadowProgramPtr->link())
qDebug() << "ERROR:" << shadowProgramPtr->log();
modelProgramPtr = new QOpenGLShaderProgram;
if (!modelProgramPtr->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/model.vert"))
qDebug() << "ERROR:" << modelProgramPtr->log();
@ -85,15 +93,16 @@ void RendererWidget::initializeGL()
finalProgramPtr->setUniformValue("gNormal", 1);
finalProgramPtr->setUniformValue("gPosition", 2);
finalProgramPtr->setUniformValue("gMetallicRoughness", 3);
finalProgramPtr->setUniformValue("gShadowMap", 4);
finalProgramPtr->release();
paintingHelper = new PaintingHelper(QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_4_5_Compatibility>());
model = new Model("Models/Sponza/Sponza.gltf", context(), modelProgramPtr, paintingProgramPtr, paintingHelper);
model = new Model("Models/Sponza/Sponza.gltf", context(), modelProgramPtr, paintingProgramPtr, shadowProgramPtr, paintingHelper);
paintingHelper->allocateBuffers();
paintingCompProgramPtr->bind();
paintingHelper->bindPaintingBuffers();
@ -127,13 +136,37 @@ void RendererWidget::initializeGL()
}
QVector3D lightPositions[] = { QVector3D(0,0,0), QVector3D(100,100,100) ,QVector3D(-100,100,100) ,QVector3D(100,100,-100) };
QVector3D lightColors[] = { QVector3D(150000,150000,130000), QVector3D(0,0,0) ,QVector3D(0,0,0) ,QVector3D(0,0,0) };
QVector3D lightPositions[] = { 2000 * QVector3D(0.2, 4, 1).normalized(), QVector3D(100,100,100) ,QVector3D(-100,100,100) ,QVector3D(100,100,-100) };
QVector3D lightColors[] = { 10000000 * QVector3D(0.7529,0.7450,0.6784).normalized(), QVector3D(0,0,0) ,QVector3D(0,0,0) ,QVector3D(0,0,0) };
static float sunPitch = 90, sunYaw = 80;
void RendererWidget::paintGL()
{
QMatrix4x4 lightProjection;
lightProjection.ortho(-1200.0f, 1200.0f, -900.0f, 900.0f, 100.f, 5000.0f);
lightPositions[0].setX(cos(qDegreesToRadians(sunPitch)) * cos(qDegreesToRadians(sunYaw)));
lightPositions[0].setY(sin(qDegreesToRadians(sunPitch)));
lightPositions[0].setZ(cos(qDegreesToRadians(sunPitch)) * sin(qDegreesToRadians(sunYaw)));
lightPositions[0] *= 2000;
QMatrix4x4 lightView;
lightView.lookAt(lightPositions[0], QVector3D(0, 0, 0), QVector3D(0, 1, 0));
if (shadowFboPtr->bind())
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, shadowMapResolution, shadowMapResolution);
shadowProgramPtr->bind();
shadowProgramPtr->setUniformValue("projection", lightProjection);
shadowProgramPtr->setUniformValue("view", lightView);
shadowProgramPtr->release();
model->drawShadow();
shadowFboPtr->release();
}
if (fboPtr->bind())
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, frameWidth, frameHeight);
QMatrix4x4 projection;
projection.perspective(camera.Zoom, (float)width() / (float)height(), 10.f, 10000.0f);
QMatrix4x4 view = camera.GetViewMatrix();
@ -156,19 +189,21 @@ void RendererWidget::paintGL()
glBindImageTexture(0, gbuffers[0], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8);
glBindImageTexture(1, gbuffers[3], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RG8);
glBindImageTexture(2, gbuffers[4], 0, GL_FALSE, 0, GL_READ_WRITE, GL_R16UI);
glBindImageTexture(3, gbuffers[5], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RG16F);
glBindImageTexture(3, gbuffers[5], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RG32F);
glDispatchCompute(ceil(frameWidth / 8.), ceil(frameHeight / 8.), 1);
//glDispatchCompute(1,1, 1);
//QOpenGLFramebufferObject::blitFramebuffer(nullptr, QRect(0, 0, 2*width(), 2*height()), fboPtr, QRect(0, 0, 1156, 756));
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, frameWidth, frameHeight);
QOpenGLVertexArrayObject::Binder vaoBinder(&quadVAO);
finalProgramPtr->bind();
finalProgramPtr->setUniformValue("camPos", camera.Position);
lightPositions[0] = camera.Position;
finalProgramPtr->setUniformValue("lightSpaceMatrix", lightProjection * lightView);
//lightPositions[0] = camera.Position;
finalProgramPtr->setUniformValueArray("lightPositions", lightPositions, 4);
finalProgramPtr->setUniformValueArray("lightColors", lightColors, 4);
@ -181,6 +216,8 @@ void RendererWidget::paintGL()
glBindTexture(GL_TEXTURE_2D, gbuffers[2]);
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, gbuffers[3]);
glActiveTexture(GL_TEXTURE4);
glBindTexture(GL_TEXTURE_2D, shadowGbuffers[3]);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
finalProgramPtr->release();
}
@ -192,6 +229,7 @@ void RendererWidget::resizeGL(int width, int height)
qDebug() << frameWidth << "x" << frameHeight;
//qDebug() << devicePixelRatioF() << width << height;
//glViewport(0, 0, (GLint)devicePixelRatio()*width, (GLint)devicePixelRatio()*height);
if (fboPtr != nullptr)
delete fboPtr;
fboPtr = new QOpenGLFramebufferObject(frameWidth, frameHeight, QOpenGLFramebufferObject::Depth, GL_TEXTURE_2D);
@ -202,36 +240,38 @@ void RendererWidget::resizeGL(int width, int height)
fboPtr->addColorAttachment(frameWidth, frameHeight, GL_RG8);
fboPtr->addColorAttachment(frameWidth, frameHeight, GL_R16F);
fboPtr->addColorAttachment(frameWidth, frameHeight, GL_RG16F);*/
//BaseColor
gbuffers[0] = fboPtr->texture();
glGenTextures(5, gbuffers+1);
glGenTextures(5, gbuffers + 1);
//Normal
glBindTexture(GL_TEXTURE_2D, gbuffers[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, frameWidth, frameHeight, 0, GL_RGB, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, gbuffers[1], 0);
//Position
glBindTexture(GL_TEXTURE_2D, gbuffers[2]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, frameWidth, frameHeight, 0, GL_RGB, GL_FLOAT, NULL);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, frameWidth, frameHeight, 0, GL_RGB, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, gbuffers[2], 0);
//MetallicRoughness
glBindTexture(GL_TEXTURE_2D, gbuffers[3]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RG8, frameWidth, frameHeight, 0, GL_RG, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, gbuffers[3], 0);
//gPaintingIndex
glBindTexture(GL_TEXTURE_2D, gbuffers[4]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_R16UI, frameWidth, frameHeight, 0, GL_RED_INTEGER, GL_UNSIGNED_INT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT4, GL_TEXTURE_2D, gbuffers[4], 0);
//PaintingTexCoord
glBindTexture(GL_TEXTURE_2D, gbuffers[5]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RG16F, frameWidth, frameHeight, 0, GL_RG, GL_FLOAT, NULL);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RG32F, frameWidth, frameHeight, 0, GL_RG, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT5, GL_TEXTURE_2D, gbuffers[5], 0);
@ -239,10 +279,54 @@ void RendererWidget::resizeGL(int width, int height)
GLenum attachments[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5 };
glDrawBuffers(6, attachments);
//gbuffers = fboPtr->textures();
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
qDebug() << "Framebuffer not complete!";
fboPtr->release();
}
if (shadowFboPtr != nullptr)
delete shadowFboPtr;
shadowMapResolution = 1 * std::max(frameWidth, frameHeight);
shadowFboPtr = new QOpenGLFramebufferObject(shadowMapResolution, shadowMapResolution);
if (shadowFboPtr->bind())
{
shadowGbuffers[0] = shadowFboPtr->texture();
glGenTextures(3, shadowGbuffers + 1);
//Normal
glBindTexture(GL_TEXTURE_2D, shadowGbuffers[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, shadowMapResolution, shadowMapResolution, 0, GL_RGB, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, shadowGbuffers[1], 0);
//Position
glBindTexture(GL_TEXTURE_2D, shadowGbuffers[2]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, shadowMapResolution, shadowMapResolution, 0, GL_RGB, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, shadowGbuffers[2], 0);
//Depth
glBindTexture(GL_TEXTURE_2D, shadowGbuffers[3]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32,
shadowMapResolution, shadowMapResolution, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, shadowGbuffers[3], 0);
GLenum attachments[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 };
glDrawBuffers(3, attachments);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
qDebug() << "ShadowFramebuffer not complete!";
shadowFboPtr->release();
}
std::cout << "\033[?25l";
}
@ -259,8 +343,8 @@ void RendererWidget::timerEvent(QTimerEvent* event)
frameCnt++;
if (accTime > 1.)
{
std::cout << " \r";
std::cout << "FPS: " << frameCnt / accTime << "\r";
std::cout << " \r";
std::cout << "FPS: " << frameCnt / accTime << " " << camera.Position.x() << " " << camera.Position.y() << " " << camera.Position.z() << "\r";
accTime = 0;
frameCnt = 0;
}
@ -293,6 +377,15 @@ void RendererWidget::timerEvent(QTimerEvent* event)
if (pressedKeys.contains(Qt::Key_Space)) {
camera.ProcessKeyboard(UP, deltaTime);
}
static int sunSpeed = 10;
sunPitch += sunSpeed * deltaTime ;
if (sunPitch > 120 || sunPitch < 65)
{
sunSpeed = -sunSpeed;
sunPitch += sunSpeed * deltaTime;
}
repaint();
}

View File

@ -35,12 +35,16 @@ private:
Camera camera;
clock_t lastFrame;
float deltaTime;
int shadowMapResolution;
QOpenGLShaderProgram* shadowProgramPtr = nullptr;
QOpenGLShaderProgram* modelProgramPtr = nullptr;
QOpenGLShaderProgram* paintingProgramPtr = nullptr;
QOpenGLShaderProgram* paintingCompProgramPtr = nullptr;
QOpenGLShaderProgram* finalProgramPtr = nullptr;
QOpenGLFramebufferObject* fboPtr = nullptr;
QOpenGLFramebufferObject* shadowFboPtr = nullptr;
GLuint gbuffers[6];
GLuint shadowGbuffers[4];
QOpenGLBuffer quadVBO;
QOpenGLVertexArrayObject quadVAO;
Model* model;

View File

@ -8,10 +8,12 @@ uniform sampler2D gBaseColor;
uniform sampler2D gNormal;
uniform sampler2D gPosition;
uniform sampler2D gMetallicRoughness;
uniform sampler2D gShadowMap;
// lights
uniform vec3 lightPositions[4];
uniform vec3 lightColors[4];
uniform mat4 lightSpaceMatrix;
uniform vec3 camPos;
@ -19,95 +21,161 @@ const float PI = 3.14159265359;
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 nom = a2;
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
denom = PI * denom * denom;
float nom = a2;
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
denom = PI * denom * denom;
return nom / denom;
return nom / 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 nom = NdotV;
float denom = NdotV * (1.0 - k) + k;
float nom = NdotV;
float denom = NdotV * (1.0 - k) + k;
return nom / denom;
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);
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 fresnelSchlick(float cosTheta, vec3 F0)
{
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
}
float Calculate_Avg_Dblockreceiver(vec2 projCoords , int AvgTextureSize)
{
vec2 texelSize =1.0/ textureSize(gShadowMap, 0);
float result=0.0f;
for(int i=-AvgTextureSize;i<=AvgTextureSize;++i)
{
for(int j=-AvgTextureSize;j<=AvgTextureSize;j++)
{
result += texture(gShadowMap, projCoords+vec2(i,j)*texelSize).r;
}
}
return result/(AvgTextureSize*AvgTextureSize*2*2);
}
float ShadowCalculation(vec4 fragPosLightSpace, float bias)
{
// 执行透视除法
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
// 变换到[0,1]的范围
projCoords = projCoords * 0.5 + 0.5;
// 取得最近点的深度(使用[0,1]范围下的fragPosLight当坐标)
float closestDepth = texture(gShadowMap, projCoords.xy).r;
// 取得当前片段在光源视角下的深度
float currentDepth = projCoords.z;
vec2 texelSize = 1.0 / textureSize(gShadowMap, 0);
float shadow = 0;
// 检查当前片段是否在阴影中
//float shadow = 0;// currentDepth - bias > closestDepth ? 1.0 : 0.0;
float fliterArea = 7;
int fliterSingleX = int(fliterArea/2);
for(int i=-fliterSingleX;i<=fliterSingleX;++i)
{
for(int j=-fliterSingleX;j<=fliterSingleX;j++)
{
// 采样周围点在ShadowMap中的深度
float closestDepth = texture(gShadowMap, projCoords.xy+vec2(i,j)*texelSize).r;
shadow += (currentDepth - bias) > closestDepth ? 1.0 : 0.0;
}
}
return shadow/(fliterArea*fliterArea);
//return clamp(shadow/(fliterArea*fliterArea),0.,1.);
}
void main()
{
vec3 albedo = pow(texture(gBaseColor, TexCoords).rgb, vec3(2.2));
float metallic = texture(gMetallicRoughness, TexCoords).r;
float roughness = texture(gMetallicRoughness, TexCoords).g;
vec3 albedo = pow(texture(gBaseColor, TexCoords).rgb, vec3(2.2));
float metallic = texture(gMetallicRoughness, TexCoords).r;
float roughness = texture(gMetallicRoughness, TexCoords).g;
vec3 N = normalize(texture(gNormal, TexCoords).xyz);
vec3 WorldPos = texture(gPosition, TexCoords).xyz;
vec3 N = normalize(texture(gNormal, TexCoords).xyz);
vec3 WorldPos = texture(gPosition, TexCoords).xyz;
vec3 V = normalize(camPos - WorldPos);
if(WorldPos==vec3(0))
{
vec3 color = lightColors[0];
vec3 F0 = vec3(0.04);
F0 = mix(F0, albedo, metallic);
color = color / (color + vec3(1.0));
color = pow(color, vec3(1.0/2.2));
// 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;
FragColor = vec4(color, 1.0);
return;
}
// cook-torrance brdf
float NDF = DistributionGGX(N, H, roughness);
float G = GeometrySmith(N, V, L, roughness);
vec3 F = fresnelSchlick(clamp(dot(H, V),0.,1.), F0);
//F = clamp(F,vec3(0),vec3(1));
vec4 FragPosLightSpace = lightSpaceMatrix * vec4(WorldPos, 1.0);
vec3 kS = F;
vec3 kD = vec3(1.0) - kS;
kD *= 1.0 - metallic;
vec3 V = normalize(camPos - WorldPos);
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;
vec3 F0 = vec3(0.04);
F0 = mix(F0, albedo, metallic);
// add to outgoing radiance Lo
float NdotL = max(dot(N, L), 0.0);
Lo += (kD * albedo / PI + specular) * radiance * NdotL;
}
// reflectance equation
vec3 Lo = vec3(0.0);
vec3 ambient = vec3(0.03) * albedo;
vec3 color = ambient + Lo;
int i = 0;
// 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;
color = color / (color + vec3(1.0));
color = pow(color, vec3(1.0/2.2));
// cook-torrance brdf
float NDF = DistributionGGX(N, H, roughness);
float G = GeometrySmith(N, V, L, roughness);
vec3 F = fresnelSchlick(clamp(dot(H, V),0.,1.), F0);
//F = clamp(F,vec3(0),vec3(1));
FragColor = vec4(color, 1.0);
//FragColor = vec4(texture(gPainting, TexCoords).rgb, 1.0);
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;
float bias = 0.08 * max(0.05 * (1.0 - dot(N, L)), 0.005);
float shadow = ShadowCalculation(FragPosLightSpace, bias);
//vec3 color = ambient + Lo;
vec3 color = ambient + (1.0 - shadow) * Lo;
color = color / (color + vec3(1.0));
color = pow(color, vec3(1.0/2.2));
FragColor = vec4(color, 1.0);
//FragColor = vec4(vec3(shadow), 1);
//FragColor = vec4(texture(gShadowMap, TexCoords).rgb, 1.0);
}

View File

@ -6,11 +6,11 @@ layout (location = 2) in vec2 aTexCoords;
out vec2 TexCoords;
out vec3 WorldPos;
out vec3 Normal;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
TexCoords = aTexCoords;
@ -19,4 +19,5 @@ void main()
gl_Position = projection * view * vec4(WorldPos, 1.0);
}

View File

@ -0,0 +1,42 @@
#version 450 core
uniform sampler2D texture_basecolor;
uniform sampler2D texture_metallic_roughness;
uniform sampler2D texture_normal;
layout (location = 0) out vec4 gBaseColor;
layout (location = 1) out vec3 gNormal;
layout (location = 2) out vec3 gPosition;
in vec2 TexCoords;
in vec3 WorldPos;
in vec3 Normal;
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);
}
void main()
{
//gBaseColor = vec4(1,0,0,1);
gBaseColor = texture(texture_basecolor, TexCoords);
if(gBaseColor.a<0.4)
discard;
gPosition = WorldPos;
gNormal = getNormalFromMap();
}

View File

@ -0,0 +1,21 @@
#version 450 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 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
TexCoords = aTexCoords;
WorldPos = vec3(model * vec4(aPos, 1.0));
Normal = mat3(model) * aNormal;
gl_Position = projection * view * vec4(WorldPos, 1.0);
}

View File

@ -5,7 +5,7 @@ layout (local_size_x = 8, local_size_y = 8) in;
layout(rgba8, binding = 0) uniform image2D gBaseColor;
layout(rg8, binding = 1) uniform image2D gMetallicRoughness;
layout(r16ui, binding = 2) uniform uimage2D gPaintingIndex;
layout(rg16f, binding = 3) uniform image2D gPaintingTexCoord;
layout(rg32f, binding = 3) uniform image2D gPaintingTexCoord;
layout(std430, binding = 1) buffer paintingOffsetBuffer
{

View File

@ -2,7 +2,7 @@
vs2022项目 qt5.15.2 msvc 2019 64-bit
采用pbr材质现在有一个光源和摄像机绑定,足以分辨出不同材质的效果
采用pbr材质现在有一个随时间变化的方向光并添加了阴影
把一块布替换成了待完成的彩绘管线见PaintingMesh类以及painting着色器
@ -12,4 +12,6 @@ TODO
- [x] 指定一块材质使用独立管线进行纹理采样
- [ ] 彩绘的表示、读取、采样...
- [ ] 彩绘的表示、读取、采样...
- [x] PCF Shadow Map