diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index ef6965157d..c87f1c8cd0 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -5,7 +5,17 @@ A new header is inserted each time a *tag* is created. ## Next release -- gltfio: fixed incorrect cone angles with lights +- gltfio: fixed incorrect cone angles with lights. +- Specular ambient occlusion now offers 3 modes: off, simple (default on desktop) and bent normals. + The latter is more accurate but more expensive and requires a bent normal to be specified in the + material. If selected and not bent normal is specified, Filament falls back to the simple mode. +- Specular ambient occlusion from bent normals now smoothly disappears as roughness goes from 0.3 + to 0.1. Specular ambient occlusion can completely remove specular light which looks bad on glossy + metals. Use the simple specular occlusion mode for glossy metals instead. +- Refraction can now be set on `MaterialBuilder` from Java. +- Refraction mode and type can now be set by calling `MaterialBuilder::refractionMode()`. + and `MaterialBuilder::refractionType()` instad of `materialRefraction()` and + `materialRefractionType()` (️⚠ API change). ## v1.5.2 diff --git a/android/filamat-android/src/main/cpp/MaterialBuilder.cpp b/android/filamat-android/src/main/cpp/MaterialBuilder.cpp index 48b83ecfdf..ecd9e43ff0 100644 --- a/android/filamat-android/src/main/cpp/MaterialBuilder.cpp +++ b/android/filamat-android/src/main/cpp/MaterialBuilder.cpp @@ -83,6 +83,13 @@ Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderName(JN builder->name(name); } +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderMaterialDomain(JNIEnv* env, + jclass, jlong nativeBuilder, jint domain) { + auto builder = (MaterialBuilder*) nativeBuilder; + builder->materialDomain((MaterialBuilder::MaterialDomain) domain); +} + extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderShading(JNIEnv*, jclass, jlong nativeBuilder, jint shading) { @@ -246,6 +253,7 @@ Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderSpecula builder->specularAntiAliasingThreshold(threshold); } + extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderClearCoatIorChange( JNIEnv*, jclass, jlong nativeBuilder, jboolean clearCoatIorChange) { @@ -269,9 +277,23 @@ Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderMultiBo extern "C" JNIEXPORT void JNICALL Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderSpecularAmbientOcclusion( - JNIEnv*, jclass, jlong nativeBuilder, jboolean specularAO) { + JNIEnv*, jclass, jlong nativeBuilder, jint specularAO) { auto builder = (MaterialBuilder*) nativeBuilder; - builder->specularAmbientOcclusion(specularAO); + builder->specularAmbientOcclusion((MaterialBuilder::SpecularAmbientOcclusion) specularAO); +} + +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderRefractionMode(JNIEnv* env, + jclass, jlong nativeBuilder, jint mode) { + auto builder = (MaterialBuilder*) nativeBuilder; + builder->refractionMode((MaterialBuilder::RefractionMode) mode); +} + +extern "C" JNIEXPORT void JNICALL +Java_com_google_android_filament_filamat_MaterialBuilder_nMaterialBuilderRefractionType(JNIEnv* env, + jclass, jlong nativeBuilder, jint type) { + auto builder = (MaterialBuilder*) nativeBuilder; + builder->refractionType((MaterialBuilder::RefractionType) type); } extern "C" JNIEXPORT void JNICALL diff --git a/android/filamat-android/src/main/java/com/google/android/filament/filamat/MaterialBuilder.java b/android/filamat-android/src/main/java/com/google/android/filament/filamat/MaterialBuilder.java index 4e0710baba..d044b9e0d2 100644 --- a/android/filamat-android/src/main/java/com/google/android/filament/filamat/MaterialBuilder.java +++ b/android/filamat-android/src/main/java/com/google/android/filament/filamat/MaterialBuilder.java @@ -146,6 +146,28 @@ public class MaterialBuilder { // mode is ignored. Can be combined with two-sided lighting } + public enum MaterialDomain { + SURFACE, + POST_PROCESS + } + + public enum SpecularAmbientOcclusion { + NONE, + SIMPLE, + BENT_NORMALS + } + + public enum RefractionMode { + NONE, + CUBEMAP, + SCREEN_SPACE + } + + public enum RefractionType { + SOLID, + THIN + } + public enum Platform { DESKTOP, MOBILE, @@ -191,6 +213,12 @@ public class MaterialBuilder { return this; } + @NonNull + public MaterialBuilder materialDomain(MaterialDomain domain) { + nMaterialBuilderMaterialDomain(mNativeObject, domain.ordinal()); + return this; + } + @NonNull public MaterialBuilder shading(@NonNull Shading shading) { nMaterialBuilderShading(mNativeObject, shading.ordinal()); @@ -325,6 +353,18 @@ public class MaterialBuilder { return this; } + @NonNull + public MaterialBuilder refractionMode(RefractionMode mode) { + nMaterialBuilderRefractionMode(mNativeObject, mode.ordinal()); + return this; + } + + @NonNull + public MaterialBuilder refractionType(RefractionType type) { + nMaterialBuilderRefractionType(mNativeObject, type.ordinal()); + return this; + } + @NonNull public MaterialBuilder clearCoatIorChange(boolean clearCoatIorChange) { nMaterialBuilderClearCoatIorChange(mNativeObject, clearCoatIorChange); @@ -344,8 +384,8 @@ public class MaterialBuilder { } @NonNull - public MaterialBuilder specularAmbientOcclusion(boolean specularAO) { - nMaterialBuilderSpecularAmbientOcclusion(mNativeObject, specularAO); + public MaterialBuilder specularAmbientOcclusion(SpecularAmbientOcclusion specularAO) { + nMaterialBuilderSpecularAmbientOcclusion(mNativeObject, specularAO.ordinal()); return this; } @@ -419,6 +459,7 @@ public class MaterialBuilder { private static native void nDestroyPackage(long nativePackage); private static native void nMaterialBuilderName(long nativeBuilder, String name); + private static native void nMaterialBuilderMaterialDomain(long nativeBuilder, int domain); private static native void nMaterialBuilderShading(long nativeBuilder, int shading); private static native void nMaterialBuilderInterpolation(long nativeBuilder, int interpolation); private static native void nMaterialBuilderUniformParameter(long nativeBuilder, int type, @@ -450,13 +491,15 @@ public class MaterialBuilder { float variance); private static native void nMaterialBuilderSpecularAntiAliasingThreshold(long mNativeObject, float threshold); + private static native void nMaterialBuilderRefractionMode(long nativeBuilder, int mode); + private static native void nMaterialBuilderRefractionType(long nativeBuilder, int type); private static native void nMaterialBuilderClearCoatIorChange(long mNativeObject, boolean clearCoatIorChange); private static native void nMaterialBuilderFlipUV(long nativeBuilder, boolean flipUV); private static native void nMaterialBuilderMultiBounceAmbientOcclusion(long nativeBuilder, boolean multiBounceAO); private static native void nMaterialBuilderSpecularAmbientOcclusion(long nativeBuilder, - boolean specularAO); + int specularAO); private static native void nMaterialBuilderTransparencyMode(long nativeBuilder, int mode); private static native void nMaterialBuilderPlatform(long nativeBuilder, int platform); private static native void nMaterialBuilderTargetApi(long nativeBuilder, int api); diff --git a/docs/Materials.html b/docs/Materials.html index 599447fd8d..068585a0ef 100644 --- a/docs/Materials.html +++ b/docs/Materials.html @@ -696,7 +696,7 @@ and with (right) The bentNormal property defines the average unoccluded direction at a point on the surface. It is -used to improve the accuracy of indirect lighting. Bent normals also improve the quality of +used to improve the accuracy of indirect lighting. Bent normals can also improve the quality of specular ambient occlusion (see section 4.2.24 about specularAmbientOcclusion). @@ -711,11 +711,6 @@ instance.

 Figure 17: Example of a model rendered with and without a bent normal map. Both versions use the same ambient occlusion map.
-

- -

Using a bent normal map increases the runtime cost of the material, particularly when - specularAmbientOcclusion is turned on.
-

   

Clear coat normal

@@ -1952,17 +1947,24 @@ occclusion enabled and disabled.

-

Type

boolean +

Type

string -

Value

true or false. Defaults to false on mobile, true on desktop. +

Value

none, simple or bentNormals. Defaults to none on mobile, simple on desktop. For + compatibility reasons, true and false are also accepted and map respectively to simple + and none.

Description

Static ambient occlusion maps and dynamic ambient occlusion (SSAO, etc.) apply to diffuse - indirect lighting. When setting this property to true, a new ambient occlusion term is - derived from the surface roughness and applied to specular indirec lighting. This effect - helps remove unwanted specular reflections as shown in figure 37. + indirect lighting. When setting this property to other than none, a new ambient occlusion + term is derived from the surface roughness and applied to specular indirect lighting. + This effect helps remove unwanted specular reflections as shown in figure 37. + When this value is set to simple, Filament uses a cheap but approximate method of computing + the specular ambient occlusion term. If this value is set to bentNormals, Filament will use + a much more accurate but much more expensive method. bentNormals only works if the material + sets the bentNormal property inside the fragment shader. If that property isn't set, + bentNormals will behave like simple.

material {
-    specularAmbientOcclusion : true
+    specularAmbientOcclusion : simple
 }

 Figure 37: Comparison of specular ambient occlusion on and off. The effect is @@ -1979,7 +1981,7 @@ particularly visible under the hose.

Description

Reduces specular aliasing and preserves the shape of specular highlights as an object moves away from the camera. This anti-aliasing solution is particularly effective on glossy materials - (low roughness) but increases the cost of the material. The strengthf of the anti-aliasing + (low roughness) but increases the cost of the material. The strength of the anti-aliasing effect can be controlled using two other properties: specularAntiAliasingVariance and specularAntiAliasingThreshold. diff --git a/docs/Materials.md.html b/docs/Materials.md.html index 36f40622db..7c4a4f736b 100644 --- a/docs/Materials.md.html +++ b/docs/Materials.md.html @@ -408,7 +408,7 @@ and with (right)](images/screenshot_normal_mapping.jpg) ### Bent normal The `bentNormal` property defines the average unoccluded direction at a point on the surface. It is -used to improve the accuracy of indirect lighting. Bent normals also improve the quality of +used to improve the accuracy of indirect lighting. Bent normals can also improve the quality of specular ambient occlusion (see section [Lighting: specularAmbientOcclusion] about `specularAmbientOcclusion`). @@ -419,10 +419,6 @@ instance. ![Figure [bentNormalMapped]: Example of a model rendered with and without a bent normal map. Both versions use the same ambient occlusion map.](images/material_bent_normal.gif) -!!! Warning - Using a bent normal map increases the runtime cost of the material, particularly when - `specularAmbientOcclusion` is turned on. - ### Clear coat normal The `clearCoatNormal` property defines the normal of the clear coat layer at a given point. It @@ -1537,20 +1533,27 @@ occclusion enabled and disabled.](images/screenshot_multi_bounce_ao.gif) ### Lighting: specularAmbientOcclusion Type -: `boolean` +: `string` Value -: `true` or `false`. Defaults to `false` on mobile, `true` on desktop. +: `none`, `simple` or `bentNormals`. Defaults to `none` on mobile, `simple` on desktop. For + compatibility reasons, `true` and `false` are also accepted and map respectively to `simple` + and `none`. Description : Static ambient occlusion maps and dynamic ambient occlusion (SSAO, etc.) apply to diffuse - indirect lighting. When setting this property to true, a new ambient occlusion term is - derived from the surface roughness and applied to specular indirec lighting. This effect - helps remove unwanted specular reflections as shown in figure [specularAO]. + indirect lighting. When setting this property to other than `none`, a new ambient occlusion + term is derived from the surface roughness and applied to specular indirect lighting. + This effect helps remove unwanted specular reflections as shown in figure [specularAO]. + When this value is set to `simple`, Filament uses a cheap but approximate method of computing + the specular ambient occlusion term. If this value is set to `bentNormals`, Filament will use + a much more accurate but much more expensive method. `bentNormals` only works if the material + sets the `bentNormal` property inside the fragment shader. If that property isn't set, + `bentNormals` will behave like `simple`. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON material { - specularAmbientOcclusion : true + specularAmbientOcclusion : simple } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1568,7 +1571,7 @@ Value Description : Reduces specular aliasing and preserves the shape of specular highlights as an object moves away from the camera. This anti-aliasing solution is particularly effective on glossy materials - (low roughness) but increases the cost of the material. The strengthf of the anti-aliasing + (low roughness) but increases the cost of the material. The strength of the anti-aliasing effect can be controlled using two other properties: `specularAntiAliasingVariance` and `specularAntiAliasingThreshold`. diff --git a/filament/include/filament/Scene.h b/filament/include/filament/Scene.h index 6a15463dd8..6dca2229fc 100644 --- a/filament/include/filament/Scene.h +++ b/filament/include/filament/Scene.h @@ -84,7 +84,6 @@ public: */ void setIndirectLight(IndirectLight const* ibl) noexcept; - /** * Adds an Entity to the Scene. * diff --git a/filament/src/Renderer.cpp b/filament/src/Renderer.cpp index 60d8e58379..232b5faeea 100644 --- a/filament/src/Renderer.cpp +++ b/filament/src/Renderer.cpp @@ -766,7 +766,7 @@ bool FRenderer::beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeN #endif // latch the frame time - std::chrono::duration time(userVsync - mUserEpoch); + std::chrono::duration time(appVsync - mUserEpoch); float h = float(time.count()); float l = float(time.count() - h); mShaderUserTime = { h, l, 0, 0 }; diff --git a/libs/filabridge/include/filament/MaterialEnums.h b/libs/filabridge/include/filament/MaterialEnums.h index 7944b7195f..c9cc70b990 100644 --- a/libs/filabridge/include/filament/MaterialEnums.h +++ b/libs/filabridge/include/filament/MaterialEnums.h @@ -145,15 +145,24 @@ static constexpr size_t MAX_CUSTOM_ATTRIBUTES = 8; /** * Material domains */ -enum MaterialDomain : uint8_t { +enum class MaterialDomain : uint8_t { SURFACE = 0, //!< shaders applied to renderables POST_PROCESS = 1, //!< shaders applied to rendered buffers }; +/** + * Specular occlusion + */ +enum class SpecularAmbientOcclusion : uint8_t { + NONE = 0, //!< no specular occlusion + SIMPLE = 1, //!< simple specular occlusion + BENT_NORMALS = 2, //!< more accurate specular occlusion, requires bent normals +}; + /** * Refraction */ -enum RefractionMode : uint8_t { +enum class RefractionMode : uint8_t { NONE = 0, //!< no refraction CUBEMAP = 1, //!< refracted rays go to the ibl cubemap SCREEN_SPACE = 2, //!< refracted rays go to screen space @@ -162,7 +171,7 @@ enum RefractionMode : uint8_t { /** * Refraction type */ -enum RefractionType : uint8_t { +enum class RefractionType : uint8_t { SOLID = 0, //!< refraction through solid objects (e.g. a sphere) THIN = 1, //!< refraction through thin objects (e.g. window) }; diff --git a/libs/filamat/include/filamat/MaterialBuilder.h b/libs/filamat/include/filamat/MaterialBuilder.h index 126fe84ccd..ce3974976e 100644 --- a/libs/filamat/include/filamat/MaterialBuilder.h +++ b/libs/filamat/include/filamat/MaterialBuilder.h @@ -184,6 +184,7 @@ public: using Interpolation = filament::Interpolation; using VertexDomain = filament::VertexDomain; using TransparencyMode = filament::TransparencyMode; + using SpecularAmbientOcclusion = filament::SpecularAmbientOcclusion; using UniformType = filament::backend::UniformType; using SamplerType = filament::backend::SamplerType; @@ -235,12 +236,6 @@ public: //! Specify the domain that this material will operate in. MaterialBuilder& materialDomain(MaterialDomain materialDomain) noexcept; - //! Specify the refraction - MaterialBuilder& materialRefraction(RefractionMode refraction) noexcept; - - //! Specify the refraction type - MaterialBuilder& materialRefractionType(RefractionType refractionType) noexcept; - /** * Set the code content of this material. * @@ -388,8 +383,14 @@ public: //! Enable / disable multi-bounce ambient occlusion, disabled by default on mobile. MaterialBuilder& multiBounceAmbientOcclusion(bool multiBounceAO) noexcept; - //! Enable / disable specular ambient occlusion, disabled by default on mobile. - MaterialBuilder& specularAmbientOcclusion(bool specularAO) noexcept; + //! Set the specular ambient occlusion technique. Disabled by default on mobile. + MaterialBuilder& specularAmbientOcclusion(SpecularAmbientOcclusion specularAO) noexcept; + + //! Specify the refraction + MaterialBuilder& refractionMode(RefractionMode refraction) noexcept; + + //! Specify the refraction type + MaterialBuilder& refractionType(RefractionType refractionType) noexcept; //! Specifies how transparent objects should be rendered (default is DEFAULT). MaterialBuilder& transparencyMode(TransparencyMode mode) noexcept; @@ -573,7 +574,8 @@ private: bool mMultiBounceAO = false; bool mMultiBounceAOSet = false; - bool mSpecularAO = false; + + SpecularAmbientOcclusion mSpecularAO = SpecularAmbientOcclusion::NONE; bool mSpecularAOSet = false; }; diff --git a/libs/filamat/src/MaterialBuilder.cpp b/libs/filamat/src/MaterialBuilder.cpp index 3d9a6a9aab..749c0403a9 100644 --- a/libs/filamat/src/MaterialBuilder.cpp +++ b/libs/filamat/src/MaterialBuilder.cpp @@ -210,12 +210,12 @@ MaterialBuilder& MaterialBuilder::materialDomain(MaterialDomain materialDomain) return *this; } -MaterialBuilder& MaterialBuilder::materialRefraction(RefractionMode refraction) noexcept { +MaterialBuilder& MaterialBuilder::refractionMode(RefractionMode refraction) noexcept { mRefractionMode = refraction; return *this; } -MaterialBuilder& MaterialBuilder::materialRefractionType(RefractionType refractionType) noexcept { +MaterialBuilder& MaterialBuilder::refractionType(RefractionType refractionType) noexcept { mRefractionType = refractionType; return *this; } @@ -303,7 +303,7 @@ MaterialBuilder& MaterialBuilder::multiBounceAmbientOcclusion(bool multiBounceAO return *this; } -MaterialBuilder& MaterialBuilder::specularAmbientOcclusion(bool specularAO) noexcept { +MaterialBuilder& MaterialBuilder::specularAmbientOcclusion(SpecularAmbientOcclusion specularAO) noexcept { mSpecularAO = specularAO; mSpecularAOSet = true; return *this; diff --git a/libs/filamat/src/shaders/MaterialInfo.h b/libs/filamat/src/shaders/MaterialInfo.h index c5fa3a80a2..f1066bd95c 100644 --- a/libs/filamat/src/shaders/MaterialInfo.h +++ b/libs/filamat/src/shaders/MaterialInfo.h @@ -41,8 +41,8 @@ struct UTILS_PUBLIC MaterialInfo { bool flipUV; bool multiBounceAO; bool multiBounceAOSet; - bool specularAO; bool specularAOSet; + filament::SpecularAmbientOcclusion specularAO; filament::RefractionMode refractionMode; filament::RefractionType refractionType; filament::AttributeBitset requiredAttributes; diff --git a/libs/filamat/src/shaders/ShaderGenerator.cpp b/libs/filamat/src/shaders/ShaderGenerator.cpp index b2886e149e..6881859539 100644 --- a/libs/filamat/src/shaders/ShaderGenerator.cpp +++ b/libs/filamat/src/shaders/ShaderGenerator.cpp @@ -296,32 +296,33 @@ std::string ShaderGenerator::createFragmentProgram(filament::backend::ShaderMode cg.generateDefine(fs, "MAX_SHADOW_CASTING_SPOTS", uint32_t(CONFIG_MAX_SHADOW_CASTING_SPOTS)); - bool specularAO = material.specularAOSet ? - material.specularAO : !isMobileTarget(shaderModel); - cg.generateDefine(fs, "SPECULAR_AMBIENT_OCCLUSION", specularAO ? 1u : 0u); + auto defaultSpecularAO = isMobileTarget(shaderModel) ? + SpecularAmbientOcclusion::NONE : SpecularAmbientOcclusion::SIMPLE; + auto specularAO = material.specularAOSet ? material.specularAO : defaultSpecularAO; + cg.generateDefine(fs, "SPECULAR_AMBIENT_OCCLUSION", uint32_t(specularAO)); cg.generateDefine(fs, "HAS_REFRACTION", material.refractionMode != RefractionMode::NONE); if (material.refractionMode != RefractionMode::NONE) { cg.generateDefine(fs, "REFRACTION_MODE_CUBEMAP", uint32_t(RefractionMode::CUBEMAP)); cg.generateDefine(fs, "REFRACTION_MODE_SCREEN_SPACE", uint32_t(RefractionMode::SCREEN_SPACE)); switch (material.refractionMode) { - case NONE: + case RefractionMode::NONE: // can't be here break; - case CUBEMAP: + case RefractionMode::CUBEMAP: cg.generateDefine(fs, "REFRACTION_MODE", "REFRACTION_MODE_CUBEMAP"); break; - case SCREEN_SPACE: + case RefractionMode::SCREEN_SPACE: cg.generateDefine(fs, "REFRACTION_MODE", "REFRACTION_MODE_SCREEN_SPACE"); break; } cg.generateDefine(fs, "REFRACTION_TYPE_SOLID", uint32_t(RefractionType::SOLID)); cg.generateDefine(fs, "REFRACTION_TYPE_THIN", uint32_t(RefractionType::THIN)); switch (material.refractionType) { - case SOLID: + case RefractionType::SOLID: cg.generateDefine(fs, "REFRACTION_TYPE", "REFRACTION_TYPE_SOLID"); break; - case THIN: + case RefractionType::THIN: cg.generateDefine(fs, "REFRACTION_TYPE", "REFRACTION_TYPE_THIN"); break; } diff --git a/libs/filamat/tests/test_filamat.cpp b/libs/filamat/tests/test_filamat.cpp index 1821f8d231..e3882c590d 100644 --- a/libs/filamat/tests/test_filamat.cpp +++ b/libs/filamat/tests/test_filamat.cpp @@ -54,7 +54,7 @@ std::string shaderWithAllProperties(ShaderType type, builder.optimization(filamat::MaterialBuilder::Optimization::NONE); builder.shading(shadingModel); builder.includeCallback(includer); - builder.materialRefraction(refractionMode); + builder.refractionMode(refractionMode); MaterialBuilder::PropertyList allProperties; std::fill_n(allProperties, MaterialBuilder::MATERIAL_PROPERTIES_COUNT, true); diff --git a/libs/gltfio/materials/ubershader.mat.in b/libs/gltfio/materials/ubershader.mat.in index f341a31213..1c141b80fe 100644 --- a/libs/gltfio/materials/ubershader.mat.in +++ b/libs/gltfio/materials/ubershader.mat.in @@ -6,7 +6,7 @@ material { depthWrite : true, doubleSided : ${DOUBLESIDED}, flipUV : false, - specularAmbientOcclusion: true, + specularAmbientOcclusion: simple, parameters : [ { type : float3, name : specularFactor }, diff --git a/libs/gltfio/src/MaterialGenerator.cpp b/libs/gltfio/src/MaterialGenerator.cpp index 2943240f58..7ab78fb07b 100644 --- a/libs/gltfio/src/MaterialGenerator.cpp +++ b/libs/gltfio/src/MaterialGenerator.cpp @@ -242,7 +242,7 @@ Material* createMaterial(Engine* engine, const MaterialKey& config, const UvMap& MaterialBuilder builder = MaterialBuilder() .name(name) .flipUV(false) - .specularAmbientOcclusion(true) + .specularAmbientOcclusion(MaterialBuilder::SpecularAmbientOcclusion::SIMPLE) .material(shader.c_str()) .doubleSided(config.doubleSided) .targetApi(filamat::targetApiFromBackend(engine->getBackend())); diff --git a/samples/sample_full_pbr.cpp b/samples/sample_full_pbr.cpp index 29b6e6853f..2629dbee59 100644 --- a/samples/sample_full_pbr.cpp +++ b/samples/sample_full_pbr.cpp @@ -362,7 +362,7 @@ static void setup(Engine* engine, View* view, Scene* scene) { .name("DefaultMaterial") .material(shader.c_str()) .multiBounceAmbientOcclusion(true) - .specularAmbientOcclusion(true) + .specularAmbientOcclusion(MaterialBuilder::SpecularAmbientOcclusion::BENT_NORMALS) .shading(Shading::LIT); if (hasUV) { diff --git a/shaders/src/ambient_occlusion.fs b/shaders/src/ambient_occlusion.fs index c723fa0589..8b7acacfa9 100644 --- a/shaders/src/ambient_occlusion.fs +++ b/shaders/src/ambient_occlusion.fs @@ -1,3 +1,12 @@ +//------------------------------------------------------------------------------ +// Ambient occlusion configuration +//------------------------------------------------------------------------------ + +// Diffuse BRDFs +#define SPECULAR_AO_OFF 0 +#define SPECULAR_AO_SIMPLE 1 +#define SPECULAR_AO_BENT_NORMALS 2 + //------------------------------------------------------------------------------ // Ambient occlusion helpers //------------------------------------------------------------------------------ @@ -8,7 +17,6 @@ float evaluateSSAO() { return textureLod(light_ssao, uv, 0.0).r; } -#if SPECULAR_AMBIENT_OCCLUSION == 1 float SpecularAO_Lagarde(float NoV, float visibility, float roughness) { // Lagarde and de Rousiers 2014, "Moving Frostbite to PBR" return saturate(pow(NoV + visibility, exp2(-16.0 * roughness - 1.0)) - 1.0 + visibility); @@ -39,9 +47,11 @@ float sphericalCapsIntersection(float cosCap1, float cosCap2, float cosDistance) float area = sq(x) * (-2.0 * x + 3.0); return area * (1.0 - max(cosCap1, cosCap2)); } +#endif // This function could (should?) be implemented as a 3D LUT instead, but we need to save samplers -float SpecularAO_Cones(float visibility, float roughness) { +float SpecularAO_Cones(float NoV, float visibility, float roughness) { +#if defined(MATERIAL_HAS_BENT_NORMAL) // Jimenez et al. 2016, "Practical Realtime Strategies for Accurate Indirect Occlusion" // aperture from ambient occlusion @@ -56,22 +66,23 @@ float SpecularAO_Cones(float visibility, float roughness) { float ao = sphericalCapsIntersection(cosAv, cosAs, 0.5 * cosB + 0.5) / (1.0 - cosAs); // Smoothly kill specular AO when entering the perceptual roughness range [0.1..0.3] // Without this, specular AO can remove all reflections, which looks bad on metals + if (fract(getUserTime().x) < 0.5) + return SpecularAO_Lagarde(NoV, visibility, roughness); + else return mix(1.0, ao, smoothstep(0.01, 0.09, roughness)); +#else + return SpecularAO_Lagarde(NoV, visibility, roughness); +#endif } -#endif - -#endif /** * Computes a specular occlusion term from the ambient occlusion term. */ float computeSpecularAO(float NoV, float visibility, float roughness) { -#if SPECULAR_AMBIENT_OCCLUSION == 1 -#if defined(MATERIAL_HAS_BENT_NORMAL) - return SpecularAO_Cones(visibility, roughness); -#else +#if SPECULAR_AMBIENT_OCCLUSION == SPECULAR_AO_SIMPLE return SpecularAO_Lagarde(NoV, visibility, roughness); -#endif +#elif SPECULAR_AMBIENT_OCCLUSION == SPECULAR_AO_BENT_NORMALS + return SpecularAO_Cones(NoV, visibility, roughness); #else return 1.0; #endif @@ -100,7 +111,7 @@ void multiBounceAO(float visibility, const vec3 albedo, inout vec3 color) { } void multiBounceSpecularAO(float visibility, const vec3 albedo, inout vec3 color) { -#if MULTI_BOUNCE_AMBIENT_OCCLUSION == 1 && SPECULAR_AMBIENT_OCCLUSION == 1 +#if MULTI_BOUNCE_AMBIENT_OCCLUSION == 1 && SPECULAR_AMBIENT_OCCLUSION != SPECULAR_AO_OFF color *= gtaoMultiBounce(visibility, albedo); #endif } diff --git a/tools/matc/src/matc/ParametersProcessor.cpp b/tools/matc/src/matc/ParametersProcessor.cpp index b28352479a..247f2ca11e 100644 --- a/tools/matc/src/matc/ParametersProcessor.cpp +++ b/tools/matc/src/matc/ParametersProcessor.cpp @@ -429,7 +429,20 @@ static bool processMultiBounceAO(MaterialBuilder& builder, const JsonishValue& v } static bool processSpecularAmbientOcclusion(MaterialBuilder& builder, const JsonishValue& value) { - builder.specularAmbientOcclusion(value.toJsonBool()->getBool()); + static const std::unordered_map strToEnum { + { "none", MaterialBuilder::SpecularAmbientOcclusion::NONE }, + { "simple", MaterialBuilder::SpecularAmbientOcclusion::SIMPLE }, + { "bentNormals", MaterialBuilder::SpecularAmbientOcclusion::BENT_NORMALS }, + // Backward compatibility + { "false", MaterialBuilder::SpecularAmbientOcclusion::NONE }, + { "true", MaterialBuilder::SpecularAmbientOcclusion::SIMPLE }, + }; + auto jsonString = value.toJsonString(); + if (!isStringValidEnum(strToEnum, jsonString->getString())) { + return logEnumIssue("specularAO", *jsonString, strToEnum); + } + + builder.specularAmbientOcclusion(stringToEnum(strToEnum, jsonString->getString())); return true; } @@ -475,7 +488,7 @@ static bool processRefractionMode(MaterialBuilder& builder, const JsonishValue& return logEnumIssue("refraction", *jsonString, strToEnum); } - builder.materialRefraction(stringToEnum(strToEnum, jsonString->getString())); + builder.refractionMode(stringToEnum(strToEnum, jsonString->getString())); return true; } @@ -489,7 +502,7 @@ static bool processRefractionType(MaterialBuilder& builder, const JsonishValue& return logEnumIssue("refractionType", *jsonString, strToEnum); } - builder.materialRefractionType(stringToEnum(strToEnum, jsonString->getString())); + builder.refractionType(stringToEnum(strToEnum, jsonString->getString())); return true; } @@ -556,7 +569,7 @@ ParametersProcessor::ParametersProcessor() { mParameters["clearCoatIorChange"] = { &processClearCoatIorChange, Type::BOOL }; mParameters["flipUV"] = { &processFlipUV, Type::BOOL }; mParameters["multiBounceAmbientOcclusion"] = { &processMultiBounceAO, Type::BOOL }; - mParameters["specularAmbientOcclusion"] = { &processSpecularAmbientOcclusion, Type::BOOL }; + mParameters["specularAmbientOcclusion"] = { &processSpecularAmbientOcclusion, Type::STRING }; mParameters["domain"] = { &processDomain, Type::STRING }; mParameters["refractionMode"] = { &processRefractionMode, Type::STRING }; mParameters["refractionType"] = { &processRefractionType, Type::STRING };