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);
if (args->_renderMode != render::Args::RenderMode::SHADOW_RENDER_MODE) {
drawMaterial->setTextureTransforms(textureTransform, MaterialMappingMode::UV, true);
// bind the material
RenderPipelines::bindMaterial(drawMaterial, batch, args->_enableTexturing);
drawMaterial->setTextureTransforms(textureTransform, MaterialMappingMode::UV, true);
// bind the material
if (RenderPipelines::bindMaterial(drawMaterial, batch, args->_renderMode, args->_enableTexturing)) {
args->_details._materialSwitches++;
}

View file

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

View file

@ -73,6 +73,22 @@ bool Light::getCastShadows() const {
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) {
_lightSchemaBuffer.edit().irradiance.color = color;
updateLightRadius();

View file

@ -106,6 +106,12 @@ public:
void setCastShadows(const bool castShadows);
bool getCastShadows() const;
void setShadowsMaxDistance(const float maxDistance);
float getShadowsMaxDistance() const;
void setShadowsBiasScale(const float scale);
float getShadowsBiasScale() const;
void setOrientation(const Quat& orientation);
const glm::quat& getOrientation() const { return _transform.getRotation(); }
@ -192,10 +198,11 @@ protected:
Type _type { SUN };
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 };
void updateLightRadius();
};
typedef std::shared_ptr< Light > LightPointer;

View file

@ -149,7 +149,6 @@ float fetchScatteringMap(vec2 uv) {
<@endfunc@>
<@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$>) {
discard;

View file

@ -120,7 +120,7 @@ float LightStage::Shadow::Cascade::computeFarDistance(const ViewFrustum& viewFru
return far;
}
LightStage::Shadow::Shadow(graphics::LightPointer light, float maxDistance, unsigned int cascadeCount) :
LightStage::Shadow::Shadow(graphics::LightPointer light, unsigned int cascadeCount) :
_light{ light } {
cascadeCount = std::min(cascadeCount, (unsigned int)SHADOW_CASCADE_MAX_COUNT);
Schema schema;
@ -149,70 +149,79 @@ LightStage::Shadow::Shadow(graphics::LightPointer light, float maxDistance, unsi
cascade.framebuffer->setDepthBuffer(map, depthFormat, cascadeIndex);
}
setMaxDistance(maxDistance);
if (light) {
setMaxDistance(light->getShadowsMaxDistance());
}
}
void LightStage::Shadow::setLight(graphics::LightPointer light) {
_light = light;
if (light) {
setMaxDistance(light->getShadowsMaxDistance());
}
}
void LightStage::Shadow::setMaxDistance(float value) {
// This overlaping factor isn't really used directly for blending of shadow cascades. It
// 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;
static const auto MINIMUM_MAXDISTANCE = 1e-3f;
_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) {
_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
_maxDistance = value;
// The max cascade distance is computed by multiplying the previous cascade's max distance by a certain
// factor. There is a "user" factor that is computed from a desired max resolution loss in the shadow
// 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));
if (_cascades.size() == 1) {
_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
float maxCascadeUserDistance = LOW_MAX_DISTANCE;
float maxCascadeOptimalDistance = LOW_MAX_DISTANCE;
float minCascadeDistance = 0.0f;
// The max cascade distance is computed by multiplying the previous cascade's max distance by a certain
// factor. There is a "user" factor that is computed from a desired max resolution loss in the shadow
// 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 blendFactor = cascadeIndex / float(_cascades.size() - 1);
float maxCascadeDistance;
float maxCascadeUserDistance = LOW_MAX_DISTANCE;
float maxCascadeOptimalDistance = LOW_MAX_DISTANCE;
float minCascadeDistance = 0.0f;
if (cascadeIndex == size_t(_cascades.size() - 1)) {
maxCascadeDistance = _maxDistance;
} else {
maxCascadeDistance = maxCascadeUserDistance + (maxCascadeOptimalDistance - maxCascadeUserDistance)*blendFactor*blendFactor;
for (size_t cascadeIndex = 0; cascadeIndex < _cascades.size(); ++cascadeIndex) {
float blendFactor = cascadeIndex / float(_cascades.size() - 1);
float maxCascadeDistance;
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
const auto& lastCascade = _cascades.back();
auto& schema = _schemaBuffer.edit<Schema>();
schema.maxDistance = _maxDistance;
schema.invFalloffDistance = 1.0f / (OVERLAP_FACTOR*lastCascade.getMaxDistance());
// Update the buffer
const auto& lastCascade = _cascades.back();
auto& schema = _schemaBuffer.edit<Schema>();
schema.maxDistance = _maxDistance;
schema.invFalloffDistance = 1.0f / (OVERLAP_FACTOR*lastCascade.getMaxDistance());
}
}
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;
};
Shadow(graphics::LightPointer light, float maxDistance, unsigned int cascadeCount = 1);
Shadow(graphics::LightPointer light, unsigned int cascadeCount = 1);
void setLight(graphics::LightPointer light);
@ -104,16 +104,14 @@ public:
};
protected:
using Cascades = std::vector<Cascade>;
static const glm::mat4 _biasMatrix;
graphics::LightPointer _light;
float _maxDistance;
float _maxDistance{ 0.0f };
Cascades _cascades;
UniformBufferView _schemaBuffer = nullptr;
};

View file

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

View file

@ -364,7 +364,7 @@ void RenderDeferredTaskDebug::build(JobModel& task, const render::Varying& input
sprintf(jobName, "DrawShadowFrustum%d", i);
task.addJob<DrawFrustum>(jobName, shadowFrustum, glm::vec3(0.0f, tint, 1.0f));
if (!renderShadowTaskOut.isNull()) {
const auto& shadowCascadeSceneBBoxes = renderShadowTaskOut;
const auto& shadowCascadeSceneBBoxes = renderShadowTaskOut.get<RenderShadowTask::CascadeBoxes>();
const auto shadowBBox = shadowCascadeSceneBBoxes[ExtractFrustums::SHADOW_CASCADE0_FRUSTUM + i];
sprintf(jobName, "DrawShadowBBox%d", i);
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);
}
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;
multiMaterial.push(graphics::MaterialLayer(material, 0));
bindMaterials(multiMaterial, batch, enableTextures);
return bindMaterials(multiMaterial, batch, renderMode, enableTextures);
}
void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial) {
@ -730,7 +730,7 @@ void RenderPipelines::updateMultiMaterial(graphics::MultiMaterial& multiMaterial
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()) {
updateMultiMaterial(multiMaterial);
}
@ -738,8 +738,13 @@ void RenderPipelines::bindMaterials(graphics::MultiMaterial& multiMaterial, gpu:
auto textureCache = DependencyManager::get<TextureCache>();
static gpu::TextureTablePointer defaultMaterialTextures = std::make_shared<gpu::TextureTable>();
static gpu::BufferView defaultMaterialSchema;
static std::once_flag once;
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::MaterialMetallic, textureCache->getBlackTexture());
defaultMaterialTextures->setTexture(gr::Texture::MaterialRoughness, textureCache->getWhiteTexture());
@ -749,17 +754,29 @@ void RenderPipelines::bindMaterials(graphics::MultiMaterial& multiMaterial, gpu:
// MaterialEmissiveLightmap has to be set later
});
auto& schemaBuffer = multiMaterial.getSchemaBuffer();
batch.setUniformBuffer(gr::Buffer::Material, schemaBuffer);
if (enableTextures) {
batch.setResourceTextureTable(multiMaterial.getTextureTable());
} else {
auto key = multiMaterial.getMaterialKey();
if (key.isLightmapMap()) {
defaultMaterialTextures->setTexture(gr::Texture::MaterialEmissiveLightmap, textureCache->getBlackTexture());
} else if (key.isEmissiveMap()) {
defaultMaterialTextures->setTexture(gr::Texture::MaterialEmissiveLightmap, textureCache->getGrayTexture());
// For shadows, we only need opacity mask information
auto key = multiMaterial.getMaterialKey();
if (renderMode != render::Args::RenderMode::SHADOW_RENDER_MODE || key.isOpacityMaskMap()) {
auto& schemaBuffer = multiMaterial.getSchemaBuffer();
batch.setUniformBuffer(gr::Buffer::Material, schemaBuffer);
if (enableTextures) {
batch.setResourceTextureTable(multiMaterial.getTextureTable());
} else {
if (renderMode != render::Args::RenderMode::SHADOW_RENDER_MODE) {
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.setUniformBuffer(gr::Buffer::Material, defaultMaterialSchema);
return false;
}
}

View file

@ -12,12 +12,13 @@
#define hifi_RenderPipelines_h
#include <graphics/Material.h>
#include <render/Args.h>
class RenderPipelines {
public:
static void bindMaterial(graphics::MaterialPointer& material, gpu::Batch& batch, bool enableTextures);
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_FAR 500.0f
static const unsigned int SHADOW_CASCADE_COUNT{ 4 };
static const float SHADOW_MAX_DISTANCE{ 40.0f };
using namespace render;
@ -90,7 +89,7 @@ void RenderShadowTask::build(JobModel& task, const render::Varying& input, rende
#endif
};
render::VaryingArray<AABox,4> cascadeSceneBBoxes;
CascadeBoxes cascadeSceneBBoxes;
for (auto i = 0; i < SHADOW_CASCADE_MAX_COUNT; i++) {
char jobName[64];
@ -336,7 +335,7 @@ void RenderShadowSetup::setConstantBias(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) {
@ -367,7 +366,7 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, c
output.edit2() = _cameraFrustum;
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);
@ -378,11 +377,12 @@ void RenderShadowSetup::run(const render::RenderContextPointer& renderContext, c
unsigned int cascadeIndex;
// Adjust each cascade frustum
const auto biasScale = currentKeyLight->getShadowsBiasScale();
for (cascadeIndex = 0; cascadeIndex < _globalShadowObject->getCascadeCount(); ++cascadeIndex) {
auto& bias = _bias[cascadeIndex];
_globalShadowObject->setKeylightCascadeFrustum(cascadeIndex, args->getViewFrustum(),
SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR,
bias._constant, bias._slope);
SHADOW_FRUSTUM_NEAR, SHADOW_FRUSTUM_FAR,
bias._constant, bias._slope * biasScale);
}
_shadowFrameCache->pushShadow(_globalShadowObject);

View file

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

View file

@ -90,8 +90,8 @@ float evalShadowAttenuationPCF(int cascadeIndex, ShadowSampleOffsets offsets, ve
return shadowAttenuation;
}
float evalShadowCascadeAttenuation(int cascadeIndex, ShadowSampleOffsets offsets, vec4 shadowTexcoord, float oneMinusNdotL) {
float bias = getShadowFixedBias(cascadeIndex) + getShadowSlopeBias(cascadeIndex) * oneMinusNdotL;
float evalShadowCascadeAttenuation(int cascadeIndex, ShadowSampleOffsets offsets, vec4 shadowTexcoord, float slopeNdotL) {
float bias = getShadowFixedBias(cascadeIndex) + getShadowSlopeBias(cascadeIndex) * slopeNdotL;
return evalShadowAttenuationPCF(cascadeIndex, offsets, shadowTexcoord, bias);
}
@ -104,7 +104,8 @@ float evalShadowAttenuation(vec3 worldLightDir, vec4 worldPosition, float viewDe
vec3 cascadeMix;
bvec4 isPixelOnCascade;
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++) {
cascadeShadowCoords[cascadeIndex] = evalShadowTexcoord(cascadeIndex, worldPosition);
@ -115,10 +116,10 @@ float evalShadowAttenuation(vec3 worldLightDir, vec4 worldPosition, float viewDe
isPixelOnCascade.z = isShadowCascadeProjectedOnPixel(cascadeShadowCoords[2]);
isPixelOnCascade.w = isShadowCascadeProjectedOnPixel(cascadeShadowCoords[3]);
cascadeAttenuations.x = mix(1.0, evalShadowCascadeAttenuation(0, offsets, cascadeShadowCoords[0], oneMinusNdotL), float(isPixelOnCascade.x));
cascadeAttenuations.y = mix(1.0, evalShadowCascadeAttenuation(1, offsets, cascadeShadowCoords[1], oneMinusNdotL), float(isPixelOnCascade.y));
cascadeAttenuations.z = mix(1.0, evalShadowCascadeAttenuation(2, offsets, cascadeShadowCoords[2], oneMinusNdotL), float(isPixelOnCascade.z));
cascadeAttenuations.w = mix(1.0, evalShadowCascadeAttenuation(3, offsets, cascadeShadowCoords[3], oneMinusNdotL), float(isPixelOnCascade.w));
cascadeAttenuations.x = mix(1.0, evalShadowCascadeAttenuation(0, offsets, cascadeShadowCoords[0], slopeNdotL), float(isPixelOnCascade.x));
cascadeAttenuations.y = mix(1.0, evalShadowCascadeAttenuation(1, offsets, cascadeShadowCoords[1], slopeNdotL), float(isPixelOnCascade.y));
cascadeAttenuations.z = mix(1.0, evalShadowCascadeAttenuation(2, offsets, cascadeShadowCoords[2], slopeNdotL), float(isPixelOnCascade.z));
cascadeAttenuations.w = mix(1.0, evalShadowCascadeAttenuation(3, offsets, cascadeShadowCoords[3], slopeNdotL), float(isPixelOnCascade.w));
cascadeWeights.x = evalShadowCascadeWeight(cascadeShadowCoords[0]);
cascadeWeights.y = evalShadowCascadeWeight(cascadeShadowCoords[1]);

View file

@ -18,9 +18,15 @@
<$declareMeshDeformer(_SCRIBE_NULL, _SCRIBE_NULL, 1, _SCRIBE_NULL, 1)$>
<$declareMeshDeformerActivation(1, 1)$>
<@include graphics/Material.slh@>
<@include graphics/MaterialTextures.slh@>
<$declareMaterialTexMapArrayBuffer()$>
<@include render-utils/ShaderConstants.h@>
layout(location=RENDER_UTILS_ATTR_POSITION_WS) out vec4 _positionWS;
layout(location=RENDER_UTILS_ATTR_TEXCOORD01) out vec4 _texCoord01;
void main(void) {
vec4 deformedPosition = vec4(0.0, 0.0, 0.0, 0.0);
@ -33,5 +39,14 @@ void main(void) {
TransformObject obj = getTransformObject();
<$transformModelToClipPos(cam, obj, deformedPosition, gl_Position)$>
<$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)$>
<$declareMeshDeformerActivation(1, 1)$>
<@include graphics/Material.slh@>
<@include graphics/MaterialTextures.slh@>
<$declareMaterialTexMapArrayBuffer()$>
<@include render-utils/ShaderConstants.h@>
layout(location=RENDER_UTILS_ATTR_POSITION_WS) out vec4 _positionWS;
layout(location=RENDER_UTILS_ATTR_TEXCOORD01) out vec4 _texCoord01;
void main(void) {
vec4 deformedPosition = vec4(0.0, 0.0, 0.0, 0.0);
@ -33,4 +39,13 @@ void main(void) {
TransformObject obj = getTransformObject();
<$transformModelToClipPos(cam, obj, deformedPosition, gl_Position)$>
<$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)$>
float opacity = 1.0;
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)&>;
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
<$discardTransparent(opacity)$>;
vec3 albedo = getMaterialAlbedo(mat);

View file

@ -9,10 +9,26 @@
// Distributed under the Apache License, Version 2.0.
// 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;
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
_fragColor = vec4(1.0, 1.0, 1.0, 0.0);
}

View file

@ -13,12 +13,16 @@
<@include gpu/Inputs.slh@>
<@include gpu/Transform.slh@>
<@include graphics/Material.slh@>
<@include graphics/MaterialTextures.slh@>
<$declareStandardTransform()$>
<$declareMaterialTexMapArrayBuffer()$>
<@include render-utils/ShaderConstants.h@>
layout(location=RENDER_UTILS_ATTR_POSITION_WS) out vec4 _positionWS;
layout(location=RENDER_UTILS_ATTR_TEXCOORD01) out vec4 _texCoord01;
void main(void) {
// standard transform
@ -26,4 +30,13 @@ void main(void) {
TransformObject obj = getTransformObject();
<$transformModelToClipPos(cam, obj, inPosition, gl_Position)$>
<$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.
// 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)$>
<@include Fade.slh@>
<$declareFadeFragment()$>
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;
@ -24,6 +29,14 @@ void main(void) {
<$fetchFadeObjectParams(fadeParams)$>
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
_fragColor = vec4(1.0, 1.0, 1.0, 0.0);
}

View file

@ -152,6 +152,7 @@ public:
template <class... A>
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)...);
}