Compare commits
31 Commits
v1.28.3
...
bjd/debugg
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
18dab53920 | ||
|
|
b754b81e6f | ||
|
|
65bb66f90c | ||
|
|
a0af84d034 | ||
|
|
3cdaf3feeb | ||
|
|
da7d1b6fa9 | ||
|
|
3129226839 | ||
|
|
6935acafff | ||
|
|
d8103f4fd6 | ||
|
|
09a13f4015 | ||
|
|
e888023102 | ||
|
|
f62f4736f0 | ||
|
|
a378272d56 | ||
|
|
3d61938fcf | ||
|
|
a9f3937da6 | ||
|
|
2dc8d6bcc0 | ||
|
|
08dc398452 | ||
|
|
cd180c9a44 | ||
|
|
0a7fe52124 | ||
|
|
b71faf47cc | ||
|
|
67babceb73 | ||
|
|
8e13fc86d5 | ||
|
|
351c8e0972 | ||
|
|
dc44e20be0 | ||
|
|
e64b498d6e | ||
|
|
31ab4a13c9 | ||
|
|
e9728dcc8d | ||
|
|
40a3644086 | ||
|
|
41ef71abdf | ||
|
|
3b40e52c98 | ||
|
|
de8c7969f3 |
@@ -5,8 +5,15 @@ A new header is inserted each time a *tag* is created.
|
||||
|
||||
## main branch
|
||||
|
||||
- backend: add support for GGP platform
|
||||
- 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
|
||||
|
||||
- backend: add support for GGP platform
|
||||
- engine: primitives with `CullingMode::FRONT_AND_BACK` are now skipped.
|
||||
|
||||
## v1.28.2
|
||||
|
||||
@@ -452,3 +452,84 @@ Java_com_google_android_filament_MaterialInstance_nDuplicate(JNIEnv* env, jclass
|
||||
}
|
||||
return (jlong)mi;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jfloat JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nGetMaskThreshold(JNIEnv* env, jclass clazz,
|
||||
jlong nativeMaterialInstance) {
|
||||
// TODO: implement nGetMaskThreshold()
|
||||
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
|
||||
return instance->getMaskThreshold();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jfloat JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nGetSpecularAntiAliasingVariance(JNIEnv* env,
|
||||
jclass clazz, jlong nativeMaterialInstance) {
|
||||
// TODO: implement nGetSpecularAntiAliasingVariance()
|
||||
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
|
||||
return instance->getSpecularAntiAliasingVariance();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jfloat JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nGetSpecularAntiAliasingThreshold(JNIEnv* env,
|
||||
jclass clazz, jlong nativeMaterialInstance) {
|
||||
// TODO: implement nGetSpecularAntiAliasingThreshold()
|
||||
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
|
||||
return instance->getSpecularAntiAliasingThreshold();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nIsDoubleSided(JNIEnv* env, jclass clazz,
|
||||
jlong nativeMaterialInstance) {
|
||||
// TODO: implement nIsDoubleSided()
|
||||
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
|
||||
return instance->isDoubleSided();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nGetCullingMode(JNIEnv* env, jclass clazz,
|
||||
jlong nativeMaterialInstance) {
|
||||
// TODO: implement nGetCullingMode()
|
||||
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
|
||||
return (jint)instance->getCullingMode();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nIsColorWriteEnabled(JNIEnv* env, jclass clazz,
|
||||
jlong nativeMaterialInstance) {
|
||||
// TODO: implement nIsColorWriteEnabled()
|
||||
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
|
||||
return instance->isColorWriteEnabled();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nIsDepthWriteEnabled(JNIEnv* env, jclass clazz,
|
||||
jlong nativeMaterialInstance) {
|
||||
// TODO: implement nIsDepthWriteEnabled()
|
||||
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
|
||||
return instance->isDepthWriteEnabled();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nIsStencilWriteEnabled(JNIEnv* env, jclass clazz,
|
||||
jlong nativeMaterialInstance) {
|
||||
// TODO: implement nIsStencilWriteEnabled()
|
||||
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
|
||||
return instance->isStencilWriteEnabled();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nIsDepthCullingEnabled(JNIEnv* env, jclass clazz,
|
||||
jlong nativeMaterialInstance) {
|
||||
// TODO: implement nIsDepthCullingEnabled()
|
||||
MaterialInstance* instance = (MaterialInstance*)nativeMaterialInstance;
|
||||
return instance->isDepthCullingEnabled();
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.google.android.filament.proguard.UsedByNative;
|
||||
|
||||
@UsedByNative("AssetLoader.cpp")
|
||||
public class MaterialInstance {
|
||||
private static final Material.CullingMode[] sCullingModeValues = Material.CullingMode.values();
|
||||
private Material mMaterial;
|
||||
private String mName;
|
||||
private long mNativeObject;
|
||||
@@ -473,6 +474,14 @@ public class MaterialInstance {
|
||||
nSetMaskThreshold(getNativeObject(), threshold);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the minimum alpha value a fragment must have to not be discarded when the blend
|
||||
* mode is MASKED
|
||||
*/
|
||||
public float getMaskThreshold() {
|
||||
return nGetMaskThreshold(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the screen space variance of the filter kernel used when applying specular
|
||||
* anti-aliasing. The default value is set to 0.15. The specified value should be between
|
||||
@@ -486,6 +495,14 @@ public class MaterialInstance {
|
||||
nSetSpecularAntiAliasingVariance(getNativeObject(), variance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the screen space variance of the filter kernel used when applying specular
|
||||
* anti-aliasing.
|
||||
*/
|
||||
public float getSpecularAntiAliasingVariance() {
|
||||
return nGetSpecularAntiAliasingVariance(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the clamping threshold used to suppress estimation errors when applying specular
|
||||
* anti-aliasing. The default value is set to 0.2. The specified value should be between 0
|
||||
@@ -499,6 +516,14 @@ public class MaterialInstance {
|
||||
nSetSpecularAntiAliasingThreshold(getNativeObject(), threshold);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the clamping threshold used to suppress estimation errors when applying specular
|
||||
* anti-aliasing.
|
||||
*/
|
||||
public float getSpecularAntiAliasingThreshold() {
|
||||
return nGetSpecularAntiAliasingThreshold(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables double-sided lighting if the parent Material has double-sided capability,
|
||||
* otherwise prints a warning. If double-sided lighting is enabled, backface culling is
|
||||
@@ -512,6 +537,14 @@ public class MaterialInstance {
|
||||
nSetDoubleSided(getNativeObject(), doubleSided);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether double-sided lighting is enabled when the parent Material has double-sided
|
||||
* capability.
|
||||
*/
|
||||
public boolean isDoubleSided() {
|
||||
return nIsDoubleSided(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the default triangle culling state that was set on the material.
|
||||
*
|
||||
@@ -519,10 +552,18 @@ public class MaterialInstance {
|
||||
* <a href="https://google.github.io/filament/Materials.html#materialdefinitions/materialblock/rasterization:culling">
|
||||
* Rasterization: culling</a>
|
||||
*/
|
||||
public void setCullingMode(Material.CullingMode mode) {
|
||||
public void setCullingMode(@NonNull Material.CullingMode mode) {
|
||||
nSetCullingMode(getNativeObject(), mode.ordinal());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the face culling mode.
|
||||
*/
|
||||
@NonNull
|
||||
public Material.CullingMode getCullingMode() {
|
||||
return sCullingModeValues[nGetCullingMode(getNativeObject())];
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the default color-buffer write state that was set on the material.
|
||||
*
|
||||
@@ -534,6 +575,13 @@ public class MaterialInstance {
|
||||
nSetColorWrite(getNativeObject(), enable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether color write is enabled.
|
||||
*/
|
||||
public boolean isColorWriteEnabled() {
|
||||
return nIsColorWriteEnabled(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the default depth-buffer write state that was set on the material.
|
||||
*
|
||||
@@ -545,10 +593,27 @@ public class MaterialInstance {
|
||||
nSetDepthWrite(getNativeObject(), enable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether depth write is enabled.
|
||||
*/
|
||||
public boolean isDepthWriteEnabled() {
|
||||
return nIsDepthWriteEnabled(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or Disable stencil writes
|
||||
*/
|
||||
public void setStencilWrite(boolean enable) {
|
||||
nSetStencilWrite(getNativeObject(), enable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether stencil write is enabled.
|
||||
*/
|
||||
public boolean isStencilWriteEnabled() {
|
||||
return nIsStencilWriteEnabled(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the default depth testing state that was set on the material.
|
||||
*
|
||||
@@ -560,6 +625,13 @@ public class MaterialInstance {
|
||||
nSetDepthCulling(getNativeObject(), enable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether depth culling is enabled.
|
||||
*/
|
||||
public boolean isDepthCullingEnabled() {
|
||||
return nIsDepthCullingEnabled(getNativeObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the stencil comparison function (default is {@link TextureSampler.CompareFunction#ALWAYS}).
|
||||
*
|
||||
@@ -856,4 +928,15 @@ public class MaterialInstance {
|
||||
private static native long nGetMaterial(long nativeMaterialInstance);
|
||||
|
||||
private static native long nDuplicate(long otherNativeMaterialInstance, String name);
|
||||
|
||||
|
||||
private static native float nGetMaskThreshold(long nativeMaterialInstance);
|
||||
private static native float nGetSpecularAntiAliasingVariance(long nativeMaterialInstance);
|
||||
private static native float nGetSpecularAntiAliasingThreshold(long nativeMaterialInstance);
|
||||
private static native boolean nIsDoubleSided(long nativeMaterialInstance);
|
||||
private static native int nGetCullingMode(long nativeMaterialInstance);
|
||||
private static native boolean nIsColorWriteEnabled(long nativeMaterialInstance);
|
||||
private static native boolean nIsDepthWriteEnabled(long nativeMaterialInstance);
|
||||
private static native boolean nIsStencilWriteEnabled(long nativeMaterialInstance);
|
||||
private static native boolean nIsDepthCullingEnabled(long nativeMaterialInstance);
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
setuptools==40.6.2
|
||||
setuptools==58.0.4
|
||||
wheel==0.37.1
|
||||
certifi==2021.10.8
|
||||
cffi==1.15.0
|
||||
charset-normalizer==2.0.12
|
||||
certifi==2022.9.24
|
||||
cffi==1.15.1
|
||||
charset-normalizer==2.1.1
|
||||
Deprecated==1.2.13
|
||||
idna==3.3
|
||||
idna==3.4
|
||||
pycparser==2.21
|
||||
PyGithub==1.55
|
||||
PyJWT==2.4.0
|
||||
PyGithub==1.56
|
||||
PyJWT==2.6.0
|
||||
PyNaCl==1.5.0
|
||||
requests==2.27.1
|
||||
urllib3==1.26.9
|
||||
wrapt==1.14.0
|
||||
requests==2.28.1
|
||||
urllib3==1.26.12
|
||||
wrapt==1.14.1
|
||||
|
||||
@@ -73,6 +73,7 @@ set(SRCS
|
||||
src/MaterialParser.cpp
|
||||
src/MorphTargetBuffer.cpp
|
||||
src/PerViewUniforms.cpp
|
||||
src/PerShadowMapUniforms.cpp
|
||||
src/PostProcessManager.cpp
|
||||
src/RenderPass.cpp
|
||||
src/RenderPrimitive.cpp
|
||||
@@ -146,6 +147,7 @@ set(PRIVATE_HDRS
|
||||
src/Intersections.h
|
||||
src/MaterialParser.h
|
||||
src/PerViewUniforms.h
|
||||
src/PerShadowMapUniforms.h
|
||||
src/PIDController.h
|
||||
src/PostProcessManager.h
|
||||
src/RendererUtils.h
|
||||
|
||||
@@ -405,6 +405,7 @@ if (APPLE)
|
||||
backend
|
||||
getopt
|
||||
gtest
|
||||
filamat
|
||||
SPIRV
|
||||
spirv-cross-glsl)
|
||||
|
||||
|
||||
@@ -96,6 +96,8 @@ struct MetalContext {
|
||||
SamplerStateCache samplerStateCache;
|
||||
ArgumentEncoderCache argumentEncoderCache;
|
||||
|
||||
PolygonOffset currentPolygonOffset = {0.0f, 0.0f};
|
||||
|
||||
MetalSamplerGroup* samplerBindings[Program::SAMPLER_BINDING_COUNT] = {};
|
||||
|
||||
// Keeps track of sampler groups we've finalized for the current render pass.
|
||||
|
||||
@@ -1005,6 +1005,7 @@ void MetalDriver::beginRenderPass(Handle<HwRenderTarget> rth,
|
||||
mContext->depthStencilState.invalidate();
|
||||
mContext->cullModeState.invalidate();
|
||||
mContext->windingState.invalidate();
|
||||
mContext->currentPolygonOffset = {0.0f, 0.0f};
|
||||
|
||||
mContext->finalizedSamplerGroups.clear();
|
||||
}
|
||||
@@ -1183,8 +1184,12 @@ void MetalDriver::startCapture(int) {
|
||||
if (@available(iOS 13, *)) {
|
||||
MTLCaptureDescriptor* descriptor = [MTLCaptureDescriptor new];
|
||||
descriptor.captureObject = mContext->device;
|
||||
#if defined(IOS)
|
||||
descriptor.destination = MTLCaptureDestinationDeveloperTools;
|
||||
#else
|
||||
descriptor.destination = MTLCaptureDestinationGPUTraceDocument;
|
||||
descriptor.outputURL = [[NSURL alloc] initFileURLWithPath:@"filament.gputrace"];
|
||||
#endif
|
||||
NSError* error = nil;
|
||||
[[MTLCaptureManager sharedCaptureManager] startCaptureWithDescriptor:descriptor
|
||||
error:&error];
|
||||
@@ -1586,10 +1591,12 @@ void MetalDriver::draw(PipelineState ps, Handle<HwRenderPrimitive> rph, uint32_t
|
||||
[mContext->currentRenderPassEncoder setDepthStencilState:state];
|
||||
}
|
||||
|
||||
if (ps.polygonOffset.constant != 0.0 || ps.polygonOffset.slope != 0.0) {
|
||||
if (ps.polygonOffset.constant != mContext->currentPolygonOffset.constant ||
|
||||
ps.polygonOffset.slope != mContext->currentPolygonOffset.slope) {
|
||||
[mContext->currentRenderPassEncoder setDepthBias:ps.polygonOffset.constant
|
||||
slopeScale:ps.polygonOffset.slope
|
||||
clamp:0.0];
|
||||
mContext->currentPolygonOffset = ps.polygonOffset;
|
||||
}
|
||||
|
||||
// Set scissor-rectangle.
|
||||
|
||||
@@ -22,8 +22,12 @@
|
||||
#include <spirv_glsl.hpp>
|
||||
#include <spirv_msl.hpp>
|
||||
|
||||
#include "../src/GLSLPostProcessor.h"
|
||||
|
||||
#include "builtinResource.h"
|
||||
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
@@ -59,38 +63,6 @@ void SpvToGlsl(const SpirvBlob* spirv, std::string* outGlsl) {
|
||||
*outGlsl = glslCompiler.compile();
|
||||
}
|
||||
|
||||
void SpvToMsl(const SpirvBlob* spirv, std::string* outMsl) {
|
||||
CompilerMSL mslCompiler(*spirv);
|
||||
mslCompiler.set_msl_options(CompilerMSL::Options {
|
||||
.msl_version = CompilerMSL::Options::make_msl_version(1, 1)
|
||||
});
|
||||
|
||||
auto executionModel = mslCompiler.get_execution_model();
|
||||
|
||||
auto duplicateResourceBinding = [executionModel, &mslCompiler](const auto& resource) {
|
||||
auto set = mslCompiler.get_decoration(resource.id, spv::DecorationDescriptorSet);
|
||||
auto binding = mslCompiler.get_decoration(resource.id, spv::DecorationBinding);
|
||||
MSLResourceBinding newBinding;
|
||||
newBinding.stage = executionModel;
|
||||
newBinding.desc_set = set;
|
||||
newBinding.binding = binding;
|
||||
newBinding.msl_texture = binding;
|
||||
newBinding.msl_sampler = binding;
|
||||
newBinding.msl_buffer = binding;
|
||||
mslCompiler.add_msl_resource_binding(newBinding);
|
||||
};
|
||||
|
||||
auto resources = mslCompiler.get_shader_resources();
|
||||
for (const auto& resource : resources.sampled_images) {
|
||||
duplicateResourceBinding(resource);
|
||||
}
|
||||
for (const auto& resource : resources.uniform_buffers) {
|
||||
duplicateResourceBinding(resource);
|
||||
}
|
||||
|
||||
*outMsl = mslCompiler.compile();
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void ShaderGenerator::init() {
|
||||
@@ -102,15 +74,16 @@ void ShaderGenerator::shutdown() {
|
||||
}
|
||||
|
||||
ShaderGenerator::ShaderGenerator(std::string vertex, std::string fragment,
|
||||
Backend backend, bool isMobile) noexcept
|
||||
Backend backend, bool isMobile, const filament::SamplerInterfaceBlock* sib) noexcept
|
||||
: mBackend(backend),
|
||||
mVertexBlob(transpileShader(ShaderStage::VERTEX, std::move(vertex), backend, isMobile)),
|
||||
mVertexBlob(transpileShader(ShaderStage::VERTEX, std::move(vertex), backend, isMobile, sib)),
|
||||
mFragmentBlob(transpileShader(ShaderStage::FRAGMENT, std::move(fragment), backend,
|
||||
isMobile)) {
|
||||
isMobile, sib)) {
|
||||
}
|
||||
|
||||
ShaderGenerator::Blob ShaderGenerator::transpileShader(
|
||||
ShaderStage stage, std::string shader, Backend backend, bool isMobile) noexcept {
|
||||
ShaderStage stage, std::string shader, Backend backend, bool isMobile,
|
||||
const filament::SamplerInterfaceBlock* sib) noexcept {
|
||||
TProgram program;
|
||||
const EShLanguage language = stage == ShaderStage::VERTEX ? EShLangVertex : EShLangFragment;
|
||||
TShader tShader(language);
|
||||
@@ -173,7 +146,10 @@ ShaderGenerator::Blob ShaderGenerator::transpileShader(
|
||||
}
|
||||
return { result.c_str(), result.c_str() + result.length() + 1 };
|
||||
} else if (backend == Backend::METAL) {
|
||||
SpvToMsl(&spirv, &result);
|
||||
const auto sm = isMobile ? ShaderModel::MOBILE : ShaderModel::DESKTOP;
|
||||
filamat::SibVector sibs = filamat::SibVector::with_capacity(1);
|
||||
if (sib) { sibs.emplace_back(0, sib); }
|
||||
filamat::GLSLPostProcessor::spirvToMsl(&spirv, &result, sm, false, sibs, nullptr);
|
||||
return { result.c_str(), result.c_str() + result.length() + 1 };
|
||||
} else if (backend == Backend::VULKAN) {
|
||||
return { (uint8_t*)spirv.data(), (uint8_t*)(spirv.data() + spirv.size()) };
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "PlatformRunner.h"
|
||||
|
||||
#include "private/filament/SamplerInterfaceBlock.h"
|
||||
#include "private/backend/DriverApi.h"
|
||||
#include "backend/Program.h"
|
||||
|
||||
@@ -38,7 +39,8 @@ public:
|
||||
* @param vertex The vertex shader, written in GLSL 450 core.
|
||||
* @param fragment The fragment shader, written in GLSL 450 core.
|
||||
*/
|
||||
ShaderGenerator(std::string vertex, std::string fragment, Backend backend, bool isMobile) noexcept;
|
||||
ShaderGenerator(std::string vertex, std::string fragment, Backend backend, bool isMobile,
|
||||
const filament::SamplerInterfaceBlock* sib = nullptr) noexcept;
|
||||
|
||||
ShaderGenerator(const ShaderGenerator& rhs) = delete;
|
||||
ShaderGenerator& operator=(const ShaderGenerator& rhs) = delete;
|
||||
@@ -50,7 +52,7 @@ private:
|
||||
|
||||
using Blob = std::vector<char>;
|
||||
static Blob transpileShader(ShaderStage stage, std::string shader, Backend backend,
|
||||
bool isMobile) noexcept;
|
||||
bool isMobile, const filament::SamplerInterfaceBlock* sib = nullptr) noexcept;
|
||||
|
||||
Backend mBackend;
|
||||
|
||||
|
||||
@@ -133,7 +133,12 @@ TEST_F(BackendTest, FeedbackLoops) {
|
||||
// Create a program.
|
||||
ProgramHandle program;
|
||||
{
|
||||
ShaderGenerator shaderGen(fullscreenVs, fullscreenFs, sBackend, sIsMobilePlatform);
|
||||
SamplerInterfaceBlock sib = filament::SamplerInterfaceBlock::Builder()
|
||||
.name("backend_test_sib")
|
||||
.stageFlags(backend::ShaderStageFlags::ALL_SHADER_STAGE_FLAGS)
|
||||
.add( {{"tex", SamplerType::SAMPLER_2D, SamplerFormat::FLOAT, Precision::HIGH }} )
|
||||
.build();
|
||||
ShaderGenerator shaderGen(fullscreenVs, fullscreenFs, sBackend, sIsMobilePlatform, &sib);
|
||||
Program prog = shaderGen.getProgram(api);
|
||||
Program::Sampler psamplers[] = { utils::CString("tex"), 0 };
|
||||
prog.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, psamplers, sizeof(psamplers) / sizeof(psamplers[0]));
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "ShaderGenerator.h"
|
||||
#include "TrianglePrimitive.h"
|
||||
|
||||
#include "private/filament/SamplerInterfaceBlock.h"
|
||||
#include "private/backend/SamplerGroup.h"
|
||||
|
||||
#include <math/half.h>
|
||||
@@ -54,7 +55,7 @@ layout(location = 0) out vec4 fragColor;
|
||||
|
||||
// Filament's Vulkan backend requires a descriptor set index of 1 for all samplers.
|
||||
// This parameter is ignored for other backends.
|
||||
layout(location = 0, set = 1) uniform {samplerType} tex;
|
||||
layout(location = 0, set = 1) uniform {samplerType} test_tex;
|
||||
|
||||
void main() {
|
||||
vec2 fbsize = vec2(512);
|
||||
@@ -62,7 +63,7 @@ void main() {
|
||||
#if defined(TARGET_METAL_ENVIRONMENT) || defined(TARGET_VULKAN_ENVIRONMENT)
|
||||
uv.y = 1.0 - uv.y;
|
||||
#endif
|
||||
fragColor = vec4(texture(tex, uv).rgb, 1.0f);
|
||||
fragColor = vec4(texture(test_tex, uv).rgb, 1.0f);
|
||||
}
|
||||
|
||||
)");
|
||||
@@ -72,8 +73,7 @@ std::string fragmentUpdateImage3DTemplate (R"(#version 450 core
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
// Filament's Vulkan backend requires a descriptor set index of 1 for all samplers.
|
||||
// This parameter is ignored for other backends.
|
||||
layout(location = 0, set = 1) uniform {samplerType} tex;
|
||||
layout(location = 0, set = 1) uniform {samplerType} test_tex;
|
||||
|
||||
float getLayer(in sampler3D s) { return 2.5f / 4.0f; }
|
||||
float getLayer(in sampler2DArray s) { return 2.0f; }
|
||||
@@ -84,7 +84,7 @@ void main() {
|
||||
#if defined(TARGET_METAL_ENVIRONMENT) || defined(TARGET_VULKAN_ENVIRONMENT)
|
||||
uv.y = 1.0 - uv.y;
|
||||
#endif
|
||||
fragColor = vec4(texture(tex, vec3(uv, getLayer(tex))).rgb, 1.0f);
|
||||
fragColor = vec4(texture(test_tex, vec3(uv, getLayer(test_tex))).rgb, 1.0f);
|
||||
}
|
||||
|
||||
)");
|
||||
@@ -94,8 +94,7 @@ std::string fragmentUpdateImageMip (R"(#version 450 core
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
|
||||
// Filament's Vulkan backend requires a descriptor set index of 1 for all samplers.
|
||||
// This parameter is ignored for other backends.
|
||||
layout(location = 0, set = 1) uniform sampler2D tex;
|
||||
layout(location = 0, set = 1) uniform sampler2D test_tex;
|
||||
|
||||
void main() {
|
||||
vec2 fbsize = vec2(512);
|
||||
@@ -103,7 +102,7 @@ void main() {
|
||||
#if defined(TARGET_METAL_ENVIRONMENT) || defined(TARGET_VULKAN_ENVIRONMENT)
|
||||
uv.y = 1.0 - uv.y;
|
||||
#endif
|
||||
fragColor = vec4(textureLod(tex, uv, 1.0f).rgb, 1.0f);
|
||||
fragColor = vec4(textureLod(test_tex, uv, 1.0f).rgb, 1.0f);
|
||||
}
|
||||
|
||||
)");
|
||||
@@ -345,10 +344,15 @@ TEST_F(BackendTest, UpdateImage2D) {
|
||||
auto defaultRenderTarget = api.createDefaultRenderTarget(0);
|
||||
|
||||
// Create a program.
|
||||
SamplerInterfaceBlock sib = filament::SamplerInterfaceBlock::Builder()
|
||||
.name("Test")
|
||||
.stageFlags(backend::ShaderStageFlags::ALL_SHADER_STAGE_FLAGS)
|
||||
.add( {{"tex", SamplerType::SAMPLER_2D, SamplerFormat::FLOAT, Precision::HIGH }} )
|
||||
.build();
|
||||
ProgramHandle program;
|
||||
std::string fragment = stringReplace("{samplerType}",
|
||||
getSamplerTypeName(t.textureFormat), fragmentTemplate);
|
||||
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform);
|
||||
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform, &sib);
|
||||
Program prog = shaderGen.getProgram(api);
|
||||
Program::Sampler psamplers[] = { utils::CString("tex"), 0 };
|
||||
prog.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, psamplers, sizeof(psamplers) / sizeof(psamplers[0]));
|
||||
@@ -425,9 +429,14 @@ TEST_F(BackendTest, UpdateImageSRGB) {
|
||||
auto defaultRenderTarget = api.createDefaultRenderTarget(0);
|
||||
|
||||
// Create a program.
|
||||
SamplerInterfaceBlock sib = filament::SamplerInterfaceBlock::Builder()
|
||||
.name("Test")
|
||||
.stageFlags(backend::ShaderStageFlags::ALL_SHADER_STAGE_FLAGS)
|
||||
.add( {{"tex", SamplerType::SAMPLER_2D, SamplerFormat::FLOAT, Precision::HIGH }} )
|
||||
.build();
|
||||
std::string fragment = stringReplace("{samplerType}",
|
||||
getSamplerTypeName(textureFormat), fragmentTemplate);
|
||||
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform);
|
||||
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform, &sib);
|
||||
Program prog = shaderGen.getProgram(api);
|
||||
Program::Sampler psamplers[] = { utils::CString("tex"), 0 };
|
||||
prog.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, psamplers, sizeof(psamplers) / sizeof(psamplers[0]));
|
||||
@@ -511,9 +520,14 @@ TEST_F(BackendTest, UpdateImageMipLevel) {
|
||||
auto defaultRenderTarget = api.createDefaultRenderTarget(0);
|
||||
|
||||
// Create a program.
|
||||
SamplerInterfaceBlock sib = filament::SamplerInterfaceBlock::Builder()
|
||||
.name("Test")
|
||||
.stageFlags(backend::ShaderStageFlags::ALL_SHADER_STAGE_FLAGS)
|
||||
.add( {{"tex", SamplerType::SAMPLER_3D, SamplerFormat::FLOAT, Precision::HIGH }} )
|
||||
.build();
|
||||
std::string fragment = stringReplace("{samplerType}",
|
||||
getSamplerTypeName(textureFormat), fragmentUpdateImageMip);
|
||||
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform);
|
||||
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform, &sib);
|
||||
Program prog = shaderGen.getProgram(api);
|
||||
Program::Sampler psamplers[] = { utils::CString("tex"), 0 };
|
||||
prog.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, psamplers, sizeof(psamplers) / sizeof(psamplers[0]));
|
||||
@@ -583,9 +597,14 @@ TEST_F(BackendTest, UpdateImage3D) {
|
||||
auto defaultRenderTarget = api.createDefaultRenderTarget(0);
|
||||
|
||||
// Create a program.
|
||||
SamplerInterfaceBlock sib = filament::SamplerInterfaceBlock::Builder()
|
||||
.name("Test")
|
||||
.stageFlags(backend::ShaderStageFlags::ALL_SHADER_STAGE_FLAGS)
|
||||
.add( {{"tex", SamplerType::SAMPLER_3D, SamplerFormat::FLOAT, Precision::HIGH }} )
|
||||
.build();
|
||||
std::string fragment = stringReplace("{samplerType}",
|
||||
getSamplerTypeName(samplerType), fragmentUpdateImage3DTemplate);
|
||||
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform);
|
||||
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform, &sib);
|
||||
Program prog = shaderGen.getProgram(api);
|
||||
Program::Sampler psamplers[] = { utils::CString("tex"), 0 };
|
||||
prog.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, psamplers, sizeof(psamplers) / sizeof(psamplers[0]));
|
||||
|
||||
@@ -45,7 +45,7 @@ std::string fragment (R"(#version 450 core
|
||||
layout(location = 0) out vec4 fragColor;
|
||||
layout(location = 0) in vec2 uv;
|
||||
|
||||
layout(set = 1, binding = 6) uniform sampler2D tex;
|
||||
layout(location = 0, set = 1) uniform sampler2D tex;
|
||||
|
||||
void main() {
|
||||
fragColor = texture(tex, uv);
|
||||
@@ -65,11 +65,16 @@ TEST_F(BackendTest, RenderExternalImageWithoutSet) {
|
||||
|
||||
auto swapChain = createSwapChain();
|
||||
|
||||
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform);
|
||||
SamplerInterfaceBlock sib = filament::SamplerInterfaceBlock::Builder()
|
||||
.name("backend_test_sib")
|
||||
.stageFlags(backend::ShaderStageFlags::ALL_SHADER_STAGE_FLAGS)
|
||||
.add( {{"tex", SamplerType::SAMPLER_EXTERNAL, SamplerFormat::FLOAT, Precision::HIGH }} )
|
||||
.build();
|
||||
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform, &sib);
|
||||
|
||||
// Create a program that samples a texture.
|
||||
Program p = shaderGen.getProgram(getDriverApi());
|
||||
Program::Sampler sampler { utils::CString("tex"), 6 };
|
||||
Program::Sampler sampler { utils::CString("tex"), 0 };
|
||||
p.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, &sampler, 1);
|
||||
backend::Handle<HwProgram> program = getDriverApi().createProgram(std::move(p));
|
||||
|
||||
@@ -139,11 +144,16 @@ TEST_F(BackendTest, RenderExternalImage) {
|
||||
|
||||
auto swapChain = createSwapChain();
|
||||
|
||||
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform);
|
||||
SamplerInterfaceBlock sib = filament::SamplerInterfaceBlock::Builder()
|
||||
.name("backend_test_sib")
|
||||
.stageFlags(backend::ShaderStageFlags::ALL_SHADER_STAGE_FLAGS)
|
||||
.add( {{"tex", SamplerType::SAMPLER_EXTERNAL, SamplerFormat::FLOAT, Precision::HIGH }} )
|
||||
.build();
|
||||
ShaderGenerator shaderGen(vertex, fragment, sBackend, sIsMobilePlatform, &sib);
|
||||
|
||||
// Create a program that samples a texture.
|
||||
Program p = shaderGen.getProgram(getDriverApi());
|
||||
Program::Sampler sampler { utils::CString("tex"), 6 };
|
||||
Program::Sampler sampler { utils::CString("tex"), 0 };
|
||||
p.setSamplerGroup(0, ShaderStageFlags::ALL_SHADER_STAGE_FLAGS, &sampler, 1);
|
||||
auto program = getDriverApi().createProgram(std::move(p));
|
||||
|
||||
|
||||
@@ -277,6 +277,12 @@ public:
|
||||
*/
|
||||
void setMaskThreshold(float threshold) noexcept;
|
||||
|
||||
/**
|
||||
* Gets the minimum alpha value a fragment must have to not be discarded when the blend
|
||||
* mode is MASKED
|
||||
*/
|
||||
float getMaskThreshold() const noexcept;
|
||||
|
||||
/**
|
||||
* Sets the screen space variance of the filter kernel used when applying specular
|
||||
* anti-aliasing. The default value is set to 0.15. The specified value should be between
|
||||
@@ -284,6 +290,12 @@ public:
|
||||
*/
|
||||
void setSpecularAntiAliasingVariance(float variance) noexcept;
|
||||
|
||||
/**
|
||||
* Gets the screen space variance of the filter kernel used when applying specular
|
||||
* anti-aliasing.
|
||||
*/
|
||||
float getSpecularAntiAliasingVariance() const noexcept;
|
||||
|
||||
/**
|
||||
* Sets the clamping threshold used to suppress estimation errors when applying specular
|
||||
* anti-aliasing. The default value is set to 0.2. The specified value should be between 0
|
||||
@@ -291,6 +303,12 @@ public:
|
||||
*/
|
||||
void setSpecularAntiAliasingThreshold(float threshold) noexcept;
|
||||
|
||||
/**
|
||||
* Gets the clamping threshold used to suppress estimation errors when applying specular
|
||||
* anti-aliasing.
|
||||
*/
|
||||
float getSpecularAntiAliasingThreshold() const noexcept;
|
||||
|
||||
/**
|
||||
* Enables or disables double-sided lighting if the parent Material has double-sided capability,
|
||||
* otherwise prints a warning. If double-sided lighting is enabled, backface culling is
|
||||
@@ -298,36 +316,72 @@ public:
|
||||
*/
|
||||
void setDoubleSided(bool doubleSided) noexcept;
|
||||
|
||||
/**
|
||||
* Returns whether double-sided lighting is enabled when the parent Material has double-sided
|
||||
* capability.
|
||||
*/
|
||||
bool isDoubleSided() const noexcept;
|
||||
|
||||
/**
|
||||
* Specifies how transparent objects should be rendered (default is DEFAULT).
|
||||
*/
|
||||
void setTransparencyMode(TransparencyMode mode) noexcept;
|
||||
|
||||
/**
|
||||
* Returns the transparency mode.
|
||||
*/
|
||||
TransparencyMode getTransparencyMode() const noexcept;
|
||||
|
||||
/**
|
||||
* Overrides the default triangle culling state that was set on the material.
|
||||
*/
|
||||
void setCullingMode(CullingMode culling) noexcept;
|
||||
|
||||
/**
|
||||
* Returns the face culling mode.
|
||||
*/
|
||||
CullingMode getCullingMode() const noexcept;
|
||||
|
||||
/**
|
||||
* Overrides the default color-buffer write state that was set on the material.
|
||||
*/
|
||||
void setColorWrite(bool enable) noexcept;
|
||||
|
||||
/**
|
||||
* Returns whether color write is enabled.
|
||||
*/
|
||||
bool isColorWriteEnabled() const noexcept;
|
||||
|
||||
/**
|
||||
* Overrides the default depth-buffer write state that was set on the material.
|
||||
*/
|
||||
void setDepthWrite(bool enable) noexcept;
|
||||
|
||||
/**
|
||||
* Returns whether depth write is enabled.
|
||||
*/
|
||||
bool isDepthWriteEnabled() const noexcept;
|
||||
|
||||
/**
|
||||
* Overrides the default depth testing state that was set on the material.
|
||||
*/
|
||||
void setDepthCulling(bool enable) noexcept;
|
||||
|
||||
/**
|
||||
* Returns whether depth culling is enabled.
|
||||
*/
|
||||
bool isDepthCullingEnabled() const noexcept;
|
||||
|
||||
/**
|
||||
* Overrides the default stencil-buffer write state that was set on the material.
|
||||
*/
|
||||
void setStencilWrite(bool enable) noexcept;
|
||||
|
||||
/**
|
||||
* Returns whether stencil write is enabled.
|
||||
*/
|
||||
bool isStencilWriteEnabled() const noexcept;
|
||||
|
||||
/**
|
||||
* Sets the stencil comparison function (default is StencilCompareFunc::A).
|
||||
*
|
||||
|
||||
@@ -292,4 +292,44 @@ MaterialInstance* MaterialInstance::duplicate(MaterialInstance const* other, con
|
||||
}
|
||||
|
||||
|
||||
float MaterialInstance::getMaskThreshold() const noexcept {
|
||||
return downcast(this)->getMaskThreshold();
|
||||
}
|
||||
|
||||
float MaterialInstance::getSpecularAntiAliasingVariance() const noexcept {
|
||||
return downcast(this)->getSpecularAntiAliasingVariance();
|
||||
}
|
||||
|
||||
float MaterialInstance::getSpecularAntiAliasingThreshold() const noexcept {
|
||||
return downcast(this)->getSpecularAntiAliasingThreshold();
|
||||
}
|
||||
|
||||
bool MaterialInstance::isDoubleSided() const noexcept {
|
||||
return downcast(this)->isDoubleSided();
|
||||
}
|
||||
|
||||
TransparencyMode MaterialInstance::getTransparencyMode() const noexcept {
|
||||
return downcast(this)->getTransparencyMode();
|
||||
}
|
||||
|
||||
CullingMode MaterialInstance::getCullingMode() const noexcept {
|
||||
return downcast(this)->getCullingMode();
|
||||
}
|
||||
|
||||
bool MaterialInstance::isColorWriteEnabled() const noexcept {
|
||||
return downcast(this)->isColorWriteEnabled();
|
||||
}
|
||||
|
||||
bool MaterialInstance::isDepthWriteEnabled() const noexcept {
|
||||
return downcast(this)->isDepthWriteEnabled();
|
||||
}
|
||||
|
||||
bool MaterialInstance::isStencilWriteEnabled() const noexcept {
|
||||
return downcast(this)->isStencilWriteEnabled();
|
||||
}
|
||||
|
||||
bool MaterialInstance::isDepthCullingEnabled() const noexcept {
|
||||
return downcast(this)->isDepthCullingEnabled();
|
||||
}
|
||||
|
||||
} // namespace filament
|
||||
|
||||
130
filament/src/PerShadowMapUniforms.cpp
Normal file
130
filament/src/PerShadowMapUniforms.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "PerShadowMapUniforms.h"
|
||||
|
||||
#include "ShadowMapManager.h"
|
||||
|
||||
#include "details/Camera.h"
|
||||
#include "details/Engine.h"
|
||||
|
||||
#include <private/filament/EngineEnums.h>
|
||||
|
||||
namespace filament {
|
||||
|
||||
using namespace backend;
|
||||
using namespace math;
|
||||
|
||||
PerShadowMapUniforms::PerShadowMapUniforms(FEngine& engine) noexcept {
|
||||
DriverApi& driver = engine.getDriverApi();
|
||||
mUniformBufferHandle = driver.createBufferObject(sizeof(PerViewUib),
|
||||
BufferObjectBinding::UNIFORM, BufferUsage::DYNAMIC);
|
||||
}
|
||||
|
||||
void PerShadowMapUniforms::terminate(DriverApi& driver) {
|
||||
driver.destroyBufferObject(mUniformBufferHandle);
|
||||
}
|
||||
|
||||
PerViewUib& PerShadowMapUniforms::edit(Transaction const& transaction) noexcept {
|
||||
assert_invariant(transaction.uniforms);
|
||||
return *transaction.uniforms;
|
||||
}
|
||||
|
||||
void PerShadowMapUniforms::prepareCamera(Transaction const& transaction,
|
||||
FEngine& engine, const CameraInfo& camera) noexcept {
|
||||
mat4f const& viewFromWorld = camera.view;
|
||||
mat4f const& worldFromView = camera.model;
|
||||
mat4f const& clipFromView = camera.projection;
|
||||
|
||||
const mat4f viewFromClip{ inverse((mat4)camera.projection) };
|
||||
const mat4f clipFromWorld{ highPrecisionMultiply(clipFromView, viewFromWorld) };
|
||||
const mat4f worldFromClip{ highPrecisionMultiply(worldFromView, viewFromClip) };
|
||||
|
||||
auto& s = edit(transaction);
|
||||
s.viewFromWorldMatrix = viewFromWorld; // view
|
||||
s.worldFromViewMatrix = worldFromView; // model
|
||||
s.clipFromViewMatrix = clipFromView; // projection
|
||||
s.viewFromClipMatrix = viewFromClip; // 1/projection
|
||||
s.clipFromWorldMatrix = clipFromWorld; // projection * view
|
||||
s.worldFromClipMatrix = worldFromClip; // 1/(projection * view)
|
||||
s.clipTransform = camera.clipTransfrom;
|
||||
s.cameraPosition = float3{ camera.getPosition() };
|
||||
s.worldOffset = camera.getWorldOffset();
|
||||
s.cameraFar = camera.zf;
|
||||
s.oneOverFarMinusNear = 1.0f / (camera.zf - camera.zn);
|
||||
s.nearOverFarMinusNear = camera.zn / (camera.zf - camera.zn);
|
||||
|
||||
// with a clip-space of [-w, w] ==> z' = -z
|
||||
// with a clip-space of [0, w] ==> z' = (w - z)/2
|
||||
s.clipControl = engine.getDriverApi().getClipSpaceParams();
|
||||
}
|
||||
|
||||
void PerShadowMapUniforms::prepareLodBias(Transaction const& transaction,
|
||||
float bias) noexcept {
|
||||
auto& s = edit(transaction);
|
||||
s.lodBias = bias;
|
||||
}
|
||||
|
||||
void PerShadowMapUniforms::prepareViewport(Transaction const& transaction,
|
||||
const filament::Viewport& viewport,
|
||||
uint32_t xoffset, uint32_t yoffset) noexcept {
|
||||
const float w = float(viewport.width);
|
||||
const float h = float(viewport.height);
|
||||
auto& s = edit(transaction);
|
||||
s.resolution = float4{ w, h, 1.0f / w, 1.0f / h };
|
||||
s.origin = float2{ viewport.left, viewport.bottom };
|
||||
s.offset = float2{ xoffset, yoffset };
|
||||
}
|
||||
|
||||
void PerShadowMapUniforms::prepareTime(Transaction const& transaction,
|
||||
FEngine& engine, math::float4 const& userTime) noexcept {
|
||||
auto& s = edit(transaction);
|
||||
const uint64_t oneSecondRemainder = engine.getEngineTime().count() % 1000000000;
|
||||
const float fraction = float(double(oneSecondRemainder) / 1000000000.0);
|
||||
s.time = fraction;
|
||||
s.userTime = userTime;
|
||||
}
|
||||
|
||||
void PerShadowMapUniforms::prepareShadowMapping(Transaction const& transaction,
|
||||
bool highPrecision) noexcept {
|
||||
auto& s = edit(transaction);
|
||||
constexpr float low = 5.54f; // ~ std::log(std::numeric_limits<math::half>::max()) * 0.5f;
|
||||
constexpr float high = 42.0f; // ~ std::log(std::numeric_limits<float>::max()) * 0.5f;
|
||||
s.vsmExponent = highPrecision ? high : low;
|
||||
}
|
||||
|
||||
|
||||
PerShadowMapUniforms::Transaction PerShadowMapUniforms::open(backend::DriverApi& driver) noexcept {
|
||||
Transaction transaction;
|
||||
// TODO: use out-of-line buffer if too large
|
||||
transaction.uniforms = (PerViewUib *)driver.allocate(sizeof(PerViewUib));
|
||||
assert_invariant(transaction.uniforms);
|
||||
return transaction;
|
||||
}
|
||||
|
||||
void PerShadowMapUniforms::commit(Transaction& transaction,
|
||||
backend::DriverApi& driver) noexcept {
|
||||
driver.updateBufferObject(mUniformBufferHandle, {
|
||||
transaction.uniforms, sizeof(PerViewUib) }, 0);
|
||||
transaction.uniforms = nullptr;
|
||||
}
|
||||
|
||||
void PerShadowMapUniforms::bind(backend::DriverApi& driver) noexcept {
|
||||
driver.bindUniformBuffer(+UniformBindingPoints::PER_VIEW, mUniformBufferHandle);
|
||||
}
|
||||
|
||||
} // namespace filament
|
||||
|
||||
91
filament/src/PerShadowMapUniforms.h
Normal file
91
filament/src/PerShadowMapUniforms.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef TNT_FILAMENT_PERSHADOWMAPUNIFORMS_H
|
||||
#define TNT_FILAMENT_PERSHADOWMAPUNIFORMS_H
|
||||
|
||||
#include <filament/Viewport.h>
|
||||
|
||||
#include <private/filament/UibStructs.h>
|
||||
#include <private/backend/SamplerGroup.h>
|
||||
|
||||
#include "TypedUniformBuffer.h"
|
||||
|
||||
#include <backend/Handle.h>
|
||||
|
||||
#include <utils/EntityInstance.h>
|
||||
|
||||
#include <random>
|
||||
|
||||
namespace filament {
|
||||
|
||||
struct CameraInfo;
|
||||
|
||||
class FEngine;
|
||||
class LightManager;
|
||||
|
||||
/*
|
||||
* PerShadowMapUniforms manages the UBO needed to generate our shadow maps. Internally it just
|
||||
* holds onto a `PerViewUniform` UBO handle, but doesn't keep any shadow copy of it, instead it
|
||||
* writes the data directly into the commandstream, for this reason partial update of the data
|
||||
* is not possible.
|
||||
*/
|
||||
class PerShadowMapUniforms {
|
||||
|
||||
using LightManagerInstance = utils::EntityInstance<LightManager>;
|
||||
|
||||
public:
|
||||
class Transaction {
|
||||
friend PerShadowMapUniforms;
|
||||
PerViewUib* uniforms = nullptr;
|
||||
Transaction() = default; // disallow creation by the caller
|
||||
};
|
||||
|
||||
explicit PerShadowMapUniforms(FEngine& engine) noexcept;
|
||||
|
||||
void terminate(backend::DriverApi& driver);
|
||||
|
||||
static void prepareCamera(Transaction const& transaction,
|
||||
FEngine& engine, const CameraInfo& camera) noexcept;
|
||||
|
||||
static void prepareLodBias(Transaction const& transaction,
|
||||
float bias) noexcept;
|
||||
|
||||
static void prepareViewport(Transaction const& transaction,
|
||||
const filament::Viewport& viewport, uint32_t xoffset, uint32_t yoffset) noexcept;
|
||||
|
||||
static void prepareTime(Transaction const& transaction,
|
||||
FEngine& engine, math::float4 const& userTime) noexcept;
|
||||
|
||||
static void prepareShadowMapping(Transaction const& transaction,
|
||||
bool highPrecision) noexcept;
|
||||
|
||||
static Transaction open(backend::DriverApi& driver) noexcept;
|
||||
|
||||
// update local data into GPU UBO
|
||||
void commit(Transaction& transaction, backend::DriverApi& driver) noexcept;
|
||||
|
||||
// bind this UBO
|
||||
void bind(backend::DriverApi& driver) noexcept;
|
||||
|
||||
private:
|
||||
static PerViewUib& edit(Transaction const& transaction) noexcept;
|
||||
backend::Handle<backend::HwBufferObject> mUniformBufferHandle;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
#endif //TNT_FILAMENT_PERSHADOWMAPUNIFORMS_H
|
||||
@@ -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,
|
||||
|
||||
@@ -48,6 +48,11 @@ class FIndirectLight;
|
||||
class Froxelizer;
|
||||
class LightManager;
|
||||
|
||||
/*
|
||||
* PerViewUniforms manages the UBO and samplers needed to render the color passes. Internally it
|
||||
* holds onto handles for the PER_VIEW UBO and SamplerGroup. This class maintains a shadow copy
|
||||
* of the UBO/sampler data, so it is possible to partially update it between commits.
|
||||
*/
|
||||
class PerViewUniforms {
|
||||
|
||||
using LightManagerInstance = utils::EntityInstance<LightManager>;
|
||||
|
||||
@@ -358,8 +358,8 @@ void RenderPass::setupColorCommand(Command& cmdDraw, Variant variant,
|
||||
|
||||
cmdDraw.primitive.rasterState.inverseFrontFaces = inverseFrontFaces;
|
||||
cmdDraw.primitive.rasterState.culling = mi->getCullingMode();
|
||||
cmdDraw.primitive.rasterState.colorWrite = mi->getColorWrite();
|
||||
cmdDraw.primitive.rasterState.depthWrite = mi->getDepthWrite();
|
||||
cmdDraw.primitive.rasterState.colorWrite = mi->isColorWriteEnabled();
|
||||
cmdDraw.primitive.rasterState.depthWrite = mi->isDepthWriteEnabled();
|
||||
cmdDraw.primitive.rasterState.depthFunc = mi->getDepthFunc();
|
||||
cmdDraw.primitive.mi = mi;
|
||||
cmdDraw.primitive.materialVariant = variant;
|
||||
@@ -663,7 +663,7 @@ RenderPass::Command* RenderPass::generateCommandsImpl(uint32_t extraFlags,
|
||||
|
||||
// FIXME: should writeDepthForShadowCasters take precedence over mi->getDepthWrite()?
|
||||
cmdDepth.primitive.rasterState.depthWrite = (1 // only keep bit 0
|
||||
& (mi->getDepthWrite() | (mode == TransparencyMode::TWO_PASSES_ONE_SIDE))
|
||||
& (mi->isDepthWriteEnabled() | (mode == TransparencyMode::TWO_PASSES_ONE_SIDE))
|
||||
& !(filterTranslucentObjects & translucent)
|
||||
& !(depthFilterAlphaMaskedObjects & rs.alphaToCoverage))
|
||||
| writeDepthForShadowCasters;
|
||||
|
||||
@@ -41,7 +41,7 @@ using namespace backend;
|
||||
static constexpr bool USE_DEPTH_CLAMP = false;
|
||||
|
||||
ShadowMap::ShadowMap(FEngine& engine) noexcept
|
||||
: mPerViewUniforms(engine),
|
||||
: mPerShadowMapUniforms(engine),
|
||||
mShadowType(ShadowType::DIRECTIONAL),
|
||||
mHasVisibleShadows(false),
|
||||
mFace(0) {
|
||||
@@ -62,7 +62,7 @@ void ShadowMap::terminate(FEngine& engine) {
|
||||
engine.destroyCameraComponent(e);
|
||||
}
|
||||
engine.getEntityManager().destroy(sizeof(entities) / sizeof(Entity), entities);
|
||||
mPerViewUniforms.terminate(engine.getDriverApi());
|
||||
mPerShadowMapUniforms.terminate(engine.getDriverApi());
|
||||
}
|
||||
|
||||
ShadowMap::~ShadowMap() = default;
|
||||
@@ -1184,6 +1184,8 @@ void ShadowMap::visitScene(const FScene& scene, uint32_t visibleLayers,
|
||||
|
||||
void ShadowMap::initSceneInfo(ShadowMap::SceneInfo& sceneInfo,
|
||||
uint8_t visibleLayers, FScene const& scene, mat4f const& viewMatrix) {
|
||||
sceneInfo.csNearFar = { -1.0f, 1.0f };
|
||||
sceneInfo.lsNearFar = {};
|
||||
sceneInfo.visibleLayers = visibleLayers;
|
||||
sceneInfo.vsNearFar = { std::numeric_limits<float>::lowest(), std::numeric_limits<float>::max() };
|
||||
|
||||
@@ -1265,34 +1267,38 @@ filament::Viewport ShadowMap::getViewport() const noexcept {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
void ShadowMap::prepareCamera(FEngine& engine, const CameraInfo& cameraInfo) noexcept {
|
||||
mPerViewUniforms.prepareCamera(engine, cameraInfo);
|
||||
mPerViewUniforms.prepareLodBias(0.0f);
|
||||
void ShadowMap::prepareCamera(Transaction const& transaction,
|
||||
FEngine& engine, const CameraInfo& cameraInfo) noexcept {
|
||||
PerShadowMapUniforms::prepareCamera(transaction, engine, cameraInfo);
|
||||
PerShadowMapUniforms::prepareLodBias(transaction, 0.0f);
|
||||
}
|
||||
|
||||
void ShadowMap::prepareViewport(const filament::Viewport& viewport) noexcept {
|
||||
mPerViewUniforms.prepareViewport(viewport, 0, 0);
|
||||
void ShadowMap::prepareViewport(Transaction const& transaction,
|
||||
const filament::Viewport& viewport) noexcept {
|
||||
PerShadowMapUniforms::prepareViewport(transaction, viewport, 0, 0);
|
||||
}
|
||||
|
||||
void ShadowMap::prepareTime(FEngine& engine, math::float4 const& userTime) noexcept {
|
||||
mPerViewUniforms.prepareTime(engine, userTime);
|
||||
void ShadowMap::prepareTime(Transaction const& transaction,
|
||||
FEngine& engine, math::float4 const& userTime) noexcept {
|
||||
PerShadowMapUniforms::prepareTime(transaction, engine, userTime);
|
||||
}
|
||||
|
||||
void ShadowMap::prepareDirectionalLight(FEngine& engine, math::float3 const& sceneSpaceDirection,
|
||||
LightManager::Instance instance) noexcept {
|
||||
mPerViewUniforms.prepareDirectionalLight(engine, 1.0f, sceneSpaceDirection, instance);
|
||||
void ShadowMap::prepareShadowMapping(Transaction const& transaction,
|
||||
bool highPrecision) noexcept {
|
||||
PerShadowMapUniforms::prepareShadowMapping(transaction, highPrecision);
|
||||
}
|
||||
|
||||
void ShadowMap::prepareShadowMapping(bool highPrecision) noexcept {
|
||||
mPerViewUniforms.prepareShadowMapping(highPrecision);
|
||||
PerShadowMapUniforms::Transaction ShadowMap::open(DriverApi& driver) noexcept {
|
||||
return PerShadowMapUniforms::open(driver);
|
||||
}
|
||||
|
||||
void ShadowMap::commitUniforms(backend::DriverApi& driver) const noexcept {
|
||||
mPerViewUniforms.commit(driver);
|
||||
void ShadowMap::commit(Transaction& transaction,
|
||||
backend::DriverApi& driver) const noexcept {
|
||||
mPerShadowMapUniforms.commit(transaction, driver);
|
||||
}
|
||||
|
||||
void ShadowMap::bindPerViewUniformsAndSamplers(backend::DriverApi& driver) const noexcept {
|
||||
mPerViewUniforms.bind(driver);
|
||||
void ShadowMap::bind(backend::DriverApi& driver) const noexcept {
|
||||
mPerShadowMapUniforms.bind(driver);
|
||||
}
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include "components/LightManager.h"
|
||||
|
||||
#include "PerViewUniforms.h"
|
||||
#include "PerShadowMapUniforms.h"
|
||||
|
||||
#include "details/Camera.h"
|
||||
#include "details/Scene.h"
|
||||
@@ -187,14 +187,20 @@ public:
|
||||
ShadowType getShadowType() const noexcept { return mShadowType; }
|
||||
uint8_t getFace() const noexcept { return mFace; }
|
||||
|
||||
void prepareCamera(FEngine& engine, const CameraInfo& cameraInfo) noexcept;
|
||||
void prepareViewport(const filament::Viewport& viewport) noexcept;
|
||||
void prepareTime(FEngine& engine, math::float4 const& userTime) noexcept;
|
||||
void prepareDirectionalLight(FEngine& engine, math::float3 const& sceneSpaceDirection,
|
||||
LightManager::Instance instance) noexcept;
|
||||
void prepareShadowMapping(bool highPrecision) noexcept;
|
||||
void commitUniforms(backend::DriverApi& driver) const noexcept;
|
||||
void bindPerViewUniformsAndSamplers(backend::DriverApi& driver) const noexcept;
|
||||
using Transaction = PerShadowMapUniforms::Transaction;
|
||||
|
||||
static void prepareCamera(Transaction const& transaction,
|
||||
FEngine& engine, const CameraInfo& cameraInfo) noexcept;
|
||||
static void prepareViewport(Transaction const& transaction,
|
||||
const filament::Viewport& viewport) noexcept;
|
||||
static void prepareTime(Transaction const& transaction,
|
||||
FEngine& engine, math::float4 const& userTime) noexcept;
|
||||
static void prepareShadowMapping(Transaction const& transaction,
|
||||
bool highPrecision) noexcept;
|
||||
static PerShadowMapUniforms::Transaction open(backend::DriverApi& driver) noexcept;
|
||||
void commit(Transaction& transaction,
|
||||
backend::DriverApi& driver) const noexcept;
|
||||
void bind(backend::DriverApi& driver) const noexcept;
|
||||
|
||||
private:
|
||||
struct Segment {
|
||||
@@ -292,12 +298,10 @@ private:
|
||||
{ 2, 6, 7, 3 }, // top
|
||||
};
|
||||
|
||||
// TODO: for shadow maps we don't need the whole `PerViewUniforms` which is large.
|
||||
// replace it with a smaller version that updates only what we need.
|
||||
mutable PerViewUniforms mPerViewUniforms; // 40 + 2048
|
||||
mutable PerShadowMapUniforms mPerShadowMapUniforms; // 4
|
||||
|
||||
FCamera* mCamera = nullptr; // 8
|
||||
FCamera* mDebugCamera = nullptr; // 8
|
||||
FCamera* mCamera = nullptr; // 8
|
||||
FCamera* mDebugCamera = nullptr; // 8
|
||||
|
||||
// The data below technically belongs to ShadowMapManager, but it simplifies allocations
|
||||
// to store it here. This data is always associated with this shadow map anyway.
|
||||
|
||||
@@ -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_SHADOWMAP_PUNCTUAL);
|
||||
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
|
||||
// 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_SHADOWMAP_PUNCTUAL);
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -157,7 +161,7 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
|
||||
|
||||
auto& prepareShadowPass = fg.addPass<PrepareShadowPassData>("Prepare Shadow Pass",
|
||||
[&](FrameGraph::Builder& builder, auto& data) {
|
||||
data.passList.reserve(CONFIG_MAX_SHADOW_LAYERS);
|
||||
data.passList.reserve(CONFIG_MAX_SHADOWMAPS);
|
||||
data.shadows = builder.createTexture("Shadowmap", {
|
||||
.width = textureRequirements.size, .height = textureRequirements.size,
|
||||
.depth = textureRequirements.layers,
|
||||
@@ -215,9 +219,6 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
|
||||
// for spot shadow map, we need to do the culling
|
||||
switch (shadowMap.getShadowType()) {
|
||||
case ShadowType::DIRECTIONAL:
|
||||
shadowMap.prepareDirectionalLight(engine,
|
||||
scene->getLightData().elementAt<FScene::DIRECTION>(0),
|
||||
scene->getLightData().elementAt<FScene::LIGHT_INSTANCE>(0));
|
||||
break;
|
||||
case ShadowType::SPOT:
|
||||
prepareSpotShadowMap(shadowMap, engine, view, mainCameraInfo,
|
||||
@@ -232,29 +233,32 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
|
||||
}
|
||||
|
||||
if (shadowMap.hasVisibleShadows()) {
|
||||
// TODO: this loop can generate a lot of commands. investigate if
|
||||
// we could compact or reduce the number of commands.
|
||||
// - we could move this into the execute of each pass, but
|
||||
// then we would have to update the UBO each time.
|
||||
// - we could also always use the same commands for all
|
||||
// shadow maps, but then we'd generate a lot of
|
||||
// unneeded draw call.
|
||||
// Note: this loop can generate a lot of commands that come out of the
|
||||
// "per frame command arena". The allocation persists until the
|
||||
// end of the frame.
|
||||
// One way to possibly mitigate this, would be to always use the
|
||||
// same command buffer for all shadow map, but then we'd generate
|
||||
// a lot of unneeded draw calls.
|
||||
// To do this efficiently, we'd need a way to cull draw calls already
|
||||
// recorded in the command buffer, per shadow map.
|
||||
|
||||
// generate and sort the commands for rendering the shadow map
|
||||
|
||||
// cameraInfo only valid after calling update
|
||||
const CameraInfo cameraInfo{ shadowMap.getCamera() };
|
||||
|
||||
shadowMap.prepareCamera(engine, cameraInfo);
|
||||
shadowMap.prepareViewport(shadowMap.getViewport());
|
||||
shadowMap.prepareTime(engine, userTime);
|
||||
shadowMap.prepareShadowMapping(view.getVsmShadowOptions().highPrecision);
|
||||
shadowMap.commitUniforms(driver);
|
||||
auto transaction = ShadowMap::open(driver);
|
||||
ShadowMap::prepareCamera(transaction, engine, cameraInfo);
|
||||
ShadowMap::prepareViewport(transaction, shadowMap.getViewport());
|
||||
ShadowMap::prepareTime(transaction, engine, userTime);
|
||||
ShadowMap::prepareShadowMapping(transaction,
|
||||
view.getVsmShadowOptions().highPrecision);
|
||||
shadowMap.commit(transaction, driver);
|
||||
|
||||
// updatePrimitivesLod must be run before RenderPass::appendCommands.
|
||||
view.updatePrimitivesLod(engine,
|
||||
cameraInfo, scene->getRenderableData(), entry.range);
|
||||
|
||||
// generate and sort the commands for rendering the shadow map
|
||||
RenderPass pass(passTemplate);
|
||||
pass.setCamera(cameraInfo);
|
||||
pass.setVisibilityMask(entry.visibilityMask);
|
||||
@@ -266,14 +270,10 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
|
||||
entry.executor = pass.getExecutor();
|
||||
|
||||
if (!view.hasVSM()) {
|
||||
auto li = scene->getLightData().elementAt<FScene::LIGHT_INSTANCE>(
|
||||
entry.shadowMap->getLightIndex());
|
||||
|
||||
auto const& params = engine.getLightManager().getShadowParams(li);
|
||||
|
||||
auto const* options = shadowMap.getShadowOptions();
|
||||
const PolygonOffset polygonOffset = { // handle reversed Z
|
||||
.slope = -params.options.polygonOffsetSlope,
|
||||
.constant = -params.options.polygonOffsetConstant
|
||||
.slope = -options->polygonOffsetSlope,
|
||||
.constant = -options->polygonOffsetConstant
|
||||
};
|
||||
entry.executor.overridePolygonOffset(&polygonOffset);
|
||||
}
|
||||
@@ -389,16 +389,15 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
|
||||
// `entry` lives in `PrepareShadowPassData` which is guaranteed to still
|
||||
// be alive when we execute here (all passes stay alive until the FrameGraph
|
||||
// is destroyed).
|
||||
// It wouldn't work to capture by copy because entry.pass wouldn't be
|
||||
// It wouldn't work to capture by copy because entry.executor wouldn't be
|
||||
// initialized, as this happens in an `execute` block.
|
||||
|
||||
entry.shadowMap->bindPerViewUniformsAndSamplers(driver);
|
||||
|
||||
auto rt = resources.getRenderPassInfo(data.rt);
|
||||
rt.params.viewport = entry.shadowMap->getViewport();
|
||||
|
||||
engine.flush();
|
||||
driver.beginRenderPass(rt.target, rt.params);
|
||||
entry.shadowMap->bind(driver);
|
||||
entry.executor.execute(engine, "Shadow Pass");
|
||||
driver.endRenderPass();
|
||||
});
|
||||
@@ -460,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();
|
||||
@@ -469,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -533,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]);
|
||||
|
||||
@@ -546,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;
|
||||
}
|
||||
@@ -674,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;
|
||||
@@ -684,6 +691,7 @@ void ShadowMapManager::prepareSpotShadowMap(ShadowMap& shadowMap,
|
||||
s.shadows[shadowIndex].bulbRadiusLs =
|
||||
mSoftShadowOptions.penumbraScale * options->shadowBulbRadius
|
||||
/ wsTexelSizeAtOneMeter;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -745,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;
|
||||
@@ -755,7 +762,7 @@ void ShadowMapManager::preparePointShadowMap(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 = {}; // no texture matrix for point lights
|
||||
s.shadows[shadowIndex].direction = {}; // no direction of point lights
|
||||
s.shadows[shadowIndex].normalBias = normalBias * wsTexelSizeAtOneMeter;
|
||||
@@ -784,14 +791,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 {
|
||||
@@ -103,9 +99,9 @@ public:
|
||||
}
|
||||
|
||||
ShadowMap* getPointOrSpotShadowMap(size_t index) noexcept {
|
||||
assert_invariant(index < CONFIG_MAX_SHADOWMAP_PUNCTUAL);
|
||||
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_SHADOWMAP_PUNCTUAL) };
|
||||
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 2120 bytes (total of 132KB for 64 shadow maps)
|
||||
// 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_LAYERS> mShadowMapCache;
|
||||
std::array<ShadowMapStorage, CONFIG_MAX_SHADOWMAPS> mShadowMapCache;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -35,17 +35,30 @@ namespace filament {
|
||||
|
||||
using namespace backend;
|
||||
|
||||
FMaterialInstance::FMaterialInstance() noexcept = default;
|
||||
FMaterialInstance::FMaterialInstance() noexcept
|
||||
: mCulling(CullingMode::BACK),
|
||||
mDepthFunc(RasterState::DepthFunc::LE),
|
||||
mColorWrite(false),
|
||||
mDepthWrite(false),
|
||||
mHasScissor(false),
|
||||
mIsDoubleSided(false),
|
||||
mTransparencyMode(TransparencyMode::DEFAULT) {
|
||||
}
|
||||
|
||||
FMaterialInstance::FMaterialInstance(FEngine& engine,
|
||||
FMaterialInstance const* other, const char* name)
|
||||
: mMaterial(other->mMaterial),
|
||||
mPolygonOffset(other->mPolygonOffset),
|
||||
mStencilState(other->mStencilState),
|
||||
mMaskThreshold(other->mMaskThreshold),
|
||||
mSpecularAntiAliasingVariance(other->mSpecularAntiAliasingVariance),
|
||||
mSpecularAntiAliasingThreshold(other->mSpecularAntiAliasingThreshold),
|
||||
mCulling(other->mCulling),
|
||||
mDepthFunc(other->mDepthFunc),
|
||||
mColorWrite(other->mColorWrite),
|
||||
mDepthWrite(other->mDepthWrite),
|
||||
mStencilState(other->mStencilState),
|
||||
mDepthFunc(other->mDepthFunc),
|
||||
mHasScissor(false),
|
||||
mIsDoubleSided(other->mIsDoubleSided),
|
||||
mScissorRect(other->mScissorRect),
|
||||
mName(name ? CString(name) : other->mName) {
|
||||
|
||||
@@ -63,10 +76,23 @@ FMaterialInstance::FMaterialInstance(FEngine& engine,
|
||||
mSbHandle = driver.createSamplerGroup(mSamplers.getSize());
|
||||
}
|
||||
|
||||
mMaterialSortingKey = RenderPass::makeMaterialSortingKey(
|
||||
material->getId(), material->generateMaterialInstanceId());
|
||||
if (material->hasDoubleSidedCapability()) {
|
||||
setDoubleSided(mIsDoubleSided);
|
||||
}
|
||||
|
||||
if (material->getBlendingMode() == BlendingMode::MASKED) {
|
||||
setMaskThreshold(mMaskThreshold);
|
||||
}
|
||||
|
||||
if (material->hasSpecularAntiAliasing()) {
|
||||
setSpecularAntiAliasingThreshold(mSpecularAntiAliasingThreshold);
|
||||
setSpecularAntiAliasingVariance(mSpecularAntiAliasingVariance);
|
||||
}
|
||||
|
||||
setTransparencyMode(material->getTransparencyMode());
|
||||
|
||||
mMaterialSortingKey = RenderPass::makeMaterialSortingKey(
|
||||
material->getId(), material->generateMaterialInstanceId());
|
||||
}
|
||||
|
||||
FMaterialInstance* FMaterialInstance::duplicate(
|
||||
@@ -183,14 +209,29 @@ void FMaterialInstance::setParameterImpl(std::string_view name,
|
||||
|
||||
void FMaterialInstance::setMaskThreshold(float threshold) noexcept {
|
||||
setParameter("_maskThreshold", math::saturate(threshold));
|
||||
mMaskThreshold = math::saturate(threshold);
|
||||
}
|
||||
|
||||
float FMaterialInstance::getMaskThreshold() const noexcept {
|
||||
return mMaskThreshold;
|
||||
}
|
||||
|
||||
void FMaterialInstance::setSpecularAntiAliasingVariance(float variance) noexcept {
|
||||
setParameter("_specularAntiAliasingVariance", math::saturate(variance));
|
||||
mSpecularAntiAliasingVariance = math::saturate(variance);
|
||||
}
|
||||
|
||||
float FMaterialInstance::getSpecularAntiAliasingVariance() const noexcept {
|
||||
return mSpecularAntiAliasingVariance;
|
||||
}
|
||||
|
||||
void FMaterialInstance::setSpecularAntiAliasingThreshold(float threshold) noexcept {
|
||||
setParameter("_specularAntiAliasingThreshold", math::saturate(threshold * threshold));
|
||||
mSpecularAntiAliasingThreshold = std::sqrt(math::saturate(threshold * threshold));
|
||||
}
|
||||
|
||||
float FMaterialInstance::getSpecularAntiAliasingThreshold() const noexcept {
|
||||
return mSpecularAntiAliasingThreshold;
|
||||
}
|
||||
|
||||
void FMaterialInstance::setDoubleSided(bool doubleSided) noexcept {
|
||||
@@ -202,6 +243,11 @@ void FMaterialInstance::setDoubleSided(bool doubleSided) noexcept {
|
||||
if (doubleSided) {
|
||||
setCullingMode(CullingMode::NONE);
|
||||
}
|
||||
mIsDoubleSided = doubleSided;
|
||||
}
|
||||
|
||||
bool FMaterialInstance::isDoubleSided() const noexcept {
|
||||
return mIsDoubleSided;
|
||||
}
|
||||
|
||||
void FMaterialInstance::setTransparencyMode(TransparencyMode mode) noexcept {
|
||||
@@ -212,6 +258,10 @@ void FMaterialInstance::setDepthCulling(bool enable) noexcept {
|
||||
mDepthFunc = enable ? RasterState::DepthFunc::GE : RasterState::DepthFunc::A;
|
||||
}
|
||||
|
||||
bool FMaterialInstance::isDepthCullingEnabled() const noexcept {
|
||||
return mDepthFunc != RasterState::DepthFunc::A;
|
||||
}
|
||||
|
||||
const char* FMaterialInstance::getName() const noexcept {
|
||||
// To decide whether to use the parent material name as a fallback, we check for the nullness of
|
||||
// the instance's CString rather than calling empty(). This allows instances to override the
|
||||
|
||||
@@ -89,9 +89,11 @@ public:
|
||||
|
||||
backend::CullingMode getCullingMode() const noexcept { return mCulling; }
|
||||
|
||||
bool getColorWrite() const noexcept { return mColorWrite; }
|
||||
bool isColorWriteEnabled() const noexcept { return mColorWrite; }
|
||||
|
||||
bool getDepthWrite() const noexcept { return mDepthWrite; }
|
||||
bool isDepthWriteEnabled() const noexcept { return mDepthWrite; }
|
||||
|
||||
bool isStencilWriteEnabled() const noexcept { return mStencilState.stencilWrite; }
|
||||
|
||||
backend::StencilState getStencilState() const noexcept { return mStencilState; }
|
||||
|
||||
@@ -108,12 +110,20 @@ public:
|
||||
|
||||
void setMaskThreshold(float threshold) noexcept;
|
||||
|
||||
float getMaskThreshold() const noexcept;
|
||||
|
||||
void setSpecularAntiAliasingVariance(float variance) noexcept;
|
||||
|
||||
float getSpecularAntiAliasingVariance() const noexcept;
|
||||
|
||||
void setSpecularAntiAliasingThreshold(float threshold) noexcept;
|
||||
|
||||
float getSpecularAntiAliasingThreshold() const noexcept;
|
||||
|
||||
void setDoubleSided(bool doubleSided) noexcept;
|
||||
|
||||
bool isDoubleSided() const noexcept;
|
||||
|
||||
void setTransparencyMode(TransparencyMode mode) noexcept;
|
||||
|
||||
void setCullingMode(CullingMode culling) noexcept { mCulling = culling; }
|
||||
@@ -126,6 +136,8 @@ public:
|
||||
|
||||
void setDepthCulling(bool enable) noexcept;
|
||||
|
||||
bool isDepthCullingEnabled() const noexcept;
|
||||
|
||||
void setStencilCompareFunction(StencilCompareFunc func, StencilFace face) noexcept {
|
||||
if (any(face & StencilFace::FRONT)) {
|
||||
mStencilState.front.stencilFunc = func;
|
||||
@@ -222,19 +234,26 @@ private:
|
||||
|
||||
// keep these grouped, they're accessed together in the render-loop
|
||||
FMaterial const* mMaterial = nullptr;
|
||||
|
||||
backend::Handle<backend::HwBufferObject> mUbHandle;
|
||||
backend::Handle<backend::HwSamplerGroup> mSbHandle;
|
||||
|
||||
UniformBuffer mUniforms;
|
||||
backend::SamplerGroup mSamplers;
|
||||
backend::PolygonOffset mPolygonOffset;
|
||||
backend::CullingMode mCulling;
|
||||
bool mColorWrite;
|
||||
bool mDepthWrite;
|
||||
bool mHasScissor = false;
|
||||
backend::StencilState mStencilState = {};
|
||||
backend::RasterState::DepthFunc mDepthFunc;
|
||||
TransparencyMode mTransparencyMode;
|
||||
|
||||
backend::PolygonOffset mPolygonOffset{};
|
||||
backend::StencilState mStencilState{};
|
||||
|
||||
float mMaskThreshold = 0.0f;
|
||||
float mSpecularAntiAliasingVariance = 0.0f;
|
||||
float mSpecularAntiAliasingThreshold = 0.0f;
|
||||
|
||||
backend::CullingMode mCulling : 2;
|
||||
backend::RasterState::DepthFunc mDepthFunc : 3;
|
||||
bool mColorWrite : 1;
|
||||
bool mDepthWrite : 1;
|
||||
bool mHasScissor : 1;
|
||||
bool mIsDoubleSided : 1;
|
||||
TransparencyMode mTransparencyMode : 2;
|
||||
|
||||
uint64_t mMaterialSortingKey = 0;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -294,10 +294,11 @@ void FView::prepareShadowing(FEngine& engine, DriverApi& driver,
|
||||
}
|
||||
|
||||
// Find all shadow-casting spotlights.
|
||||
size_t shadowLayerCount = 0;
|
||||
size_t shadowMapCount = 0;
|
||||
|
||||
// We allow a max of CONFIG_MAX_SHADOW_CASTING_SPOTS spotlight shadows. Any additional
|
||||
// We allow a max of CONFIG_MAX_SHADOWMAPS point/spotlight shadows. Any additional
|
||||
// shadow-casting spotlights are ignored.
|
||||
// Note that pointlight shadows cost 6 shadowmaps, reducing the total count.
|
||||
for (size_t l = FScene::DIRECTIONAL_LIGHTS_COUNT; l < lightData.size(); l++) {
|
||||
|
||||
// when we get here all the lights should be visible
|
||||
@@ -317,12 +318,12 @@ void FView::prepareShadowing(FEngine& engine, DriverApi& driver,
|
||||
mShadowMapManager.addShadowMap(l, lcm.isSpotLight(li), &shadowOptions);
|
||||
|
||||
if (lcm.isSpotLight(li)) {
|
||||
shadowLayerCount += 6;
|
||||
shadowMapCount += 6;
|
||||
} else {
|
||||
shadowLayerCount += 1;
|
||||
shadowMapCount += 1;
|
||||
}
|
||||
|
||||
if (shadowLayerCount > CONFIG_MAX_SHADOWMAP_PUNCTUAL - 1) {
|
||||
if (shadowMapCount > CONFIG_MAX_SHADOWMAPS - 1) {
|
||||
break; // we ran out of spotlight shadow casting
|
||||
}
|
||||
}
|
||||
@@ -693,13 +694,6 @@ void FView::prepareSSR(Handle<HwTexture> ssr, float refractionLodOffset,
|
||||
mPerViewUniforms.prepareSSR(ssr, refractionLodOffset, ssrOptions);
|
||||
}
|
||||
|
||||
void FView::prepareHistorySSR(Handle<HwTexture> ssr,
|
||||
mat4f const& historyProjection, mat4f const& uvFromViewMatrix,
|
||||
ScreenSpaceReflectionsOptions const& ssrOptions) const noexcept {
|
||||
mPerViewUniforms.prepareHistorySSR(ssr,
|
||||
historyProjection, uvFromViewMatrix, ssrOptions);
|
||||
}
|
||||
|
||||
void FView::prepareStructure(Handle<HwTexture> structure) const noexcept {
|
||||
// sampler must be NEAREST
|
||||
mPerViewUniforms.prepareStructure(structure);
|
||||
|
||||
@@ -145,9 +145,6 @@ public:
|
||||
void prepareSSAO(backend::Handle<backend::HwTexture> ssao) const noexcept;
|
||||
void prepareSSR(backend::Handle<backend::HwTexture> ssr, float refractionLodOffset,
|
||||
ScreenSpaceReflectionsOptions const& ssrOptions) const noexcept;
|
||||
void prepareHistorySSR(backend::Handle<backend::HwTexture> ssr,
|
||||
math::mat4f const& historyProjection, math::mat4f const& uvFromViewMatrix,
|
||||
ScreenSpaceReflectionsOptions const& ssrOptions) const noexcept;
|
||||
void prepareStructure(backend::Handle<backend::HwTexture> structure) const noexcept;
|
||||
void prepareShadow(backend::Handle<backend::HwTexture> structure) const noexcept;
|
||||
void prepareShadowMapping(bool highPrecision) const noexcept;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -60,29 +60,23 @@ enum class SamplerBindingPoints : uint8_t {
|
||||
constexpr size_t CONFIG_MAX_LIGHT_COUNT = 256;
|
||||
constexpr size_t CONFIG_MAX_LIGHT_INDEX = CONFIG_MAX_LIGHT_COUNT - 1;
|
||||
|
||||
// The maximum number of shadowmaps.
|
||||
// There is currently a maximum limit of 128 shadowmaps.
|
||||
// Factors contributing to this limit:
|
||||
// - minspec for UBOs is 16KiB, which currently can hold a maximum of 128 entries
|
||||
constexpr size_t CONFIG_MAX_SHADOWMAPS = 64;
|
||||
|
||||
// The maximum number of shadow layers.
|
||||
// There is currently a limit to 146 layers.
|
||||
// There is currently a maximum limit of 255 layers.
|
||||
// Several factors are contributing to this limit:
|
||||
// - minspec for 2d texture arrays layer is 256
|
||||
// - we're using uint8_t to store the number of layers (255 max)
|
||||
// - minspec for UBOs is 16KiB, which currently can hold a maximum of 146 entries
|
||||
// - we need to reserve 4 entries for the cascaded shadow map
|
||||
//
|
||||
// CONFIG_MAX_SHADOW_LAYERS determines how many shadows can be used in the
|
||||
// scene. Currently, a spotlight uses 1 layer, a cascaded directional light uses up to 4
|
||||
// and a point light uses 6.
|
||||
//
|
||||
constexpr size_t CONFIG_MAX_SHADOW_LAYERS = 64;
|
||||
// - nonsensical to be larger than the number of shadowmaps
|
||||
constexpr size_t CONFIG_MAX_SHADOW_LAYERS = CONFIG_MAX_SHADOWMAPS;
|
||||
|
||||
// The maximum number of shadow cascades that can be used for directional lights.
|
||||
constexpr size_t CONFIG_MAX_SHADOW_CASCADES = 4;
|
||||
|
||||
// Maximum number of shadowmap for point and spotlights
|
||||
// spotlights use 1, point lights use 6
|
||||
constexpr size_t CONFIG_MAX_SHADOWMAP_PUNCTUAL =
|
||||
CONFIG_MAX_SHADOW_LAYERS - CONFIG_MAX_SHADOW_CASCADES;
|
||||
|
||||
|
||||
// The maximum UBO size, in bytes. This value is set to 16 KiB due to the ES3.0 spec.
|
||||
// Note that this value constrains the maximum number of skinning bones, morph targets,
|
||||
// instances, and shadow casting spotlights.
|
||||
|
||||
@@ -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);
|
||||
@@ -258,8 +256,13 @@ struct ShadowUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
|
||||
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_SHADOWMAP_PUNCTUAL];
|
||||
ShadowData shadows[CONFIG_MAX_SHADOWMAPS];
|
||||
};
|
||||
static_assert(sizeof(ShadowUib) <= CONFIG_MINSPEC_UBO_SIZE,
|
||||
"ShadowUib exceeds max UBO size");
|
||||
|
||||
@@ -54,9 +54,7 @@ namespace msl { // this is only used for MSL
|
||||
|
||||
using BindingIndexMap = std::unordered_map<std::string, uint16_t>;
|
||||
|
||||
template<typename F>
|
||||
static void forEachSib(const GLSLPostProcessor::Config& config, F fn) {
|
||||
const auto& samplerBindings = config.materialInfo->samplerBindings;
|
||||
static void collectSibs(const GLSLPostProcessor::Config& config, SibVector& sibs) {
|
||||
switch (config.domain) {
|
||||
case MaterialDomain::SURFACE:
|
||||
UTILS_NOUNROLL
|
||||
@@ -67,14 +65,15 @@ static void forEachSib(const GLSLPostProcessor::Config& config, F fn) {
|
||||
auto const* sib =
|
||||
SibGenerator::getSib((SamplerBindingPoints)blockIndex, config.variant);
|
||||
if (sib && hasShaderType(sib->getStageFlags(), config.shaderType)) {
|
||||
fn(blockIndex, sib);
|
||||
sibs.emplace_back(blockIndex, sib);
|
||||
}
|
||||
}
|
||||
case MaterialDomain::POST_PROCESS:
|
||||
case MaterialDomain::COMPUTE:
|
||||
break;
|
||||
}
|
||||
fn((uint8_t) SamplerBindingPoints::PER_MATERIAL_INSTANCE, &config.materialInfo->sib);
|
||||
sibs.emplace_back((uint8_t) SamplerBindingPoints::PER_MATERIAL_INSTANCE,
|
||||
&config.materialInfo->sib);
|
||||
}
|
||||
|
||||
}; // namespace msl
|
||||
@@ -138,8 +137,9 @@ static std::string stringifySpvOptimizerMessage(spv_message_level_t level, const
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
void GLSLPostProcessor::spirvToToMsl(const SpirvBlob *spirv, std::string *outMsl,
|
||||
const Config &config, ShaderMinifier& minifier) {
|
||||
void GLSLPostProcessor::spirvToMsl(const SpirvBlob *spirv, std::string *outMsl,
|
||||
filament::backend::ShaderModel shaderModel, bool useFramebufferFetch, const SibVector& sibs,
|
||||
const ShaderMinifier* minifier) {
|
||||
|
||||
using namespace msl;
|
||||
|
||||
@@ -148,19 +148,19 @@ void GLSLPostProcessor::spirvToToMsl(const SpirvBlob *spirv, std::string *outMsl
|
||||
mslCompiler.set_common_options(options);
|
||||
|
||||
const CompilerMSL::Options::Platform platform =
|
||||
config.shaderModel == ShaderModel::MOBILE ?
|
||||
shaderModel == ShaderModel::MOBILE ?
|
||||
CompilerMSL::Options::Platform::iOS : CompilerMSL::Options::Platform::macOS;
|
||||
|
||||
CompilerMSL::Options mslOptions = {};
|
||||
mslOptions.platform = platform,
|
||||
mslOptions.msl_version = config.shaderModel == ShaderModel::MOBILE ?
|
||||
mslOptions.msl_version = shaderModel == ShaderModel::MOBILE ?
|
||||
CompilerMSL::Options::make_msl_version(2, 0) : CompilerMSL::Options::make_msl_version(2, 2);
|
||||
|
||||
if (config.hasFramebufferFetch) {
|
||||
if (useFramebufferFetch) {
|
||||
mslOptions.use_framebuffer_fetch_subpasses = true;
|
||||
// On macOS, framebuffer fetch is only available starting with MSL 2.3. Filament will only
|
||||
// use framebuffer fetch materials on devices that support it.
|
||||
if (config.shaderModel == ShaderModel::DESKTOP) {
|
||||
if (shaderModel == ShaderModel::DESKTOP) {
|
||||
mslOptions.msl_version = CompilerMSL::Options::make_msl_version(2, 3);
|
||||
}
|
||||
}
|
||||
@@ -221,9 +221,7 @@ void GLSLPostProcessor::spirvToToMsl(const SpirvBlob *spirv, std::string *outMsl
|
||||
//
|
||||
// Which is then bound to the vertex/fragment functions:
|
||||
// constant spvDescriptorSetBuffer1& spvDescriptorSet1 [[buffer(27)]]
|
||||
forEachSib(config,
|
||||
[&executionModel, &mslCompiler, &argumentBuffers](
|
||||
uint8_t bindingPoint, const SamplerInterfaceBlock* sib) {
|
||||
for (auto [bindingPoint, sib] : sibs) {
|
||||
const auto& infoList = sib->getSamplerInfoList();
|
||||
|
||||
// bindingPoint + 1, because the first descriptor set is for uniforms
|
||||
@@ -251,7 +249,7 @@ void GLSLPostProcessor::spirvToToMsl(const SpirvBlob *spirv, std::string *outMsl
|
||||
argBufferBinding.msl_buffer =
|
||||
CodeGenerator::METAL_SAMPLER_GROUP_BINDING_START + bindingPoint;
|
||||
mslCompiler.add_msl_resource_binding(argBufferBinding);
|
||||
});
|
||||
}
|
||||
|
||||
auto updateResourceBindingDefault = [executionModel, &mslCompiler]
|
||||
(const auto& resource, const BindingIndexMap* map = nullptr) {
|
||||
@@ -283,7 +281,9 @@ void GLSLPostProcessor::spirvToToMsl(const SpirvBlob *spirv, std::string *outMsl
|
||||
mslCompiler.add_discrete_descriptor_set(0);
|
||||
|
||||
*outMsl = mslCompiler.compile();
|
||||
*outMsl = minifier.removeWhitespace(*outMsl);
|
||||
if (minifier) {
|
||||
*outMsl = minifier->removeWhitespace(*outMsl);
|
||||
}
|
||||
|
||||
// Replace spirv-cross' generated argument buffers with our own.
|
||||
for (auto* argBuffer : argumentBuffers) {
|
||||
@@ -374,8 +374,11 @@ bool GLSLPostProcessor::process(const std::string& inputShader, Config const& co
|
||||
GlslangToSpv(*program.getIntermediate(internalConfig.shLang),
|
||||
*internalConfig.spirvOutput, &options);
|
||||
if (internalConfig.mslOutput) {
|
||||
spirvToToMsl(internalConfig.spirvOutput, internalConfig.mslOutput, config,
|
||||
internalConfig.minifier);
|
||||
auto sibs = SibVector::with_capacity(CONFIG_SAMPLER_BINDING_COUNT);
|
||||
msl::collectSibs(config, sibs);
|
||||
spirvToMsl(internalConfig.spirvOutput, internalConfig.mslOutput,
|
||||
config.shaderModel, config.hasFramebufferFetch, sibs,
|
||||
&internalConfig.minifier);
|
||||
}
|
||||
} else {
|
||||
slog.e << "GLSL post-processor invoked with optimization level NONE"
|
||||
@@ -453,8 +456,10 @@ void GLSLPostProcessor::preprocessOptimization(glslang::TShader& tShader,
|
||||
}
|
||||
|
||||
if (internalConfig.mslOutput) {
|
||||
spirvToToMsl(internalConfig.spirvOutput, internalConfig.mslOutput, config,
|
||||
internalConfig.minifier);
|
||||
auto sibs = SibVector::with_capacity(CONFIG_SAMPLER_BINDING_COUNT);
|
||||
msl::collectSibs(config, sibs);
|
||||
spirvToMsl(internalConfig.spirvOutput, internalConfig.mslOutput, config.shaderModel,
|
||||
config.hasFramebufferFetch, sibs, &internalConfig.minifier);
|
||||
}
|
||||
|
||||
if (internalConfig.glslOutput) {
|
||||
@@ -480,7 +485,10 @@ void GLSLPostProcessor::fullOptimization(const TShader& tShader,
|
||||
}
|
||||
|
||||
if (internalConfig.mslOutput) {
|
||||
spirvToToMsl(&spirv, internalConfig.mslOutput, config, internalConfig.minifier);
|
||||
auto sibs = SibVector::with_capacity(CONFIG_SAMPLER_BINDING_COUNT);
|
||||
msl::collectSibs(config, sibs);
|
||||
spirvToMsl(&spirv, internalConfig.mslOutput, config.shaderModel, config.hasFramebufferFetch,
|
||||
sibs, &internalConfig.minifier);
|
||||
}
|
||||
|
||||
// Transpile back to GLSL
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
|
||||
#include "filamat/MaterialBuilder.h" // for MaterialBuilder:: enums
|
||||
|
||||
#include <utils/FixedCapacityVector.h>
|
||||
|
||||
#include "ShaderMinifier.h"
|
||||
|
||||
#include <ShaderLang.h>
|
||||
@@ -34,9 +36,15 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace filament {
|
||||
class SamplerInterfaceBlock;
|
||||
};
|
||||
|
||||
namespace filamat {
|
||||
|
||||
using SpirvBlob = std::vector<uint32_t>;
|
||||
using BindingPointAndSib = std::pair<uint8_t, const filament::SamplerInterfaceBlock*>;
|
||||
using SibVector = utils::FixedCapacityVector<BindingPointAndSib>;
|
||||
|
||||
class GLSLPostProcessor {
|
||||
public:
|
||||
@@ -69,6 +77,11 @@ public:
|
||||
SpirvBlob* outputSpirv,
|
||||
std::string* outputMsl);
|
||||
|
||||
// public so backend_test can also use it
|
||||
static void spirvToMsl(const SpirvBlob* spirv, std::string* outMsl,
|
||||
filament::backend::ShaderModel shaderModel, bool useFramebufferFetch,
|
||||
const SibVector& sibs, const ShaderMinifier* minifier);
|
||||
|
||||
private:
|
||||
struct InternalConfig {
|
||||
std::string* glslOutput = nullptr;
|
||||
@@ -97,8 +110,6 @@ private:
|
||||
static void registerPerformancePasses(spvtools::Optimizer& optimizer, Config const& config);
|
||||
|
||||
void optimizeSpirv(OptimizerPtr optimizer, SpirvBlob& spirv) const;
|
||||
static void spirvToToMsl(const SpirvBlob* spirv, std::string* outMsl, const Config& config,
|
||||
ShaderMinifier& minifier);
|
||||
|
||||
const MaterialBuilder::Optimization mOptimization;
|
||||
const bool mPrintShaders;
|
||||
|
||||
@@ -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]
|
||||
@@ -171,7 +170,7 @@ BufferInterfaceBlock const& UibGenerator::getLightsUib() noexcept {
|
||||
BufferInterfaceBlock const& UibGenerator::getShadowUib() noexcept {
|
||||
static BufferInterfaceBlock uib = BufferInterfaceBlock::Builder()
|
||||
.name(ShadowUib::_name)
|
||||
.add({{ "shadows", CONFIG_MAX_SHADOWMAP_PUNCTUAL,
|
||||
.add({{ "shadows", CONFIG_MAX_SHADOWMAPS,
|
||||
BufferInterfaceBlock::Type::STRUCT, {},
|
||||
"ShadowData", sizeof(ShadowUib::ShadowData) }})
|
||||
.build();
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -42,7 +42,7 @@ TEST(ArgBufferFixup, Empty) {
|
||||
TEST(ArgBufferFixup, NoName) {
|
||||
// A valid arg buffer name must be provided to MetalArgumentBuffer.
|
||||
// This assertion is only fired in debug builds.
|
||||
#ifndef NDEBUG
|
||||
#if !defined(NDEBUG) && defined(GTEST_HAS_DEATH_TEST)
|
||||
EXPECT_DEATH({
|
||||
auto argBuffer = MetalArgumentBuffer::Builder().build();
|
||||
MetalArgumentBuffer::destroy(&argBuffer);
|
||||
@@ -56,7 +56,7 @@ TEST(ArgBufferFixup, NoName) {
|
||||
|
||||
TEST(ArgBufferFixup, DuplicateIndices) {
|
||||
// Each index must be unique.
|
||||
#ifndef NDEBUG
|
||||
#if !defined(NDEBUG) && defined(GTEST_HAS_DEATH_TEST)
|
||||
EXPECT_DEATH({
|
||||
auto argBuffer = MetalArgumentBuffer::Builder()
|
||||
.name("myArgumentBuffer")
|
||||
@@ -142,7 +142,7 @@ TEST(ArgBufferFixup, TextureTypes) {
|
||||
|
||||
TEST(ArgBufferFixup, InvalidType) {
|
||||
// All combinations of SamplerType and SamplerFormat are valid except for SAMPLER_3D / SHADOW.
|
||||
#ifndef NDEBUG
|
||||
#if !defined(NDEBUG) && defined(GTEST_HAS_DEATH_TEST)
|
||||
EXPECT_DEATH({
|
||||
auto argBuffer =
|
||||
MetalArgumentBuffer::Builder()
|
||||
|
||||
@@ -603,7 +603,7 @@ void FAssetLoader::recurseEntities(const cgltf_data* srcAsset, const cgltf_node*
|
||||
}
|
||||
}
|
||||
|
||||
if (node->light ) {
|
||||
if (node->light) {
|
||||
createLight(node->light, entity);
|
||||
}
|
||||
|
||||
@@ -991,7 +991,7 @@ bool FAssetLoader::createPrimitive(const cgltf_primitive& inPrim, Primitive* out
|
||||
const float* minp = &accessor->min[0];
|
||||
const float* maxp = &accessor->max[0];
|
||||
|
||||
// We assume that the range of morph target weight is [-1,1].
|
||||
// We assume that the range of morph target weight is [0, 1].
|
||||
targetAabb.min += float3(minp[0], minp[1], minp[2]);
|
||||
targetAabb.max += float3(maxp[0], maxp[1], maxp[2]);
|
||||
|
||||
|
||||
@@ -130,6 +130,45 @@ void FFilamentInstance::recomputeBoundingBoxes() {
|
||||
aabb.min = min(aabb.min, pt);
|
||||
aabb.max = max(aabb.max, pt);
|
||||
}
|
||||
|
||||
if (!prim->targets_count) {
|
||||
break;
|
||||
}
|
||||
|
||||
Aabb baseAabb(aabb);
|
||||
for (cgltf_size targetIndex = 0; targetIndex < prim->targets_count; ++targetIndex) {
|
||||
const cgltf_morph_target& target = prim->targets[targetIndex];
|
||||
for (cgltf_size attribIndex = 0; attribIndex < target.attributes_count; ++attribIndex) {
|
||||
const cgltf_attribute& targetAttribute = target.attributes[attribIndex];
|
||||
if (targetAttribute.type != cgltf_attribute_type_position) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const cgltf_accessor* targetAccessor = targetAttribute.data;
|
||||
const cgltf_size targetCount = targetAccessor->count;
|
||||
const cgltf_size targetDim = cgltf_num_components(targetAccessor->type);
|
||||
|
||||
assert_invariant(targetCount == accessor->count);
|
||||
assert_invariant(targetDim == dim);
|
||||
|
||||
cgltf_accessor_unpack_floats(targetAccessor, unpacked.data(), unpacked.size());
|
||||
|
||||
Aabb targetAabb;
|
||||
for (cgltf_size i = 0, j = 0, n = accessor->count; i < n; ++i, j += dim) {
|
||||
float3 delta(unpacked[j + 0], unpacked[j + 1], unpacked[j + 2]);
|
||||
targetAabb.min = min(targetAabb.min, delta);
|
||||
targetAabb.max = max(targetAabb.max, delta);
|
||||
}
|
||||
|
||||
targetAabb.min += baseAabb.min;
|
||||
targetAabb.max += baseAabb.max;
|
||||
|
||||
aabb.min = min(aabb.min, targetAabb.min);
|
||||
aabb.max = max(aabb.max, targetAabb.max);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,7 +217,7 @@ inline bool getElementType(cgltf_type type, cgltf_component_type ctype,
|
||||
*actualType = filament::VertexBuffer::AttributeType::UBYTE3;
|
||||
return true;
|
||||
case cgltf_component_type_r_16:
|
||||
*permitType = filament::VertexBuffer::AttributeType::FLOAT3;
|
||||
*permitType = filament::VertexBuffer::AttributeType::SHORT3;
|
||||
*actualType = filament::VertexBuffer::AttributeType::SHORT3;
|
||||
return true;
|
||||
case cgltf_component_type_r_16u:
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -134,8 +134,9 @@ highp vec4 getCascadeLightSpacePosition(uint cascade) {
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
@@ -154,17 +154,18 @@ Light getLight(const uint lightIndex) {
|
||||
light.worldPosition = positionFalloff.xyz;
|
||||
light.channels = channels;
|
||||
light.contactShadows = bool(typeShadow & 0x10u);
|
||||
#if defined(VARIANT_HAS_SHADOWING)
|
||||
#if defined(VARIANT_HAS_DYNAMIC_LIGHTING)
|
||||
light.shadowIndex = (typeShadow >> 8u) & 0xFFu;
|
||||
light.shadowLayer = (typeShadow >> 16u) & 0xFFu;
|
||||
light.castsShadows = bool(channels & 0x10000u);
|
||||
light.type = (typeShadow & 0x1u);
|
||||
#if defined(VARIANT_HAS_SHADOWING)
|
||||
light.shadowIndex = (typeShadow >> 8u) & 0xFFu;
|
||||
light.castsShadows = bool(channels & 0x10000u);
|
||||
if (light.type == LIGHT_TYPE_SPOT) {
|
||||
light.attenuation *= getAngleAttenuation(-direction, light.l, scaleOffset);
|
||||
light.zLight = dot(shadowUniforms.shadows[light.shadowIndex].lightFromWorldZ, vec4(worldPosition, 1.0));
|
||||
}
|
||||
#endif
|
||||
if (light.type == LIGHT_TYPE_SPOT) {
|
||||
light.attenuation *= getAngleAttenuation(-direction, light.l, scaleOffset);
|
||||
}
|
||||
#endif
|
||||
return light;
|
||||
}
|
||||
@@ -209,19 +210,20 @@ void evaluatePunctualLights(const MaterialInputs material,
|
||||
#if defined(VARIANT_HAS_SHADOWING)
|
||||
if (light.NoL > 0.0) {
|
||||
if (light.castsShadows) {
|
||||
uint layer = light.shadowLayer;
|
||||
uint shadowIndex = light.shadowIndex;
|
||||
highp vec4 shadowPosition;
|
||||
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;
|
||||
highp uint face = 0u;
|
||||
// getShadowPosition returns zLight which is needed for PCSS/DPCF
|
||||
shadowPosition = getShadowPosition(r, nf, layer, light.zLight);
|
||||
shadowPosition = getShadowPosition(r, shadowIndex, light.zLight, face);
|
||||
shadowIndex += face;
|
||||
} else {
|
||||
// getShadowPosition needs zLight for applying the normal bias
|
||||
shadowPosition = getShadowPosition(false, light.shadowIndex, 0u, light.zLight);
|
||||
shadowPosition = getShadowPosition(false, shadowIndex, 0u, light.zLight);
|
||||
}
|
||||
visibility = shadow(false, light_shadowMap, layer, light.shadowIndex,
|
||||
visibility = shadow(false, light_shadowMap, shadowIndex,
|
||||
shadowPosition, light.zLight);
|
||||
}
|
||||
if (light.contactShadows && visibility > 0.0) {
|
||||
|
||||
@@ -143,7 +143,9 @@ void main() {
|
||||
#if defined(VARIANT_HAS_SHADOWING) && defined(VARIANT_HAS_DIRECTIONAL_LIGHTING)
|
||||
vertex_lightSpacePosition = computeLightSpacePosition(
|
||||
vertex_worldPosition.xyz, vertex_worldNormal,
|
||||
frameUniforms.lightDirection, frameUniforms.shadowBias, getLightFromWorldMatrix());
|
||||
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;
|
||||
@@ -495,8 +495,8 @@ highp vec4 getShadowPosition(const bool DIRECTIONAL,
|
||||
}
|
||||
|
||||
// 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) {
|
||||
highp vec4 getShadowPosition(const highp vec3 r, const highp uint shadowIndex,
|
||||
out highp float d, out highp uint face) {
|
||||
highp vec4 tc;
|
||||
highp float rx = abs(r.x);
|
||||
highp float ry = abs(r.y);
|
||||
@@ -506,20 +506,22 @@ highp vec4 getShadowPosition(const highp vec3 r, const highp vec4 nf,
|
||||
if (d == rx) {
|
||||
tc.x = r.x >= 0.0 ? r.z : -r.z;
|
||||
tc.y = r.y;
|
||||
layer += (r.x >= 0.0 ? 0u : 1u);
|
||||
face = (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);
|
||||
face = (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);
|
||||
face = (r.z >= 0.0 ? 4u : 5u);
|
||||
}
|
||||
|
||||
// ma is guaranteed to be >= sc and tc
|
||||
tc.xy = (tc.xy * ma + vec2(1.0)) * 0.5;
|
||||
|
||||
highp vec4 nf = shadowUniforms.shadows[shadowIndex + face].lightFromWorldZ;
|
||||
|
||||
// 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;
|
||||
@@ -542,7 +544,8 @@ highp vec4 getShadowPosition(const highp vec3 r, const highp vec4 nf,
|
||||
// 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 +556,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);
|
||||
}
|
||||
|
||||
|
||||
15
web/filament-js/filament.d.ts
vendored
15
web/filament-js/filament.d.ts
vendored
@@ -417,7 +417,13 @@ export class Camera {
|
||||
|
||||
export class ColorGrading$Builder {
|
||||
public quality(qualityLevel: ColorGrading$QualityLevel): ColorGrading$Builder;
|
||||
public format(format: ColorGrading$LutFormat): ColorGrading$Builder;
|
||||
public dimensions(dim: number): ColorGrading$Builder;
|
||||
public toneMapping(toneMapping: ColorGrading$ToneMapping): ColorGrading$Builder;
|
||||
public luminanceScaling(luminanceScaling: boolean): ColorGrading$Builder;
|
||||
public gamutMapping(gamutMapping: boolean): ColorGrading$Builder;
|
||||
public exposure(exposure: number): ColorGrading$Builder;
|
||||
public nightAdaptation(adaptation: boolean): ColorGrading$Builder;
|
||||
public whiteBalance(temperature: number, tint: number): ColorGrading$Builder;
|
||||
public channelMixer(outRed: float3, outGreen: float3, outBlue: float3): ColorGrading$Builder;
|
||||
public shadowsMidtonesHighlights(shadows: float4, midtones: float4, highlights: float4,
|
||||
@@ -671,12 +677,17 @@ export enum Camera$Projection {
|
||||
ORTHO,
|
||||
}
|
||||
|
||||
export enum ColorGrading$QualityLevel {
|
||||
export enum ColorGrading$QualityLevel {
|
||||
LOW,
|
||||
MEDIUM,
|
||||
HIGH,
|
||||
ULTRA,
|
||||
}
|
||||
}
|
||||
|
||||
export enum ColorGrading$LutFormat {
|
||||
INTEGER,
|
||||
FLOAT,
|
||||
}
|
||||
|
||||
export enum ColorGrading$ToneMapping {
|
||||
LINEAR,
|
||||
|
||||
@@ -747,11 +747,40 @@ class_<ColorBuilder>("ColorGrading$Builder")
|
||||
return &builder->quality(ql);
|
||||
})
|
||||
|
||||
.BUILDER_FUNCTION("format", ColorBuilder, (ColorBuilder* builder,
|
||||
ColorGrading::LutFormat format), {
|
||||
return &builder->format(format);
|
||||
})
|
||||
|
||||
.BUILDER_FUNCTION("dimensions", ColorBuilder, (ColorBuilder* builder, uint8_t dim), {
|
||||
return &builder->dimensions(dim);
|
||||
})
|
||||
|
||||
.BUILDER_FUNCTION("toneMapping", ColorBuilder, (ColorBuilder* builder,
|
||||
ColorGrading::ToneMapping tm), {
|
||||
return &builder->toneMapping(tm);
|
||||
})
|
||||
|
||||
.BUILDER_FUNCTION("luminanceScaling", ColorBuilder, (ColorBuilder* builder,
|
||||
bool luminanceScaling), {
|
||||
return &builder->luminanceScaling(luminanceScaling);
|
||||
})
|
||||
|
||||
.BUILDER_FUNCTION("gamutMapping", ColorBuilder, (ColorBuilder* builder,
|
||||
bool gamutMapping), {
|
||||
return &builder->gamutMapping(gamutMapping);
|
||||
})
|
||||
|
||||
.BUILDER_FUNCTION("exposure", ColorBuilder, (ColorBuilder* builder,
|
||||
float exposure), {
|
||||
return &builder->exposure(exposure);
|
||||
})
|
||||
|
||||
.BUILDER_FUNCTION("nightAdaptation", ColorBuilder, (ColorBuilder* builder,
|
||||
float adaptation), {
|
||||
return &builder->nightAdaptation(adaptation);
|
||||
})
|
||||
|
||||
.BUILDER_FUNCTION("whiteBalance", ColorBuilder, (ColorBuilder* builder, float temp,
|
||||
float tint), {
|
||||
return &builder->whiteBalance(temp, tint);
|
||||
@@ -1250,12 +1279,24 @@ class_<MaterialInstance>("MaterialInstance")
|
||||
self->setParameter(name.c_str(), type, value); }), allow_raw_pointers())
|
||||
.function("setPolygonOffset", &MaterialInstance::setPolygonOffset)
|
||||
.function("setMaskThreshold", &MaterialInstance::setMaskThreshold)
|
||||
.function("getMaskThreshold", &MaterialInstance::getMaskThreshold)
|
||||
.function("setSpecularAntiAliasingVariance", &MaterialInstance::setSpecularAntiAliasingVariance)
|
||||
.function("getSpecularAntiAliasingVariance", &MaterialInstance::getSpecularAntiAliasingVariance)
|
||||
.function("setSpecularAntiAliasingThreshold", &MaterialInstance::setSpecularAntiAliasingThreshold)
|
||||
.function("getSpecularAntiAliasingThreshold", &MaterialInstance::getSpecularAntiAliasingThreshold)
|
||||
.function("setDoubleSided", &MaterialInstance::setDoubleSided)
|
||||
.function("isDoubleSided", &MaterialInstance::isDoubleSided)
|
||||
.function("setTransparencyMode", &MaterialInstance::setTransparencyMode)
|
||||
.function("getTransparencyMode", &MaterialInstance::getTransparencyMode)
|
||||
.function("setCullingMode", &MaterialInstance::setCullingMode)
|
||||
.function("getCullingMode", &MaterialInstance::getCullingMode)
|
||||
.function("setColorWrite", &MaterialInstance::setColorWrite)
|
||||
.function("isColorWriteEnabled", &MaterialInstance::isColorWriteEnabled)
|
||||
.function("setDepthWrite", &MaterialInstance::setDepthWrite)
|
||||
.function("isDepthWriteEnabled", &MaterialInstance::isDepthWriteEnabled)
|
||||
.function("setStencilWrite", &MaterialInstance::setStencilWrite)
|
||||
.function("setDepthCulling", &MaterialInstance::setDepthCulling)
|
||||
.function("isDepthCullingEnabled", &MaterialInstance::isDepthCullingEnabled)
|
||||
.function("setStencilCompareFunction", &MaterialInstance::setStencilCompareFunction)
|
||||
.function("setStencilCompareFunction", EMBIND_LAMBDA(void,
|
||||
(MaterialInstance* self, MaterialInstance::StencilCompareFunc func), {
|
||||
|
||||
@@ -147,6 +147,10 @@ enum_<ColorGrading::ToneMapping>("ColorGrading$ToneMapping")
|
||||
.value("FILMIC", ColorGrading::ToneMapping::FILMIC)
|
||||
.value("DISPLAY_RANGE", ColorGrading::ToneMapping::DISPLAY_RANGE);
|
||||
|
||||
enum_<ColorGrading::LutFormat>("ColorGrading$LutFormat")
|
||||
.value("INTEGER", ColorGrading::LutFormat::INTEGER)
|
||||
.value("FLOAT", ColorGrading::LutFormat::FLOAT);
|
||||
|
||||
enum_<Frustum::Plane>("Frustum$Plane")
|
||||
.value("LEFT", Frustum::Plane::LEFT)
|
||||
.value("RIGHT", Frustum::Plane::RIGHT)
|
||||
@@ -398,6 +402,11 @@ enum_<backend::CullingMode>("CullingMode")
|
||||
.value("BACK", backend::CullingMode::BACK)
|
||||
.value("FRONT_AND_BACK", backend::CullingMode::FRONT_AND_BACK);
|
||||
|
||||
enum_<filament::TransparencyMode>("TransparencyMode")
|
||||
.value("DEFAULT", filament::TransparencyMode::DEFAULT)
|
||||
.value("TWO_PASSES_ONE_SIDE", filament::TransparencyMode::TWO_PASSES_ONE_SIDE)
|
||||
.value("TWO_PASSES_TWO_SIDES", filament::TransparencyMode::TWO_PASSES_TWO_SIDES);
|
||||
|
||||
enum_<backend::FeatureLevel>("FeatureLevel")
|
||||
.value("FEATURE_LEVEL_1", backend::FeatureLevel::FEATURE_LEVEL_1)
|
||||
.value("FEATURE_LEVEL_2", backend::FeatureLevel::FEATURE_LEVEL_2);
|
||||
|
||||
Reference in New Issue
Block a user