初步实现Cascaded Shadow Maps

dev-VirtualTexture
wuyize 2022-08-23 22:55:59 +08:00
parent 0efd3b1dbc
commit 3bf1444092
16 changed files with 610 additions and 162 deletions

View File

@ -87,6 +87,7 @@
<ItemGroup> <ItemGroup>
<ClCompile Include="BvhTree.cpp" /> <ClCompile Include="BvhTree.cpp" />
<ClCompile Include="Camera.cpp" /> <ClCompile Include="Camera.cpp" />
<ClCompile Include="Light.cpp" />
<ClCompile Include="Mesh.cpp" /> <ClCompile Include="Mesh.cpp" />
<ClCompile Include="Model.cpp" /> <ClCompile Include="Model.cpp" />
<ClCompile Include="PaintingHelper.cpp" /> <ClCompile Include="PaintingHelper.cpp" />
@ -102,11 +103,14 @@
<QtMoc Include="RendererWidget.h" /> <QtMoc Include="RendererWidget.h" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Include="Shaders\depth_init.comp" />
<None Include="Shaders\depth_mipmap.comp" />
<None Include="Shaders\final.frag" /> <None Include="Shaders\final.frag" />
<None Include="Shaders\final.vert" /> <None Include="Shaders\final.vert" />
<None Include="Shaders\model.frag" /> <None Include="Shaders\model.frag" />
<None Include="Shaders\model.vert" /> <None Include="Shaders\model.vert" />
<None Include="Shaders\model_shadow.frag" /> <None Include="Shaders\model_shadow.frag" />
<None Include="Shaders\model_shadow.geom" />
<None Include="Shaders\model_shadow.vert" /> <None Include="Shaders\model_shadow.vert" />
<None Include="Shaders\painting.comp" /> <None Include="Shaders\painting.comp" />
<None Include="Shaders\painting.frag" /> <None Include="Shaders\painting.frag" />
@ -118,6 +122,7 @@
<ClInclude Include="BvhTree.h" /> <ClInclude Include="BvhTree.h" />
<ClInclude Include="Camera.h" /> <ClInclude Include="Camera.h" />
<ClInclude Include="Drawable.h" /> <ClInclude Include="Drawable.h" />
<ClInclude Include="Light.h" />
<ClInclude Include="Mesh.h" /> <ClInclude Include="Mesh.h" />
<ClInclude Include="Model.h" /> <ClInclude Include="Model.h" />
<ClInclude Include="PaintingHelper.h" /> <ClInclude Include="PaintingHelper.h" />

View File

@ -64,6 +64,9 @@
<ClCompile Include="PaintingHelper.cpp"> <ClCompile Include="PaintingHelper.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Light.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<QtMoc Include="RendererWidget.h"> <QtMoc Include="RendererWidget.h">
@ -104,6 +107,15 @@
<None Include="Shaders\model_shadow.vert"> <None Include="Shaders\model_shadow.vert">
<Filter>Resource Files\Shaders</Filter> <Filter>Resource Files\Shaders</Filter>
</None> </None>
<None Include="Shaders\depth_mipmap.comp">
<Filter>Resource Files\Shaders</Filter>
</None>
<None Include="Shaders\depth_init.comp">
<Filter>Resource Files\Shaders</Filter>
</None>
<None Include="Shaders\model_shadow.geom">
<Filter>Resource Files\Shaders</Filter>
</None>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="Camera.h"> <ClInclude Include="Camera.h">
@ -127,5 +139,8 @@
<ClInclude Include="PaintingHelper.h"> <ClInclude Include="PaintingHelper.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Light.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -41,6 +41,9 @@ public:
float MovementSpeed; float MovementSpeed;
float MouseSensitivity; float MouseSensitivity;
float Zoom; float Zoom;
float Ratio;
float NearPlane = 10.f;
float FarPlane = 10000.f;
// constructor with vectors // constructor with vectors
Camera(QVector3D position = QVector3D(0.0f, 0.0f, 0.0f), QVector3D up = QVector3D(0.0f, 1.0f, 0.0f), float yaw = YAW, float pitch = PITCH); Camera(QVector3D position = QVector3D(0.0f, 0.0f, 0.0f), QVector3D up = QVector3D(0.0f, 1.0f, 0.0f), float yaw = YAW, float pitch = PITCH);

View File

@ -0,0 +1,137 @@
#include "Light.h"
#include <qDebug>
Light::Light(Camera* camera)
: camera(camera)
, shadowCascadeLevels{ camera->FarPlane / 50.0f, camera->FarPlane / 25.0f, camera->FarPlane / 10.0f, camera->FarPlane / 2.0f }
{
}
std::vector<QVector4D> Light::getFrustumCornersWorldSpace(const QMatrix4x4& projview)
{
const auto inv = projview.inverted();
std::vector<QVector4D> frustumCorners;
for (unsigned int x = 0; x < 2; ++x)
{
for (unsigned int y = 0; y < 2; ++y)
{
for (unsigned int z = 0; z < 2; ++z)
{
const QVector4D pt = inv * QVector4D(2.0f * x - 1.0f, 2.0f * y - 1.0f, 2.0f * z - 1.0f, 1.0f);
frustumCorners.push_back(pt / pt.w());
}
}
}
return frustumCorners;
}
std::vector<QVector4D> Light::getFrustumCornersWorldSpace(const QMatrix4x4& proj, const QMatrix4x4& view)
{
return getFrustumCornersWorldSpace(proj * view);
}
QMatrix4x4 Light::getLightSpaceMatrix(const float nearPlane, const float farPlane)
{
QMatrix4x4 proj;
proj.perspective(camera->Zoom, camera->Ratio, nearPlane, farPlane);
const std::vector<QVector4D> corners = getFrustumCornersWorldSpace(proj, camera->GetViewMatrix());
QVector3D center = QVector3D(0, 0, 0);
for (const QVector4D& v : corners)
{
center += QVector3D(v);
}
center /= corners.size();
QVector3D right = QVector3D::crossProduct(lightDirection, QVector3D(1, 0, 0)).normalized();
QVector3D up = QVector3D::crossProduct(right, lightDirection).normalized();
QMatrix4x4 lightView;
//qDebug() << "lightDirection:" << lightDirection << "up:" << up;
lightView.lookAt(center, center - lightDirection, up);
float minX = std::numeric_limits<float>::max();
float maxX = std::numeric_limits<float>::min();
float minY = std::numeric_limits<float>::max();
float maxY = std::numeric_limits<float>::min();
float minZ = std::numeric_limits<float>::max();
float maxZ = std::numeric_limits<float>::min();
for (const QVector4D& v : corners)
{
QVector4D trf = lightView * v;
//qDebug() << v;
//qDebug() << trf;
minX = std::min(minX, trf.x());
maxX = std::max(maxX, trf.x());
minY = std::min(minY, trf.y());
maxY = std::max(maxY, trf.y());
minZ = std::min(minZ, -trf.z());
maxZ = std::max(maxZ, -trf.z());
}
for (const QVector3D& v : model->AABB)
{
const QVector4D trf = lightView * QVector4D(v, 1);
//qDebug() << v;
//qDebug() << trf;
//minX = std::min(minX, trf.x());
//maxX = std::max(maxX, trf.x());
//minY = std::min(minY, trf.y());
//maxY = std::max(maxY, trf.y());
minZ = std::min(minZ, -trf.z());
//maxZ = std::max(maxZ, trf.z());
}
//qDebug() << minZ;
// Tune this parameter according to the scene
/* constexpr float zMult = 10.0f;
if (minZ < 0)
{
minZ *= zMult;
}
else
{
minZ /= zMult;
}
if (maxZ < 0)
{
maxZ /= zMult;
}
else
{
maxZ *= zMult;
}*/
QMatrix4x4 lightProjection;
//qDebug() << minX<< maxX<< minY<< maxY<< minZ<< maxZ;
lightProjection.ortho(minX, maxX, minY, maxY, minZ, maxZ);
frustumSizes.push_back(std::max(maxX - minX, maxY - minY));
return lightProjection * lightView;
}
std::vector<QMatrix4x4> Light::getLightSpaceMatrices()
{
std::vector<QMatrix4x4> ret;
frustumSizes.clear();
for (size_t i = 0; i < shadowCascadeLevels.size() + 1; ++i)
{
if (i == 0)
{
ret.push_back(getLightSpaceMatrix(camera->NearPlane, shadowCascadeLevels[i]));
}
else if (i < shadowCascadeLevels.size())
{
ret.push_back(getLightSpaceMatrix(shadowCascadeLevels[i - 1], shadowCascadeLevels[i]));
}
else
{
ret.push_back(getLightSpaceMatrix(shadowCascadeLevels[i - 1], camera->FarPlane));
}
}
return ret;
}

View File

@ -0,0 +1,28 @@
#pragma once
#include <vector>
#include <QVector3D>
#include <QVector4D>
#include <QMatrix4x4>
#include <QtMath>
#include <QOpenGLFunctions_4_5_Compatibility>
#include "Camera.h"
#include "Model.h"
class Light
{
public:
QVector3D lightDirection = QVector3D(0.2, 4, 1).normalized();
std::vector<float> shadowCascadeLevels;
std::vector<float> frustumSizes;
Model* model;
Light(Camera* camera);
std::vector<QVector4D> getFrustumCornersWorldSpace(const QMatrix4x4& projview);
std::vector<QVector4D> getFrustumCornersWorldSpace(const QMatrix4x4& proj, const QMatrix4x4& view);
QMatrix4x4 getLightSpaceMatrix(const float nearPlane, const float farPlane);
std::vector<QMatrix4x4> getLightSpaceMatrices();
private:
Camera* camera;
};

View File

@ -12,5 +12,8 @@
<file>Shaders/painting.comp</file> <file>Shaders/painting.comp</file>
<file>Shaders/model_shadow.frag</file> <file>Shaders/model_shadow.frag</file>
<file>Shaders/model_shadow.vert</file> <file>Shaders/model_shadow.vert</file>
<file>Shaders/depth_mipmap.comp</file>
<file>Shaders/depth_init.comp</file>
<file>Shaders/model_shadow.geom</file>
</qresource> </qresource>
</RCC> </RCC>

View File

@ -52,6 +52,14 @@ Model::Model(QString path, QOpenGLContext* context, QOpenGLShaderProgram* shader
qDebug() << "NumTextures: " << scene->mNumTextures; qDebug() << "NumTextures: " << scene->mNumTextures;
directory.cdUp(); directory.cdUp();
processNode(scene->mRootNode, scene); processNode(scene->mRootNode, scene);
AABB.push_back(QVector3D(minX, minY, minZ));
AABB.push_back(QVector3D(minX, minY, maxZ));
AABB.push_back(QVector3D(minX, maxY, minZ));
AABB.push_back(QVector3D(minX, maxY, maxZ));
AABB.push_back(QVector3D(maxX, minY, minZ));
AABB.push_back(QVector3D(maxX, minY, maxZ));
AABB.push_back(QVector3D(maxX, maxY, minZ));
AABB.push_back(QVector3D(maxX, maxY, maxZ));
} }
Model::~Model() //Ïú»Ù¶ÔÏó Model::~Model() //Ïú»Ù¶ÔÏó
@ -123,6 +131,14 @@ Drawable* Model::processMesh(aiMesh* mesh, const aiScene* scene, aiMatrix4x4 mod
{ {
PaintingVertex vertex; PaintingVertex vertex;
vertex.Position = QVector3D(mesh->mVertices[i].x, mesh->mVertices[i].y, mesh->mVertices[i].z); vertex.Position = QVector3D(mesh->mVertices[i].x, mesh->mVertices[i].y, mesh->mVertices[i].z);
minX = std::min(minX, vertex.Position.x());
maxX = std::max(maxX, vertex.Position.x());
minY = std::min(minY, vertex.Position.y());
maxY = std::max(maxY, vertex.Position.y());
minZ = std::min(minZ, vertex.Position.z());
maxZ = std::max(maxZ, vertex.Position.z());
// ·¨ÏòÁ¿ // ·¨ÏòÁ¿
if (mesh->mNormals) if (mesh->mNormals)
vertex.Normal = QVector3D(mesh->mNormals[i].x, mesh->mNormals[i].y, mesh->mNormals[i].z); vertex.Normal = QVector3D(mesh->mNormals[i].x, mesh->mNormals[i].y, mesh->mNormals[i].z);
@ -278,6 +294,14 @@ Drawable* Model::processMesh(aiMesh* mesh, const aiScene* scene, aiMatrix4x4 mod
vector.setY(mesh->mVertices[i].y); vector.setY(mesh->mVertices[i].y);
vector.setZ(mesh->mVertices[i].z); vector.setZ(mesh->mVertices[i].z);
vertex.Position = vector; vertex.Position = vector;
minX = std::min(minX, vertex.Position.x());
maxX = std::max(maxX, vertex.Position.x());
minY = std::min(minY, vertex.Position.y());
maxY = std::max(maxY, vertex.Position.y());
minZ = std::min(minZ, vertex.Position.z());
maxZ = std::max(maxZ, vertex.Position.z());
// ·¨ÏòÁ¿ // ·¨ÏòÁ¿
if (mesh->mNormals) { if (mesh->mNormals) {
vector.setX(mesh->mNormals[i].x); vector.setX(mesh->mNormals[i].x);

View File

@ -8,6 +8,8 @@
class Model class Model
{ {
public: public:
std::vector<QVector3D> AABB;
void draw(); void draw();
void drawShadow(); void drawShadow();
void destroy(); void destroy();
@ -29,6 +31,13 @@ private:
QVector<Drawable*> meshes; //网格 QVector<Drawable*> meshes; //网格
QDir directory; //模型所在路径 QDir directory; //模型所在路径
float minX = std::numeric_limits<float>::max();
float maxX = std::numeric_limits<float>::min();
float minY = std::numeric_limits<float>::max();
float maxY = std::numeric_limits<float>::min();
float minZ = std::numeric_limits<float>::max();
float maxZ = std::numeric_limits<float>::min();
//递归遍历结点 //递归遍历结点
void processNode(aiNode* node, const aiScene* scene, aiMatrix4x4 mat4 = aiMatrix4x4()); void processNode(aiNode* node, const aiScene* scene, aiMatrix4x4 mat4 = aiMatrix4x4());

View File

@ -5,10 +5,13 @@
#include <sstream> #include <sstream>
#include <QScreen> #include <QScreen>
#include <QGuiApplication> #include <QGuiApplication>
#include <random>
RendererWidget::RendererWidget(QWidget* parent) RendererWidget::RendererWidget(QWidget* parent)
: QOpenGLWidget(parent), camera(QVector3D(0.0f, 100.0f, 0.0f)) : QOpenGLWidget(parent)
, camera(QVector3D(0.0f, 100.0f, 0.0f))
, light(&camera)
{ {
startTimer(1000 / QGuiApplication::primaryScreen()->refreshRate()); startTimer(1000 / QGuiApplication::primaryScreen()->refreshRate());
lastFrame = std::clock(); lastFrame = std::clock();
@ -40,18 +43,21 @@ RendererWidget::~RendererWidget()
} }
} }
QOpenGLTexture randomMap(QOpenGLTexture::Target2D);
void RendererWidget::initializeGL() void RendererWidget::initializeGL()
{ {
initializeOpenGLFunctions(); initializeOpenGLFunctions();
qDebug() << "GL_VERSION" << (char*)glGetString(GL_VERSION); qDebug() << "GL_VERSION" << (char*)glGetString(GL_VERSION);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glClearColor(0, 0, 0, 1); glClearColor(0, 0, 0, 1);
shadowProgramPtr = new QOpenGLShaderProgram; shadowProgramPtr = new QOpenGLShaderProgram;
if (!shadowProgramPtr->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/model_shadow.vert")) if (!shadowProgramPtr->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/model_shadow.vert"))
qDebug() << "ERROR:" << shadowProgramPtr->log(); qDebug() << "ERROR:" << shadowProgramPtr->log();
if (!shadowProgramPtr->addShaderFromSourceFile(QOpenGLShader::Geometry, ":/Shaders/model_shadow.geom"))
qDebug() << "ERROR:" << shadowProgramPtr->log();
if (!shadowProgramPtr->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/Shaders/model_shadow.frag")) if (!shadowProgramPtr->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/Shaders/model_shadow.frag"))
qDebug() << "ERROR:" << shadowProgramPtr->log(); qDebug() << "ERROR:" << shadowProgramPtr->log();
if (!shadowProgramPtr->link()) if (!shadowProgramPtr->link())
@ -79,6 +85,18 @@ void RendererWidget::initializeGL()
if (!paintingCompProgramPtr->link()) if (!paintingCompProgramPtr->link())
qDebug() << "ERROR:" << paintingCompProgramPtr->log(); qDebug() << "ERROR:" << paintingCompProgramPtr->log();
depthInitProgramPtr = new QOpenGLShaderProgram;
if (!depthInitProgramPtr->addShaderFromSourceFile(QOpenGLShader::Compute, ":/Shaders/depth_init.comp"))
qDebug() << "ERROR:" << depthInitProgramPtr->log();
if (!depthInitProgramPtr->link())
qDebug() << "ERROR:" << depthInitProgramPtr->log();
depthMipmapProgramPtr = new QOpenGLShaderProgram;
if (!depthMipmapProgramPtr->addShaderFromSourceFile(QOpenGLShader::Compute, ":/Shaders/depth_mipmap.comp"))
qDebug() << "ERROR:" << depthMipmapProgramPtr->log();
if (!depthMipmapProgramPtr->link())
qDebug() << "ERROR:" << depthMipmapProgramPtr->log();
finalProgramPtr = new QOpenGLShaderProgram; finalProgramPtr = new QOpenGLShaderProgram;
if (!finalProgramPtr->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/final.vert")) if (!finalProgramPtr->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/Shaders/final.vert"))
qDebug() << "ERROR:" << finalProgramPtr->log(); qDebug() << "ERROR:" << finalProgramPtr->log();
@ -88,12 +106,50 @@ void RendererWidget::initializeGL()
qDebug() << "ERROR:" << finalProgramPtr->log(); qDebug() << "ERROR:" << finalProgramPtr->log();
shadowProgramPtr->bind();
glGenBuffers(1, &lightSpaceMatricesUBO);
glBindBuffer(GL_UNIFORM_BUFFER, lightSpaceMatricesUBO);
glBufferData(GL_UNIFORM_BUFFER, sizeof(QMatrix4x4) * 16, nullptr, GL_STATIC_DRAW);
glBindBufferBase(GL_UNIFORM_BUFFER, 0, lightSpaceMatricesUBO);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
shadowProgramPtr->release();
depthInitProgramPtr->bind();
depthInitProgramPtr->setUniformValue("depthBuffer", 6);
depthInitProgramPtr->release();
finalProgramPtr->bind(); finalProgramPtr->bind();
finalProgramPtr->setUniformValue("gBaseColor", 0); finalProgramPtr->setUniformValue("gBaseColor", 0);
finalProgramPtr->setUniformValue("gNormal", 1); finalProgramPtr->setUniformValue("gNormal", 1);
finalProgramPtr->setUniformValue("gPosition", 2); finalProgramPtr->setUniformValue("gPosition", 2);
finalProgramPtr->setUniformValue("gMetallicRoughness", 3); finalProgramPtr->setUniformValue("gMetallicRoughness", 3);
finalProgramPtr->setUniformValue("gShadowMap", 4); finalProgramPtr->setUniformValue("gDepth", 4);
finalProgramPtr->setUniformValue("gShadowMap", 5);
//std::vector<QVector3D> rsmSampleCoordsAndWeights;
//std::default_random_engine e;
//std::uniform_real_distribution<float> u(0, 1);
//int rsmSampleNum = 50;
//finalProgramPtr->setUniformValue("rsmSampleNum", rsmSampleNum);
//for (int i = 0; i < rsmSampleNum; ++i)
//{
// float xi1 = u(e);
// float xi2 = u(e);
// rsmSampleCoordsAndWeights.push_back(QVector3D(xi1 * sin(2 * M_PI * xi2), xi1 * cos(2 * M_PI * xi2), xi1 * xi1));
//}
////QOpenGLTexture randomMap(QOpenGLTexture::Target2D);
//randomMap.create();
//randomMap.setSize(rsmSampleCoordsAndWeights.size());
//randomMap.setFormat(QOpenGLTexture::RGB8_UNorm);
//randomMap.allocateStorage();
//randomMap.setData(QOpenGLTexture::RGB, QOpenGLTexture::Float32, rsmSampleCoordsAndWeights.data());
//randomMap.setMinMagFilters(QOpenGLTexture::Nearest, QOpenGLTexture::Nearest);
finalProgramPtr->release(); finalProgramPtr->release();
@ -101,7 +157,8 @@ void RendererWidget::initializeGL()
paintingHelper = new PaintingHelper(QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_4_5_Compatibility>()); paintingHelper = new PaintingHelper(QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_4_5_Compatibility>());
model = new Model("Models/Sponza/Sponza.gltf", context(), modelProgramPtr, paintingProgramPtr, shadowProgramPtr, paintingHelper); model = new Model("Models/Sponza/Sponza.gltf", context(), modelProgramPtr, paintingProgramPtr, shadowProgramPtr, paintingHelper);
light.model = model;
qDebug() << model->AABB;
paintingHelper->allocateBuffers(); paintingHelper->allocateBuffers();
paintingCompProgramPtr->bind(); paintingCompProgramPtr->bind();
@ -137,39 +194,59 @@ void RendererWidget::initializeGL()
} }
QVector3D lightPositions[] = { 2000 * QVector3D(0.2, 4, 1).normalized(), QVector3D(100,100,100) ,QVector3D(-100,100,100) ,QVector3D(100,100,-100) }; 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) }; QVector3D lightColors[] = { 20 * 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; static float sunPitch = 90, sunYaw = 80;
static int sunSpeed = 10;
void RendererWidget::paintGL() void RendererWidget::paintGL()
{ {
QMatrix4x4 lightProjection; QMatrix4x4 lightProjection;
lightProjection.ortho(-1200.0f, 1200.0f, -900.0f, 900.0f, 100.f, 5000.0f); lightProjection.ortho(-1200.0f, 1200.0f, -900.0f, 900.0f, -2000.f, 5000.0f);
light.lightDirection.setX(cos(qDegreesToRadians(sunPitch)) * cos(qDegreesToRadians(sunYaw)));
light.lightDirection.setY(sin(qDegreesToRadians(sunPitch)));
light.lightDirection.setZ(cos(qDegreesToRadians(sunPitch)) * sin(qDegreesToRadians(sunYaw)));
light.lightDirection.normalize();
lightPositions[0].setX(cos(qDegreesToRadians(sunPitch)) * cos(qDegreesToRadians(sunYaw))); lightPositions[0].setX(cos(qDegreesToRadians(sunPitch)) * cos(qDegreesToRadians(sunYaw)));
lightPositions[0].setY(sin(qDegreesToRadians(sunPitch))); lightPositions[0].setY(sin(qDegreesToRadians(sunPitch)));
lightPositions[0].setZ(cos(qDegreesToRadians(sunPitch)) * sin(qDegreesToRadians(sunYaw))); lightPositions[0].setZ(cos(qDegreesToRadians(sunPitch)) * sin(qDegreesToRadians(sunYaw)));
lightPositions[0] *= 2000; //lightPositions[0] *= 2000;
QMatrix4x4 lightView; QMatrix4x4 lightView;
lightView.lookAt(lightPositions[0], QVector3D(0, 0, 0), QVector3D(0, 1, 0)); lightView.lookAt(lightPositions[0], QVector3D(0, 0, 0), QVector3D(0, 1, 0));
if (shadowFboPtr->bind())
const std::vector<QMatrix4x4> lightMatrices = light.getLightSpaceMatrices();
//qDebug() << lightMatrices;
glBindBuffer(GL_UNIFORM_BUFFER, lightSpaceMatricesUBO);
for (size_t i = 0; i < lightMatrices.size(); i++)
{ {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glBufferSubData(GL_UNIFORM_BUFFER, i * 16 * sizeof(GLfloat), 16 * sizeof(GLfloat), lightMatrices[i].data());
}
//glBufferSubData(GL_UNIFORM_BUFFER, 0 * 16 * sizeof(GLfloat), 16 * sizeof(GLfloat), (lightProjection * lightView).data());
glBindBuffer(GL_UNIFORM_BUFFER, 0);
{
glBindFramebuffer(GL_FRAMEBUFFER, shadowFboHandle);
glViewport(0, 0, shadowMapResolution, shadowMapResolution); glViewport(0, 0, shadowMapResolution, shadowMapResolution);
shadowProgramPtr->bind(); glClear(GL_DEPTH_BUFFER_BIT);
/*shadowProgramPtr->bind();
shadowProgramPtr->setUniformValue("projection", lightProjection); shadowProgramPtr->setUniformValue("projection", lightProjection);
shadowProgramPtr->setUniformValue("view", lightView); shadowProgramPtr->setUniformValue("view", lightView);
shadowProgramPtr->release(); shadowProgramPtr->setUniformValue("mainLightPositon", lightPositions[0]);
shadowProgramPtr->setUniformValue("mainLightColor", lightColors[0]);
shadowProgramPtr->release();*/
//glCullFace(GL_FRONT);
model->drawShadow(); model->drawShadow();
shadowFboPtr->release(); //glCullFace(GL_BACK);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
} }
QMatrix4x4 projection;
projection.perspective(camera.Zoom, camera.Ratio, camera.NearPlane, camera.FarPlane);
QMatrix4x4 view = camera.GetViewMatrix();
if (fboPtr->bind()) if (fboPtr->bind())
{ {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, frameWidth, frameHeight); glViewport(0, 0, frameWidth, frameHeight);
QMatrix4x4 projection;
projection.perspective(camera.Zoom, (float)width() / (float)height(), 10.f, 10000.0f);
QMatrix4x4 view = camera.GetViewMatrix();
modelProgramPtr->bind(); modelProgramPtr->bind();
modelProgramPtr->setUniformValue("projection", projection); modelProgramPtr->setUniformValue("projection", projection);
modelProgramPtr->setUniformValue("view", view); modelProgramPtr->setUniformValue("view", view);
@ -178,14 +255,15 @@ void RendererWidget::paintGL()
paintingProgramPtr->setUniformValue("projection", projection); paintingProgramPtr->setUniformValue("projection", projection);
paintingProgramPtr->setUniformValue("view", view); paintingProgramPtr->setUniformValue("view", view);
paintingProgramPtr->release(); paintingProgramPtr->release();
model->draw(); model->draw();
fboPtr->release(); fboPtr->release();
} }
paintingCompProgramPtr->bind(); paintingCompProgramPtr->bind();
glActiveTexture(GL_TEXTURE4); //glActiveTexture(GL_TEXTURE4);
glBindTexture(GL_TEXTURE_2D, gbuffers[4]); //glBindTexture(GL_TEXTURE_2D, gbuffers[4]);
glBindImageTexture(0, gbuffers[0], 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA8); 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(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(2, gbuffers[4], 0, GL_FALSE, 0, GL_READ_WRITE, GL_R16UI);
@ -193,21 +271,44 @@ void RendererWidget::paintGL()
glDispatchCompute(ceil(frameWidth / 8.), ceil(frameHeight / 8.), 1); glDispatchCompute(ceil(frameWidth / 8.), ceil(frameHeight / 8.), 1);
//glDispatchCompute(1,1, 1); //glDispatchCompute(1,1, 1);
paintingCompProgramPtr->release();
depthInitProgramPtr->bind();
glActiveTexture(GL_TEXTURE6);
glBindTexture(GL_TEXTURE_2D, gbuffers[6]);
glBindImageTexture(0, gbuffers[7], 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32F);
glDispatchCompute(ceil(depthWidth / 8.), ceil(depthHeight / 8.), 1);
depthInitProgramPtr->release();
depthMipmapProgramPtr->bind();
for (int i = 0; i <= 3; i++)
glBindImageTexture(i, gbuffers[7], i, GL_FALSE, 0, GL_READ_WRITE, GL_R32F);
glDispatchCompute(ceil(depthWidth / 2 / 8.), ceil(depthHeight / 2 / 8.), 1);
for (int i = 0; i <= 3; i++)
glBindImageTexture(i, gbuffers[7], i + 3, GL_FALSE, 0, GL_READ_WRITE, GL_R32F);
glDispatchCompute(ceil(depthWidth / 2 / 8 / 8.), ceil(depthHeight / 2 / 8 / 8.), 1);
depthMipmapProgramPtr->release();
//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); glViewport(0, 0, frameWidth, frameHeight);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
QOpenGLVertexArrayObject::Binder vaoBinder(&quadVAO); QOpenGLVertexArrayObject::Binder vaoBinder(&quadVAO);
finalProgramPtr->bind(); finalProgramPtr->bind();
finalProgramPtr->setUniformValue("camPos", camera.Position); finalProgramPtr->setUniformValue("camPos", camera.Position);
finalProgramPtr->setUniformValue("lightSpaceMatrix", lightProjection * lightView); //finalProgramPtr->setUniformValue("lightSpaceMatrix", lightProjection * lightView);
//lightPositions[0] = camera.Position; //lightPositions[0] = camera.Position;
finalProgramPtr->setUniformValueArray("lightPositions", lightPositions, 4); //finalProgramPtr->setUniformValueArray("lightPositions", lightPositions, 4);
finalProgramPtr->setUniformValueArray("lightColors", lightColors, 4); //finalProgramPtr->setUniformValueArray("lightColors", lightColors, 4);
finalProgramPtr->setUniformValue("view", view);
finalProgramPtr->setUniformValue("farPlane", camera.FarPlane);
finalProgramPtr->setUniformValueArray("shadowCascadePlaneDistances", light.shadowCascadeLevels.data(), light.shadowCascadeLevels.size(), 1);
finalProgramPtr->setUniformValueArray("shadowBiases", light.frustumSizes.data(), light.frustumSizes.size(), 1);
//qDebug() << light.frustumSizes;
finalProgramPtr->setUniformValue("shadowCascadeCount", (GLint)light.shadowCascadeLevels.size());
finalProgramPtr->setUniformValue("mainLightDirection", light.lightDirection);
finalProgramPtr->setUniformValue("mainLightRadiance", lightColors[0]);
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, gbuffers[0]); glBindTexture(GL_TEXTURE_2D, gbuffers[0]);
glActiveTexture(GL_TEXTURE1); glActiveTexture(GL_TEXTURE1);
@ -217,7 +318,9 @@ void RendererWidget::paintGL()
glActiveTexture(GL_TEXTURE3); glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, gbuffers[3]); glBindTexture(GL_TEXTURE_2D, gbuffers[3]);
glActiveTexture(GL_TEXTURE4); glActiveTexture(GL_TEXTURE4);
glBindTexture(GL_TEXTURE_2D, shadowGbuffers[3]); glBindTexture(GL_TEXTURE_2D, gbuffers[7]);
glActiveTexture(GL_TEXTURE5);
glBindTexture(GL_TEXTURE_2D_ARRAY, shadowGbuffer);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
finalProgramPtr->release(); finalProgramPtr->release();
} }
@ -227,24 +330,23 @@ void RendererWidget::resizeGL(int width, int height)
frameWidth = devicePixelRatioF() * width; frameWidth = devicePixelRatioF() * width;
frameHeight = devicePixelRatioF() * height; frameHeight = devicePixelRatioF() * height;
qDebug() << frameWidth << "x" << frameHeight; qDebug() << frameWidth << "x" << frameHeight;
camera.Ratio = (float)frameWidth / (float)frameHeight;
//qDebug() << devicePixelRatioF() << width << height; //qDebug() << devicePixelRatioF() << width << height;
//glViewport(0, 0, (GLint)devicePixelRatio()*width, (GLint)devicePixelRatio()*height); //glViewport(0, 0, (GLint)devicePixelRatio()*width, (GLint)devicePixelRatio()*height);
if (fboPtr != nullptr) if (fboPtr != nullptr)
{
glDeleteTextures(7, gbuffers + 1);
delete fboPtr; delete fboPtr;
fboPtr = new QOpenGLFramebufferObject(frameWidth, frameHeight, QOpenGLFramebufferObject::Depth, GL_TEXTURE_2D); }
fboPtr = new QOpenGLFramebufferObject(frameWidth, frameHeight, QOpenGLFramebufferObject::NoAttachment, GL_TEXTURE_2D);
if (fboPtr->bind()) if (fboPtr->bind())
{ {
/*fboPtr->addColorAttachment(frameWidth, frameHeight, GL_RGB16F);
fboPtr->addColorAttachment(frameWidth, frameHeight, GL_RGB16F);
fboPtr->addColorAttachment(frameWidth, frameHeight, GL_RG8);
fboPtr->addColorAttachment(frameWidth, frameHeight, GL_R16F);
fboPtr->addColorAttachment(frameWidth, frameHeight, GL_RG16F);*/
//BaseColor //BaseColor
gbuffers[0] = fboPtr->texture(); gbuffers[0] = fboPtr->texture();
glGenTextures(5, gbuffers + 1); glGenTextures(7, gbuffers + 1);
//Normal //Normal
glBindTexture(GL_TEXTURE_2D, gbuffers[1]); glBindTexture(GL_TEXTURE_2D, gbuffers[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, frameWidth, frameHeight, 0, GL_RGB, GL_FLOAT, NULL); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, frameWidth, frameHeight, 0, GL_RGB, GL_FLOAT, NULL);
@ -275,6 +377,30 @@ void RendererWidget::resizeGL(int width, int height)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 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_MAG_FILTER, GL_NEAREST);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT5, GL_TEXTURE_2D, gbuffers[5], 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT5, GL_TEXTURE_2D, gbuffers[5], 0);
//Depth
glBindTexture(GL_TEXTURE_2D, gbuffers[6]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32F, frameWidth, frameHeight, 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);
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, std::begin({ 1.0f, 1.0f, 1.0f, 1.0f }));
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, gbuffers[6], 0);
depthWidth = ceil(frameWidth / 64.) * 64;
depthHeight = ceil(frameHeight / 64.) * 64;
qDebug() << depthWidth << depthHeight;
glBindTexture(GL_TEXTURE_2D, gbuffers[7]);
for (int i = 0; i <= 6; i++)
glTexImage2D(GL_TEXTURE_2D, i, GL_R32F, depthWidth / pow(2, i), depthHeight / pow(2, i), 0, GL_RED, GL_FLOAT, NULL);
//glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, depthWidth, depthHeight, 0, GL_RED, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 6);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST_MIPMAP_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);
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, std::begin({ 1.0f, 1.0f, 1.0f, 1.0f }));
GLenum attachments[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5 }; GLenum attachments[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5 };
glDrawBuffers(6, attachments); glDrawBuffers(6, attachments);
@ -285,46 +411,43 @@ void RendererWidget::resizeGL(int width, int height)
fboPtr->release(); fboPtr->release();
} }
if (shadowFboPtr != nullptr)
delete shadowFboPtr;
shadowMapResolution = 1 * std::max(frameWidth, frameHeight);
shadowFboPtr = new QOpenGLFramebufferObject(shadowMapResolution, shadowMapResolution);
if (shadowFboPtr->bind())
if (shadowFboHandle != 0)
{ {
glDeleteTextures(1, &shadowGbuffer);
glDeleteFramebuffers(1, &shadowFboHandle);
}
shadowGbuffers[0] = shadowFboPtr->texture(); //shadowMapResolution = 1.5 * std::max(frameWidth, frameHeight);
shadowMapResolution = 4096;
glGenTextures(3, shadowGbuffers + 1); glGenFramebuffers(1, &shadowFboHandle);
//Normal {
glBindTexture(GL_TEXTURE_2D, shadowGbuffers[1]); glBindFramebuffer(GL_FRAMEBUFFER, shadowFboHandle);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, shadowMapResolution, shadowMapResolution, 0, GL_RGB, GL_FLOAT, NULL); glGenTextures(1, &shadowGbuffer);
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 //Depth
glBindTexture(GL_TEXTURE_2D, shadowGbuffers[3]); glBindTexture(GL_TEXTURE_2D_ARRAY, shadowGbuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, glTexImage3D(
shadowMapResolution, shadowMapResolution, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT32F, shadowMapResolution, shadowMapResolution, int(light.shadowCascadeLevels.size()) + 1,
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 0, GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
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 }; /*glBindTexture(GL_TEXTURE_2D, shadowGbuffer);
glDrawBuffers(3, attachments); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32,
shadowMapResolution, shadowMapResolution, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);*/
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameterfv(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BORDER_COLOR, std::begin({ 1.0f, 1.0f, 1.0f, 1.0f }));
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, shadowGbuffer, 0);
//glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, shadowGbuffer, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
qDebug() << "ShadowFramebuffer not complete!"; qDebug() << "ShadowFramebuffer not complete!";
shadowFboPtr->release(); glBindFramebuffer(GL_FRAMEBUFFER, 0);
} }
@ -378,14 +501,14 @@ void RendererWidget::timerEvent(QTimerEvent* event)
camera.ProcessKeyboard(UP, deltaTime); camera.ProcessKeyboard(UP, deltaTime);
} }
static int sunSpeed = 10;
sunPitch += sunSpeed * deltaTime ; sunPitch += sunSpeed * deltaTime;
if (sunPitch > 120 || sunPitch < 65) if (sunPitch > 120 || sunPitch < 65)
{ {
sunSpeed = -sunSpeed; sunSpeed = -sunSpeed;
sunPitch += sunSpeed * deltaTime; sunPitch += sunSpeed * deltaTime;
} }
repaint(); repaint();
} }

View File

@ -8,6 +8,7 @@
#include <QOpenGLFramebufferObject> #include <QOpenGLFramebufferObject>
#include <QKeyEvent> #include <QKeyEvent>
#include "Camera.h" #include "Camera.h"
#include "Light.h"
#include "Model.h" #include "Model.h"
#include "PaintingHelper.h" #include "PaintingHelper.h"
@ -31,20 +32,26 @@ protected:
private: private:
int frameWidth, frameHeight; int frameWidth, frameHeight;
int depthWidth, depthHeight;
QSet<int> pressedKeys; QSet<int> pressedKeys;
Camera camera; Camera camera;
Light light;
clock_t lastFrame; clock_t lastFrame;
float deltaTime; float deltaTime;
int shadowMapResolution; int shadowMapResolution;
QOpenGLShaderProgram* shadowProgramPtr = nullptr; QOpenGLShaderProgram* shadowProgramPtr = nullptr;
QOpenGLShaderProgram* modelProgramPtr = nullptr; QOpenGLShaderProgram* modelProgramPtr = nullptr;
QOpenGLShaderProgram* paintingProgramPtr = nullptr; QOpenGLShaderProgram* paintingProgramPtr = nullptr;
QOpenGLShaderProgram* paintingCompProgramPtr = nullptr; QOpenGLShaderProgram* paintingCompProgramPtr = nullptr;
QOpenGLShaderProgram* depthInitProgramPtr = nullptr;
QOpenGLShaderProgram* depthMipmapProgramPtr = nullptr;
QOpenGLShaderProgram* finalProgramPtr = nullptr; QOpenGLShaderProgram* finalProgramPtr = nullptr;
QOpenGLFramebufferObject* fboPtr = nullptr; QOpenGLFramebufferObject* fboPtr = nullptr;
QOpenGLFramebufferObject* shadowFboPtr = nullptr; GLuint gbuffers[8];
GLuint gbuffers[6]; GLuint shadowFboHandle = 0;
GLuint shadowGbuffers[4]; GLuint shadowGbuffer;
GLuint lightSpaceMatricesUBO;
QOpenGLBuffer quadVBO; QOpenGLBuffer quadVBO;
QOpenGLVertexArrayObject quadVAO; QOpenGLVertexArrayObject quadVAO;
Model* model; Model* model;

View File

@ -0,0 +1,14 @@
#version 450 core
layout (local_size_x = 8, local_size_y = 8) in;
uniform sampler2D depthBuffer;
layout(r32f, binding = 0) uniform image2D gDepth;
void main()
{
ivec2 pixelLocation = ivec2(gl_GlobalInvocationID.xy);
float depth = textureLod(depthBuffer, vec2(pixelLocation)/textureSize(depthBuffer, 0), 0).r;
imageStore(gDepth, pixelLocation, vec4(depth));
}

View File

@ -0,0 +1,31 @@
#version 450 core
layout (local_size_x = 8, local_size_y = 8) in;
layout(r32f, binding = 0) uniform image2D gDepth[4];
void main()
{
ivec2 targetLocation = ivec2(gl_GlobalInvocationID.xy);
ivec2 sourceLocation = targetLocation * 2;
float depth0 = min(imageLoad(gDepth[0], sourceLocation).r, imageLoad(gDepth[0], sourceLocation+ivec2(0,1)).r);
float depth1 = min(imageLoad(gDepth[0], sourceLocation+ivec2(1,0)).r, imageLoad(gDepth[0], sourceLocation+ivec2(1,1)).r);
imageStore(gDepth[1], targetLocation, vec4(min(depth0,depth1)));
if(targetLocation.x%2==0 && targetLocation.y%2==0)
{
sourceLocation = targetLocation;
targetLocation /= 2;
float depth0 = min(imageLoad(gDepth[1], sourceLocation).r, imageLoad(gDepth[1], sourceLocation+ivec2(0,1)).r);
float depth1 = min(imageLoad(gDepth[1], sourceLocation+ivec2(1,0)).r, imageLoad(gDepth[1], sourceLocation+ivec2(1,1)).r);
imageStore(gDepth[2], targetLocation, vec4(min(depth0,depth1)));
if(targetLocation.x%2==0 && targetLocation.y%2==0)
{
sourceLocation = targetLocation;
targetLocation /= 2;
float depth0 = min(imageLoad(gDepth[2], sourceLocation).r, imageLoad(gDepth[2], sourceLocation+ivec2(0,1)).r);
float depth1 = min(imageLoad(gDepth[2], sourceLocation+ivec2(1,0)).r, imageLoad(gDepth[2], sourceLocation+ivec2(1,1)).r);
imageStore(gDepth[3], targetLocation, vec4(min(depth0,depth1)));
}
}
}

View File

@ -8,12 +8,23 @@ uniform sampler2D gBaseColor;
uniform sampler2D gNormal; uniform sampler2D gNormal;
uniform sampler2D gPosition; uniform sampler2D gPosition;
uniform sampler2D gMetallicRoughness; uniform sampler2D gMetallicRoughness;
uniform sampler2D gShadowMap; uniform sampler2D gDepth;
uniform sampler2DArray gShadowMap;
layout (std140, binding = 0) uniform LightSpaceMatrices
{
mat4 lightSpaceMatrices[16];
};
uniform mat4 view;
uniform float farPlane;
uniform float shadowCascadePlaneDistances[16];
uniform float shadowBiases[16];
uniform int shadowCascadeCount;
uniform vec3 mainLightDirection;
uniform vec3 mainLightRadiance;
// lights // lights
uniform vec3 lightPositions[4]; //uniform vec3 lightPositions[4];
uniform vec3 lightColors[4]; //uniform vec3 lightColors[4];
uniform mat4 lightSpaceMatrix;
uniform vec3 camPos; uniform vec3 camPos;
@ -61,55 +72,100 @@ vec3 fresnelSchlick(float cosTheta, vec3 F0)
float Calculate_Avg_Dblockreceiver(vec2 projCoords , int AvgTextureSize) float Calculate_Avg_Dblockreceiver(vec2 projCoords , int AvgTextureSize)
{ {
vec2 texelSize =1.0/ textureSize(gShadowMap, 0); vec2 texelSize =1.0/ textureSize(gShadowMap, 0).xy;
float result=0.0f; float result=0.0f;
for(int i=-AvgTextureSize;i<=AvgTextureSize;++i) for(int i=-AvgTextureSize;i<=AvgTextureSize;++i)
{ {
for(int j=-AvgTextureSize;j<=AvgTextureSize;j++) for(int j=-AvgTextureSize;j<=AvgTextureSize;j++)
{ {
result += texture(gShadowMap, projCoords+vec2(i,j)*texelSize).r; result += texture(gShadowMap, vec3( projCoords+vec2(i,j)*texelSize, 0)).r;
} }
} }
return result/(AvgTextureSize*AvgTextureSize*2*2); return result/(AvgTextureSize*AvgTextureSize*2*2);
} }
float ShadowCalculation(vec4 fragPosLightSpace, float bias) float ShadowCalculation(vec3 fragPosWorldSpace, vec3 normal)
{ {
// 执行透视除法 // select cascade layer
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w; vec4 fragPosViewSpace = view * vec4(fragPosWorldSpace, 1.0);
// 变换到[0,1]的范围 float depthValue = abs(fragPosViewSpace.z);
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); int layer = -1;
float shadow = 0; for (int i = 0; i < shadowCascadeCount; ++i)
{
if (depthValue < shadowCascadePlaneDistances[i])
{
layer = i;
break;
}
}
if (layer == -1)
{
layer = shadowCascadeCount;
}
// 检查当前片段是否在阴影中 int pcfRadius = 3;
//float shadow = 0;// currentDepth - bias > closestDepth ? 1.0 : 0.0; float normalBias = 4. /** (1+pcfRadius)*/ * shadowBiases[layer]*max((1.0 - dot(normal, mainLightDirection)), 0.1)/textureSize(gShadowMap, 0).x;
float fliterArea = 7; vec4 fragPosLightSpace = lightSpaceMatrices[layer] * vec4(fragPosWorldSpace+normal*normalBias, 1.0);
int fliterSingleX = int(fliterArea/2); // perform perspective divide
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
for(int i=-fliterSingleX;i<=fliterSingleX;++i) // transform to [0,1] range
{ projCoords = projCoords * 0.5 + 0.5;
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); // get depth of current fragment from light's perspective
//return clamp(shadow/(fliterArea*fliterArea),0.,1.); float currentDepth = projCoords.z;
// keep the shadow at 0.0 when outside the far_plane region of the light's frustum.
if (currentDepth > 1.0)
{
return 0.0;
}
// calculate bias (based on depth map resolution and slope)
//float bias = 1* max(0.05 * (1.0 - dot(normal, mainLightDirection)), 0.005);
//const float biasModifier = 0.5f;
// if (layer == shadowCascadeCount)
// {
// bias *= 1 / (farPlane * biasModifier);
// }
// else
// {
// bias *= 1 / (shadowCascadePlaneDistances[layer] * biasModifier);
// }
// PCF
float shadow = 0.0;
vec2 texelSize = 1.0 / vec2(textureSize(gShadowMap, 0));
for(int x = -pcfRadius; x <= pcfRadius; ++x)
{
for(int y = -pcfRadius; y <= pcfRadius; ++y)
{
float pcfDepth = texture(gShadowMap, vec3(projCoords.xy + vec2(x, y) * texelSize, layer)).r;
//shadow += (currentDepth - bias) > pcfDepth ? 1.0 : 0.0;
shadow += currentDepth > pcfDepth ? 1.0 : 0.0;
}
}
shadow /= (2*pcfRadius+1)*(2*pcfRadius+1);
return shadow;
} }
void main() void main()
{ {
vec3 albedo = pow(texture(gBaseColor, TexCoords).rgb, vec3(2.2));
//FragColor = vec4(vec3(textureLod(gDepth, TexCoords, 1).x), 1.0);
//FragColor -= vec4(vec3(textureLod(gDepth, TexCoords, 0).x), 1.0);
//ivec2 depthCoords = ivec2(TexCoords*(textureSize(gDepth,0)-ivec2(1)) + vec2(0.5));
//float depth = texelFetch(gDepth, depthCoords/64, 6).x;
//depth -= texelFetch(gDepth, depthCoords, 0).x;
//FragColor = vec4(vec3(depth*10000),1);
//FragColor = vec4(vec3(textureSize(gShadowMap, 0)-vec3(1)),1);
//FragColor = vec4(texture(gBaseColor, TexCoords).rgb, 1);
//return;
vec3 albedo = pow(texture(gBaseColor, TexCoords).rgb, vec3(2.2));
float metallic = texture(gMetallicRoughness, TexCoords).r; float metallic = texture(gMetallicRoughness, TexCoords).r;
float roughness = texture(gMetallicRoughness, TexCoords).g; float roughness = texture(gMetallicRoughness, TexCoords).g;
@ -119,7 +175,7 @@ void main()
if(WorldPos==vec3(0)) if(WorldPos==vec3(0))
{ {
vec3 color = lightColors[0]; vec3 color = mainLightRadiance;
color = color / (color + vec3(1.0)); color = color / (color + vec3(1.0));
color = pow(color, vec3(1.0/2.2)); color = pow(color, vec3(1.0/2.2));
@ -128,7 +184,6 @@ void main()
return; return;
} }
vec4 FragPosLightSpace = lightSpaceMatrix * vec4(WorldPos, 1.0);
vec3 V = normalize(camPos - WorldPos); vec3 V = normalize(camPos - WorldPos);
@ -138,13 +193,13 @@ void main()
// reflectance equation // reflectance equation
vec3 Lo = vec3(0.0); vec3 Lo = vec3(0.0);
int i = 0;
// calculate per-light radiance // calculate per-light radiance
vec3 L = normalize(lightPositions[i] - WorldPos); vec3 L = normalize(mainLightDirection);
vec3 H = normalize(V + L); vec3 H = normalize(V + L);
float distance = length(lightPositions[i] - WorldPos); //float distance = length(lightPositions[i] - WorldPos);
float attenuation = 1.0 / (distance * distance); //float attenuation = 1.0 / (distance * distance);
vec3 radiance = lightColors[i] * attenuation; vec3 radiance = mainLightRadiance ;//* attenuation;
// cook-torrance brdf // cook-torrance brdf
float NDF = DistributionGGX(N, H, roughness); float NDF = DistributionGGX(N, H, roughness);
@ -166,16 +221,22 @@ void main()
vec3 ambient = vec3(0.03) * albedo; 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;
//vec4 FragPosLightSpace = lightSpaceMatrix * vec4(WorldPos, 1.0);
//float bias = 0.08 * max(0.05 * (1.0 - dot(N, L)), 0.005);
float shadow = ShadowCalculation(WorldPos, N);
//vec3 color = ambient + Lo;
//vec3 color = indirect*1;
vec3 color = ambient + (1.0 - shadow) * Lo;
//vec3 color = (1.0 - shadow) * Lo;
//vec3 color = (1.0 - shadow) * Lo + indirect*10;
color = color / (color + vec3(1.0)); color = color / (color + vec3(1.0));
color = pow(color, vec3(1.0/2.2)); color = pow(color, vec3(1.0/2.2));
FragColor = vec4(color, 1.0); FragColor = vec4(color, 1.0);
//FragColor = vec4(vec3(shadow), 1); //FragColor = vec4(vec3(shadow), 1);
//FragColor = vec4(texture(gShadowMap, TexCoords).rgb, 1.0); //FragColor = vec4(texture(gShadowNormal, TexCoords).rgb, 1.0);
} }

View File

@ -1,42 +1,13 @@
#version 450 core #version 450 core
uniform sampler2D texture_basecolor; 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 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() void main()
{ {
//gBaseColor = vec4(1,0,0,1); //gBaseColor = vec4(1,0,0,1);
gBaseColor = texture(texture_basecolor, TexCoords); vec4 baseColor = texture(texture_basecolor, TexCoords);
if(gBaseColor.a<0.4) if(baseColor.a<0.4)
discard; discard;
gPosition = WorldPos;
gNormal = getNormalFromMap();
} }

View File

@ -0,0 +1,24 @@
#version 450 core
layout(triangles, invocations = 5) in;
layout(triangle_strip, max_vertices = 3) out;
layout (std140, binding = 0) uniform LightSpaceMatrices
{
mat4 lightSpaceMatrices[16];
};
in vec2 vTexCoords[];
out vec2 TexCoords;
void main()
{
for (int i = 0; i < 3; ++i)
{
TexCoords = vTexCoords[i];
gl_Position = lightSpaceMatrices[gl_InvocationID] * gl_in[i].gl_Position;
gl_Layer = gl_InvocationID;
EmitVertex();
}
EndPrimitive();
}

View File

@ -3,19 +3,12 @@ layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal; layout (location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords; layout (location = 2) in vec2 aTexCoords;
out vec2 TexCoords; out vec2 vTexCoords;
out vec3 WorldPos;
out vec3 Normal;
uniform mat4 model; uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main() void main()
{ {
TexCoords = aTexCoords; vTexCoords = aTexCoords;
WorldPos = vec3(model * vec4(aPos, 1.0)); gl_Position = model * vec4(aPos, 1.0);
Normal = mat3(model) * aNormal;
gl_Position = projection * view * vec4(WorldPos, 1.0);
} }