Compare commits
8 Commits
bjd/debugg
...
bjd/fix-op
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b236bd4f50 | ||
|
|
b7b7afb62a | ||
|
|
957380b258 | ||
|
|
fe3f16924d | ||
|
|
ffc3128377 | ||
|
|
c05e2ec47d | ||
|
|
9768f49714 | ||
|
|
6c54cfe88a |
@@ -31,7 +31,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.android.filament:filament-android:1.28.2'
|
||||
implementation 'com.google.android.filament:filament-android:1.29.0'
|
||||
}
|
||||
```
|
||||
|
||||
@@ -51,7 +51,7 @@ Here are all the libraries available in the group `com.google.android.filament`:
|
||||
iOS projects can use CocoaPods to install the latest release:
|
||||
|
||||
```
|
||||
pod 'Filament', '~> 1.28.2'
|
||||
pod 'Filament', '~> 1.29.0'
|
||||
```
|
||||
|
||||
### Snapshots
|
||||
|
||||
@@ -5,10 +5,13 @@ A new header is inserted each time a *tag* is created.
|
||||
|
||||
## main branch
|
||||
|
||||
## v1.29.0
|
||||
|
||||
- gltfio: calculate primitive's AABB correctly.
|
||||
- gltfio: recompute bounding boxes with morph targets
|
||||
- engine: add missing getters on `MaterialInstance`
|
||||
- WebGL: add missing `ColorGrading` JS bindings
|
||||
- engine: improvements/cleanup of Shadow mapping code [⚠️ **Recompile Materials**]
|
||||
|
||||
## v1.28.3
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
GROUP=com.google.android.filament
|
||||
VERSION_NAME=1.28.2
|
||||
VERSION_NAME=1.29.0
|
||||
|
||||
POM_DESCRIPTION=Real-time physically based rendering engine for Android.
|
||||
|
||||
|
||||
@@ -290,14 +290,10 @@ void PerViewUniforms::prepareShadowMapping(bool highPrecision) noexcept {
|
||||
|
||||
void PerViewUniforms::prepareShadowSampling(PerViewUib& uniforms,
|
||||
ShadowMappingUniforms const& shadowMappingUniforms) noexcept {
|
||||
uniforms.lightFromWorldMatrix = shadowMappingUniforms.lightFromWorldMatrix;
|
||||
uniforms.cascadeSplits = shadowMappingUniforms.cascadeSplits;
|
||||
uniforms.shadowBulbRadiusLs = shadowMappingUniforms.shadowBulbRadiusLs;
|
||||
uniforms.shadowBias = shadowMappingUniforms.shadowBias;
|
||||
uniforms.ssContactShadowDistance = shadowMappingUniforms.ssContactShadowDistance;
|
||||
uniforms.directionalShadows = shadowMappingUniforms.directionalShadows;
|
||||
uniforms.cascades = shadowMappingUniforms.cascades;
|
||||
uniforms.cascades |= uint32_t(shadowMappingUniforms.elvsm) << 31u;
|
||||
}
|
||||
|
||||
void PerViewUniforms::prepareShadowVSM(Handle<HwTexture> texture,
|
||||
|
||||
@@ -750,6 +750,11 @@ void RenderPass::Executor::execute(backend::DriverApi& driver,
|
||||
continue;
|
||||
}
|
||||
|
||||
// primitiveHandle may be invalid if no geometry was set on the renderable.
|
||||
if (UTILS_UNLIKELY(!first->primitive.primitiveHandle)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// per-renderable uniform
|
||||
const PrimitiveInfo info = first->primitive;
|
||||
pipeline.rasterState = info.rasterState;
|
||||
|
||||
@@ -413,41 +413,10 @@ ShadowMap::ShaderParameters ShadowMap::updateDirectional(FEngine& engine,
|
||||
return shaderParameters;
|
||||
}
|
||||
|
||||
ShadowMap::ShaderParameters ShadowMap::updateSpot(FEngine& engine,
|
||||
const FScene::LightSoa& lightData, size_t index,
|
||||
filament::CameraInfo const& camera,
|
||||
const ShadowMapInfo& shadowMapInfo,
|
||||
FScene const& scene, SceneInfo sceneInfo) noexcept {
|
||||
|
||||
ShaderParameters shaderParameters;
|
||||
|
||||
auto& lcm = engine.getLightManager();
|
||||
auto li = lightData.elementAt<FScene::LIGHT_INSTANCE>(index);
|
||||
auto position = lightData.elementAt<FScene::POSITION_RADIUS>(index).xyz;
|
||||
auto direction = lightData.elementAt<FScene::DIRECTION>(index);
|
||||
auto radius = lightData.elementAt<FScene::POSITION_RADIUS>(index).w;
|
||||
auto outerConeAngle = lcm.getSpotLightOuterCone(li);
|
||||
const FLightManager::ShadowParams& params = lcm.getShadowParams(li);
|
||||
|
||||
/*
|
||||
* Compute the light model matrix.
|
||||
*/
|
||||
|
||||
// Choose a reasonable value for the near plane.
|
||||
const mat4f Mv = getDirectionalLightViewMatrix(direction, position);
|
||||
|
||||
// find decent near/far
|
||||
ShadowMap::updateSceneInfoSpot(Mv, scene, sceneInfo);
|
||||
|
||||
// if the scene was empty, near > far
|
||||
mHasVisibleShadows = -sceneInfo.lsNearFar[0] < -sceneInfo.lsNearFar[1];
|
||||
|
||||
// FIXME: we need a configuration for minimum near plane (for now hardcoded to 1cm)
|
||||
float nearPlane = std::max(0.01f, -sceneInfo.lsNearFar[0]);
|
||||
float farPlane = std::min(radius, -sceneInfo.lsNearFar[1]);
|
||||
|
||||
float outerConeAngleDegrees = outerConeAngle * f::RAD_TO_DEG;
|
||||
const mat4f Mp = mat4f::perspective(outerConeAngleDegrees * 2.0f, 1.0f, nearPlane, farPlane);
|
||||
ShadowMap::ShaderParameters ShadowMap::updateSpotOrPoint(
|
||||
mat4f const& Mv, float outerConeAngle, float nearPlane, float farPlane,
|
||||
const ShadowMapInfo& shadowMapInfo, const FLightManager::ShadowParams& params) noexcept {
|
||||
const mat4f Mp = mat4f::perspective(outerConeAngle * f::RAD_TO_DEG * 2.0f, 1.0f, nearPlane, farPlane);
|
||||
const mat4f MpMv(math::highPrecisionMultiply(Mp, Mv));
|
||||
|
||||
// Final shadow transform
|
||||
@@ -469,7 +438,9 @@ ShadowMap::ShaderParameters ShadowMap::updateSpot(FEngine& engine,
|
||||
// = zInLightSpace * texelSizeAtOneMeter
|
||||
// = zInLightSpace * (2*tan(halfConeAngle)/dimension)
|
||||
// Note: this would not work with LISPSM, which warps the texture space.
|
||||
shaderParameters.texelSizeAtOneMeterWs = (2.0f * std::tan(outerConeAngle) / float(shadowMapInfo.shadowDimension));
|
||||
ShaderParameters shaderParameters;
|
||||
shaderParameters.texelSizeAtOneMeterWs =
|
||||
(2.0f * std::tan(outerConeAngle) / float(shadowMapInfo.shadowDimension));
|
||||
shaderParameters.lightFromWorldZ = -transpose(Mv)[2]; // negate because camera looks in -Z
|
||||
|
||||
if (!shadowMapInfo.vsm) {
|
||||
@@ -478,9 +449,9 @@ ShadowMap::ShaderParameters ShadowMap::updateSpot(FEngine& engine,
|
||||
shaderParameters.lightSpace = computeVsmLightSpaceMatrix(St, Mv, nearPlane, farPlane);
|
||||
}
|
||||
|
||||
const float3 direction = -transpose(Mv)[2].xyz;
|
||||
const float constantBias = shadowMapInfo.vsm ? 0.0f : params.options.constantBias;
|
||||
const mat4f b = mat4f::translation(direction * constantBias);
|
||||
const mat4f Sb = S * b;
|
||||
|
||||
// It's important to set the light camera's model matrix separately from its projection, so that
|
||||
// the cameraPosition uniform gets set correctly.
|
||||
@@ -493,19 +464,44 @@ ShadowMap::ShaderParameters ShadowMap::updateSpot(FEngine& engine,
|
||||
mCamera->setModelMatrix(mat4{ FCamera::rigidTransformInverse(Mv * b) });
|
||||
mCamera->setCustomProjection(mat4(Mp), nearPlane, farPlane);
|
||||
|
||||
// for the debug camera, we need to undo the world origin
|
||||
mDebugCamera->setCustomProjection(mat4(Sb * camera.worldOrigin), nearPlane, radius);
|
||||
|
||||
return shaderParameters;
|
||||
}
|
||||
|
||||
ShadowMap::ShaderParameters ShadowMap::updateSpot(FEngine& engine,
|
||||
const FScene::LightSoa& lightData, size_t index,
|
||||
filament::CameraInfo const& camera,
|
||||
const ShadowMapInfo& shadowMapInfo,
|
||||
FScene const& scene, SceneInfo sceneInfo) noexcept {
|
||||
|
||||
auto& lcm = engine.getLightManager();
|
||||
auto position = lightData.elementAt<FScene::POSITION_RADIUS>(index).xyz;
|
||||
auto direction = lightData.elementAt<FScene::DIRECTION>(index);
|
||||
auto radius = lightData.elementAt<FScene::POSITION_RADIUS>(index).w;
|
||||
auto li = lightData.elementAt<FScene::LIGHT_INSTANCE>(index);
|
||||
const FLightManager::ShadowParams& params = lcm.getShadowParams(li);
|
||||
const mat4f Mv = getDirectionalLightViewMatrix(direction, position);
|
||||
|
||||
// find decent near/far
|
||||
ShadowMap::updateSceneInfoSpot(Mv, scene, sceneInfo);
|
||||
|
||||
// if the scene was empty, near > far
|
||||
mHasVisibleShadows = -sceneInfo.lsNearFar[0] < -sceneInfo.lsNearFar[1];
|
||||
if (!mHasVisibleShadows) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// FIXME: we need a configuration for minimum near plane (for now hardcoded to 1cm)
|
||||
float nearPlane = std::max(0.01f, -sceneInfo.lsNearFar[0]);
|
||||
float farPlane = std::min(radius, -sceneInfo.lsNearFar[1]);
|
||||
auto outerConeAngle = lcm.getSpotLightOuterCone(li);
|
||||
return updateSpotOrPoint(Mv, outerConeAngle, nearPlane, farPlane, shadowMapInfo, params);
|
||||
}
|
||||
|
||||
ShadowMap::ShaderParameters ShadowMap::updatePoint(FEngine& engine,
|
||||
const FScene::LightSoa& lightData, size_t index,
|
||||
filament::CameraInfo const& camera, const ShadowMapInfo& shadowMapInfo, FScene const& scene,
|
||||
SceneInfo, uint8_t face) noexcept {
|
||||
|
||||
ShaderParameters shaderParameters;
|
||||
|
||||
// check if this shadow map has anything to render
|
||||
mHasVisibleShadows = false;
|
||||
FScene::RenderableSoa const& UTILS_RESTRICT soa = scene.getRenderableData();
|
||||
@@ -518,53 +514,16 @@ ShadowMap::ShaderParameters ShadowMap::updatePoint(FEngine& engine,
|
||||
}
|
||||
}
|
||||
if (!mHasVisibleShadows) {
|
||||
return shaderParameters;
|
||||
return {};
|
||||
}
|
||||
|
||||
auto& lcm = engine.getLightManager();
|
||||
|
||||
auto li = lightData.elementAt<FScene::LIGHT_INSTANCE>(index);
|
||||
auto position = lightData.elementAt<FScene::POSITION_RADIUS>(index).xyz;
|
||||
auto radius = lightData.elementAt<FScene::POSITION_RADIUS>(index).w;
|
||||
auto li = lightData.elementAt<FScene::LIGHT_INSTANCE>(index);
|
||||
const FLightManager::ShadowParams& params = lcm.getShadowParams(li);
|
||||
|
||||
/*
|
||||
* Compute the light model matrix.
|
||||
*/
|
||||
|
||||
const mat4f Mv = getPointLightViewMatrix(TextureCubemapFace(face), position);
|
||||
const float3 direction = -transpose(Mv)[2].xyz;
|
||||
|
||||
// TODO: don't hardcode near plane
|
||||
// Choose a reasonable value for the near plane.
|
||||
float nearPlane = 0.01f;
|
||||
float farPlane = radius;
|
||||
const mat4f Mp = mat4f::perspective(90.0f, 1.0f, nearPlane, farPlane);
|
||||
|
||||
// For calculating the point light normal bias, we need the texel size in world space at the
|
||||
// sample location. Using Thales's theorem, we find:
|
||||
// texelSize(zInLightSpace) = zInLightSpace * texelSizeOnTheNearPlane / near
|
||||
// = zInLightSpace * texelSizeAtOneMeter
|
||||
// = zInLightSpace * (2*tan(halfConeAngle)/dimension)
|
||||
// Note: this would not work with LISPSM, which warps the texture space.
|
||||
shaderParameters.texelSizeAtOneMeterWs =
|
||||
(2.0f * std::tan(f::PI_4) / float(shadowMapInfo.shadowDimension));
|
||||
|
||||
const float constantBias = shadowMapInfo.vsm ? 0.0f : params.options.constantBias;
|
||||
const mat4f b = mat4f::translation(direction * constantBias);
|
||||
|
||||
// It's important to set the light camera's model matrix separately from its projection, so that
|
||||
// the cameraPosition uniform gets set correctly.
|
||||
// mLightSpace is used in the shader to access the shadow map texture, and has the model matrix
|
||||
// baked in.
|
||||
|
||||
// The model matrix below is in fact inverted to get the view matrix and passed to the
|
||||
// shader as 'viewFromWorldMatrix', and is used in the VSM case to compute the depth metric.
|
||||
// (see depth_main.fs). Note that in the case of VSM, 'b' below is identity.
|
||||
mCamera->setModelMatrix(mat4{ FCamera::rigidTransformInverse(Mv * b) });
|
||||
mCamera->setCustomProjection(mat4(Mp), nearPlane, farPlane);
|
||||
|
||||
return shaderParameters;
|
||||
return updateSpotOrPoint(Mv, 45.0f * f::DEG_TO_RAD, 0.01f, radius, shadowMapInfo, params);
|
||||
}
|
||||
|
||||
mat4f ShadowMap::applyLISPSM(mat4f& Wp,
|
||||
|
||||
@@ -214,6 +214,11 @@ private:
|
||||
// 8 corners, 12 segments w/ 2 intersection max -- all of this twice (8 + 12 * 2) * 2 (768 bytes)
|
||||
using FrustumBoxIntersection = std::array<math::float3, 64>;
|
||||
|
||||
ShaderParameters updateSpotOrPoint(
|
||||
math::mat4f const& Mv, float outerConeAngle, float nearPlane, float farPlane,
|
||||
const ShadowMapInfo& shadowMapInfo,
|
||||
const FLightManager::ShadowParams& params) noexcept;
|
||||
|
||||
static math::mat4f applyLISPSM(math::mat4f& Wp,
|
||||
filament::CameraInfo const& camera, FLightManager::ShadowParams const& params,
|
||||
const math::mat4f& LMpMv,
|
||||
|
||||
@@ -97,8 +97,10 @@ void ShadowMapManager::setDirectionalShadowMap(size_t lightIndex,
|
||||
LightManager::ShadowOptions const* options) noexcept {
|
||||
assert_invariant(options->shadowCascades <= CONFIG_MAX_SHADOW_CASCADES);
|
||||
for (size_t c = 0; c < options->shadowCascades; c++) {
|
||||
auto* pShadowMap = getCascadeShadowMap(c);
|
||||
pShadowMap->initialize(lightIndex, ShadowType::DIRECTIONAL, c, 0, options);
|
||||
const size_t i = c;
|
||||
assert_invariant(i < CONFIG_MAX_SHADOW_CASCADES);
|
||||
auto* pShadowMap = getCascadeShadowMap(i);
|
||||
pShadowMap->initialize(lightIndex, ShadowType::DIRECTIONAL, i, 0, options);
|
||||
mCascadeShadowMaps.push_back(pShadowMap);
|
||||
}
|
||||
}
|
||||
@@ -107,17 +109,19 @@ void ShadowMapManager::addShadowMap(size_t lightIndex, bool spotlight,
|
||||
LightManager::ShadowOptions const* options) noexcept {
|
||||
if (spotlight) {
|
||||
const size_t c = mSpotShadowMaps.size();
|
||||
assert_invariant(c < CONFIG_MAX_SHADOWMAPS);
|
||||
auto* pShadowMap = getPointOrSpotShadowMap(c);
|
||||
pShadowMap->initialize(lightIndex, ShadowType::SPOT, c, 0, options);
|
||||
const size_t i = c + CONFIG_MAX_SHADOW_CASCADES;
|
||||
assert_invariant(i < CONFIG_MAX_SHADOWMAPS);
|
||||
auto* pShadowMap = getPointOrSpotShadowMap(i);
|
||||
pShadowMap->initialize(lightIndex, ShadowType::SPOT, i, 0, options);
|
||||
mSpotShadowMaps.push_back(pShadowMap);
|
||||
} else {
|
||||
// point-light, generate 6 independent shadowmaps
|
||||
for (size_t face = 0; face < 6; face++) {
|
||||
const size_t c = mSpotShadowMaps.size();
|
||||
assert_invariant(c < CONFIG_MAX_SHADOWMAPS);
|
||||
auto* pShadowMap = getPointOrSpotShadowMap(c);
|
||||
pShadowMap->initialize(lightIndex, ShadowType::POINT, c, face, options);
|
||||
const size_t i = c + CONFIG_MAX_SHADOW_CASCADES;
|
||||
assert_invariant(i < CONFIG_MAX_SHADOWMAPS);
|
||||
auto* pShadowMap = getPointOrSpotShadowMap(i);
|
||||
pShadowMap->initialize(lightIndex, ShadowType::POINT, i, face, options);
|
||||
mSpotShadowMaps.push_back(pShadowMap);
|
||||
}
|
||||
}
|
||||
@@ -455,7 +459,7 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEng
|
||||
// entire camera frustum, as if we only had a single cascade.
|
||||
ShadowMap& shadowMap = *mCascadeShadowMaps[0];
|
||||
|
||||
auto shaderParameters = shadowMap.updateDirectional(mEngine,
|
||||
shadowMap.updateDirectional(mEngine,
|
||||
lightData, 0, cameraInfo, shadowMapInfo, *scene, sceneInfo);
|
||||
|
||||
hasVisibleShadows = shadowMap.hasVisibleShadows();
|
||||
@@ -464,18 +468,6 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEng
|
||||
Frustum const& frustum = shadowMap.getCamera().getCullingFrustum();
|
||||
FView::cullRenderables(engine.getJobSystem(), renderableData, frustum,
|
||||
VISIBLE_DIR_SHADOW_RENDERABLE_BIT);
|
||||
|
||||
// Set shadowBias, using the first directional cascade.
|
||||
// when computing the required bias we need a half-texel size, so we multiply by 0.5 here.
|
||||
// note: normalBias is set to zero for VSM
|
||||
const float normalBias = shadowMapInfo.vsm ? 0.0f : 0.5f * lcm.getShadowNormalBias(0);
|
||||
// Texel size is constant for directional light (although that's not true when LISPSM
|
||||
// is used, but in that case we're pretending it is).
|
||||
const float wsTexelSize = shaderParameters.texelSizeAtOneMeterWs;
|
||||
mShadowMappingUniforms.shadowBias = normalBias * wsTexelSize;
|
||||
mShadowMappingUniforms.shadowBulbRadiusLs =
|
||||
mSoftShadowOptions.penumbraScale * options.shadowBulbRadius / wsTexelSize;
|
||||
mShadowMappingUniforms.elvsm = options.vsm.elvsm;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -528,6 +520,10 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEng
|
||||
|
||||
mShadowMappingUniforms.cascadeSplits = wsSplitPositionUniform;
|
||||
|
||||
// when computing the required bias we need a half-texel size, so we multiply by 0.5 here.
|
||||
// note: normalBias is set to zero for VSM
|
||||
const float normalBias = shadowMapInfo.vsm ? 0.0f : 0.5f * lcm.getShadowNormalBias(0);
|
||||
|
||||
for (size_t i = 0, c = mCascadeShadowMaps.size(); i < c; i++) {
|
||||
assert_invariant(mCascadeShadowMaps[i]);
|
||||
|
||||
@@ -541,7 +537,22 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateCascadeShadowMaps(FEng
|
||||
lightData, 0, cameraInfo, shadowMapInfo, *scene, sceneInfo);
|
||||
|
||||
if (shadowMap.hasVisibleShadows()) {
|
||||
mShadowMappingUniforms.lightFromWorldMatrix[i] = shaderParameters.lightSpace;
|
||||
const size_t shadowIndex = shadowMap.getShadowIndex();
|
||||
assert_invariant(shadowIndex == i);
|
||||
|
||||
// Texel size is constant for directional light (although that's not true when LISPSM
|
||||
// is used, but in that case we're pretending it is).
|
||||
const float wsTexelSize = shaderParameters.texelSizeAtOneMeterWs;
|
||||
|
||||
auto& s = mShadowUb.edit();
|
||||
s.shadows[shadowIndex].layer = shadowMap.getLayer();
|
||||
s.shadows[shadowIndex].lightFromWorldMatrix = shaderParameters.lightSpace;
|
||||
s.shadows[shadowIndex].normalBias = normalBias * wsTexelSize;
|
||||
s.shadows[shadowIndex].texelSizeAtOneMeter = wsTexelSize;
|
||||
s.shadows[shadowIndex].elvsm = options.vsm.elvsm;
|
||||
s.shadows[shadowIndex].bulbRadiusLs =
|
||||
mSoftShadowOptions.penumbraScale * options.shadowBulbRadius / wsTexelSize;
|
||||
|
||||
shadowTechnique |= ShadowTechnique::SHADOW_MAP;
|
||||
cascadeHasVisibleShadows |= 0x1u << i;
|
||||
}
|
||||
@@ -669,6 +680,7 @@ void ShadowMapManager::prepareSpotShadowMap(ShadowMap& shadowMap,
|
||||
auto& s = mShadowUb.edit();
|
||||
const double n = shadowMap.getCamera().getNear();
|
||||
const double f = shadowMap.getCamera().getCullingFar();
|
||||
s.shadows[shadowIndex].layer = shadowMap.getLayer();
|
||||
s.shadows[shadowIndex].lightFromWorldMatrix = shaderParameters.lightSpace;
|
||||
s.shadows[shadowIndex].direction = direction;
|
||||
s.shadows[shadowIndex].normalBias = normalBias * wsTexelSizeAtOneMeter;
|
||||
@@ -678,7 +690,8 @@ void ShadowMapManager::prepareSpotShadowMap(ShadowMap& shadowMap,
|
||||
s.shadows[shadowIndex].elvsm = options->vsm.elvsm;
|
||||
s.shadows[shadowIndex].bulbRadiusLs =
|
||||
mSoftShadowOptions.penumbraScale * options->shadowBulbRadius
|
||||
/ wsTexelSizeAtOneMeter;
|
||||
/ wsTexelSizeAtOneMeter;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -740,7 +753,6 @@ void ShadowMapManager::preparePointShadowMap(ShadowMap& shadowMap,
|
||||
|
||||
|
||||
// and if we need to generate it, update all the UBO data
|
||||
// Note: this below is done for all six faces even if it sets identical values each time
|
||||
if (shadowMap.hasVisibleShadows()) {
|
||||
const size_t shadowIndex = shadowMap.getShadowIndex();
|
||||
const float wsTexelSizeAtOneMeter = shaderParameters.texelSizeAtOneMeterWs;
|
||||
@@ -750,16 +762,11 @@ void ShadowMapManager::preparePointShadowMap(ShadowMap& shadowMap,
|
||||
auto& s = mShadowUb.edit();
|
||||
const double n = shadowMap.getCamera().getNear();
|
||||
const double f = shadowMap.getCamera().getCullingFar();
|
||||
|
||||
s.shadows[shadowIndex].lightFromWorldMatrix = {}; // no texture matrix for point lights
|
||||
s.shadows[shadowIndex].layer = shadowMap.getLayer();
|
||||
s.shadows[shadowIndex].lightFromWorldMatrix = shaderParameters.lightSpace;
|
||||
s.shadows[shadowIndex].direction = {}; // no direction of point lights
|
||||
s.shadows[shadowIndex].normalBias = normalBias * wsTexelSizeAtOneMeter;
|
||||
s.shadows[shadowIndex].lightFromWorldZ = {
|
||||
-((n + f) / (f - n)) * 0.5f + 0.5f,
|
||||
(f * n) / (f - n),
|
||||
-n / (f - n),
|
||||
1.0f / (f - n),
|
||||
};
|
||||
s.shadows[shadowIndex].lightFromWorldZ = shaderParameters.lightFromWorldZ;
|
||||
s.shadows[shadowIndex].texelSizeAtOneMeter = wsTexelSizeAtOneMeter;
|
||||
s.shadows[shadowIndex].nearOverFarMinusNear = float(n / (f - n));
|
||||
s.shadows[shadowIndex].elvsm = options->vsm.elvsm;
|
||||
@@ -779,14 +786,12 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateSpotShadowMaps(FEngine
|
||||
shadowTechnique |= ShadowTechnique::SHADOW_MAP;
|
||||
for (auto const* pShadowMap : mSpotShadowMaps) {
|
||||
const size_t lightIndex = pShadowMap->getLightIndex();
|
||||
|
||||
// FIXME: currently we have one slot per shadowmap in the UBO, but we now have up to
|
||||
// 6 shadowmap per light. So for now, we only write the data of the face 0,
|
||||
// and the shader will figure out where to find the other face (layer+face)
|
||||
// gather the per-light (not per shadow map) information. For point lights we will
|
||||
// "see" 6 shadowmaps (one per face), we must use the first face one, the shader
|
||||
// knows how to find the entry for other faces (they're guaranteed to be sequential).
|
||||
if (pShadowMap->getFace() == 0) {
|
||||
shadowInfo[lightIndex].castsShadows = true; // FIXME: is that set correctly?
|
||||
shadowInfo[lightIndex].index = pShadowMap->getShadowIndex();
|
||||
shadowInfo[lightIndex].layer = pShadowMap->getLayer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,14 +45,10 @@ class FrameGraph;
|
||||
class RenderPass;
|
||||
|
||||
struct ShadowMappingUniforms {
|
||||
std::array<math::mat4f, CONFIG_MAX_SHADOW_CASCADES> lightFromWorldMatrix;
|
||||
math::float4 cascadeSplits;
|
||||
float shadowBulbRadiusLs;
|
||||
float shadowBias;
|
||||
float ssContactShadowDistance;
|
||||
uint32_t directionalShadows;
|
||||
uint32_t cascades;
|
||||
bool elvsm;
|
||||
};
|
||||
|
||||
class ShadowMapManager {
|
||||
@@ -105,7 +101,7 @@ public:
|
||||
ShadowMap* getPointOrSpotShadowMap(size_t index) noexcept {
|
||||
assert_invariant(index < CONFIG_MAX_SHADOWMAPS);
|
||||
return std::launder(reinterpret_cast<ShadowMap*>(
|
||||
&mShadowMapCache[CONFIG_MAX_SHADOW_CASCADES + index]));
|
||||
&mShadowMapCache[index]));
|
||||
}
|
||||
|
||||
ShadowMap const* getPointOrSpotShadowMap(size_t spot) const noexcept {
|
||||
@@ -215,13 +211,13 @@ private:
|
||||
|
||||
utils::FixedCapacityVector<ShadowMap*> mSpotShadowMaps{
|
||||
utils::FixedCapacityVector<ShadowMap*>::with_capacity(
|
||||
CONFIG_MAX_SHADOWMAPS) };
|
||||
CONFIG_MAX_SHADOWMAPS - CONFIG_MAX_SHADOW_CASCADES) };
|
||||
|
||||
// inline storage for all our ShadowMap objects, we can't easily use a std::array<> directly.
|
||||
// because ShadowMap doesn't have a default ctor, and we avoid out-of-line allocations.
|
||||
// Each ShadowMap is currently 40 bytes (total of 2.5KB for 64 shadow maps)
|
||||
using ShadowMapStorage = std::aligned_storage<sizeof(ShadowMap), alignof(ShadowMap)>::type;
|
||||
std::array<ShadowMapStorage, CONFIG_MAX_SHADOW_CASCADES + CONFIG_MAX_SHADOWMAPS> mShadowMapCache;
|
||||
std::array<ShadowMapStorage, CONFIG_MAX_SHADOWMAPS> mShadowMapCache;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -442,9 +442,15 @@ Program FMaterial::getProgramBuilderWithVariants(
|
||||
}
|
||||
}
|
||||
|
||||
int platformId = 0;
|
||||
#if defined(IOS)
|
||||
platformId = 1;
|
||||
#endif
|
||||
|
||||
program.specializationConstants({
|
||||
{ 0, (int)mEngine.getSupportedFeatureLevel() },
|
||||
{ 1, (int)CONFIG_MAX_INSTANCES }
|
||||
{ 1, (int)CONFIG_MAX_INSTANCES },
|
||||
{ 2, platformId }
|
||||
});
|
||||
|
||||
return program;
|
||||
|
||||
@@ -343,9 +343,10 @@ void FScene::prepareDynamicLights(const CameraInfo& camera, ArenaScope& rootAren
|
||||
lp[gpuIndex].typeShadow = LightsUib::packTypeShadow(
|
||||
lcm.isPointLight(li) ? 0u : 1u,
|
||||
shadowInfo[i].contactShadows,
|
||||
shadowInfo[i].index,
|
||||
shadowInfo[i].layer);
|
||||
lp[gpuIndex].channels = LightsUib::packChannels(lcm.getLightChannels(li), shadowInfo[i].castsShadows);
|
||||
shadowInfo[i].index);
|
||||
lp[gpuIndex].channels = LightsUib::packChannels(
|
||||
lcm.getLightChannels(li),
|
||||
shadowInfo[i].castsShadows);
|
||||
}
|
||||
|
||||
driver.updateBufferObject(lightUbh, { lp, positionalLightCount * sizeof(LightsUib) }, 0);
|
||||
|
||||
@@ -155,7 +155,6 @@ public:
|
||||
bool castsShadows = false; // whether this light casts shadows
|
||||
bool contactShadows = false; // whether this light casts contact shadows
|
||||
uint8_t index = 0; // an index into the arrays in the Shadows uniform buffer
|
||||
uint8_t layer = 0; // which layer of the shadow texture array to sample from
|
||||
};
|
||||
|
||||
enum {
|
||||
@@ -179,7 +178,8 @@ public:
|
||||
LightSoa const& getLightData() const noexcept { return mLightData; }
|
||||
LightSoa& getLightData() noexcept { return mLightData; }
|
||||
|
||||
void updateUBOs(utils::Range<uint32_t> visibleRenderables, backend::Handle<backend::HwBufferObject> renderableUbh) noexcept;
|
||||
void updateUBOs(utils::Range<uint32_t> visibleRenderables,
|
||||
backend::Handle<backend::HwBufferObject> renderableUbh) noexcept;
|
||||
|
||||
bool hasContactShadows() const noexcept;
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
Pod::Spec.new do |spec|
|
||||
spec.name = "Filament"
|
||||
spec.version = "1.28.2"
|
||||
spec.version = "1.29.0"
|
||||
spec.license = { :type => "Apache 2.0", :file => "LICENSE" }
|
||||
spec.homepage = "https://google.github.io/filament"
|
||||
spec.authors = "Google LLC."
|
||||
spec.summary = "Filament is a real-time physically based rendering engine for Android, iOS, Windows, Linux, macOS, and WASM/WebGL."
|
||||
spec.platform = :ios, "11.0"
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.28.2/filament-v1.28.2-ios.tgz" }
|
||||
spec.source = { :http => "https://github.com/google/filament/releases/download/v1.29.0/filament-v1.29.0-ios.tgz" }
|
||||
|
||||
# Fix linking error with Xcode 12; we do not yet support the simulator on Apple silicon.
|
||||
spec.pod_target_xcconfig = {
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
namespace filament {
|
||||
|
||||
// update this when a new version of filament wouldn't work with older materials
|
||||
static constexpr size_t MATERIAL_VERSION = 28;
|
||||
static constexpr size_t MATERIAL_VERSION = 29;
|
||||
|
||||
/**
|
||||
* Supported shading models
|
||||
|
||||
@@ -124,12 +124,10 @@ struct PerViewUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
|
||||
// bit 0-3: cascade count
|
||||
// bit 4: visualize cascades
|
||||
// bit 8-11: cascade has visible shadows
|
||||
// bit 31: elvsm
|
||||
uint32_t cascades;
|
||||
float shadowBulbRadiusLs; // light radius in light-space
|
||||
float shadowBias; // normal bias
|
||||
float reserved0;
|
||||
float reserved1; // normal bias
|
||||
float shadowPenumbraRatioScale; // For DPCF or PCSS, scale penumbra ratio for artistic use
|
||||
std::array<math::mat4f, CONFIG_MAX_SHADOW_CASCADES> lightFromWorldMatrix;
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
// VSM shadows [variant: VSM]
|
||||
@@ -164,7 +162,7 @@ struct PerViewUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
|
||||
float ssrStride; // ssr texel stride, >= 1.0
|
||||
|
||||
// bring PerViewUib to 2 KiB
|
||||
math::float4 reserved[47];
|
||||
math::float4 reserved[63];
|
||||
};
|
||||
|
||||
// 2 KiB == 128 float4s
|
||||
@@ -229,11 +227,11 @@ struct LightsUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
|
||||
math::float2 spotScaleOffset; // { scale, offset }
|
||||
float reserved3; // 0
|
||||
float intensity; // float
|
||||
uint32_t typeShadow; // 0x00.ll.ii.ct (t: 0=point, 1=spot, c:contact, ii: index, ll: layer)
|
||||
uint32_t typeShadow; // 0x00.00.ii.ct (t: 0=point, 1=spot, c:contact, ii: index)
|
||||
uint32_t channels; // 0x000c00ll (ll: light channels, c: caster)
|
||||
|
||||
static uint32_t packTypeShadow(uint8_t type, bool contactShadow, uint8_t index, uint8_t layer) noexcept {
|
||||
return (type & 0xF) | (contactShadow ? 0x10 : 0x00) | (index << 8) | (layer << 16);
|
||||
static uint32_t packTypeShadow(uint8_t type, bool contactShadow, uint8_t index) noexcept {
|
||||
return (type & 0xF) | (contactShadow ? 0x10 : 0x00) | (index << 8);
|
||||
}
|
||||
static uint32_t packChannels(uint8_t lightChannels, bool castShadows) noexcept {
|
||||
return lightChannels | (castShadows ? 0x10000 : 0);
|
||||
@@ -249,15 +247,20 @@ static_assert(sizeof(LightsUib) == 64,
|
||||
struct ShadowUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
|
||||
static constexpr std::string_view _name{ "ShadowUniforms" };
|
||||
struct alignas(16) ShadowData {
|
||||
math::mat4f lightFromWorldMatrix; // 64 - unused for point lights
|
||||
math::float3 direction; // 12 - unused for point lights
|
||||
float normalBias; // 4 - unused for point lights
|
||||
math::float4 lightFromWorldZ; // 16 - point lights { depth reconstruction values }
|
||||
math::mat4f lightFromWorldMatrix; // 64
|
||||
math::float3 direction; // 12
|
||||
float normalBias; // 4
|
||||
math::float4 lightFromWorldZ; // 16
|
||||
|
||||
float texelSizeAtOneMeter; // 4
|
||||
float bulbRadiusLs; // 4
|
||||
float nearOverFarMinusNear; // 4
|
||||
bool elvsm; // 4
|
||||
|
||||
uint32_t layer; // 4
|
||||
uint32_t reserved0; // 4
|
||||
uint32_t reserved1; // 4
|
||||
uint32_t reserved2; // 4
|
||||
};
|
||||
ShadowData shadows[CONFIG_MAX_SHADOWMAPS];
|
||||
};
|
||||
|
||||
@@ -35,6 +35,11 @@ Variant Variant::filterUserVariant(
|
||||
if (filterMask & (uint32_t)UserVariantFilterBit::FOG) {
|
||||
variant.key &= ~(filterMask & FOG);
|
||||
}
|
||||
} else {
|
||||
// depth variants can have their VSM bit filtered
|
||||
if (filterMask & (uint32_t)UserVariantFilterBit::VSM) {
|
||||
variant.key &= ~(filterMask & VSM);
|
||||
}
|
||||
}
|
||||
if (!isSSRVariant(variant)) {
|
||||
// SSR variant needs to be handled separately
|
||||
@@ -53,8 +58,6 @@ Variant Variant::filterUserVariant(
|
||||
return variant;
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace details {
|
||||
|
||||
// compile time sanity-check tests
|
||||
|
||||
@@ -105,10 +105,9 @@ BufferInterfaceBlock const& UibGenerator::getPerViewUib() noexcept {
|
||||
|
||||
{ "cascadeSplits", 0, Type::FLOAT4, Precision::HIGH },
|
||||
{ "cascades", 0, Type::UINT },
|
||||
{ "shadowBulbRadiusLs", 0, Type::FLOAT },
|
||||
{ "shadowBias", 0, Type::FLOAT },
|
||||
{ "reserved0", 0, Type::FLOAT },
|
||||
{ "reserved1", 0, Type::FLOAT },
|
||||
{ "shadowPenumbraRatioScale", 0, Type::FLOAT },
|
||||
{ "lightFromWorldMatrix", 4, Type::MAT4, Precision::HIGH },
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
// VSM shadows [variant: VSM]
|
||||
|
||||
@@ -123,6 +123,7 @@ utils::io::sstream& CodeGenerator::generateProlog(utils::io::sstream& out, Shade
|
||||
out << '\n';
|
||||
generateSpecificationConstant(out, "BACKEND_FEATURE_LEVEL", 0, 1);
|
||||
generateSpecificationConstant(out, "CONFIG_MAX_INSTANCES", 1, (int)CONFIG_MAX_INSTANCES);
|
||||
generateSpecificationConstant(out, "TARGET_PLATFORM", 2, 0);
|
||||
|
||||
out << '\n';
|
||||
out << SHADERS_COMMON_DEFINES_GLSL_DATA;
|
||||
|
||||
@@ -287,6 +287,10 @@ std::string ShaderGenerator::createVertexProgram(ShaderModel shaderModel,
|
||||
UniformBindingPoints::PER_VIEW, UibGenerator::getPerViewUib());
|
||||
cg.generateUniforms(vs, ShaderStage::VERTEX,
|
||||
UniformBindingPoints::PER_RENDERABLE, UibGenerator::getPerRenderableUib());
|
||||
if (litVariants && filament::Variant::isShadowReceiverVariant(variant)) {
|
||||
cg.generateUniforms(vs, ShaderStage::FRAGMENT,
|
||||
UniformBindingPoints::SHADOW, UibGenerator::getShadowUib());
|
||||
}
|
||||
if (variant.hasSkinningOrMorphing()) {
|
||||
cg.generateUniforms(vs, ShaderStage::VERTEX,
|
||||
UniformBindingPoints::PER_RENDERABLE_BONES,
|
||||
|
||||
@@ -22,3 +22,11 @@
|
||||
|
||||
#define float3x3 mat3
|
||||
#define float4x4 mat4
|
||||
|
||||
#define TARGET_PLATFORM_UNKNOWN 0
|
||||
#define TARGET_PLATFORM_IOS 1
|
||||
#if defined(TARGET_GLES_ENVIRONMENT)
|
||||
const bool openGlesIos = TARGET_PLATFORM == TARGET_PLATFORM_IOS;
|
||||
#else
|
||||
const bool openGlesIos = false;
|
||||
#endif
|
||||
|
||||
@@ -9,7 +9,6 @@ struct Light {
|
||||
bool contactShadows;
|
||||
uint type;
|
||||
uint shadowIndex;
|
||||
uint shadowLayer;
|
||||
uint channels;
|
||||
};
|
||||
|
||||
|
||||
@@ -9,6 +9,10 @@ struct ShadowData {
|
||||
float bulbRadiusLs;
|
||||
float nearOverFarMinusNear;
|
||||
bool elvsm;
|
||||
uint layer;
|
||||
uint reserved0;
|
||||
uint reserved1;
|
||||
uint reserved2;
|
||||
};
|
||||
|
||||
struct BoneData {
|
||||
|
||||
@@ -128,14 +128,15 @@ highp vec4 getCascadeLightSpacePosition(uint cascade) {
|
||||
// For the first cascade, return the interpolated light space position.
|
||||
// This branch will be coherent (mostly) for neighboring fragments, and it's worth avoiding
|
||||
// the matrix multiply inside computeLightSpacePosition.
|
||||
if (cascade == 0u) {
|
||||
if (cascade == 0u && !openGlesIos) {
|
||||
// Note: this branch may cause issues with derivatives
|
||||
return vertex_lightSpacePosition;
|
||||
}
|
||||
|
||||
return computeLightSpacePosition(getWorldPosition(), getWorldNormalVector(),
|
||||
frameUniforms.lightDirection, frameUniforms.shadowBias,
|
||||
frameUniforms.lightFromWorldMatrix[cascade]);
|
||||
frameUniforms.lightDirection,
|
||||
shadowUniforms.shadows[cascade].normalBias,
|
||||
shadowUniforms.shadows[cascade].lightFromWorldMatrix);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -13,10 +13,6 @@ int getInstanceIndex() {
|
||||
// Uniforms access
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
mat4 getLightFromWorldMatrix() {
|
||||
return frameUniforms.lightFromWorldMatrix[0];
|
||||
}
|
||||
|
||||
PerRenderableData getObjectUniforms() {
|
||||
#if defined(MATERIAL_HAS_INSTANCES)
|
||||
// the material manages instancing, all instances share the same uniform block.
|
||||
|
||||
@@ -56,9 +56,8 @@ void evaluateDirectionalLight(const MaterialInputs material,
|
||||
bool cascadeHasVisibleShadows = bool(frameUniforms.cascades & ((1u << cascade) << 8u));
|
||||
bool hasDirectionalShadows = bool(frameUniforms.directionalShadows & 1u);
|
||||
if (hasDirectionalShadows && cascadeHasVisibleShadows) {
|
||||
uint layer = cascade;
|
||||
highp vec4 shadowPosition = getShadowPosition(true, 0u, cascade, 0.0f);
|
||||
visibility = shadow(true, light_shadowMap, layer, 0u, shadowPosition, 0.0f);
|
||||
visibility = shadow(true, light_shadowMap, cascade, shadowPosition, 0.0f);
|
||||
}
|
||||
if ((frameUniforms.directionalShadows & 0x2u) != 0u && visibility > 0.0) {
|
||||
if ((getObjectUniforms().flagsChannels & FILAMENT_OBJECT_CONTACT_SHADOWS_BIT) != 0u) {
|
||||
|
||||
@@ -158,7 +158,6 @@ Light getLight(const uint lightIndex) {
|
||||
light.type = (typeShadow & 0x1u);
|
||||
#if defined(VARIANT_HAS_SHADOWING)
|
||||
light.shadowIndex = (typeShadow >> 8u) & 0xFFu;
|
||||
light.shadowLayer = (typeShadow >> 16u) & 0xFFu;
|
||||
light.castsShadows = bool(channels & 0x10000u);
|
||||
if (light.type == LIGHT_TYPE_SPOT) {
|
||||
light.zLight = dot(shadowUniforms.shadows[light.shadowIndex].lightFromWorldZ, vec4(worldPosition, 1.0));
|
||||
@@ -211,19 +210,17 @@ void evaluatePunctualLights(const MaterialInputs material,
|
||||
#if defined(VARIANT_HAS_SHADOWING)
|
||||
if (light.NoL > 0.0) {
|
||||
if (light.castsShadows) {
|
||||
uint layer = light.shadowLayer;
|
||||
highp vec4 shadowPosition;
|
||||
uint shadowIndex = light.shadowIndex;
|
||||
if (light.type == LIGHT_TYPE_POINT) {
|
||||
// point-light shadows are sampled from a direction
|
||||
highp vec3 r = getWorldPosition() - light.worldPosition;
|
||||
highp vec4 nf = shadowUniforms.shadows[light.shadowIndex].lightFromWorldZ;
|
||||
// getShadowPosition returns zLight which is needed for PCSS/DPCF
|
||||
shadowPosition = getShadowPosition(r, nf, layer, light.zLight);
|
||||
} else {
|
||||
// getShadowPosition needs zLight for applying the normal bias
|
||||
shadowPosition = getShadowPosition(false, light.shadowIndex, 0u, light.zLight);
|
||||
uint face = getPointLightFace(r);
|
||||
shadowIndex += face;
|
||||
light.zLight = dot(shadowUniforms.shadows[shadowIndex].lightFromWorldZ,
|
||||
vec4(getWorldPosition(), 1.0));
|
||||
}
|
||||
visibility = shadow(false, light_shadowMap, layer, light.shadowIndex,
|
||||
highp vec4 shadowPosition = getShadowPosition(false, shadowIndex, 0u, light.zLight);
|
||||
visibility = shadow(false, light_shadowMap, shadowIndex,
|
||||
shadowPosition, light.zLight);
|
||||
}
|
||||
if (light.contactShadows && visibility > 0.0) {
|
||||
|
||||
@@ -141,9 +141,16 @@ void main() {
|
||||
#endif
|
||||
|
||||
#if defined(VARIANT_HAS_SHADOWING) && defined(VARIANT_HAS_DIRECTIONAL_LIGHTING)
|
||||
vertex_lightSpacePosition = computeLightSpacePosition(
|
||||
vertex_worldPosition.xyz, vertex_worldNormal,
|
||||
frameUniforms.lightDirection, frameUniforms.shadowBias, getLightFromWorldMatrix());
|
||||
if (openGlesIos) {
|
||||
// Hack for OpenGL ES on iOS.
|
||||
vertex_lightSpacePosition = vec4(1.0);
|
||||
} else {
|
||||
vertex_lightSpacePosition = computeLightSpacePosition(
|
||||
vertex_worldPosition.xyz, vertex_worldNormal,
|
||||
frameUniforms.lightDirection,
|
||||
shadowUniforms.shadows[0].normalBias,
|
||||
shadowUniforms.shadows[0].lightFromWorldMatrix);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // !defined(USE_OPTIMIZED_DEPTH_VERTEX_SHADER)
|
||||
|
||||
@@ -50,9 +50,8 @@ vec4 evaluateMaterial(const MaterialInputs material) {
|
||||
bool cascadeHasVisibleShadows = bool(frameUniforms.cascades & ((1u << cascade) << 8u));
|
||||
bool hasDirectionalShadows = bool(frameUniforms.directionalShadows & 1u);
|
||||
if (hasDirectionalShadows && cascadeHasVisibleShadows) {
|
||||
uint layer = cascade;
|
||||
highp vec4 shadowPosition = getShadowPosition(true, 0u, cascade, 0.0f);
|
||||
visibility = shadow(true, light_shadowMap, layer, 0u, shadowPosition, 0.0f);
|
||||
visibility = shadow(true, light_shadowMap, cascade, shadowPosition, 0.0f);
|
||||
}
|
||||
if ((frameUniforms.directionalShadows & 0x2u) != 0u && visibility > 0.0) {
|
||||
if ((getObjectUniforms().flagsChannels & FILAMENT_OBJECT_CONTACT_SHADOWS_BIT) != 0u) {
|
||||
|
||||
@@ -161,7 +161,7 @@ float getPenumbraLs(const bool DIRECTIONAL, const uint index, const highp float
|
||||
float penumbra;
|
||||
// This conditional is resolved at compile time
|
||||
if (DIRECTIONAL) {
|
||||
penumbra = frameUniforms.shadowBulbRadiusLs;
|
||||
penumbra = shadowUniforms.shadows[index].bulbRadiusLs;
|
||||
} else {
|
||||
// the penumbra radius depends on the light-space z for spotlights
|
||||
penumbra = shadowUniforms.shadows[index].bulbRadiusLs / zLight;
|
||||
@@ -494,55 +494,27 @@ highp vec4 getShadowPosition(const bool DIRECTIONAL,
|
||||
return p;
|
||||
}
|
||||
|
||||
// get {texture coordinate, layer} for point shadow maps
|
||||
highp vec4 getShadowPosition(const highp vec3 r, const highp vec4 nf,
|
||||
inout uint layer, out highp float d) {
|
||||
|
||||
uint getPointLightFace(const highp vec3 r) {
|
||||
highp vec4 tc;
|
||||
highp float rx = abs(r.x);
|
||||
highp float ry = abs(r.y);
|
||||
highp float rz = abs(r.z);
|
||||
d = max(rx, max(ry, rz));
|
||||
highp float ma = 1.0 / d;
|
||||
highp float d = max(rx, max(ry, rz));
|
||||
if (d == rx) {
|
||||
tc.x = r.x >= 0.0 ? r.z : -r.z;
|
||||
tc.y = r.y;
|
||||
layer += (r.x >= 0.0 ? 0u : 1u);
|
||||
return (r.x >= 0.0 ? 0u : 1u);
|
||||
} else if (d == ry) {
|
||||
tc.x = r.y >= 0.0 ? r.x : -r.x;
|
||||
tc.y = r.z;
|
||||
layer += (r.y >= 0.0 ? 2u : 3u);
|
||||
return (r.y >= 0.0 ? 2u : 3u);
|
||||
} else {
|
||||
tc.x = r.z >= 0.0 ? -r.x : r.x;
|
||||
tc.y = r.y;
|
||||
layer += (r.z >= 0.0 ? 4u : 5u);
|
||||
return (r.z >= 0.0 ? 4u : 5u);
|
||||
}
|
||||
|
||||
// ma is guaranteed to be >= sc and tc
|
||||
tc.xy = (tc.xy * ma + vec2(1.0)) * 0.5;
|
||||
|
||||
// z coordinate of the normalized fragment position in light-space
|
||||
// i.e.: remap [near, far] to [0,1] : d = (d - n) / (f - n)
|
||||
d = nf[2] + nf[3] * d;
|
||||
|
||||
if (frameUniforms.shadowSamplingType == SHADOW_SAMPLING_RUNTIME_EVSM) {
|
||||
// for VSM, the depth metric is linear normalized in light-space
|
||||
tc.z = d;
|
||||
} else {
|
||||
// for other types of shadows it's clip-space depth. Below is an optimized version of
|
||||
// (lightProjection * position).z
|
||||
tc.z = nf[0] + nf[1] * ma;
|
||||
}
|
||||
|
||||
// FIXME: the normal bias is not applied
|
||||
|
||||
tc.w = 1.0;
|
||||
return tc;
|
||||
}
|
||||
|
||||
// PCF sampling
|
||||
float shadow(const bool DIRECTIONAL,
|
||||
const mediump sampler2DArrayShadow shadowMap,
|
||||
const uint layer, const uint index, highp vec4 shadowPosition, highp float zLight) {
|
||||
const uint index, highp vec4 shadowPosition, highp float zLight) {
|
||||
uint layer = shadowUniforms.shadows[index].layer;
|
||||
#if SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_HARD
|
||||
return ShadowSample_PCF_Hard(shadowMap, layer, shadowPosition);
|
||||
#elif SHADOW_SAMPLING_METHOD == SHADOW_SAMPLING_PCF_LOW
|
||||
@@ -553,16 +525,11 @@ float shadow(const bool DIRECTIONAL,
|
||||
// Shadow requiring a sampler2D sampler (VSM, DPCF and PCSS)
|
||||
float shadow(const bool DIRECTIONAL,
|
||||
const mediump sampler2DArray shadowMap,
|
||||
const uint layer, const uint index, highp vec4 shadowPosition, highp float zLight) {
|
||||
|
||||
const uint index, highp vec4 shadowPosition, highp float zLight) {
|
||||
uint layer = shadowUniforms.shadows[index].layer;
|
||||
// This conditional is resolved at compile time
|
||||
if (frameUniforms.shadowSamplingType == SHADOW_SAMPLING_RUNTIME_EVSM) {
|
||||
bool elvsm = false;
|
||||
if (DIRECTIONAL) {
|
||||
elvsm = bool((frameUniforms.cascades >> 31u) & 1u);
|
||||
} else {
|
||||
elvsm = shadowUniforms.shadows[index].elvsm;
|
||||
}
|
||||
bool elvsm = shadowUniforms.shadows[index].elvsm;
|
||||
return ShadowSample_VSM(elvsm, shadowMap, layer, shadowPosition);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "filament",
|
||||
"version": "1.28.2",
|
||||
"version": "1.29.0",
|
||||
"description": "Real-time physically based rendering engine",
|
||||
"main": "filament.js",
|
||||
"module": "filament.js",
|
||||
|
||||
Reference in New Issue
Block a user