Compare commits

...

9 Commits

Author SHA1 Message Date
Benjamin Doherty
d67e1a9ee8 Fix matc variantFilter 2022-11-03 15:53:48 -07:00
Benjamin Doherty
dc44e20be0 Fix RELEASE_NOTES 2022-11-03 09:57:21 -07:00
daemyung jang
e64b498d6e Update a comment about the range of morph target weight (#6265) 2022-11-03 09:19:01 -07:00
Mathias Agopian
31ab4a13c9 fix recently introduced crash on init
certain material properties can only be set if supported by the 
material.
2022-11-01 13:23:52 -07:00
Benjamin Doherty
e9728dcc8d Fix iOS build 2022-11-01 15:03:44 -04:00
Mathias Agopian
40a3644086 Reduce the size of ShadowMap to 40 bytes from 2KB+
ShadowMap had recently inflated due to its internal use of 
PerViewUniforms, which keeps a shadow copy of the uniform data. This
copy is not needed for ShadowMaps.
2022-11-01 11:58:28 -07:00
Mathias Agopian
41ef71abdf Add MaterialInstance getters for overridable properties (#6243)
In addition to the new getters, this change fixes the duplication of
a MaterialInstance, which didn't carry along the following states:
  - alpha mask threshold
  - specular AA threshold
  - specular AA variance
  - double sidedness

TODO: stencil state, polygon offset and scissor are stil not queryable
2022-11-01 11:22:01 -07:00
daemyung jang
3b40e52c98 Recompute bounding boxes with morph targets (#6246)
* Recompute bounding boxes with morph targets

* Reduce the number of heap allocation while recomputing bounding boxes

Co-authored-by: Romain Guy <romainguy@curious-creature.com>
2022-11-01 11:20:28 -07:00
daemyung jang
de8c7969f3 Return the correct permit type corresponding to the component type (#6255) 2022-11-01 11:03:27 -07:00
23 changed files with 748 additions and 66 deletions

View File

@@ -5,8 +5,13 @@ 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`
## v1.28.3
- backend: add support for GGP platform
- engine: primitives with `CullingMode::FRONT_AND_BACK` are now skipped.
## v1.28.2

View File

@@ -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();
}

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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).
*

View File

@@ -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

View File

@@ -0,0 +1,169 @@
/*
* 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::prepareDirectionalLight(Transaction const& transaction,
FEngine& engine,
float exposure,
float3 const& sceneSpaceDirection,
PerShadowMapUniforms::LightManagerInstance directionalLight) noexcept {
FLightManager& lcm = engine.getLightManager();
auto& s = edit(transaction);
const float3 l = -sceneSpaceDirection; // guaranteed normalized
if (directionalLight.isValid()) {
const float4 colorIntensity = {
lcm.getColor(directionalLight), lcm.getIntensity(directionalLight) * exposure };
s.lightDirection = l;
s.lightColorIntensity = colorIntensity;
s.lightChannels = lcm.getLightChannels(directionalLight);
const bool isSun = lcm.isSunLight(directionalLight);
// The last parameter must be < 0.0f for regular directional lights
float4 sun{ 0.0f, 0.0f, 0.0f, -1.0f };
if (UTILS_UNLIKELY(isSun && colorIntensity.w > 0.0f)) {
// currently we have only a single directional light, so it's probably likely that it's
// also the Sun. However, conceptually, most directional lights won't be sun lights.
float radius = lcm.getSunAngularRadius(directionalLight);
float haloSize = lcm.getSunHaloSize(directionalLight);
float haloFalloff = lcm.getSunHaloFalloff(directionalLight);
sun.x = std::cos(radius);
sun.y = std::sin(radius);
sun.z = 1.0f / (std::cos(radius * haloSize) - sun.x);
sun.w = haloFalloff;
}
s.sun = sun;
} else {
// Disable the sun if there's no directional light
s.sun = float4{ 0.0f, 0.0f, 0.0f, -1.0f };
}
}
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

View File

@@ -0,0 +1,95 @@
/*
* 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 void prepareDirectionalLight(Transaction const& transaction,
FEngine& engine, float exposure,
math::float3 const& sceneSpaceDirection, LightManagerInstance instance) 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

View File

@@ -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>;

View File

@@ -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;

View File

@@ -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;
@@ -1265,34 +1265,45 @@ 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,
void ShadowMap::prepareDirectionalLight(Transaction const& transaction,
FEngine& engine, math::float3 const& sceneSpaceDirection,
LightManager::Instance instance) noexcept {
mPerViewUniforms.prepareDirectionalLight(engine, 1.0f, sceneSpaceDirection, instance);
PerShadowMapUniforms::prepareDirectionalLight(transaction,
engine, 1.0f, sceneSpaceDirection, instance);
}
void ShadowMap::prepareShadowMapping(bool highPrecision) noexcept {
mPerViewUniforms.prepareShadowMapping(highPrecision);
void ShadowMap::prepareShadowMapping(Transaction const& transaction,
bool highPrecision) noexcept {
PerShadowMapUniforms::prepareShadowMapping(transaction, highPrecision);
}
void ShadowMap::commitUniforms(backend::DriverApi& driver) const noexcept {
mPerViewUniforms.commit(driver);
PerShadowMapUniforms::Transaction ShadowMap::open(DriverApi& driver) noexcept {
return PerShadowMapUniforms::open(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);
mPerShadowMapUniforms.bind(driver);
}
} // namespace filament

View File

@@ -19,7 +19,7 @@
#include "components/LightManager.h"
#include "PerViewUniforms.h"
#include "PerShadowMapUniforms.h"
#include "details/Camera.h"
#include "details/Scene.h"
@@ -187,13 +187,22 @@ 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,
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 prepareDirectionalLight(Transaction const& transaction,
FEngine& engine, math::float3 const& sceneSpaceDirection,
LightManager::Instance instance) noexcept;
void prepareShadowMapping(bool highPrecision) noexcept;
void commitUniforms(backend::DriverApi& driver) const 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 bindPerViewUniformsAndSamplers(backend::DriverApi& driver) const noexcept;
private:
@@ -292,12 +301,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.

View File

@@ -215,9 +215,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,
@@ -245,11 +242,18 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameG
// 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);
if (shadowMap.getShadowType() == ShadowType::DIRECTIONAL) {
ShadowMap::prepareDirectionalLight(transaction, engine,
scene->getLightData().elementAt<FScene::DIRECTION>(0),
scene->getLightData().elementAt<FScene::LIGHT_INSTANCE>(0));
}
shadowMap.commit(transaction, driver);
// updatePrimitivesLod must be run before RenderPass::appendCommands.
view.updatePrimitivesLod(engine,

View File

@@ -219,7 +219,7 @@ private:
// 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;
};

View File

@@ -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

View File

@@ -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;

View File

@@ -232,14 +232,15 @@ enum class Property : uint8_t {
// when adding new Properties, make sure to update MATERIAL_PROPERTIES_COUNT
};
// These flags should match the equivalents in Variant.h.
enum class UserVariantFilterBit : uint32_t {
DIRECTIONAL_LIGHTING = 0x01,
DYNAMIC_LIGHTING = 0x02,
SHADOW_RECEIVER = 0x04,
SKINNING = 0x08,
FOG = 0x10,
VSM = 0x20,
SSR = 0x40,
FOG = 0x20,
VSM = 0x40,
SSR = VSM | SHADOW_RECEIVER,
};
using UserVariantFilterMask = uint32_t;

View File

@@ -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()

View File

@@ -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]);

View File

@@ -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;
}
}

View File

@@ -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:

View File

@@ -1250,12 +1250,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), {

View File

@@ -398,6 +398,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);