Starting to add cascading shadow maps
This commit is contained in:
@@ -535,8 +535,11 @@ template <typename T, size_t N> struct StaticArray {
|
||||
}
|
||||
}
|
||||
}
|
||||
constexpr StaticArray(const StaticArray& other) = default;
|
||||
constexpr StaticArray(StaticArray&& other) = default;
|
||||
constexpr ~StaticArray() {}
|
||||
|
||||
constexpr StaticArray& operator=(const StaticArray& other) = default;
|
||||
constexpr StaticArray& operator=(StaticArray&& other) = default;
|
||||
constexpr size_type size() const { return N; }
|
||||
constexpr pointer data() { return _data; }
|
||||
constexpr const_pointer data() const { return _data; }
|
||||
|
||||
@@ -84,7 +84,8 @@ BasePass::BasePass(Gfx::PGraphics graphics, PScene scene) : RenderPass(graphics)
|
||||
BasePass::~BasePass() {}
|
||||
|
||||
void BasePass::beginFrame(const Component::Camera& cam, const Component::Transform& transform) {
|
||||
viewParamsSet = createViewParamsSet(cam, transform);
|
||||
updateViewParameters(cam, transform);
|
||||
viewParamsSet = createViewParamsSet();
|
||||
|
||||
cameraPos = transform.getPosition();
|
||||
cameraForward = transform.getForward();
|
||||
|
||||
@@ -42,7 +42,8 @@ CachedDepthPass::CachedDepthPass(Gfx::PGraphics graphics, PScene scene) : Render
|
||||
CachedDepthPass::~CachedDepthPass() {}
|
||||
|
||||
void CachedDepthPass::beginFrame(const Component::Camera& cam, const Component::Transform& transform) {
|
||||
viewParamsSet = createViewParamsSet(cam, transform);
|
||||
updateViewParameters(cam, transform);
|
||||
viewParamsSet = createViewParamsSet();
|
||||
}
|
||||
|
||||
void CachedDepthPass::render() {
|
||||
|
||||
@@ -66,7 +66,8 @@ DepthCullingPass::DepthCullingPass(Gfx::PGraphics graphics, PScene scene) : Rend
|
||||
DepthCullingPass::~DepthCullingPass() {}
|
||||
|
||||
void DepthCullingPass::beginFrame(const Component::Camera& cam, const Component::Transform& transform) {
|
||||
viewParamsSet = createViewParamsSet(cam, transform);
|
||||
updateViewParameters(cam, transform);
|
||||
viewParamsSet = createViewParamsSet();
|
||||
}
|
||||
|
||||
void DepthCullingPass::render() {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "LightCullingPass.h"
|
||||
#include "Actor/CameraActor.h"
|
||||
#include "Component/Camera.h"
|
||||
#include "Component/Transform.h"
|
||||
#include "Graphics/Command.h"
|
||||
#include "Graphics/Graphics.h"
|
||||
#include "Graphics/Pipeline.h"
|
||||
@@ -15,7 +16,8 @@ LightCullingPass::LightCullingPass(Gfx::PGraphics graphics, PScene scene) : Rend
|
||||
LightCullingPass::~LightCullingPass() {}
|
||||
|
||||
void LightCullingPass::beginFrame(const Component::Camera& cam, const Component::Transform& transform) {
|
||||
viewParamsSet = createViewParamsSet(cam, transform);
|
||||
updateViewParameters(cam, transform);
|
||||
viewParamsSet = createViewParamsSet();
|
||||
|
||||
oLightIndexCounter->pipelineBarrier(Gfx::SE_ACCESS_MEMORY_WRITE_BIT | Gfx::SE_ACCESS_MEMORY_READ_BIT,
|
||||
Gfx::SE_PIPELINE_STAGE_COMPUTE_SHADER_BIT, Gfx::SE_ACCESS_MEMORY_WRITE_BIT,
|
||||
@@ -232,7 +234,8 @@ void LightCullingPass::setupFrustums() {
|
||||
numThreads = glm::ceil(glm::vec4(viewportWidth / (float)BLOCK_SIZE, viewportHeight / (float)BLOCK_SIZE, 1, 0));
|
||||
numThreadGroups = glm::ceil(glm::vec4(numThreads.x / (float)BLOCK_SIZE, numThreads.y / (float)BLOCK_SIZE, 1, 0));
|
||||
|
||||
viewParamsSet = createViewParamsSet(Component::Camera(), Component::Transform());
|
||||
updateViewParameters(Component::Camera(), Component::Transform());
|
||||
viewParamsSet = createViewParamsSet();
|
||||
|
||||
dispatchParamsLayout = graphics->createDescriptorLayout("pDispatchParams");
|
||||
dispatchParamsLayout->addDescriptorBinding(Gfx::DescriptorBinding{
|
||||
|
||||
@@ -65,8 +65,8 @@ RayTracingPass::RayTracingPass(Gfx::PGraphics graphics, PScene scene) : RenderPa
|
||||
static uint32 pass = 0;
|
||||
static Component::Transform lastCam;
|
||||
void RayTracingPass::beginFrame(const Component::Camera& cam, const Component::Transform& transform) {
|
||||
viewParamsSet = createViewParamsSet(cam, transform);
|
||||
if (lastCam.getPosition() != transform.getPosition() || lastCam.getForward() != transform.getForward()) {
|
||||
updateViewParameters(cam, transform);
|
||||
viewParamsSet = createViewParamsSet(); if (lastCam.getPosition() != transform.getPosition() || lastCam.getForward() != transform.getForward()) {
|
||||
lastCam = transform;
|
||||
pass = 0;
|
||||
}
|
||||
|
||||
@@ -27,8 +27,7 @@ void RenderPass::setResources(PRenderGraphResources _resources) { resources = _r
|
||||
|
||||
void RenderPass::setViewport(Gfx::PViewport _viewport) { viewport = _viewport; }
|
||||
|
||||
Gfx::PDescriptorSet RenderPass::createViewParamsSet(const Component::Camera& cam, const Component::Transform& transform)
|
||||
{
|
||||
void RenderPass::updateViewParameters(const Component::Camera& cam, const Component::Transform& transform) {
|
||||
auto screenDim = Vector2(static_cast<float>(viewport->getWidth()), static_cast<float>(viewport->getHeight()));
|
||||
Vector eyePos = transform.getPosition();
|
||||
Vector lookAt = eyePos + transform.getForward();
|
||||
@@ -48,24 +47,27 @@ Gfx::PDescriptorSet RenderPass::createViewParamsSet(const Component::Camera& cam
|
||||
.frameIndex = Gfx::getCurrentFrameIndex(),
|
||||
.time = static_cast<float>(Gfx::getCurrentFrameTime()),
|
||||
};
|
||||
}
|
||||
|
||||
Gfx::PDescriptorSet RenderPass::createViewParamsSet()
|
||||
{
|
||||
// screen space
|
||||
StaticArray<Vector4, 4> corners = {
|
||||
Vector4(0, 0, -1, 1),
|
||||
Vector4(screenDim.x, 0, -1, 1),
|
||||
Vector4(screenDim.y, 0, -1, 1),
|
||||
Vector4(screenDim.x, screenDim.y, -1, 1),
|
||||
};
|
||||
|
||||
for (uint32 i = 0; i < corners.size(); ++i) {
|
||||
Vector2 texCoord = Vector2(corners[i].x, corners[i].y) / screenDim;
|
||||
|
||||
Vector4 clip = Vector4(Vector2(texCoord.x, 1 - texCoord.y) * 2.0f - 1.0f, corners[i].z, corners[i].w);
|
||||
|
||||
Vector4 world = viewParams.inverseViewProjectionMatrix * clip;
|
||||
|
||||
corners[i] = world / world.w;
|
||||
}
|
||||
//StaticArray<Vector4, 4> corners = {
|
||||
// Vector4(0, 0, -1, 1),
|
||||
// Vector4(screenDim.x, 0, -1, 1),
|
||||
// Vector4(screenDim.y, 0, -1, 1),
|
||||
// Vector4(screenDim.x, screenDim.y, -1, 1),
|
||||
//};
|
||||
//
|
||||
//for (uint32 i = 0; i < corners.size(); ++i) {
|
||||
// Vector2 texCoord = Vector2(corners[i].x, corners[i].y) / screenDim;
|
||||
//
|
||||
// Vector4 clip = Vector4(Vector2(texCoord.x, 1 - texCoord.y) * 2.0f - 1.0f, corners[i].z, corners[i].w);
|
||||
//
|
||||
// Vector4 world = viewParams.inverseViewProjectionMatrix * clip;
|
||||
//
|
||||
// corners[i] = world / world.w;
|
||||
//}
|
||||
|
||||
// extract_planes_from_view_projection_matrix(viewParams.viewProjectionMatrix, viewParams.viewFrustum);
|
||||
|
||||
|
||||
@@ -27,7 +27,8 @@ class RenderPass {
|
||||
void setViewport(Gfx::PViewport _viewport);
|
||||
|
||||
protected:
|
||||
Gfx::PDescriptorSet createViewParamsSet(const Component::Camera& cam, const Component::Transform& transform);
|
||||
void updateViewParameters(const Component::Camera& cam, const Component::Transform& transform);
|
||||
Gfx::PDescriptorSet createViewParamsSet();
|
||||
struct Plane {
|
||||
Vector n;
|
||||
float d;
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
#include "ShadowPass.h"
|
||||
#include "Graphics/Enums.h"
|
||||
#include "Graphics/Graphics.h"
|
||||
#include "Graphics/Initializer.h"
|
||||
#include "Graphics/Shader.h"
|
||||
#include <glm/ext/matrix_transform.hpp>
|
||||
#include <glm/matrix.hpp>
|
||||
|
||||
using namespace Seele;
|
||||
|
||||
@@ -39,126 +43,214 @@ ShadowPass::ShadowPass(Gfx::PGraphics graphics, PScene scene) : RenderPass(graph
|
||||
|
||||
ShadowPass::~ShadowPass() {}
|
||||
|
||||
void ShadowPass::beginFrame(const Component::Camera&, const Component::Transform&) {}
|
||||
void ShadowPass::beginFrame(const Component::Camera& camera, const Component::Transform& transform) {
|
||||
uint32 cascadeDim = SHADOW_MAP_SIZE;
|
||||
float cascadeSplits[NUM_CASCADES];
|
||||
|
||||
float nearClip = camera.nearPlane;
|
||||
float farClip = camera.farPlane;
|
||||
float clipRange = farClip - nearClip;
|
||||
|
||||
float minZ = nearClip;
|
||||
float maxZ = nearClip + clipRange;
|
||||
|
||||
float range = maxZ - minZ;
|
||||
float ratio = maxZ / minZ;
|
||||
constexpr float cascadeSplitLambda = 0.95f;
|
||||
for (uint32 i = 0; i < NUM_CASCADES; ++i) {
|
||||
cascades[i].shadowMaps = graphics->createTexture2D(TextureCreateInfo{
|
||||
.format = Gfx::SE_FORMAT_D32_SFLOAT,
|
||||
.width = cascadeDim,
|
||||
.height = cascadeDim,
|
||||
.elements = (uint32)scene->getLightEnvironment()->getNumDirectionalLights(),
|
||||
.usage = Gfx::SE_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | Gfx::SE_IMAGE_USAGE_SAMPLED_BIT,
|
||||
.name = "ShadowMapCascade",
|
||||
});
|
||||
cascades[i].views.clear();
|
||||
for (uint32 j = 0; j < cascades[i].shadowMaps->getNumLayers(); ++j) {
|
||||
cascades[i].views.add(cascades[i].shadowMaps->createTextureView(0, 1, j, 1));
|
||||
}
|
||||
cascadeDim /= 2;
|
||||
float p = (i + 1) / static_cast<float>(NUM_CASCADES);
|
||||
float log = minZ * std::pow(ratio, p);
|
||||
float uniform = minZ + range * p;
|
||||
float d = cascadeSplitLambda * (log - uniform) + uniform;
|
||||
cascadeSplits[i] = (d - nearClip) / clipRange;
|
||||
}
|
||||
|
||||
// call this to update view params member, ignore descriptor set
|
||||
updateViewParameters(camera, transform);
|
||||
Array<Vector> frustumCorners = {
|
||||
Vector(-1.0f, 1.0f, 0.0f), Vector(1.0f, 1.0f, 0.0f), Vector(1.0f, -1.0f, 0.0f), Vector(-1.0f, -1.0f, 0.0f),
|
||||
Vector(-1.0f, 1.0f, 1.0f), Vector(1.0f, 1.0f, 1.0f), Vector(1.0f, -1.0f, 1.0f), Vector(-1.0f, -1.0f, 1.0f),
|
||||
};
|
||||
|
||||
for (auto& c : frustumCorners) {
|
||||
Vector4 invCorner = viewParams.inverseViewProjectionMatrix * Vector4(c, 1);
|
||||
c = invCorner / invCorner.w;
|
||||
}
|
||||
for (uint32 s = 0; s < scene->getLightEnvironment()->getNumDirectionalLights(); ++s) {
|
||||
float lastSplitDist = 0.0;
|
||||
for (uint32 i = 0; i < NUM_CASCADES; ++i) {
|
||||
float splitDist = cascadeSplits[i];
|
||||
|
||||
Array<Vector> cascadeCorners(8);
|
||||
for (uint32 j = 0; j < 4; j++) {
|
||||
Vector dist = frustumCorners[j + 4] - frustumCorners[j];
|
||||
cascadeCorners[j + 4] = frustumCorners[j] + (dist * splitDist);
|
||||
cascadeCorners[j] = frustumCorners[j] + (dist * lastSplitDist);
|
||||
}
|
||||
|
||||
Vector frustumCenter = Vector(0);
|
||||
for (uint32 j = 0; j < 8; j++) {
|
||||
frustumCenter += cascadeCorners[j];
|
||||
}
|
||||
frustumCenter /= 8.0f;
|
||||
|
||||
float radius = 0.0f;
|
||||
for (uint j = 0; j < 8; j++) {
|
||||
float distance = glm::length(cascadeCorners[j] - frustumCenter);
|
||||
radius = glm::max(radius, distance);
|
||||
}
|
||||
radius = std::ceil(radius * 16.0f) / 16.0f;
|
||||
|
||||
Vector maxExtents = Vector(radius);
|
||||
Vector minExtents = -maxExtents;
|
||||
|
||||
Vector lightDir = glm::normalize(scene->getLightEnvironment()->getDirectionalLight(s).direction);
|
||||
Matrix4 viewMatrix = glm::lookAt(frustumCenter - lightDir * -minExtents.z, frustumCenter, Vector(0, 1, 0));
|
||||
Matrix4 projectionMatrix =
|
||||
glm::ortho(minExtents.x, maxExtents.x, minExtents.y, maxExtents.y, 0.0f, maxExtents.z - minExtents.z);
|
||||
Matrix4 viewProjectionMatrix = projectionMatrix * viewMatrix;
|
||||
viewParams.viewMatrix = viewMatrix;
|
||||
viewParams.inverseViewMatrix = glm::inverse(viewMatrix);
|
||||
viewParams.projectionMatrix = projectionMatrix;
|
||||
viewParams.inverseProjection = glm::inverse(projectionMatrix);
|
||||
viewParams.viewProjectionMatrix = viewProjectionMatrix;
|
||||
viewParams.inverseViewProjectionMatrix = glm::inverse(viewProjectionMatrix);
|
||||
viewParams.screenDimensions = Vector2(maxExtents.x - minExtents.x, maxExtents.y - minExtents.y);
|
||||
viewParams.invScreenDimensions = 1.0f / viewParams.screenDimensions;
|
||||
cascades[i].viewParams.add(createViewParamsSet());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShadowPass::render() {
|
||||
graphics->beginDebugRegion("ShadowPass");
|
||||
Gfx::ShaderPermutation permutation = graphics->getShaderCompiler()->getTemplate("ShadowPass");
|
||||
permutation.setDepthCulling(true);
|
||||
permutation.setPositionOnly(true);
|
||||
const auto& shadowMaps = scene->getLightEnvironment()->getShadowMaps();
|
||||
for (uint32 shadowIndex = 0; shadowIndex < scene->getLightEnvironment()->getNumDirectionalLights(); ++shadowIndex) {
|
||||
Array<Gfx::ORenderCommand> commands;
|
||||
renderPass = graphics->createRenderPass(
|
||||
Gfx::RenderTargetLayout{
|
||||
.depthAttachment = Gfx::RenderTargetAttachment(shadowMaps[shadowIndex]->getDefaultView(), Gfx::SE_IMAGE_LAYOUT_UNDEFINED,
|
||||
Gfx::SE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL,
|
||||
Gfx::SE_ATTACHMENT_LOAD_OP_CLEAR, Gfx::SE_ATTACHMENT_STORE_OP_STORE),
|
||||
for (uint32 c = 0; c < NUM_CASCADES; ++c) {
|
||||
graphics->beginDebugRegion("Cascade");
|
||||
for (uint32 shadowIndex = 0; shadowIndex < cascades[c].shadowMaps->getNumLayers(); ++shadowIndex) {
|
||||
Array<Gfx::ORenderCommand> commands;
|
||||
renderPass = graphics->createRenderPass(
|
||||
Gfx::RenderTargetLayout{
|
||||
.depthAttachment = Gfx::RenderTargetAttachment(
|
||||
cascades[c].views[shadowIndex], Gfx::SE_IMAGE_LAYOUT_UNDEFINED,
|
||||
Gfx::SE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, Gfx::SE_ATTACHMENT_LOAD_OP_CLEAR, Gfx::SE_ATTACHMENT_STORE_OP_STORE),
|
||||
|
||||
},
|
||||
{
|
||||
Gfx::SubPassDependency{
|
||||
.srcSubpass = ~0U,
|
||||
.dstSubpass = 0,
|
||||
.srcStage = Gfx::SE_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | Gfx::SE_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
||||
.dstStage = Gfx::SE_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | Gfx::SE_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
||||
.srcAccess = Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
||||
.dstAccess = Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
||||
},
|
||||
Gfx::SubPassDependency{
|
||||
.srcSubpass = 0,
|
||||
.dstSubpass = ~0U,
|
||||
.srcStage = Gfx::SE_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | Gfx::SE_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
||||
.dstStage = Gfx::SE_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | Gfx::SE_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
||||
.srcAccess = Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
||||
.dstAccess = Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
||||
{
|
||||
Gfx::SubPassDependency{
|
||||
.srcSubpass = ~0U,
|
||||
.dstSubpass = 0,
|
||||
.srcStage = Gfx::SE_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | Gfx::SE_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
||||
.dstStage = Gfx::SE_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | Gfx::SE_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
||||
.srcAccess = Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
||||
.dstAccess = Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
||||
},
|
||||
Gfx::SubPassDependency{
|
||||
.srcSubpass = 0,
|
||||
.dstSubpass = ~0U,
|
||||
.srcStage = Gfx::SE_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | Gfx::SE_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
||||
.dstStage = Gfx::SE_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | Gfx::SE_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT,
|
||||
.srcAccess = Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
||||
.dstAccess = Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
.size = {shadowMaps[shadowIndex]->getWidth(), shadowMaps[shadowIndex]->getHeight()},
|
||||
.offset = {0, 0},
|
||||
},
|
||||
"Shadow");
|
||||
Component::Camera lightCamera = Component::Camera{
|
||||
.nearPlane = -100.f,
|
||||
.farPlane = 100.0f,
|
||||
};
|
||||
Gfx::PDescriptorSet viewParamsSet = createViewParamsSet(lightCamera, scene->getLightEnvironment()->getDirectionalTransform(shadowIndex));
|
||||
graphics->beginRenderPass(renderPass);
|
||||
for (VertexData* vertexData : VertexData::getList()) {
|
||||
permutation.setVertexData(vertexData->getTypeName());
|
||||
Gfx::PermutationId id(permutation);
|
||||
{
|
||||
.size = {cascades[c].shadowMaps->getWidth(), cascades[c].shadowMaps->getHeight()},
|
||||
.offset = {0, 0},
|
||||
},
|
||||
"Shadow");
|
||||
graphics->beginRenderPass(renderPass);
|
||||
for (VertexData* vertexData : VertexData::getList()) {
|
||||
permutation.setVertexData(vertexData->getTypeName());
|
||||
Gfx::PermutationId id(permutation);
|
||||
|
||||
Gfx::ORenderCommand command = graphics->createRenderCommand("ShadowRender");
|
||||
command->setViewport(shadowViewport);
|
||||
Gfx::ORenderCommand command = graphics->createRenderCommand("ShadowRender");
|
||||
command->setViewport(shadowViewport);
|
||||
|
||||
const Gfx::ShaderCollection* collection = graphics->getShaderCompiler()->findShaders(id);
|
||||
constexpr float depthBiasConstant = -1.25f;
|
||||
constexpr float depthBiasSlope = -1.75f;
|
||||
if (graphics->supportMeshShading()) {
|
||||
Gfx::MeshPipelineCreateInfo pipelineInfo = {
|
||||
.taskShader = collection->taskShader,
|
||||
.meshShader = collection->meshShader,
|
||||
.fragmentShader = collection->fragmentShader,
|
||||
.renderPass = renderPass,
|
||||
.pipelineLayout = collection->pipelineLayout,
|
||||
.rasterizationState =
|
||||
{
|
||||
.cullMode = Gfx::SE_CULL_MODE_FRONT_BIT,
|
||||
.depthBiasEnable = true,
|
||||
.depthBiasConstantFactor = depthBiasConstant,
|
||||
.depthBiasSlopeFactor = depthBiasSlope,
|
||||
},
|
||||
const Gfx::ShaderCollection* collection = graphics->getShaderCompiler()->findShaders(id);
|
||||
constexpr float depthBiasConstant = -1.25f;
|
||||
constexpr float depthBiasSlope = -1.75f;
|
||||
if (graphics->supportMeshShading()) {
|
||||
Gfx::MeshPipelineCreateInfo pipelineInfo = {
|
||||
.taskShader = collection->taskShader,
|
||||
.meshShader = collection->meshShader,
|
||||
.fragmentShader = collection->fragmentShader,
|
||||
.renderPass = renderPass,
|
||||
.pipelineLayout = collection->pipelineLayout,
|
||||
.rasterizationState =
|
||||
{
|
||||
.cullMode = Gfx::SE_CULL_MODE_FRONT_BIT,
|
||||
.depthBiasEnable = true,
|
||||
.depthBiasConstantFactor = depthBiasConstant,
|
||||
.depthBiasSlopeFactor = depthBiasSlope,
|
||||
},
|
||||
};
|
||||
Gfx::PGraphicsPipeline pipeline = graphics->createGraphicsPipeline(std::move(pipelineInfo));
|
||||
command->bindPipeline(pipeline);
|
||||
} else {
|
||||
Gfx::LegacyPipelineCreateInfo pipelineInfo = {
|
||||
.vertexShader = collection->vertexShader,
|
||||
.fragmentShader = collection->fragmentShader,
|
||||
.renderPass = renderPass,
|
||||
.pipelineLayout = collection->pipelineLayout,
|
||||
.rasterizationState =
|
||||
{
|
||||
.cullMode = Gfx::SE_CULL_MODE_FRONT_BIT,
|
||||
.depthBiasEnable = true,
|
||||
.depthBiasConstantFactor = depthBiasConstant,
|
||||
.depthBiasSlopeFactor = depthBiasSlope,
|
||||
},
|
||||
};
|
||||
Gfx::PGraphicsPipeline pipeline = graphics->createGraphicsPipeline(std::move(pipelineInfo));
|
||||
command->bindPipeline(pipeline);
|
||||
}
|
||||
command->bindDescriptor({cascades[c].viewParams[shadowIndex], vertexData->getVertexDataSet(), vertexData->getInstanceDataSet()});
|
||||
VertexData::DrawCallOffsets offsets = {
|
||||
.instanceOffset = 0,
|
||||
};
|
||||
Gfx::PGraphicsPipeline pipeline = graphics->createGraphicsPipeline(std::move(pipelineInfo));
|
||||
command->bindPipeline(pipeline);
|
||||
} else {
|
||||
Gfx::LegacyPipelineCreateInfo pipelineInfo = {
|
||||
.vertexShader = collection->vertexShader,
|
||||
.fragmentShader = collection->fragmentShader,
|
||||
.renderPass = renderPass,
|
||||
.pipelineLayout = collection->pipelineLayout,
|
||||
.rasterizationState =
|
||||
{
|
||||
.cullMode = Gfx::SE_CULL_MODE_FRONT_BIT,
|
||||
.depthBiasEnable = true,
|
||||
.depthBiasConstantFactor = depthBiasConstant,
|
||||
.depthBiasSlopeFactor = depthBiasSlope,
|
||||
},
|
||||
};
|
||||
Gfx::PGraphicsPipeline pipeline = graphics->createGraphicsPipeline(std::move(pipelineInfo));
|
||||
command->bindPipeline(pipeline);
|
||||
}
|
||||
command->bindDescriptor({viewParamsSet, vertexData->getVertexDataSet(), vertexData->getInstanceDataSet()});
|
||||
VertexData::DrawCallOffsets offsets = {
|
||||
.instanceOffset = 0,
|
||||
};
|
||||
command->pushConstants(Gfx::SE_SHADER_STAGE_TASK_BIT_EXT | Gfx::SE_SHADER_STAGE_VERTEX_BIT, 0,
|
||||
sizeof(VertexData::DrawCallOffsets), &offsets);
|
||||
if (graphics->supportMeshShading()) {
|
||||
command->drawMesh((uint32)vertexData->getNumInstances(), 1, 1);
|
||||
} else {
|
||||
const auto& materials = vertexData->getMaterialData();
|
||||
for (const auto& materialData : materials) {
|
||||
// material not used for any active meshes, skip
|
||||
if (materialData.instances.size() == 0)
|
||||
continue;
|
||||
for (const auto& drawCall : materialData.instances) {
|
||||
command->bindIndexBuffer(vertexData->getIndexBuffer());
|
||||
uint32 inst = drawCall.offsets.instanceOffset;
|
||||
for (const auto& meshData : drawCall.instanceMeshData) {
|
||||
// all meshlets of a mesh share the same indices offset
|
||||
command->drawIndexed(meshData.indicesRange.size, 1, meshData.indicesRange.offset,
|
||||
vertexData->getIndicesOffset(meshData.meshletRange.offset), inst++);
|
||||
command->pushConstants(Gfx::SE_SHADER_STAGE_TASK_BIT_EXT | Gfx::SE_SHADER_STAGE_VERTEX_BIT, 0,
|
||||
sizeof(VertexData::DrawCallOffsets), &offsets);
|
||||
if (graphics->supportMeshShading()) {
|
||||
command->drawMesh((uint32)vertexData->getNumInstances(), 1, 1);
|
||||
} else {
|
||||
const auto& materials = vertexData->getMaterialData();
|
||||
for (const auto& materialData : materials) {
|
||||
// material not used for any active meshes, skip
|
||||
if (materialData.instances.size() == 0)
|
||||
continue;
|
||||
for (const auto& drawCall : materialData.instances) {
|
||||
command->bindIndexBuffer(vertexData->getIndexBuffer());
|
||||
uint32 inst = drawCall.offsets.instanceOffset;
|
||||
for (const auto& meshData : drawCall.instanceMeshData) {
|
||||
// all meshlets of a mesh share the same indices offset
|
||||
command->drawIndexed(meshData.indicesRange.size, 1, meshData.indicesRange.offset,
|
||||
vertexData->getIndicesOffset(meshData.meshletRange.offset), inst++);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
commands.add(std::move(command));
|
||||
}
|
||||
commands.add(std::move(command));
|
||||
graphics->executeCommands(std::move(commands));
|
||||
graphics->endRenderPass();
|
||||
graphics->waitDeviceIdle();
|
||||
}
|
||||
graphics->executeCommands(std::move(commands));
|
||||
graphics->endRenderPass();
|
||||
graphics->waitDeviceIdle();
|
||||
graphics->endDebugRegion();
|
||||
}
|
||||
graphics->endDebugRegion();
|
||||
}
|
||||
@@ -168,7 +260,7 @@ void ShadowPass::endFrame() {}
|
||||
void ShadowPass::publishOutputs() {
|
||||
shadowViewport = graphics->createViewport(nullptr, ViewportCreateInfo{.dimensions =
|
||||
{
|
||||
.size = {8192, 8192},
|
||||
.size = {SHADOW_MAP_SIZE, SHADOW_MAP_SIZE},
|
||||
.offset = {0, 0},
|
||||
},
|
||||
.fieldOfView = 0,
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
#pragma once
|
||||
#include "Graphics/Buffer.h"
|
||||
#include "Graphics/Descriptor.h"
|
||||
#include "RenderPass.h"
|
||||
|
||||
namespace Seele {
|
||||
|
||||
static constexpr uint64 SHADOW_MAP_SIZE = 8192;
|
||||
|
||||
class ShadowPass : public RenderPass {
|
||||
public:
|
||||
ShadowPass(Gfx::PGraphics graphics, PScene scene);
|
||||
@@ -15,6 +20,13 @@ class ShadowPass : public RenderPass {
|
||||
virtual void createRenderPass() override;
|
||||
private:
|
||||
AABB cameraFrustumBox;
|
||||
static constexpr uint64 NUM_CASCADES = 4;
|
||||
struct Cascade {
|
||||
Gfx::OTexture2D shadowMaps;
|
||||
Array<Gfx::OTextureView> views;
|
||||
Array<Gfx::PDescriptorSet> viewParams;
|
||||
};
|
||||
StaticArray<Cascade, NUM_CASCADES> cascades;
|
||||
Gfx::OPipelineLayout shadowLayout;
|
||||
Gfx::PShaderBuffer cullingBuffer;
|
||||
Gfx::OViewport shadowViewport;
|
||||
|
||||
@@ -124,7 +124,8 @@ ToneMappingPass::ToneMappingPass(Gfx::PGraphics graphics) : RenderPass(graphics)
|
||||
ToneMappingPass::~ToneMappingPass() {}
|
||||
|
||||
void ToneMappingPass::beginFrame(const Component::Camera& cam, const Component::Transform& transform) {
|
||||
viewParamsSet = createViewParamsSet(cam, transform);
|
||||
updateViewParameters(cam, transform);
|
||||
viewParamsSet = createViewParamsSet();
|
||||
}
|
||||
|
||||
void ToneMappingPass::render() {
|
||||
|
||||
@@ -54,7 +54,8 @@ UIPass::UIPass(Gfx::PGraphics graphics, UI::PSystem system) : RenderPass(graphic
|
||||
UIPass::~UIPass() {}
|
||||
|
||||
void UIPass::beginFrame(const Component::Camera& cam, const Component::Transform& transform) {
|
||||
viewParamsSet = createViewParamsSet(cam, transform);
|
||||
updateViewParameters(cam, transform);
|
||||
viewParamsSet = createViewParamsSet();
|
||||
glyphs.clear();
|
||||
usedTextures.clear();
|
||||
elements.clear();
|
||||
|
||||
@@ -8,7 +8,8 @@ VisibilityPass::VisibilityPass(Gfx::PGraphics graphics) : RenderPass(graphics) {
|
||||
VisibilityPass::~VisibilityPass() {}
|
||||
|
||||
void VisibilityPass::beginFrame(const Component::Camera& cam, const Component::Transform& transform) {
|
||||
viewParamsSet = createViewParamsSet(cam, transform);
|
||||
updateViewParameters(cam, transform);
|
||||
viewParamsSet = createViewParamsSet();
|
||||
cullingBuffer->rotateBuffer(VertexData::getMeshletCount() * sizeof(VertexData::MeshletCullingInfo), true);
|
||||
}
|
||||
|
||||
|
||||
@@ -82,34 +82,11 @@ void LightEnvironment::reset() {
|
||||
}
|
||||
|
||||
void LightEnvironment::addDirectionalLight(const Component::DirectionalLight& dirLight, const Component::Transform& transform) {
|
||||
Vector eyePos = transform.getPosition();
|
||||
Vector lookAt = eyePos + transform.getForward();
|
||||
Matrix4 cameraMatrix = glm::lookAt(eyePos, lookAt, Vector(0, 1, 0));
|
||||
Matrix4 correctionMatrix = Matrix4(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1 / 2.f, 0, 0, 0, 1 / 2.f, 1);
|
||||
dirs.add(ShaderDirectionalLight{
|
||||
.color = Vector4(dirLight.color, dirLight.intensity),
|
||||
.direction = Vector4(transform.getForward(), 0),
|
||||
.lightSpaceMatrix = correctionMatrix * glm::ortho(-100.0f, 100.0f, -100.0f, 100.0f, 100.0f, -100.0f) * cameraMatrix,
|
||||
});
|
||||
directionalTransforms.add(transform);
|
||||
if (shadowMaps.size() < dirs.size()) {
|
||||
shadowMaps.add(graphics->createTexture2D(TextureCreateInfo{
|
||||
.format = Gfx::SE_FORMAT_D32_SFLOAT,
|
||||
.width = 8192,
|
||||
.height = 8192,
|
||||
.elements = (uint32)dirs.size(),
|
||||
.usage = Gfx::SE_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | Gfx::SE_IMAGE_USAGE_SAMPLED_BIT,
|
||||
.name = "ShadowMap",
|
||||
}));
|
||||
shadowMaps.back()->changeLayout(Gfx::SE_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, Gfx::SE_ACCESS_NONE, Gfx::SE_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
Gfx::SE_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT);
|
||||
shadowSamplers.add(graphics->createSampler(SamplerCreateInfo{
|
||||
.addressModeU = Gfx::SE_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
|
||||
.addressModeV = Gfx::SE_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
|
||||
.addressModeW = Gfx::SE_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE,
|
||||
.name = "ShadowSampler",
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
void LightEnvironment::addPointLight(const Component::PointLight& pointLight, const Component::Transform& transform) {
|
||||
@@ -136,8 +113,6 @@ void LightEnvironment::commit() {
|
||||
uint32 numDirectionalLights = (uint32)dirs.size();
|
||||
set->updateConstants("numDirectionalLights", 0, &numDirectionalLights);
|
||||
set->updateBuffer("directionalLights", 0, directionalLights);
|
||||
set->updateTexture("shadowMap", 0, shadowMaps[0]->getDefaultView());
|
||||
set->updateSampler("shadowSampler", 0, Gfx::PSampler(shadowSamplers[0]));
|
||||
set->updateConstants("numPointLights", 0, &numPointLights);
|
||||
set->updateBuffer("pointLights", 0, pointLights);
|
||||
set->updateTexture("irradianceMap", 0, environment->getIrradianceMap()->getDefaultView());
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include "Component/Transform.h"
|
||||
#include "Graphics/Buffer.h"
|
||||
#include "Graphics/Descriptor.h"
|
||||
#include "Graphics/Texture.h"
|
||||
|
||||
namespace Seele {
|
||||
DECLARE_REF(EnvironmentMapAsset)
|
||||
@@ -13,7 +12,6 @@ class LightEnvironment {
|
||||
struct ShaderDirectionalLight {
|
||||
Vector4 color;
|
||||
Vector4 direction;
|
||||
Matrix4 lightSpaceMatrix;
|
||||
};
|
||||
struct ShaderPointLight {
|
||||
Vector4 position_WS;
|
||||
@@ -31,12 +29,10 @@ class LightEnvironment {
|
||||
Gfx::PDescriptorSet getDescriptorSet();
|
||||
PEnvironmentMapAsset getEnvironmentMap() { return environment; }
|
||||
uint64 getNumDirectionalLights() const { return dirs.size(); }
|
||||
const Array<Gfx::OTexture2D>& getShadowMaps() const { return shadowMaps; }
|
||||
|
||||
private:
|
||||
Gfx::PGraphics graphics;
|
||||
Gfx::OShaderBuffer directionalLights;
|
||||
Array<Gfx::OTexture2D> shadowMaps;
|
||||
Array<Gfx::OSampler> shadowSamplers;
|
||||
Gfx::OShaderBuffer pointLights;
|
||||
Array<ShaderDirectionalLight> dirs;
|
||||
|
||||
Reference in New Issue
Block a user