Merge pull request #15411 from Zvork/shadow

Case 22117: Shadows Appear Incorrectly Placed Relative to Avatars
This commit is contained in:
Shannon Romano 2019-04-23 09:32:53 -07:00 committed by GitHub
commit 7a9dd49eed
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 220 additions and 103 deletions

View file

@ -313,11 +313,9 @@ void MaterialEntityRenderer::doRender(RenderArgs* args) {
batch.setModelTransform(renderTransform); batch.setModelTransform(renderTransform);
if (args->_renderMode != render::Args::RenderMode::SHADOW_RENDER_MODE) { drawMaterial->setTextureTransforms(textureTransform, MaterialMappingMode::UV, true);
drawMaterial->setTextureTransforms(textureTransform, MaterialMappingMode::UV, true); // bind the material
if (RenderPipelines::bindMaterial(drawMaterial, batch, args->_renderMode, args->_enableTexturing)) {
// bind the material
RenderPipelines::bindMaterial(drawMaterial, batch, args->_enableTexturing);
args->_details._materialSwitches++; args->_details._materialSwitches++;
} }

View file

@ -291,8 +291,7 @@ void ShapeEntityRenderer::doRender(RenderArgs* args) {
geometryCache->renderSolidShapeInstance(args, batch, geometryShape, outColor, pipeline); geometryCache->renderSolidShapeInstance(args, batch, geometryShape, outColor, pipeline);
} }
} else { } else {
if (args->_renderMode != render::Args::RenderMode::SHADOW_RENDER_MODE) { if (RenderPipelines::bindMaterials(materials, batch, args->_renderMode, args->_enableTexturing)) {
RenderPipelines::bindMaterials(materials, batch, args->_enableTexturing);
args->_details._materialSwitches++; args->_details._materialSwitches++;
} }

View file

@ -73,6 +73,22 @@ bool Light::getCastShadows() const {
return _castShadows; return _castShadows;
} }
void Light::setShadowsMaxDistance(const float maxDistance) {
_shadowsMaxDistance = std::max(0.0f, maxDistance);
}
float Light::getShadowsMaxDistance() const {
return _shadowsMaxDistance;
}
void Light::setShadowsBiasScale(const float scale) {
_shadowsBiasScale = std::max(0.0f, scale);
}
float Light::getShadowsBiasScale() const {
return _shadowsBiasScale;
}
void Light::setColor(const Color& color) { void Light::setColor(const Color& color) {
_lightSchemaBuffer.edit().irradiance.color = color; _lightSchemaBuffer.edit().irradiance.color = color;
updateLightRadius(); updateLightRadius();

View file

@ -106,6 +106,12 @@ public:
void setCastShadows(const bool castShadows); void setCastShadows(const bool castShadows);
bool getCastShadows() const; bool getCastShadows() const;
void setShadowsMaxDistance(const float maxDistance);
float getShadowsMaxDistance() const;
void setShadowsBiasScale(const float scale);
float getShadowsBiasScale() const;
void setOrientation(const Quat& orientation); void setOrientation(const Quat& orientation);
const glm::quat& getOrientation() const { return _transform.getRotation(); } const glm::quat& getOrientation() const { return _transform.getRotation(); }
@ -192,10 +198,11 @@ protected:
Type _type { SUN }; Type _type { SUN };
float _spotCos { -1.0f }; // stored here to be able to reset the spot angle when turning the type spot on/off float _spotCos { -1.0f }; // stored here to be able to reset the spot angle when turning the type spot on/off
void updateLightRadius(); float _shadowsMaxDistance{ 40.0f };
float _shadowsBiasScale{ 1.0f };
bool _castShadows{ false }; bool _castShadows{ false };
void updateLightRadius();
}; };
typedef std::shared_ptr< Light > LightPointer; typedef std::shared_ptr< Light > LightPointer;

View file

@ -149,7 +149,6 @@ float fetchScatteringMap(vec2 uv) {
<@endfunc@> <@endfunc@>
<@func fetchMaterialTexturesCoord0(matKey, texcoord0, albedo, roughness, normal, metallic, emissive, scattering)@> <@func fetchMaterialTexturesCoord0(matKey, texcoord0, albedo, roughness, normal, metallic, emissive, scattering)@>
if (getTexMapArray()._materialParams.y != 1.0 && clamp(<$texcoord0$>, vec2(0.0), vec2(1.0)) != <$texcoord0$>) { if (getTexMapArray()._materialParams.y != 1.0 && clamp(<$texcoord0$>, vec2(0.0), vec2(1.0)) != <$texcoord0$>) {
discard; discard;

View file

@ -120,7 +120,7 @@ float LightStage::Shadow::Cascade::computeFarDistance(const ViewFrustum& viewFru
return far; return far;
} }
LightStage::Shadow::Shadow(graphics::LightPointer light, float maxDistance, unsigned int cascadeCount) : LightStage::Shadow::Shadow(graphics::LightPointer light, unsigned int cascadeCount) :
_light{ light } { _light{ light } {
cascadeCount = std::min(cascadeCount, (unsigned int)SHADOW_CASCADE_MAX_COUNT); cascadeCount = std::min(cascadeCount, (unsigned int)SHADOW_CASCADE_MAX_COUNT);
Schema schema; Schema schema;
@ -149,70 +149,79 @@ LightStage::Shadow::Shadow(graphics::LightPointer light, float maxDistance, unsi
cascade.framebuffer->setDepthBuffer(map, depthFormat, cascadeIndex); cascade.framebuffer->setDepthBuffer(map, depthFormat, cascadeIndex);
} }
setMaxDistance(maxDistance); if (light) {
setMaxDistance(light->getShadowsMaxDistance());
}
} }
void LightStage::Shadow::setLight(graphics::LightPointer light) { void LightStage::Shadow::setLight(graphics::LightPointer light) {
_light = light; _light = light;
if (light) {
setMaxDistance(light->getShadowsMaxDistance());
}
} }
void LightStage::Shadow::setMaxDistance(float value) { void LightStage::Shadow::setMaxDistance(float value) {
// This overlaping factor isn't really used directly for blending of shadow cascades. It static const auto MINIMUM_MAXDISTANCE = 1e-3f;
// just there to be sure the cascades do overlap. The blending width used is relative
// to the UV space and is set in the Schema with invCascadeBlendWidth.
static const auto OVERLAP_FACTOR = 1.0f / 5.0f;
_maxDistance = std::max(0.0f, value); value = std::max(MINIMUM_MAXDISTANCE, value);
if (value != _maxDistance) {
// This overlaping factor isn't really used directly for blending of shadow cascades. It's
// just there to be sure the cascades do overlap. The blending width used is relative
// to the UV space and is set in the Schema with invCascadeBlendWidth.
static const auto OVERLAP_FACTOR = 1.0f / 5.0f;
if (_cascades.size() == 1) { _maxDistance = value;
_cascades.front().setMinDistance(0.0f);
_cascades.front().setMaxDistance(_maxDistance);
} else {
// Distribute the cascades along that distance
// TODO : these parameters should be exposed to the user as part of the light entity parameters, no?
static const auto LOW_MAX_DISTANCE = 2.0f;
static const auto MAX_RESOLUTION_LOSS = 0.6f; // Between 0 and 1, 0 giving tighter distributions
// The max cascade distance is computed by multiplying the previous cascade's max distance by a certain if (_cascades.size() == 1) {
// factor. There is a "user" factor that is computed from a desired max resolution loss in the shadow _cascades.front().setMinDistance(0.0f);
// and an optimal one based on the global min and max shadow distance, all cascades considered. The final _cascades.front().setMaxDistance(_maxDistance);
// distance is a gradual blend between the two } else {
const auto userDistanceScale = 1.0f / (1.0f - MAX_RESOLUTION_LOSS); // Distribute the cascades along that distance
const auto optimalDistanceScale = powf(_maxDistance / LOW_MAX_DISTANCE, 1.0f / (_cascades.size() - 1)); // TODO : these parameters should be exposed to the user as part of the light entity parameters, no?
static const auto LOW_MAX_DISTANCE = 2.0f;
static const auto MAX_RESOLUTION_LOSS = 0.6f; // Between 0 and 1, 0 giving tighter distributions
float maxCascadeUserDistance = LOW_MAX_DISTANCE; // The max cascade distance is computed by multiplying the previous cascade's max distance by a certain
float maxCascadeOptimalDistance = LOW_MAX_DISTANCE; // factor. There is a "user" factor that is computed from a desired max resolution loss in the shadow
float minCascadeDistance = 0.0f; // and an optimal one based on the global min and max shadow distance, all cascades considered. The final
// distance is a gradual blend between the two
const auto userDistanceScale = 1.0f / (1.0f - MAX_RESOLUTION_LOSS);
const auto optimalDistanceScale = powf(_maxDistance / LOW_MAX_DISTANCE, 1.0f / (_cascades.size() - 1));
for (size_t cascadeIndex = 0; cascadeIndex < _cascades.size(); ++cascadeIndex) { float maxCascadeUserDistance = LOW_MAX_DISTANCE;
float blendFactor = cascadeIndex / float(_cascades.size() - 1); float maxCascadeOptimalDistance = LOW_MAX_DISTANCE;
float maxCascadeDistance; float minCascadeDistance = 0.0f;
if (cascadeIndex == size_t(_cascades.size() - 1)) { for (size_t cascadeIndex = 0; cascadeIndex < _cascades.size(); ++cascadeIndex) {
maxCascadeDistance = _maxDistance; float blendFactor = cascadeIndex / float(_cascades.size() - 1);
} else { float maxCascadeDistance;
maxCascadeDistance = maxCascadeUserDistance + (maxCascadeOptimalDistance - maxCascadeUserDistance)*blendFactor*blendFactor;
if (cascadeIndex == size_t(_cascades.size() - 1)) {
maxCascadeDistance = _maxDistance;
} else {
maxCascadeDistance = maxCascadeUserDistance + (maxCascadeOptimalDistance - maxCascadeUserDistance)*blendFactor*blendFactor;
}
float shadowOverlapDistance = maxCascadeDistance * OVERLAP_FACTOR;
_cascades[cascadeIndex].setMinDistance(minCascadeDistance);
_cascades[cascadeIndex].setMaxDistance(maxCascadeDistance + shadowOverlapDistance);
// Compute distances for next cascade
minCascadeDistance = maxCascadeDistance;
maxCascadeUserDistance = maxCascadeUserDistance * userDistanceScale;
maxCascadeOptimalDistance = maxCascadeOptimalDistance * optimalDistanceScale;
maxCascadeUserDistance = std::min(maxCascadeUserDistance, _maxDistance);
} }
float shadowOverlapDistance = maxCascadeDistance * OVERLAP_FACTOR;
_cascades[cascadeIndex].setMinDistance(minCascadeDistance);
_cascades[cascadeIndex].setMaxDistance(maxCascadeDistance + shadowOverlapDistance);
// Compute distances for next cascade
minCascadeDistance = maxCascadeDistance;
maxCascadeUserDistance = maxCascadeUserDistance * userDistanceScale;
maxCascadeOptimalDistance = maxCascadeOptimalDistance * optimalDistanceScale;
maxCascadeUserDistance = std::min(maxCascadeUserDistance, _maxDistance);
} }
}
// Update the buffer // Update the buffer
const auto& lastCascade = _cascades.back(); const auto& lastCascade = _cascades.back();
auto& schema = _schemaBuffer.edit<Schema>(); auto& schema = _schemaBuffer.edit<Schema>();
schema.maxDistance = _maxDistance; schema.maxDistance = _maxDistance;
schema.invFalloffDistance = 1.0f / (OVERLAP_FACTOR*lastCascade.getMaxDistance()); schema.invFalloffDistance = 1.0f / (OVERLAP_FACTOR*lastCascade.getMaxDistance());
}
} }
void LightStage::Shadow::setKeylightFrustum(const ViewFrustum& viewFrustum, void LightStage::Shadow::setKeylightFrustum(const ViewFrustum& viewFrustum,

View file

@ -74,7 +74,7 @@ public:
float left, float right, float bottom, float top, float viewMaxShadowDistance) const; float left, float right, float bottom, float top, float viewMaxShadowDistance) const;
}; };
Shadow(graphics::LightPointer light, float maxDistance, unsigned int cascadeCount = 1); Shadow(graphics::LightPointer light, unsigned int cascadeCount = 1);
void setLight(graphics::LightPointer light); void setLight(graphics::LightPointer light);
@ -104,16 +104,14 @@ public:
}; };
protected: protected:
using Cascades = std::vector<Cascade>; using Cascades = std::vector<Cascade>;
static const glm::mat4 _biasMatrix; static const glm::mat4 _biasMatrix;
graphics::LightPointer _light; graphics::LightPointer _light;
float _maxDistance; float _maxDistance{ 0.0f };
Cascades _cascades; Cascades _cascades;
UniformBufferView _schemaBuffer = nullptr; UniformBufferView _schemaBuffer = nullptr;
}; };

View file

@ -154,8 +154,7 @@ void MeshPartPayload::render(RenderArgs* args) {
bindMesh(batch); bindMesh(batch);
// apply material properties // apply material properties
if (args->_renderMode != render::Args::RenderMode::SHADOW_RENDER_MODE) { if (RenderPipelines::bindMaterials(_drawMaterials, batch, args->_renderMode, args->_enableTexturing)) {
RenderPipelines::bindMaterials(_drawMaterials, batch, args->_enableTexturing);
args->_details._materialSwitches++; args->_details._materialSwitches++;
} }
@ -434,8 +433,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) {
} }
// apply material properties // apply material properties
if (args->_renderMode != render::Args::RenderMode::SHADOW_RENDER_MODE) { if (RenderPipelines::bindMaterials(_drawMaterials, batch, args->_renderMode, args->_enableTexturing)) {
RenderPipelines::bindMaterials(_drawMaterials, batch, args->_enableTexturing);
args->_details._materialSwitches++; args->_details._materialSwitches++;
} }

View file

@ -364,7 +364,7 @@ void RenderDeferredTaskDebug::build(JobModel& task, const render::Varying& input
sprintf(jobName, "DrawShadowFrustum%d", i); sprintf(jobName, "DrawShadowFrustum%d", i);
task.addJob<DrawFrustum>(jobName, shadowFrustum, glm::vec3(0.0f, tint, 1.0f)); task.addJob<DrawFrustum>(jobName, shadowFrustum, glm::vec3(0.0f, tint, 1.0f));
if (!renderShadowTaskOut.isNull()) { if (!renderShadowTaskOut.isNull()) {
const auto& shadowCascadeSceneBBoxes = renderShadowTaskOut; const auto& shadowCascadeSceneBBoxes = renderShadowTaskOut.get<RenderShadowTask::CascadeBoxes>();
const auto shadowBBox = shadowCascadeSceneBBoxes[ExtractFrustums::SHADOW_CASCADE0_FRUSTUM + i]; const auto shadowBBox = shadowCascadeSceneBBoxes[ExtractFrustums::SHADOW_CASCADE0_FRUSTUM + i];
sprintf(jobName, "DrawShadowBBox%d", i); sprintf(jobName, "DrawShadowBBox%d", i);
task.addJob<DrawAABox>(jobName, shadowBBox, glm::vec3(1.0f, tint, 0.0f)); task.addJob<DrawAABox>(jobName, shadowBBox, glm::vec3(1.0f, tint, 0.0f));

View file

@ -373,10 +373,10 @@ void initZPassPipelines(ShapePlumber& shapePlumber, gpu::StatePointer state, con
gpu::Shader::createProgram(deformed_model_shadow_fade_dq), state, extraBatchSetter, itemSetter); gpu::Shader::createProgram(deformed_model_shadow_fade_dq), state, extraBatchSetter, itemSetter);
} }
void RenderPipelines::bindMaterial(graphics::MaterialPointer& material, gpu::Batch& batch, bool enableTextures) { bool RenderPipelines::bindMaterial(graphics::MaterialPointer& material, gpu::Batch& batch, render::Args::RenderMode renderMode, bool enableTextures) {
graphics::MultiMaterial multiMaterial; graphics::MultiMaterial multiMaterial;
multiMaterial.push(graphics::MaterialLayer(material, 0)); multiMaterial.push(graphics::MaterialLayer(material, 0));
bindMaterials(multiMaterial, batch, enableTextures); return bindMaterials(multiMaterial, batch, renderMode, enableTextures);
} }
void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial) { void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial) {
@ -730,7 +730,7 @@ void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial
multiMaterial.setInitialized(); multiMaterial.setInitialized();
} }
void RenderPipelines::bindMaterials(graphics::MultiMaterial& multiMaterial, gpu::Batch& batch, bool enableTextures) { bool RenderPipelines::bindMaterials(graphics::MultiMaterial& multiMaterial, gpu::Batch& batch, render::Args::RenderMode renderMode, bool enableTextures) {
if (multiMaterial.shouldUpdate()) { if (multiMaterial.shouldUpdate()) {
updateMultiMaterial(multiMaterial); updateMultiMaterial(multiMaterial);
} }
@ -738,8 +738,13 @@ void RenderPipelines::bindMaterials(graphics::MultiMaterial& multiMaterial, gpu:
auto textureCache = DependencyManager::get<TextureCache>(); auto textureCache = DependencyManager::get<TextureCache>();
static gpu::TextureTablePointer defaultMaterialTextures = std::make_shared<gpu::TextureTable>(); static gpu::TextureTablePointer defaultMaterialTextures = std::make_shared<gpu::TextureTable>();
static gpu::BufferView defaultMaterialSchema;
static std::once_flag once; static std::once_flag once;
std::call_once(once, [textureCache] { std::call_once(once, [textureCache] {
graphics::MultiMaterial::Schema schema;
defaultMaterialSchema = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(schema), (const gpu::Byte*) &schema, sizeof(schema)));
defaultMaterialTextures->setTexture(gr::Texture::MaterialAlbedo, textureCache->getWhiteTexture()); defaultMaterialTextures->setTexture(gr::Texture::MaterialAlbedo, textureCache->getWhiteTexture());
defaultMaterialTextures->setTexture(gr::Texture::MaterialMetallic, textureCache->getBlackTexture()); defaultMaterialTextures->setTexture(gr::Texture::MaterialMetallic, textureCache->getBlackTexture());
defaultMaterialTextures->setTexture(gr::Texture::MaterialRoughness, textureCache->getWhiteTexture()); defaultMaterialTextures->setTexture(gr::Texture::MaterialRoughness, textureCache->getWhiteTexture());
@ -749,17 +754,29 @@ void RenderPipelines::bindMaterials(graphics::MultiMaterial& multiMaterial, gpu:
// MaterialEmissiveLightmap has to be set later // MaterialEmissiveLightmap has to be set later
}); });
auto& schemaBuffer = multiMaterial.getSchemaBuffer(); // For shadows, we only need opacity mask information
batch.setUniformBuffer(gr::Buffer::Material, schemaBuffer); auto key = multiMaterial.getMaterialKey();
if (enableTextures) { if (renderMode != render::Args::RenderMode::SHADOW_RENDER_MODE || key.isOpacityMaskMap()) {
batch.setResourceTextureTable(multiMaterial.getTextureTable()); auto& schemaBuffer = multiMaterial.getSchemaBuffer();
} else { batch.setUniformBuffer(gr::Buffer::Material, schemaBuffer);
auto key = multiMaterial.getMaterialKey(); if (enableTextures) {
if (key.isLightmapMap()) { batch.setResourceTextureTable(multiMaterial.getTextureTable());
defaultMaterialTextures->setTexture(gr::Texture::MaterialEmissiveLightmap, textureCache->getBlackTexture()); } else {
} else if (key.isEmissiveMap()) { if (renderMode != render::Args::RenderMode::SHADOW_RENDER_MODE) {
defaultMaterialTextures->setTexture(gr::Texture::MaterialEmissiveLightmap, textureCache->getGrayTexture()); if (key.isLightmapMap()) {
defaultMaterialTextures->setTexture(gr::Texture::MaterialEmissiveLightmap, textureCache->getBlackTexture());
} else if (key.isEmissiveMap()) {
defaultMaterialTextures->setTexture(gr::Texture::MaterialEmissiveLightmap, textureCache->getGrayTexture());
}
}
batch.setResourceTextureTable(defaultMaterialTextures);
} }
return true;
} else {
batch.setResourceTextureTable(defaultMaterialTextures); batch.setResourceTextureTable(defaultMaterialTextures);
batch.setUniformBuffer(gr::Buffer::Material, defaultMaterialSchema);
return false;
} }
} }

View file

@ -12,12 +12,13 @@
#define hifi_RenderPipelines_h #define hifi_RenderPipelines_h
#include <graphics/Material.h> #include <graphics/Material.h>
#include <render/Args.h>
class RenderPipelines { class RenderPipelines {
public: public:
static void bindMaterial(graphics::MaterialPointer& material, gpu::Batch& batch, bool enableTextures);
static void updateMultiMaterial(graphics::MultiMaterial& multiMaterial); static void updateMultiMaterial(graphics::MultiMaterial& multiMaterial);
static void bindMaterials(graphics::MultiMaterial& multiMaterial, gpu::Batch& batch, bool enableTextures); static bool bindMaterial(graphics::MaterialPointer& material, gpu::Batch& batch, render::Args::RenderMode renderMode, bool enableTextures);
static bool bindMaterials(graphics::MultiMaterial& multiMaterial, gpu::Batch& batch, render::Args::RenderMode renderMode, bool enableTextures);
}; };

View file

@ -34,7 +34,6 @@
#define SHADOW_FRUSTUM_NEAR 1.0f #define SHADOW_FRUSTUM_NEAR 1.0f
#define SHADOW_FRUSTUM_FAR 500.0f #define SHADOW_FRUSTUM_FAR 500.0f
static const unsigned int SHADOW_CASCADE_COUNT{ 4 }; static const unsigned int SHADOW_CASCADE_COUNT{ 4 };
static const float SHADOW_MAX_DISTANCE{ 40.0f };
using namespace render; using namespace render;
@ -90,7 +89,7 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende
#endif #endif
}; };
render::VaryingArray<AABox,4> cascadeSceneBBoxes; CascadeBoxes cascadeSceneBBoxes;
for (auto i = 0; i < SHADOW_CASCADE_MAX_COUNT; i++) { for (auto i = 0; i < SHADOW_CASCADE_MAX_COUNT; i++) {
char jobName[64]; char jobName[64];
@ -336,7 +335,7 @@ void RenderShadowSetup::setConstantBias(int cascadeIndex, float value) {
} }
void RenderShadowSetup::setSlopeBias(int cascadeIndex, float value) { void RenderShadowSetup::setSlopeBias(int cascadeIndex, float value) {
_bias[cascadeIndex]._slope = value * value * value * 0.01f; _bias[cascadeIndex]._slope = value * value * value * 0.001f;
} }
void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, const Input& input, Output& output) { void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, const Input& input, Output& output) {
@ -367,7 +366,7 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, c
output.edit2() = _cameraFrustum; output.edit2() = _cameraFrustum;
if (!_globalShadowObject) { if (!_globalShadowObject) {
_globalShadowObject = std::make_shared<LightStage::Shadow>(graphics::LightPointer(), SHADOW_MAX_DISTANCE, SHADOW_CASCADE_COUNT); _globalShadowObject = std::make_shared<LightStage::Shadow>(currentKeyLight, SHADOW_CASCADE_COUNT);
} }
_globalShadowObject->setLight(currentKeyLight); _globalShadowObject->setLight(currentKeyLight);
@ -378,11 +377,12 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, c
unsigned int cascadeIndex; unsigned int cascadeIndex;
// Adjust each cascade frustum // Adjust each cascade frustum
const auto biasScale = currentKeyLight->getShadowsBiasScale();
for (cascadeIndex = 0; cascadeIndex < _globalShadowObject->getCascadeCount(); ++cascadeIndex) { for (cascadeIndex = 0; cascadeIndex < _globalShadowObject->getCascadeCount(); ++cascadeIndex) {
auto& bias = _bias[cascadeIndex]; auto& bias = _bias[cascadeIndex];
_globalShadowObject->setKeylightCascadeFrustum(cascadeIndex, args->getViewFrustum(), _globalShadowObject->setKeylightCascadeFrustum(cascadeIndex, args->getViewFrustum(),
SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR, SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR,
bias._constant, bias._slope); bias._constant, bias._slope * biasScale);
} }
_shadowFrameCache->pushShadow(_globalShadowObject); _shadowFrameCache->pushShadow(_globalShadowObject);

View file

@ -52,8 +52,9 @@ class RenderShadowTask {
public: public:
// There is one AABox per shadow cascade // There is one AABox per shadow cascade
using CascadeBoxes = render::VaryingArray<AABox, SHADOW_CASCADE_MAX_COUNT>;
using Input = render::VaryingSet2<LightStage::FramePointer, LightingModelPointer>; using Input = render::VaryingSet2<LightStage::FramePointer, LightingModelPointer>;
using Output = render::VaryingSet2<render::VaryingArray<AABox, SHADOW_CASCADE_MAX_COUNT>, LightStage::ShadowFramePointer>; using Output = render::VaryingSet2<CascadeBoxes, LightStage::ShadowFramePointer>;
using Config = RenderShadowTaskConfig; using Config = RenderShadowTaskConfig;
using JobModel = render::Task::ModelIO<RenderShadowTask, Input, Output, Config>; using JobModel = render::Task::ModelIO<RenderShadowTask, Input, Output, Config>;
@ -92,10 +93,10 @@ public:
float constantBias1{ 0.15f }; float constantBias1{ 0.15f };
float constantBias2{ 0.175f }; float constantBias2{ 0.175f };
float constantBias3{ 0.2f }; float constantBias3{ 0.2f };
float slopeBias0{ 0.6f }; float slopeBias0{ 0.4f };
float slopeBias1{ 0.6f }; float slopeBias1{ 0.45f };
float slopeBias2{ 0.7f }; float slopeBias2{ 0.65f };
float slopeBias3{ 0.82f }; float slopeBias3{ 0.7f };
signals: signals:
void dirty(); void dirty();

View file

@ -90,8 +90,8 @@ float evalShadowAttenuationPCF(int cascadeIndex, ShadowSampleOffsets offsets, ve
return shadowAttenuation; return shadowAttenuation;
} }
float evalShadowCascadeAttenuation(int cascadeIndex, ShadowSampleOffsets offsets, vec4 shadowTexcoord, float oneMinusNdotL) { float evalShadowCascadeAttenuation(int cascadeIndex, ShadowSampleOffsets offsets, vec4 shadowTexcoord, float slopeNdotL) {
float bias = getShadowFixedBias(cascadeIndex) + getShadowSlopeBias(cascadeIndex) * oneMinusNdotL; float bias = getShadowFixedBias(cascadeIndex) + getShadowSlopeBias(cascadeIndex) * slopeNdotL;
return evalShadowAttenuationPCF(cascadeIndex, offsets, shadowTexcoord, bias); return evalShadowAttenuationPCF(cascadeIndex, offsets, shadowTexcoord, bias);
} }
@ -104,7 +104,8 @@ float evalShadowAttenuation(vec3 worldLightDir, vec4 worldPosition, float viewDe
vec3 cascadeMix; vec3 cascadeMix;
bvec4 isPixelOnCascade; bvec4 isPixelOnCascade;
int cascadeIndex; int cascadeIndex;
float oneMinusNdotL = 1.0 - clamp(dot(worldLightDir, worldNormal), 0.0, 1.0); float NdotL = clamp(dot(worldLightDir, worldNormal), 0.0, 1.0);
float slopeNdotL = min(2.0, sqrt(1.0-NdotL*NdotL) / NdotL);
for (cascadeIndex=0 ; cascadeIndex<getShadowCascadeCount() ; cascadeIndex++) { for (cascadeIndex=0 ; cascadeIndex<getShadowCascadeCount() ; cascadeIndex++) {
cascadeShadowCoords[cascadeIndex] = evalShadowTexcoord(cascadeIndex, worldPosition); cascadeShadowCoords[cascadeIndex] = evalShadowTexcoord(cascadeIndex, worldPosition);
@ -115,10 +116,10 @@ float evalShadowAttenuation(vec3 worldLightDir, vec4 worldPosition, float viewDe
isPixelOnCascade.z = isShadowCascadeProjectedOnPixel(cascadeShadowCoords[2]); isPixelOnCascade.z = isShadowCascadeProjectedOnPixel(cascadeShadowCoords[2]);
isPixelOnCascade.w = isShadowCascadeProjectedOnPixel(cascadeShadowCoords[3]); isPixelOnCascade.w = isShadowCascadeProjectedOnPixel(cascadeShadowCoords[3]);
cascadeAttenuations.x = mix(1.0, evalShadowCascadeAttenuation(0, offsets, cascadeShadowCoords[0], oneMinusNdotL), float(isPixelOnCascade.x)); cascadeAttenuations.x = mix(1.0, evalShadowCascadeAttenuation(0, offsets, cascadeShadowCoords[0], slopeNdotL), float(isPixelOnCascade.x));
cascadeAttenuations.y = mix(1.0, evalShadowCascadeAttenuation(1, offsets, cascadeShadowCoords[1], oneMinusNdotL), float(isPixelOnCascade.y)); cascadeAttenuations.y = mix(1.0, evalShadowCascadeAttenuation(1, offsets, cascadeShadowCoords[1], slopeNdotL), float(isPixelOnCascade.y));
cascadeAttenuations.z = mix(1.0, evalShadowCascadeAttenuation(2, offsets, cascadeShadowCoords[2], oneMinusNdotL), float(isPixelOnCascade.z)); cascadeAttenuations.z = mix(1.0, evalShadowCascadeAttenuation(2, offsets, cascadeShadowCoords[2], slopeNdotL), float(isPixelOnCascade.z));
cascadeAttenuations.w = mix(1.0, evalShadowCascadeAttenuation(3, offsets, cascadeShadowCoords[3], oneMinusNdotL), float(isPixelOnCascade.w)); cascadeAttenuations.w = mix(1.0, evalShadowCascadeAttenuation(3, offsets, cascadeShadowCoords[3], slopeNdotL), float(isPixelOnCascade.w));
cascadeWeights.x = evalShadowCascadeWeight(cascadeShadowCoords[0]); cascadeWeights.x = evalShadowCascadeWeight(cascadeShadowCoords[0]);
cascadeWeights.y = evalShadowCascadeWeight(cascadeShadowCoords[1]); cascadeWeights.y = evalShadowCascadeWeight(cascadeShadowCoords[1]);

View file

@ -18,9 +18,15 @@
<$declareMeshDeformer(_SCRIBE_NULL, _SCRIBE_NULL, 1, _SCRIBE_NULL, 1)$> <$declareMeshDeformer(_SCRIBE_NULL, _SCRIBE_NULL, 1, _SCRIBE_NULL, 1)$>
<$declareMeshDeformerActivation(1, 1)$> <$declareMeshDeformerActivation(1, 1)$>
<@include graphics/Material.slh@>
<@include graphics/MaterialTextures.slh@>
<$declareMaterialTexMapArrayBuffer()$>
<@include render-utils/ShaderConstants.h@> <@include render-utils/ShaderConstants.h@>
layout(location=RENDER_UTILS_ATTR_POSITION_WS) out vec4 _positionWS; layout(location=RENDER_UTILS_ATTR_POSITION_WS) out vec4 _positionWS;
layout(location=RENDER_UTILS_ATTR_TEXCOORD01) out vec4 _texCoord01;
void main(void) { void main(void) {
vec4 deformedPosition = vec4(0.0, 0.0, 0.0, 0.0); vec4 deformedPosition = vec4(0.0, 0.0, 0.0, 0.0);
@ -33,5 +39,14 @@ void main(void) {
TransformObject obj = getTransformObject(); TransformObject obj = getTransformObject();
<$transformModelToClipPos(cam, obj, deformedPosition, gl_Position)$> <$transformModelToClipPos(cam, obj, deformedPosition, gl_Position)$>
<$transformModelToWorldPos(obj, deformedPosition, _positionWS)$> <$transformModelToWorldPos(obj, deformedPosition, _positionWS)$>
Material mat = getMaterial();
BITFIELD matKey = getMaterialKey(mat);
_texCoord01 = vec4(0.0, 0.0, 0.0, 0.0);
// If we have an opacity mask than we need the first tex coord
if ((matKey & OPACITY_MASK_MAP_BIT) != 0) {
TexMapArray texMapArray = getTexMapArray();
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _positionWS, _texCoord01.xy)$>
}
} }

View file

@ -18,9 +18,15 @@
<$declareMeshDeformer(_SCRIBE_NULL, _SCRIBE_NULL, 1, 1, 1)$> <$declareMeshDeformer(_SCRIBE_NULL, _SCRIBE_NULL, 1, 1, 1)$>
<$declareMeshDeformerActivation(1, 1)$> <$declareMeshDeformerActivation(1, 1)$>
<@include graphics/Material.slh@>
<@include graphics/MaterialTextures.slh@>
<$declareMaterialTexMapArrayBuffer()$>
<@include render-utils/ShaderConstants.h@> <@include render-utils/ShaderConstants.h@>
layout(location=RENDER_UTILS_ATTR_POSITION_WS) out vec4 _positionWS; layout(location=RENDER_UTILS_ATTR_POSITION_WS) out vec4 _positionWS;
layout(location=RENDER_UTILS_ATTR_TEXCOORD01) out vec4 _texCoord01;
void main(void) { void main(void) {
vec4 deformedPosition = vec4(0.0, 0.0, 0.0, 0.0); vec4 deformedPosition = vec4(0.0, 0.0, 0.0, 0.0);
@ -33,4 +39,13 @@ void main(void) {
TransformObject obj = getTransformObject(); TransformObject obj = getTransformObject();
<$transformModelToClipPos(cam, obj, deformedPosition, gl_Position)$> <$transformModelToClipPos(cam, obj, deformedPosition, gl_Position)$>
<$transformModelToWorldPos(obj, deformedPosition, _positionWS)$> <$transformModelToWorldPos(obj, deformedPosition, _positionWS)$>
Material mat = getMaterial();
BITFIELD matKey = getMaterialKey(mat);
_texCoord01 = vec4(0.0, 0.0, 0.0, 0.0);
// If we have an opacity mask than we need the first tex coord
if ((matKey & OPACITY_MASK_MAP_BIT) != 0) {
TexMapArray texMapArray = getTexMapArray();
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _positionWS, _texCoord01.xy)$>
}
} }

View file

@ -32,7 +32,7 @@ void main(void) {
<$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$> <$fetchMaterialTexturesCoord1(matKey, _texCoord1, occlusionTex)$>
float opacity = 1.0; float opacity = 1.0;
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)&>; <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
<$discardTransparent(opacity)$>; <$discardTransparent(opacity)$>;
vec3 albedo = getMaterialAlbedo(mat); vec3 albedo = getMaterialAlbedo(mat);

View file

@ -9,10 +9,26 @@
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
<@include graphics/Material.slh@>
<@include graphics/MaterialTextures.slh@>
<@include render-utils/ShaderConstants.h@>
<$declareMaterialTextures(ALBEDO, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL)$>
layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01;
#define _texCoord0 _texCoord01.xy
layout(location=0) out vec4 _fragColor; layout(location=0) out vec4 _fragColor;
void main(void) { void main(void) {
Material mat = getMaterial();
BITFIELD matKey = getMaterialKey(mat);
<$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL)$>
float opacity = 1.0;
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
<$discardTransparent(opacity)$>;
// pass-through to set z-buffer // pass-through to set z-buffer
_fragColor = vec4(1.0, 1.0, 1.0, 0.0); _fragColor = vec4(1.0, 1.0, 1.0, 0.0);
} }

View file

@ -13,12 +13,16 @@
<@include gpu/Inputs.slh@> <@include gpu/Inputs.slh@>
<@include gpu/Transform.slh@> <@include gpu/Transform.slh@>
<@include graphics/Material.slh@>
<@include graphics/MaterialTextures.slh@>
<$declareStandardTransform()$> <$declareStandardTransform()$>
<$declareMaterialTexMapArrayBuffer()$>
<@include render-utils/ShaderConstants.h@> <@include render-utils/ShaderConstants.h@>
layout(location=RENDER_UTILS_ATTR_POSITION_WS) out vec4 _positionWS; layout(location=RENDER_UTILS_ATTR_POSITION_WS) out vec4 _positionWS;
layout(location=RENDER_UTILS_ATTR_TEXCOORD01) out vec4 _texCoord01;
void main(void) { void main(void) {
// standard transform // standard transform
@ -26,4 +30,13 @@ void main(void) {
TransformObject obj = getTransformObject(); TransformObject obj = getTransformObject();
<$transformModelToClipPos(cam, obj, inPosition, gl_Position)$> <$transformModelToClipPos(cam, obj, inPosition, gl_Position)$>
<$transformModelToWorldPos(obj, inPosition, _positionWS)$> <$transformModelToWorldPos(obj, inPosition, _positionWS)$>
Material mat = getMaterial();
BITFIELD matKey = getMaterialKey(mat);
_texCoord01 = vec4(0.0, 0.0, 0.0, 0.0);
// If we have an opacity mask than we need the first tex coord
if ((matKey & OPACITY_MASK_MAP_BIT) != 0) {
TexMapArray texMapArray = getTexMapArray();
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _positionWS, _texCoord01.xy)$>
}
} }

View file

@ -9,13 +9,18 @@
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
<@include graphics/Material.slh@>
<@include graphics/MaterialTextures.slh@>
<@include render-utils/ShaderConstants.h@> <@include render-utils/ShaderConstants.h@>
<$declareMaterialTextures(ALBEDO, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL)$>
<@include Fade.slh@> <@include Fade.slh@>
<$declareFadeFragment()$> <$declareFadeFragment()$>
layout(location=RENDER_UTILS_ATTR_POSITION_WS) in vec4 _positionWS; layout(location=RENDER_UTILS_ATTR_POSITION_WS) in vec4 _positionWS;
layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01;
#define _texCoord0 _texCoord01.xy
layout(location=0) out vec4 _fragColor; layout(location=0) out vec4 _fragColor;
@ -24,6 +29,14 @@ void main(void) {
<$fetchFadeObjectParams(fadeParams)$> <$fetchFadeObjectParams(fadeParams)$>
applyFadeClip(fadeParams, _positionWS.xyz); applyFadeClip(fadeParams, _positionWS.xyz);
Material mat = getMaterial();
BITFIELD matKey = getMaterialKey(mat);
<$fetchMaterialTexturesCoord0(matKey, _texCoord0, albedoTex, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL)$>
float opacity = 1.0;
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
<$discardTransparent(opacity)$>;
// pass-through to set z-buffer // pass-through to set z-buffer
_fragColor = vec4(1.0, 1.0, 1.0, 0.0); _fragColor = vec4(1.0, 1.0, 1.0, 0.0);
} }

View file

@ -152,6 +152,7 @@ public:
template <class... A> template <class... A>
static std::shared_ptr<Model> create(const std::string& name, const Varying& input, A&&... args) { static std::shared_ptr<Model> create(const std::string& name, const Varying& input, A&&... args) {
assert(input.canCast<I>());
return std::make_shared<Model>(name, input, std::make_shared<C>(), std::forward<A>(args)...); return std::make_shared<Model>(name, input, std::make_shared<C>(), std::forward<A>(args)...);
} }