Add clearCoatIorChange property to materials (#890)

This property can be used to control the darkening of the base layer
due to a change in index of refraction when going through the clear
coat layer.
This commit is contained in:
Romain Guy
2019-02-27 10:30:46 -08:00
committed by GitHub
parent ace38eff24
commit 705c1969b2
15 changed files with 82 additions and 3 deletions

View File

@@ -229,18 +229,28 @@ Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderCurvatu
auto builder = (MaterialBuilder*) nativeBuilder;
builder->curvatureToRoughness(curvatureToRoughness);
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderLimitOverInterpolation(
JNIEnv* env, jclass type, jlong nativeBuilder, jboolean limitOverInterpolation) {
auto builder = (MaterialBuilder*) nativeBuilder;
builder->limitOverInterpolation(limitOverInterpolation);
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderClearCoatIorChange(
JNIEnv* env, jclass type, jlong nativeBuilder, jboolean clearCoatIorChange) {
auto builder = (MaterialBuilder*) nativeBuilder;
builder->clearCoatIorChange(clearCoatIorChange);
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderFlipUV(JNIEnv* env,
jclass type, jlong nativeBuilder, jboolean flipUV) {
auto builder = (MaterialBuilder*) nativeBuilder;
builder->flipUV(flipUV);
}
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderTransparencyMode(
JNIEnv* env, jclass type, jlong nativeBuilder, jint mode) {

View File

@@ -294,6 +294,12 @@ public class MaterialBuilder {
return this;
}
@NonNull
public MaterialBuilder clearCoatIorChange(boolean clearCoatIorChange) {
nMaterialBuilderClearCoatIorChange(mNativeObject, clearCoatIorChange);
return this;
}
@NonNull
public MaterialBuilder flipUV(boolean flipUV) {
nMaterialBuilderFlipUV(mNativeObject, flipUV);
@@ -398,6 +404,8 @@ public class MaterialBuilder {
boolean curvatureToRoughness);
private static native void nMaterialBuilderLimitOverInterpolation(long mNativeObject,
boolean limitOverInterpolation);
private static native void nMaterialBuilderClearCoatIorChange(long mNativeObject,
boolean clearCoatIorChange);
private static native void nMaterialBuilderFlipUV(long nativeBuilder, boolean flipUV);
private static native void nMaterialBuilderTransparencyMode(long nativeBuilder, int mode);
private static native void nMaterialBuilderPlatform(long nativeBuilder, int platform);

View File

@@ -1093,7 +1093,7 @@ Value
Description
: Reduces specular aliasing by increasing roughness based on the local geometric curvature.
This property is particularly effective if you only use MSAA.
This property is particularly effective if you only use MSAA as your anti-aliasing method.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
material {
@@ -1102,7 +1102,7 @@ material {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
![Figure [curvatureToRoughness]: Close up of a glossy metallic surface rendered normally (left) and
with `curvatureToRoughness` (right).](images/screenshot_curvature_to_roughness.png)
with `curvatureToRoughness` (right).](images/screenshot_curvature_to_roughness.jpg)
### limitOverInterpolation
@@ -1125,6 +1125,31 @@ material {
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
### clearCoatIorChange
Type
: `boolean`
Value
: `true` or `false`. Defaults to `true`.
Description
: When adding a clear coat layer, the change in index of refraction (IoR) is taken into account
to modify the specular color of the base layer. This appears to darken `baseColor`. When this
effect is disabled, `baseColor` is left unmodified. See figure [clearCoatIorChange] for an
example of how this property can affect a red metallic base layer.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
material {
clearCoatIorChange : false
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
![Figure [clearCoatIorChange]: The same rough metallic ball with a clear coat layer rendered
with `clearCoatIorChange` enabled (left) and disabled
(right).](images/screenshot_clear_coat_ior_change.jpg)
### variantFilter
Type

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 346 KiB

View File

@@ -68,6 +68,7 @@ enum UTILS_PUBLIC ChunkType : uint64_t {
MaterialShadowMultiplier = charTo64bitNum("MAT_SHML"),
MaterialCurvatureToRoughness = charTo64bitNum("MAT_CV2R"),
MaterialLimitOverInterpolation = charTo64bitNum("MAT_LMOI"),
MaterialClearCoatIorChange = charTo64bitNum("MAT_CIOR"),
MaterialRequiredAttributes = charTo64bitNum("MAT_REQA"),
MaterialDepthWriteSet = charTo64bitNum("MAT_DEWS"),

View File

@@ -189,6 +189,12 @@ public:
// disabled by default
MaterialBuilder& limitOverInterpolation(bool limitOverInterpolation) noexcept;
// enables or disables the index of refraction (IoR) change caused by the clear coat layer when
// present. When the IoR changes, the base color is darkened. Disabling this feature preserves
// the base color as initially specified
// enabled by default
MaterialBuilder& clearCoatIorChange(bool clearCoatIorChange) noexcept;
// enable/disable flipping of the Y coordinate of UV attributes, enabled by default
MaterialBuilder& flipUV(bool flipUV) noexcept;
@@ -305,6 +311,7 @@ private:
bool mCurvatureToRoughness = false;
bool mLimitOverInterpolation = false;
bool mClearCoatIorChange = true;
bool mFlipUV = true;
};

View File

@@ -241,6 +241,11 @@ MaterialBuilder& MaterialBuilder::limitOverInterpolation(bool limitOverInterpola
return *this;
}
MaterialBuilder& MaterialBuilder::clearCoatIorChange(bool clearCoatIorChange) noexcept {
mClearCoatIorChange = clearCoatIorChange;
return *this;
}
MaterialBuilder& MaterialBuilder::flipUV(bool flipUV) noexcept {
mFlipUV = flipUV;
return *this;
@@ -318,6 +323,7 @@ void MaterialBuilder::prepareToBuild(MaterialInfo& info) noexcept {
info.hasExternalSamplers = hasExternalSampler();
info.curvatureToRoughness = mCurvatureToRoughness;
info.limitOverInterpolation = mLimitOverInterpolation;
info.clearCoatIorChange = mClearCoatIorChange;
info.flipUV = mFlipUV;
info.requiredAttributes = mRequiredAttributes;
info.blendingMode = mBlendingMode;
@@ -422,6 +428,10 @@ Package MaterialBuilder::build() noexcept {
ChunkType::MaterialLimitOverInterpolation, mLimitOverInterpolation);
container.addChild(&matLimitOverInterpolation);
SimpleFieldChunk<bool> matClearCoatIorChange(
ChunkType::MaterialClearCoatIorChange, mClearCoatIorChange);
container.addChild(&matClearCoatIorChange);
SimpleFieldChunk<uint8_t> matTransparency(ChunkType::MaterialTransparencyMode,
static_cast<uint8_t>(mTransparencyMode));
container.addChild(&matTransparency);

View File

@@ -39,6 +39,7 @@ struct UTILS_PUBLIC MaterialInfo {
bool hasShadowMultiplier;
bool curvatureToRoughness;
bool limitOverInterpolation;
bool clearCoatIorChange;
bool flipUV;
filament::AttributeBitset requiredAttributes;
filament::BlendingMode blendingMode;

View File

@@ -249,6 +249,8 @@ const std::string ShaderGenerator::createFragmentProgram(filament::driver::Shade
cg.generateDefine(fs, "GEOMETRIC_SPECULAR_AA_ROUGHNESS", material.curvatureToRoughness);
cg.generateDefine(fs, "GEOMETRIC_SPECULAR_AA_NORMAL", material.limitOverInterpolation);
cg.generateDefine(fs, "CLEAR_COAT_IOR_CHANGE", material.clearCoatIorChange);
// lighting variants
bool litVariants = lit || material.hasShadowMultiplier;
cg.generateDefine(fs, "HAS_DIRECTIONAL_LIGHTING", litVariants && variant.hasDirectionalLighting());

View File

@@ -68,11 +68,13 @@ void getPixelParams(const MaterialInputs material, out PixelParams pixel) {
// Remap the roughness to perceptually linear roughness
pixel.clearCoatRoughness = clearCoatRoughness;
pixel.clearCoatLinearRoughness = clearCoatRoughness * clearCoatRoughness;
#if defined(CLEAR_COAT_IOR_CHANGE)
// The base layer's f0 is computed assuming an interface from air to an IOR
// of 1.5, but the clear coat layer forms an interface from IOR 1.5 to IOR
// 1.5. We recompute f0 by first computing its IOR, then reconverting to f0
// by using the correct interface
pixel.f0 = mix(pixel.f0, f0ClearCoatToSurface(pixel.f0), pixel.clearCoat);
#endif
#if defined(MATERIAL_HAS_CLEAR_COAT_ROUGHNESS)
// This is a hack but it will do: the base layer must be at least as rough

View File

@@ -48,6 +48,7 @@ static constexpr const char* PARAM_KEY_SHADING = "shadingModel"
static constexpr const char* PARAM_KEY_VARIANT_FILTER = "variantFilter";
static constexpr const char* PARAM_KEY_CURVATURE_TO_ROUGHNESS = "curvatureToRoughness";
static constexpr const char* PARAM_KEY_LIMIT_OVER_INTERPOLATION = "limitOverInterpolation";
static constexpr const char* PARAM_KEY_CLEAR_COAT_IOR_CHANGE = "clearCoatIorChange";
static constexpr const char* PARAM_KEY_FLIP_UV = "flipUV";
ParametersProcessor::ParametersProcessor() {
@@ -72,6 +73,8 @@ ParametersProcessor::ParametersProcessor() {
= &ParametersProcessor::processCurvatureToRoughness;
mConfigProcessor[PARAM_KEY_LIMIT_OVER_INTERPOLATION]
= &ParametersProcessor::processLimitOverInterpolation;
mConfigProcessor[PARAM_KEY_CLEAR_COAT_IOR_CHANGE]
= &ParametersProcessor::processClearCoatIorChange;
mConfigProcessor[PARAM_KEY_FLIP_UV] = &ParametersProcessor::processFlipUV;
mRootAsserts[PARAM_KEY_NAME] = JsonishValue::Type::STRING;
@@ -93,6 +96,7 @@ ParametersProcessor::ParametersProcessor() {
mRootAsserts[PARAM_KEY_VARIANT_FILTER] = JsonishValue::Type::ARRAY;
mRootAsserts[PARAM_KEY_CURVATURE_TO_ROUGHNESS] = JsonishValue::Type::BOOL;
mRootAsserts[PARAM_KEY_LIMIT_OVER_INTERPOLATION] = JsonishValue::Type::BOOL;
mRootAsserts[PARAM_KEY_CLEAR_COAT_IOR_CHANGE] = JsonishValue::Type::BOOL;
mRootAsserts[PARAM_KEY_FLIP_UV] = JsonishValue::Type::BOOL;
mStringToInterpolation["smooth"] = MaterialBuilder::Interpolation::SMOOTH;
@@ -464,7 +468,14 @@ bool ParametersProcessor::processLimitOverInterpolation(filamat::MaterialBuilder
return true;
}
bool ParametersProcessor::processFlipUV(filamat::MaterialBuilder& builder, const JsonishValue& value) {
bool ParametersProcessor::processClearCoatIorChange(filamat::MaterialBuilder& builder,
const JsonishValue& value) {
builder.clearCoatIorChange(value.toJsonBool()->getBool());
return true;
}
bool ParametersProcessor::processFlipUV(filamat::MaterialBuilder& builder,
const JsonishValue& value) {
builder.flipUV(value.toJsonBool()->getBool());
return true;
}

View File

@@ -53,6 +53,7 @@ private:
bool processShadowMultiplier(filamat::MaterialBuilder &builder, const JsonishValue &value);
bool processCurvatureToRoughness(filamat::MaterialBuilder &builder, const JsonishValue &value);
bool processLimitOverInterpolation(filamat::MaterialBuilder &builder, const JsonishValue &value);
bool processClearCoatIorChange(filamat::MaterialBuilder &builder, const JsonishValue &value);
bool processFlipUV(filamat::MaterialBuilder &builder, const JsonishValue &value);
bool processShading(filamat::MaterialBuilder &builder, const JsonishValue &value);
bool processVariantFilter(filamat::MaterialBuilder &builder, const JsonishValue &value);

View File

@@ -380,6 +380,7 @@ static bool printMaterial(const ChunkContainer& container) {
printChunk<bool, bool>(container, filamat::MaterialShadowMultiplier, "Shadow multiply: ");
printChunk<bool, bool>(container, filamat::MaterialCurvatureToRoughness, "Curvature to roughness: ");
printChunk<bool, bool>(container, filamat::MaterialLimitOverInterpolation, "Limit interpolation: ");
printChunk<bool, bool>(container, filamat::MaterialClearCoatIorChange, "Clear coat IOR change: ");
std::cout << std::endl;