Allow dynamic doubleSided and materialThreshold. (#1072)
* MaterialInstance now has setMaskThreshold for convenience. * Materials now support dynamic doubleSided property. This does not change the format of material packages because they already have both getDoubleSided() and getDoubleSidedSet(). The only way in which this change could impact existing applications is that materials that explicity set doubleSided to "false" will now respect the material's culling mode, rather than forcing it to NONE. Fixes gltf_viewer with littlest_tokyo in ubershader mode. Fixes #963. * JNI for dynamic material properties. * Add underscore prefix to internal material params. * Remove un-needed mat info field.
This commit is contained in:
@@ -217,3 +217,19 @@ Java_com_google_android_filament_MaterialInstance_nSetPolygonOffset(JNIEnv*,
|
||||
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
|
||||
instance->setPolygonOffset(scale, constant);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nSetMaskThreshold(JNIEnv*,
|
||||
jclass, jlong nativeMaterialInstance, jfloat threshold) {
|
||||
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
|
||||
instance->setMaskThreshold(threshold);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_google_android_filament_MaterialInstance_nSetDoubleSided(JNIEnv*,
|
||||
jclass, jlong nativeMaterialInstance, jboolean doubleSided) {
|
||||
MaterialInstance* instance = (MaterialInstance*) nativeMaterialInstance;
|
||||
instance->setDoubleSided(doubleSided);
|
||||
}
|
||||
|
||||
@@ -151,6 +151,14 @@ public class MaterialInstance {
|
||||
nSetPolygonOffset(getNativeObject(), scale, constant);
|
||||
}
|
||||
|
||||
public void setMaskThreshold(float threshold) {
|
||||
nSetMaskThreshold(getNativeObject(), threshold);
|
||||
}
|
||||
|
||||
public void setDoubleSided(boolean doubleSided) {
|
||||
nSetDoubleSided(getNativeObject(), doubleSided);
|
||||
}
|
||||
|
||||
long getNativeObject() {
|
||||
if (mNativeObject == 0) {
|
||||
throw new IllegalStateException("Calling method on destroyed MaterialInstance");
|
||||
@@ -211,4 +219,8 @@ public class MaterialInstance {
|
||||
|
||||
private static native void nSetPolygonOffset(long nativeMaterialInstance,
|
||||
float scale, float constant);
|
||||
|
||||
private static native void nSetMaskThreshold(long nativeMaterialInstance, float threshold);
|
||||
|
||||
private static native void nSetDoubleSided(long nativeMaterialInstance, boolean doubleSided);
|
||||
}
|
||||
|
||||
@@ -1029,9 +1029,10 @@ Value
|
||||
: `true` or `false`. Defaults to `false`.
|
||||
|
||||
Description
|
||||
: Enables or disables two-sided rendering. When set to `true`, `culling` is automatically set to
|
||||
`none`; if the triangle is back-facing, the triangle's normal is automatically flipped to
|
||||
become front-facing.
|
||||
: Enables two-sided rendering and its capability to be toggled at run time. When set to `true`,
|
||||
`culling` is automatically set to `none`; if the triangle is back-facing, the triangle's
|
||||
normal is flipped to become front-facing. When explicitly set to `false`, this allows the
|
||||
doubleSided property to be toggled at run time.
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
|
||||
material {
|
||||
|
||||
@@ -123,6 +123,18 @@ public:
|
||||
* @param constant scale factore used to create a constant depth offset for each triangle
|
||||
*/
|
||||
void setPolygonOffset(float scale, float constant) noexcept;
|
||||
|
||||
/**
|
||||
* Overrides the minimum alpha value a fragment must have to not be discarded when the blend
|
||||
* mode is MASKED. Defaults to 0.4 if it has not been set in the parent Material.
|
||||
*/
|
||||
void setMaskThreshold(float threshold) noexcept;
|
||||
|
||||
/**
|
||||
* Enables or disables double-sided lighting if the parent Material has double-sided capability,
|
||||
* otherwise prints a warning.
|
||||
*/
|
||||
void setDoubleSided(bool doubleSided) noexcept;
|
||||
};
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -204,19 +204,8 @@ FMaterial::FMaterial(FEngine& engine, const Material::Builder& builder)
|
||||
parser->getDepthTest(&depthTest);
|
||||
|
||||
if (doubleSideSet) {
|
||||
// double sided disables face culling
|
||||
if (mDoubleSided) {
|
||||
mRasterState.culling = CullingMode::NONE;
|
||||
} else {
|
||||
// the cull mode is double sided but we set the double-sided bit to false,
|
||||
// revert culling to default
|
||||
if (mCullingMode == CullingMode::NONE) {
|
||||
mRasterState.culling = CullingMode::BACK;
|
||||
} else {
|
||||
// use the front/back/front&back mode set by the user
|
||||
mRasterState.culling = mCullingMode;
|
||||
}
|
||||
}
|
||||
mDoubleSidedCapability = true;
|
||||
mRasterState.culling = mDoubleSided ? CullingMode::NONE : mCullingMode;
|
||||
} else {
|
||||
mRasterState.culling = mCullingMode;
|
||||
}
|
||||
|
||||
@@ -26,9 +26,12 @@
|
||||
#include "details/Material.h"
|
||||
#include "details/Texture.h"
|
||||
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
using namespace filament::math;
|
||||
using namespace utils;
|
||||
|
||||
namespace filament {
|
||||
|
||||
@@ -56,7 +59,12 @@ FMaterialInstance::FMaterialInstance(FEngine& engine, FMaterial const* material)
|
||||
|
||||
if (material->getBlendingMode() == BlendingMode::MASKED) {
|
||||
static_cast<MaterialInstance*>(this)->setParameter(
|
||||
"maskThreshold", material->getMaskThreshold());
|
||||
"_maskThreshold", material->getMaskThreshold());
|
||||
}
|
||||
|
||||
if (material->hasDoubleSidedCapability()) {
|
||||
static_cast<MaterialInstance*>(this)->setParameter(
|
||||
"_doubleSided", material->isDoubleSided());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +87,12 @@ void FMaterialInstance::initDefaultInstance(FEngine& engine, FMaterial const* ma
|
||||
|
||||
if (material->getBlendingMode() == BlendingMode::MASKED) {
|
||||
static_cast<MaterialInstance*>(this)->setParameter(
|
||||
"maskThreshold", material->getMaskThreshold());
|
||||
"_maskThreshold", material->getMaskThreshold());
|
||||
}
|
||||
|
||||
if (material->hasDoubleSidedCapability()) {
|
||||
static_cast<MaterialInstance*>(this)->setParameter(
|
||||
"_doubleSided", material->isDoubleSided());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,6 +138,14 @@ void FMaterialInstance::setParameter(const char* name,
|
||||
mSamplers.setSampler(index, { upcast(texture)->getHwHandle(), sampler.getSamplerParams() });
|
||||
}
|
||||
|
||||
void FMaterialInstance::setDoubleSided(bool doubleSided) noexcept {
|
||||
if (!mMaterial->hasDoubleSidedCapability()) {
|
||||
slog.w << "Parent material does not have double-sided capability." << io::endl;
|
||||
return;
|
||||
}
|
||||
setParameter("_doubleSided", doubleSided);
|
||||
}
|
||||
|
||||
} // namespace details
|
||||
|
||||
using namespace details;
|
||||
@@ -209,4 +230,12 @@ void MaterialInstance::setPolygonOffset(float scale, float constant) noexcept {
|
||||
upcast(this)->setPolygonOffset(scale, constant);
|
||||
}
|
||||
|
||||
void MaterialInstance::setMaskThreshold(float threshold) noexcept {
|
||||
upcast(this)->setMaskThreshold(threshold);
|
||||
}
|
||||
|
||||
void MaterialInstance::setDoubleSided(bool doubleSided) noexcept {
|
||||
upcast(this)->setDoubleSided(doubleSided);
|
||||
}
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -102,6 +102,7 @@ public:
|
||||
return mRasterState.depthFunc != backend::RasterState::DepthFunc::A;
|
||||
}
|
||||
bool isDoubleSided() const noexcept { return mDoubleSided; }
|
||||
bool hasDoubleSidedCapability() const noexcept { return mDoubleSidedCapability; }
|
||||
float getMaskThreshold() const noexcept { return mMaskThreshold; }
|
||||
bool hasShadowMultiplier() const noexcept { return mHasShadowMultiplier; }
|
||||
AttributeBitset getRequiredAttributes() const noexcept { return mRequiredAttributes; }
|
||||
@@ -131,6 +132,7 @@ private:
|
||||
AttributeBitset mRequiredAttributes;
|
||||
float mMaskThreshold;
|
||||
bool mDoubleSided;
|
||||
bool mDoubleSidedCapability = false;
|
||||
bool mHasShadowMultiplier = false;
|
||||
bool mHasCustomDepthShader = false;
|
||||
bool mIsDefaultMaterial = false;
|
||||
|
||||
@@ -97,6 +97,12 @@ public:
|
||||
|
||||
backend::PolygonOffset getPolygonOffset() const noexcept { return mPolygonOffset; }
|
||||
|
||||
void setMaskThreshold(float threshold) noexcept {
|
||||
setParameter("_maskThreshold", threshold);
|
||||
}
|
||||
|
||||
void setDoubleSided(bool doubleSided) noexcept;
|
||||
|
||||
private:
|
||||
friend class FMaterial;
|
||||
friend class MaterialInstance;
|
||||
|
||||
@@ -211,6 +211,7 @@ public:
|
||||
|
||||
// double-sided materials don't cull faces, equivalent to culling(CullingMode::NONE)
|
||||
// doubleSided() overrides culling() if called
|
||||
// when called with "false", this enables the capability for a run-time toggle
|
||||
MaterialBuilder& doubleSided(bool doubleSided) noexcept;
|
||||
|
||||
// any fragment with an alpha below this threshold is clipped (MASKED blending mode only)
|
||||
@@ -342,7 +343,7 @@ private:
|
||||
uint8_t mParameterCount = 0;
|
||||
|
||||
bool mDoubleSided = false;
|
||||
bool mDoubleSidedSet = false;
|
||||
bool mDoubleSidedCapability = false;
|
||||
bool mColorWrite = true;
|
||||
bool mDepthTest = true;
|
||||
bool mDepthWrite = true;
|
||||
|
||||
@@ -223,7 +223,7 @@ MaterialBuilder& MaterialBuilder::depthCulling(bool enable) noexcept {
|
||||
|
||||
MaterialBuilder& MaterialBuilder::doubleSided(bool doubleSided) noexcept {
|
||||
mDoubleSided = doubleSided;
|
||||
mDoubleSidedSet = true;
|
||||
mDoubleSidedCapability = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -313,7 +313,11 @@ void MaterialBuilder::prepareToBuild(MaterialInfo& info) noexcept {
|
||||
}
|
||||
|
||||
if (mBlendingMode == BlendingMode::MASKED) {
|
||||
ibb.add("maskThreshold", 1, UniformType::FLOAT);
|
||||
ibb.add("_maskThreshold", 1, UniformType::FLOAT);
|
||||
}
|
||||
|
||||
if (mDoubleSidedCapability) {
|
||||
ibb.add("_doubleSided", 1, UniformType::BOOL);
|
||||
}
|
||||
|
||||
mRequiredAttributes.set(filament::VertexAttribute::POSITION);
|
||||
@@ -325,7 +329,7 @@ void MaterialBuilder::prepareToBuild(MaterialInfo& info) noexcept {
|
||||
info.uib = ibb.name("MaterialParams").build();
|
||||
|
||||
info.isLit = isLit();
|
||||
info.isDoubleSided = mDoubleSided;
|
||||
info.hasDoubleSidedCapability = mDoubleSidedCapability;
|
||||
info.hasExternalSamplers = hasExternalSampler();
|
||||
info.curvatureToRoughness = mCurvatureToRoughness;
|
||||
info.limitOverInterpolation = mLimitOverInterpolation;
|
||||
@@ -458,7 +462,7 @@ Package MaterialBuilder::build() noexcept {
|
||||
SimpleFieldChunk<bool> matDepthWriteSet(ChunkType::MaterialDepthWriteSet, mDepthWriteSet);
|
||||
container.addChild(&matDepthWriteSet);
|
||||
|
||||
SimpleFieldChunk<bool> matDoubleSidedSet(ChunkType::MaterialDoubleSidedSet, mDoubleSidedSet);
|
||||
SimpleFieldChunk<bool> matDoubleSidedSet(ChunkType::MaterialDoubleSidedSet, mDoubleSidedCapability);
|
||||
container.addChild(&matDoubleSidedSet);
|
||||
|
||||
SimpleFieldChunk<bool> matDoubleSided(ChunkType::MaterialDoubleSided, mDoubleSided);
|
||||
|
||||
@@ -33,7 +33,7 @@ using CullingMode = filament::backend::CullingMode;
|
||||
|
||||
struct UTILS_PUBLIC MaterialInfo {
|
||||
bool isLit;
|
||||
bool isDoubleSided;
|
||||
bool hasDoubleSidedCapability;
|
||||
bool hasExternalSamplers;
|
||||
bool hasShadowMultiplier;
|
||||
bool curvatureToRoughness;
|
||||
|
||||
@@ -246,7 +246,7 @@ const std::string ShaderGenerator::createFragmentProgram(filament::backend::Shad
|
||||
cg.generateDefine(fs, "HAS_SHADOW_MULTIPLIER", material.hasShadowMultiplier);
|
||||
|
||||
// material defines
|
||||
cg.generateDefine(fs, "MATERIAL_IS_DOUBLE_SIDED", material.isDoubleSided);
|
||||
cg.generateDefine(fs, "MATERIAL_HAS_DOUBLE_SIDED_CAPABILITY", material.hasDoubleSidedCapability);
|
||||
switch (material.blendingMode) {
|
||||
case BlendingMode::OPAQUE:
|
||||
cg.generateDefine(fs, "BLEND_MODE_OPAQUE", true);
|
||||
@@ -311,11 +311,6 @@ const std::string ShaderGenerator::createFragmentProgram(filament::backend::Shad
|
||||
cg.generateCommonMaterial(fs, ShaderType::FRAGMENT);
|
||||
cg.generateParameters(fs, ShaderType::FRAGMENT);
|
||||
|
||||
if (material.blendingMode == BlendingMode::MASKED) {
|
||||
cg.generateFunction(fs, "float", "getMaskThreshold",
|
||||
" return materialParams.maskThreshold;");
|
||||
}
|
||||
|
||||
// shading model
|
||||
if (variant.isDepthPass()) {
|
||||
if (material.blendingMode == BlendingMode::MASKED) {
|
||||
|
||||
@@ -4,7 +4,7 @@ material {
|
||||
shadingModel : ${SHADINGMODEL},
|
||||
blending : ${BLENDING},
|
||||
depthWrite : true,
|
||||
doubleSided : true,
|
||||
doubleSided : false,
|
||||
flipUV : false,
|
||||
parameters : [
|
||||
// Base Color
|
||||
|
||||
@@ -161,7 +161,6 @@ static std::string shaderFromKey(const MaterialKey& config) {
|
||||
|
||||
static Material* createMaterial(Engine* engine, const MaterialKey& config, const UvMap& uvmap,
|
||||
const char* name) {
|
||||
using CullingMode = MaterialBuilder::CullingMode;
|
||||
std::string shader = shaderFromKey(config);
|
||||
gltfio::details::processShaderString(&shader, uvmap, config);
|
||||
MaterialBuilder builder = MaterialBuilder()
|
||||
|
||||
@@ -115,10 +115,10 @@ MaterialInstance* UbershaderLoader::createMaterialInstance(MaterialKey* config,
|
||||
mi->setParameter("emissiveIndex", getUvIndex(config->emissiveUV, config->hasEmissiveTexture));
|
||||
|
||||
if (config->alphaMode == AlphaMode::MASK) {
|
||||
mi->setParameter("maskThreshold", config->alphaMaskThreshold);
|
||||
mi->setMaskThreshold(config->alphaMaskThreshold);
|
||||
}
|
||||
|
||||
// TODO: honor config->doubleSided
|
||||
mi->setDoubleSided(config->doubleSided);
|
||||
|
||||
mat3f identity;
|
||||
mi->setParameter("baseColorUvMatrix", identity);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// Input access (varyings)
|
||||
// Input access
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#if defined(HAS_ATTRIBUTE_COLOR)
|
||||
@@ -28,3 +28,15 @@ HIGHP vec3 getLightSpacePosition() {
|
||||
return vertex_lightSpacePosition.xyz * (1.0 / vertex_lightSpacePosition.w);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(BLEND_MODE_MASKED)
|
||||
float getMaskThreshold() {
|
||||
return materialParams._maskThreshold;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(MATERIAL_HAS_DOUBLE_SIDED_CAPABILITY)
|
||||
bool isDoubleSided() {
|
||||
return materialParams._doubleSided;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -17,8 +17,10 @@ void computeShadingParams() {
|
||||
HIGHP vec3 n = vertex_worldNormal;
|
||||
#endif
|
||||
|
||||
#if defined(MATERIAL_IS_DOUBLE_SIDED)
|
||||
n = gl_FrontFacing ? n : -n;
|
||||
#if defined(MATERIAL_HAS_DOUBLE_SIDED_CAPABILITY)
|
||||
if (isDoubleSided()) {
|
||||
n = gl_FrontFacing ? n : -n;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(MATERIAL_HAS_ANISOTROPY) || defined(MATERIAL_HAS_NORMAL) || defined(MATERIAL_HAS_CLEAR_COAT_NORMAL)
|
||||
|
||||
2
web/filament-js/filament.d.ts
vendored
2
web/filament-js/filament.d.ts
vendored
@@ -72,6 +72,8 @@ export class MaterialInstance {
|
||||
public setTextureParameter(name: string, value: Texture, sampler: TextureSampler): void;
|
||||
public setColorParameter(name: string, ctype: RgbType, value: float3): void;
|
||||
public setPolygonOffset(scale: number, constant: number): void;
|
||||
public setMaskThreshold(threshold: number): void;
|
||||
public setDoubleSided(doubleSided: boolean): void;
|
||||
}
|
||||
|
||||
export class EntityManager {
|
||||
|
||||
@@ -821,7 +821,9 @@ class_<MaterialInstance>("MaterialInstance")
|
||||
.function("setColorParameter", EMBIND_LAMBDA(void,
|
||||
(MaterialInstance* self, std::string name, RgbType type, filament::math::float3 value), {
|
||||
self->setParameter(name.c_str(), type, value); }), allow_raw_pointers())
|
||||
.function("setPolygonOffset", &MaterialInstance::setPolygonOffset);
|
||||
.function("setPolygonOffset", &MaterialInstance::setPolygonOffset)
|
||||
.function("setMaskThreshold", &MaterialInstance::setMaskThreshold)
|
||||
.function("setDoubleSided", &MaterialInstance::setDoubleSided);
|
||||
|
||||
class_<TextureSampler>("TextureSampler")
|
||||
.constructor<backend::SamplerMinFilter, backend::SamplerMagFilter, backend::SamplerWrapMode>();
|
||||
|
||||
Reference in New Issue
Block a user