Change specularAmbientOcclusion from boolean to enum (#2352)

The user can now choose amongst 3 specular AO methods:
- None, specAO is off
- Simple, specAO is inferred from roughness and diffuse AO
- Bent normals, specAO is computed accurately from cone intersections

The last method is more expensive but produces the best results.

This change also fixes a few issues:
- Rename materialRefraction() and materialRefractionType() for
  consistency
- Fixes user time in shaders
This commit is contained in:
Romain Guy
2020-04-07 09:19:48 -07:00
committed by GitHub
parent 887f8e8a1c
commit bf0dc32ee3
18 changed files with 191 additions and 76 deletions
+11 -1
View File
@@ -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
@@ -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
@@ -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);
+15 -13
View File
@@ -696,7 +696,7 @@ and with (right)</div></div></center>
The <code>bentNormal</code> 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 <a href="#toc4.2.24">4.2.24</a> about
<code>specularAmbientOcclusion</code>).
@@ -711,11 +711,6 @@ instance.
</p><center><div class="image" style><a href="images/material_bent_normal.gif" target="_blank"><img class="markdeep" src="images/material_bent_normal.gif"></a><div class="imagecaption"><a class="target" name="figure_bentnormalmapped">&#xA0;</a><b style="font-style:normal;">Figure&#xA0;17:</b> Example of a model rendered with and without a bent normal map. Both
versions use the same ambient occlusion map.</div></div></center>
<p></p><p>
</p><div class="admonition warning">Using a bent normal map increases the runtime cost of the material, particularly when
<code>specularAmbientOcclusion</code> is turned on.</div>
<p></p>
<a class="target" name="clearcoatnormal">&#xA0;</a><a class="target" name="materialmodels/litmodel/clearcoatnormal">&#xA0;</a><a class="target" name="toc3.1.15">&#xA0;</a><h3>Clear coat normal</h3>
<p>
@@ -1952,17 +1947,24 @@ occclusion enabled and disabled.</div></div></center>
<p>
</p><dl><dt>Type</dt><dd><p> <code>boolean</code>
</p><dl><dt>Type</dt><dd><p> <code>string</code>
</p></dd><dt>Value</dt><dd><p> <code>true</code> or <code>false</code>. Defaults to <code>false</code> on mobile, <code>true</code> on desktop.
</p></dd><dt>Value</dt><dd><p> <code>none</code>, <code>simple</code> or <code>bentNormals</code>. Defaults to <code>none</code> on mobile, <code>simple</code> on desktop. For
compatibility reasons, <code>true</code> and <code>false</code> are also accepted and map respectively to <code>simple</code>
and <code>none</code>.
</p></dd><dt>Description</dt><dd><p> 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 <a href="#figure_specularao">figure&#xA0;37</a>.
indirect lighting. When setting this property to other than <code>none</code>, 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 <a href="#figure_specularao">figure&#xA0;37</a>.
When this value is set to <code>simple</code>, Filament uses a cheap but approximate method of computing
the specular ambient occlusion term. If this value is set to <code>bentNormals</code>, Filament will use
a much more accurate but much more expensive method. <code>bentNormals</code> only works if the material
sets the <code>bentNormal</code> property inside the fragment shader. If that property isn&apos;t set,
<code>bentNormals</code> will behave like <code>simple</code>.
</p></dd></dl><p></p><pre class="listing tilde"><code><span class="line">material {</span>
<span class="line"> specularAmbientOcclusion : true</span>
<span class="line"> specularAmbientOcclusion : simple</span>
<span class="line">}</span></code></pre><p>
</p><center><div class="image" style><a href="images/screenshot_specular_ao.gif" target="_blank"><img class="markdeep" src="images/screenshot_specular_ao.gif"></a><div class="imagecaption"><a class="target" name="figure_specularao">&#xA0;</a><b style="font-style:normal;">Figure&#xA0;37:</b> Comparison of specular ambient occlusion on and off. The effect is
@@ -1979,7 +1981,7 @@ particularly visible under the hose.</div></div></center>
</p></dd><dt>Description</dt><dd><p> 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: <code>specularAntiAliasingVariance</code> and
<code>specularAntiAliasingThreshold</code>.
+15 -12
View File
@@ -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`.
-1
View File
@@ -84,7 +84,6 @@ public:
*/
void setIndirectLight(IndirectLight const* ibl) noexcept;
/**
* Adds an Entity to the Scene.
*
+1 -1
View File
@@ -766,7 +766,7 @@ bool FRenderer::beginFrame(FSwapChain* swapChain, uint64_t vsyncSteadyClockTimeN
#endif
// latch the frame time
std::chrono::duration<double> time(userVsync - mUserEpoch);
std::chrono::duration<double> time(appVsync - mUserEpoch);
float h = float(time.count());
float l = float(time.count() - h);
mShaderUserTime = { h, l, 0, 0 };
@@ -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)
};
+11 -9
View File
@@ -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;
};
+3 -3
View File
@@ -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;
+1 -1
View File
@@ -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;
+9 -8
View File
@@ -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;
}
+1 -1
View File
@@ -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);
+1 -1
View File
@@ -6,7 +6,7 @@ material {
depthWrite : true,
doubleSided : ${DOUBLESIDED},
flipUV : false,
specularAmbientOcclusion: true,
specularAmbientOcclusion: simple,
parameters : [
{ type : float3, name : specularFactor },
+1 -1
View File
@@ -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()));
+1 -1
View File
@@ -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) {
+22 -11
View File
@@ -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
}
+17 -4
View File
@@ -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<std::string, MaterialBuilder::SpecularAmbientOcclusion> 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 };