Still working on solving that underestimated shadow far plane on the first cascade. I have finally understood the problem (see TODO in LightStage)

This commit is contained in:
Olivier Prat 2017-11-17 19:25:21 +01:00
parent b246c479e3
commit d98dfff0a8
8 changed files with 212 additions and 80 deletions

View file

@ -116,9 +116,12 @@ void LightStage::Shadow::setKeylightFrustum(unsigned int cascadeIndex, const Vie
fitFrustum(farCorners.bottomRight);
fitFrustum(farCorners.topLeft);
fitFrustum(farCorners.topRight);
// TODO: Far distance should be extended to the intersection of the exteruded shadow frustum far plane
// with the view frustum.
// Re-adjust near shadow distance
auto near = glm::max(max.z, -nearDepth);
auto near = glm::min(-max.z, nearDepth);
auto far = -min.z;
glm::mat4 ortho = glm::ortho<float>(min.x, max.x, min.y, max.y, near, far);
cascade._frustum->setProjection(ortho);

View file

@ -204,7 +204,9 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
for (auto i = 0; i < ExtractFrustums::SHADOW_CASCADE_FRUSTUM_COUNT; i++) {
const auto shadowFrustum = frustums.getN<ExtractFrustums::Output>(ExtractFrustums::SHADOW_CASCADE0_FRUSTUM+i);
float tint = 1.0f - i / float(ExtractFrustums::SHADOW_CASCADE_FRUSTUM_COUNT - 1);
task.addJob<DrawFrustum>("DrawShadowFrustum", shadowFrustum, glm::vec3(0.0f, tint, 1.0f));
char jobName[64];
sprintf(jobName, "DrawShadowFrustum%d", i);
task.addJob<DrawFrustum>(jobName, shadowFrustum, glm::vec3(0.0f, tint, 1.0f));
}
// Render.getConfig("RenderMainView.DrawSelectionBounds").enabled = true

View file

@ -112,8 +112,7 @@ static void adjustNearFar(const AABox& inShapeBounds, ViewFrustum& shadowFrustum
float far = 0.0f;
computeNearFar(sceneBoundVertices, shadowClipPlanes, near, far);
// Limit the far range to the one used originally. There's no point in rendering objects
// that are not in the view frustum.
// Limit the far range to the one used originally.
far = glm::min(far, shadowFrustum.getFarClip());
const auto depthEpsilon = 0.1f;
@ -233,7 +232,6 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende
// GPU jobs: Render to shadow map
task.addJob<RenderShadowMap>("RenderShadowMap", sortedShapesAndBounds, shapePlumber, i);
task.addJob<RenderShadowTeardown>("ShadowTeardown", setupOutput);
}
}
@ -272,12 +270,13 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, O
minCascadeDistance = maxCascadeDistance / cascadeLevelScale;
}
shadowOverlapDistance = (maxCascadeDistance - minCascadeDistance) / 3.0f;
shadowOverlapDistance = (maxCascadeDistance - minCascadeDistance) / 4.0f;
maxCascadeDistance += shadowOverlapDistance;
if (_cascadeIndex == 0) {
minCascadeDistance = nearClip;
} else {
minCascadeDistance = std::max(minCascadeDistance, nearClip);
}
minCascadeDistance = std::max(minCascadeDistance, nearClip);
maxCascadeDistance = std::min(maxCascadeDistance, farClip);
globalShadow->setKeylightFrustum(_cascadeIndex, args->getViewFrustum(), minCascadeDistance, maxCascadeDistance, shadowOverlapDistance, SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR);

View file

@ -49,8 +49,8 @@ vec4 evalShadowTexcoord(int cascadeIndex, vec4 position) {
}
bool isShadowCascadeProjectedOnPixel(vec4 cascadeTexCoords) {
bvec3 greaterThanZero = greaterThanEqual(cascadeTexCoords.xyz, vec3(0));
bvec3 lessThanOne = lessThanEqual(cascadeTexCoords.xyz, vec3(1));
bvec2 greaterThanZero = greaterThanEqual(cascadeTexCoords.xy, vec2(0));
bvec2 lessThanOne = lessThanEqual(cascadeTexCoords.xy, vec2(1));
return all(greaterThanZero) && all(lessThanOne);
}

View file

@ -215,79 +215,158 @@ void DrawBounds::run(const RenderContextPointer& renderContext,
});
}
gpu::PipelinePointer DrawFrustum::_pipeline;
DrawQuadVolume::DrawQuadVolume(const glm::vec3& color) :
_color{ color } {
_meshVertices = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(glm::vec3) * 8, nullptr), gpu::Element::VEC3F_XYZ);
_meshStream.addBuffer(_meshVertices._buffer, _meshVertices._offset, _meshVertices._stride);
}
void DrawQuadVolume::configure(const Config& configuration) {
_isUpdateEnabled = !configuration.isFrozen;
}
void DrawQuadVolume::run(const render::RenderContextPointer& renderContext, const glm::vec3 vertices[8],
const gpu::BufferView& indices, int indexCount) {
assert(renderContext->args);
assert(renderContext->args->_context);
if (_isUpdateEnabled) {
auto& streamVertices = _meshVertices.edit<std::array<glm::vec3, 8U> >();
std::copy(vertices, vertices + 8, streamVertices.begin());
}
RenderArgs* args = renderContext->args;
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
args->_batch = &batch;
batch.setViewportTransform(args->_viewport);
batch.setStateScissorRect(args->_viewport);
glm::mat4 projMat;
Transform viewMat;
args->getViewFrustum().evalProjectionMatrix(projMat);
args->getViewFrustum().evalViewTransform(viewMat);
batch.setProjectionTransform(projMat);
batch.setViewTransform(viewMat);
batch.setPipeline(getPipeline());
batch.setIndexBuffer(indices);
batch._glUniform4f(0, _color.x, _color.y, _color.z, 1.0f);
batch.setInputStream(0, _meshStream);
batch.drawIndexed(gpu::LINES, indexCount, 0U);
args->_batch = nullptr;
});
}
gpu::PipelinePointer DrawQuadVolume::getPipeline() {
static gpu::PipelinePointer pipeline;
if (!pipeline) {
auto vs = gpu::StandardShaderLib::getDrawTransformVertexPositionVS();
auto ps = gpu::StandardShaderLib::getDrawColorPS();
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding("color", 0));
gpu::Shader::makeProgram(*program, slotBindings);
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
state->setDepthTest(gpu::State::DepthTest(true, false));
pipeline = gpu::Pipeline::create(program, state);
}
return pipeline;
}
gpu::BufferView DrawAABox::_cubeMeshIndices;
DrawAABox::DrawAABox(const glm::vec3& color) :
DrawQuadVolume{ color } {
}
void DrawAABox::run(const render::RenderContextPointer& renderContext, const Inputs& box) {
if (!box.isNull()) {
static const uint8_t indexData[] = {
0, 1,
1, 2,
2, 3,
3, 0,
4, 5,
5, 6,
6, 7,
7, 4,
0, 4,
1, 5,
3, 7,
2, 6
};
if (!_cubeMeshIndices._buffer) {
auto indices = std::make_shared<gpu::Buffer>(sizeof(indexData), indexData);
_cubeMeshIndices = gpu::BufferView(indices, gpu::Element(gpu::SCALAR, gpu::UINT8, gpu::INDEX));
}
glm::vec3 vertices[8];
getVertices(box, vertices);
DrawQuadVolume::run(renderContext, vertices, _cubeMeshIndices, sizeof(indexData) / sizeof(indexData[0]));
}
}
void DrawAABox::getVertices(const AABox& box, glm::vec3 vertices[8]) {
vertices[0] = box.getVertex(TOP_LEFT_NEAR);
vertices[1] = box.getVertex(TOP_RIGHT_NEAR);
vertices[2] = box.getVertex(BOTTOM_RIGHT_NEAR);
vertices[3] = box.getVertex(BOTTOM_LEFT_NEAR);
vertices[4] = box.getVertex(TOP_LEFT_FAR);
vertices[5] = box.getVertex(TOP_RIGHT_FAR);
vertices[6] = box.getVertex(BOTTOM_RIGHT_FAR);
vertices[7] = box.getVertex(BOTTOM_LEFT_FAR);
}
gpu::BufferView DrawFrustum::_frustumMeshIndices;
DrawFrustum::DrawFrustum(const glm::vec3& color) :
_color{ color } {
_frustumMeshVertices = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(glm::vec3) * 8, nullptr), gpu::Element::VEC3F_XYZ);
_frustumMeshStream.addBuffer(_frustumMeshVertices._buffer, _frustumMeshVertices._offset, _frustumMeshVertices._stride);
}
void DrawFrustum::configure(const Config& configuration) {
_updateFrustum = !configuration.isFrozen;
DrawQuadVolume{ color } {
}
void DrawFrustum::run(const render::RenderContextPointer& renderContext, const Input& input) {
assert(renderContext->args);
assert(renderContext->args->_context);
RenderArgs* args = renderContext->args;
if (input) {
const auto& frustum = *input;
static uint8_t indexData[] = { 0, 1, 2, 3, 0, 4, 5, 6, 7, 4, 5, 1, 2, 6, 7, 3 };
static const uint8_t indexData[] = {
0, 1,
1, 2,
2, 3,
3, 0,
0, 2,
3, 1,
4, 5,
5, 6,
6, 7,
7, 4,
4, 6,
7, 5,
0, 4,
1, 5,
3, 7,
2, 6
};
if (!_frustumMeshIndices._buffer) {
auto indices = std::make_shared<gpu::Buffer>(sizeof(indexData), indexData);
_frustumMeshIndices = gpu::BufferView(indices, gpu::Element(gpu::SCALAR, gpu::UINT8, gpu::INDEX));
}
if (!_pipeline) {
auto vs = gpu::StandardShaderLib::getDrawTransformVertexPositionVS();
auto ps = gpu::StandardShaderLib::getDrawColorPS();
gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps);
glm::vec3 vertices[8];
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding("color", 0));
gpu::Shader::makeProgram(*program, slotBindings);
getVertices(frustum, vertices);
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
state->setDepthTest(gpu::State::DepthTest(true, false));
_pipeline = gpu::Pipeline::create(program, state);
}
if (_updateFrustum) {
updateFrustum(frustum);
}
// Render the frustums in wireframe
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
args->_batch = &batch;
batch.setViewportTransform(args->_viewport);
batch.setStateScissorRect(args->_viewport);
glm::mat4 projMat;
Transform viewMat;
args->getViewFrustum().evalProjectionMatrix(projMat);
args->getViewFrustum().evalViewTransform(viewMat);
batch.setProjectionTransform(projMat);
batch.setViewTransform(viewMat);
batch.setPipeline(_pipeline);
batch.setIndexBuffer(_frustumMeshIndices);
batch._glUniform4f(0, _color.x, _color.y, _color.z, 1.0f);
batch.setInputStream(0, _frustumMeshStream);
batch.drawIndexed(gpu::LINE_STRIP, sizeof(indexData) / sizeof(indexData[0]), 0U);
args->_batch = nullptr;
});
DrawQuadVolume::run(renderContext, vertices, _frustumMeshIndices, sizeof(indexData) / sizeof(indexData[0]));
}
}
void DrawFrustum::updateFrustum(const ViewFrustum& frustum) {
auto& vertices = _frustumMeshVertices.edit<std::array<glm::vec3, 8U> >();
void DrawFrustum::getVertices(const ViewFrustum& frustum, glm::vec3 vertices[8]) {
vertices[0] = frustum.getNearTopLeft();
vertices[1] = frustum.getNearTopRight();
vertices[2] = frustum.getNearBottomRight();

View file

@ -70,12 +70,12 @@ private:
int _colorLocation { -1 };
};
class DrawFrustumConfig : public render::JobConfig {
class DrawQuadVolumeConfig : public render::JobConfig {
Q_OBJECT
Q_PROPERTY(bool isFrozen MEMBER isFrozen NOTIFY dirty)
public:
DrawFrustumConfig(bool enabled = false) : JobConfig(enabled) {}
DrawQuadVolumeConfig(bool enabled = false) : JobConfig(enabled) {}
bool isFrozen{ false };
signals:
@ -83,30 +83,58 @@ signals:
};
class DrawFrustum {
class DrawQuadVolume {
public:
using Config = DrawQuadVolumeConfig;
void configure(const Config& configuration);
protected:
DrawQuadVolume(const glm::vec3& color);
void run(const render::RenderContextPointer& renderContext, const glm::vec3 vertices[8],
const gpu::BufferView& indices, int indexCount);
gpu::BufferView _meshVertices;
gpu::BufferStream _meshStream;
glm::vec3 _color;
bool _isUpdateEnabled{ true };
static gpu::PipelinePointer getPipeline();
};
class DrawAABox : public DrawQuadVolume {
public:
using Inputs = AABox;
using JobModel = render::Job::ModelI<DrawAABox, Inputs, Config>;
DrawAABox(const glm::vec3& color = glm::vec3(1.0f, 1.0f, 1.0f));
void run(const render::RenderContextPointer& renderContext, const Inputs& box);
protected:
static gpu::BufferView _cubeMeshIndices;
static void getVertices(const AABox& box, glm::vec3 vertices[8]);
};
class DrawFrustum : public DrawQuadVolume {
public:
using Config = DrawFrustumConfig;
using Input = ViewFrustumPointer;
using JobModel = render::Job::ModelI<DrawFrustum, Input, Config>;
DrawFrustum(const glm::vec3& color = glm::vec3(1.0f, 1.0f, 1.0f));
void configure(const Config& configuration);
void run(const render::RenderContextPointer& renderContext, const Input& input);
private:
static gpu::PipelinePointer _pipeline;
static gpu::BufferView _frustumMeshIndices;
bool _updateFrustum{ true };
gpu::BufferView _frustumMeshVertices;
gpu::BufferStream _frustumMeshStream;
glm::vec3 _color;
void updateFrustum(const ViewFrustum& frustum);
static void getVertices(const ViewFrustum& frustum, glm::vec3 vertices[8]);
};
}
#endif // hifi_render_DrawTask_h

View file

@ -422,7 +422,7 @@ int clipTriangleWithPlanes(const Triangle& triangle, const Plane* planes, int pl
*clippedTriangles = triangle;
while (planes < planesEnd) {
while (planes < planesEnd && triangleCount) {
int clippedSubTriangleCount;
trianglesToTest.clear();

View file

@ -15,15 +15,24 @@ Column {
id: root
spacing: 8
property var viewConfig: Render.getConfig("RenderMainView.DrawViewFrustum");
property var shadowConfig: Render.getConfig("RenderMainView.DrawShadowFrustum");
property var shadow0Config: Render.getConfig("RenderMainView.DrawShadowFrustum0");
property var shadow1Config: Render.getConfig("RenderMainView.DrawShadowFrustum1");
property var shadow2Config: Render.getConfig("RenderMainView.DrawShadowFrustum2");
property var shadow3Config: Render.getConfig("RenderMainView.DrawShadowFrustum3");
Component.onCompleted: {
viewConfig.enabled = true;
shadowConfig.enabled = true;
shadow0Config.enabled = true;
shadow1Config.enabled = true;
shadow2Config.enabled = true;
shadow3Config.enabled = true;
}
Component.onDestruction: {
viewConfig.enabled = false;
shadowConfig.enabled = false;
shadow0Config.enabled = false;
shadow1Config.enabled = false;
shadow2Config.enabled = false;
shadow3Config.enabled = false;
}
CheckBox {
@ -31,7 +40,14 @@ Column {
checked: false
onCheckedChanged: {
viewConfig.isFrozen = checked;
shadowConfig.isFrozen = checked;
shadow0Config.isFrozen = checked;
shadow1Config.isFrozen = checked;
shadow2Config.isFrozen = checked;
shadow3Config.isFrozen = checked;
shadow0BoundConfig.isFrozen = checked;
shadow1BoundConfig.isFrozen = checked;
shadow2BoundConfig.isFrozen = checked;
shadow3BoundConfig.isFrozen = checked;
}
}
Row {
@ -46,5 +62,10 @@ Column {
color: "blue"
font.italic: true
}
Label {
text: "Items"
color: "magenta"
font.italic: true
}
}
}