Skip to content

Commit b92af35

Browse files
authored
add a material option to use linear fog calculations (#9030)
The new `linearFog` material property, when set to `true` enables a simplified fog calculation. The fog equation becomes linear which is unrealistic, but more efficient to compute. In some situations with a shallow fog range, it doesn't make a huge difference visually. In this mode, height falloff and in-scattering are ignored. The linear equation slope is calculated from the regular parameters to match the slope of the real equation at a camera height. If `heightFalloff` is disabled, set to 0, the `density` parameter exactly corresponds to the slope of the equation in [1/m] units.
1 parent f2a1051 commit b92af35

File tree

16 files changed

+178
-23
lines changed

16 files changed

+178
-23
lines changed

NEW_RELEASE_NOTES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
88

99
## Release notes for next branch cut
1010

11+
- engine: add a `linearFog` material parameter. [⚠️ **New Material Version**]
1112
- opengl: When `Material::compile()` is called on a platform which doesn't support parallel compilation, shaders are automatically compiled over a number of frames

android/filament-android/src/main/java/com/google/android/filament/View.java

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1561,7 +1561,9 @@ public enum BlendMode {
15611561
}
15621562

15631563
/**
1564-
* Options to control large-scale fog in the scene
1564+
* Options to control large-scale fog in the scene. Materials can enable the `linearFog` property,
1565+
* which uses a simplified, linear equation for fog calculation; in this mode, the heightFalloff
1566+
* is ignored as well as the mipmap selection in IBL or skyColor mode.
15651567
*/
15661568
public static class FogOptions {
15671569
/**
@@ -1578,20 +1580,23 @@ public static class FogOptions {
15781580
*/
15791581
public float cutOffDistance = Float.POSITIVE_INFINITY;
15801582
/**
1581-
* fog's maximum opacity between 0 and 1
1583+
* fog's maximum opacity between 0 and 1. Ignored in `linearFog` mode.
15821584
*/
15831585
public float maximumOpacity = 1.0f;
15841586
/**
15851587
* Fog's floor in world units [m]. This sets the "sea level".
15861588
*/
15871589
public float height = 0.0f;
15881590
/**
1589-
* How fast the fog dissipates with altitude. heightFalloff has a unit of [1/m].
1591+
* How fast the fog dissipates with the altitude. heightFalloff has a unit of [1/m].
15901592
* It can be expressed as 1/H, where H is the altitude change in world units [m] that causes a
15911593
* factor 2.78 (e) change in fog density.
15921594
*
15931595
* A falloff of 0 means the fog density is constant everywhere and may result is slightly
15941596
* faster computations.
1597+
*
1598+
* In `linearFog` mode, only use to compute the slope of the linear equation. Completely
1599+
* ignored if set to 0.
15951600
*/
15961601
public float heightFalloff = 1.0f;
15971602
/**
@@ -1612,7 +1617,7 @@ public static class FogOptions {
16121617
@NonNull @Size(min = 3)
16131618
public float[] color = {1.0f, 1.0f, 1.0f};
16141619
/**
1615-
* Extinction factor in [1/m] at altitude 'height'. The extinction factor controls how much
1620+
* Extinction factor in [1/m] at an altitude 'height'. The extinction factor controls how much
16161621
* light is absorbed and out-scattered per unit of distance. Each unit of extinction reduces
16171622
* the incoming light to 37% of its original value.
16181623
*
@@ -1621,17 +1626,23 @@ public static class FogOptions {
16211626
* the composition of the fog/atmosphere.
16221627
*
16231628
* For historical reason this parameter is called `density`.
1629+
*
1630+
* In `linearFog` mode this is the slope of the linear equation if heightFalloff is set to 0.
1631+
* Otherwise, heightFalloff affects the slope calculation such that it matches the slope of
1632+
* the standard equation at the camera height.
16241633
*/
16251634
public float density = 0.1f;
16261635
/**
16271636
* Distance in world units [m] from the camera where the Sun in-scattering starts.
1637+
* Ignored in `linearFog` mode.
16281638
*/
16291639
public float inScatteringStart = 0.0f;
16301640
/**
16311641
* Very inaccurately simulates the Sun's in-scattering. That is, the light from the sun that
16321642
* is scattered (by the fog) towards the camera.
16331643
* Size of the Sun in-scattering (>0 to activate). Good values are >> 1 (e.g. ~10 - 100).
16341644
* Smaller values result is a larger scattering size.
1645+
* Ignored in `linearFog` mode.
16351646
*/
16361647
public float inScatteringSize = -1.0f;
16371648
/**
@@ -1657,6 +1668,8 @@ public static class FogOptions {
16571668
*
16581669
* `fogColorFromIbl` is ignored when skyTexture is specified.
16591670
*
1671+
* In `linearFog` mode mipmap level 0 is always used.
1672+
*
16601673
* @see Texture
16611674
* @see fogColorFromIbl
16621675
*/
@@ -1671,7 +1684,7 @@ public static class FogOptions {
16711684
/**
16721685
* Options to control Depth of Field (DoF) effect in the scene.
16731686
*
1674-
* cocScale can be used to set the depth of field blur independently from the camera
1687+
* cocScale can be used to set the depth of field blur independently of the camera
16751688
* aperture, e.g. for artistic reasons. This can be achieved by setting:
16761689
* cocScale = cameraAperture / desiredDoFAperture
16771690
*

docs_src/src_markdeep/Materials.md.html

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,6 +1199,24 @@
11991199
}
12001200
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
12011201

1202+
### General: linearFog
1203+
1204+
Type
1205+
: `boolean`
1206+
1207+
Value
1208+
: `true` or `false`. Defaults to `false`.
1209+
1210+
Description
1211+
: When set to `true`, a simplified fog equation is used for large-scale fog calculations. In this mode,
1212+
in-scattering is ignored as well as height falloff.
1213+
1214+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ JSON
1215+
material {
1216+
linearFog : true
1217+
}
1218+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1219+
12021220
### General: quality
12031221

12041222
Type

filament/include/filament/Options.h

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,9 @@ struct BloomOptions {
164164
};
165165

166166
/**
167-
* Options to control large-scale fog in the scene
167+
* Options to control large-scale fog in the scene. Materials can enable the `linearFog` property,
168+
* which uses a simplified, linear equation for fog calculation; in this mode, the heightFalloff
169+
* is ignored as well as the mipmap selection in IBL or skyColor mode.
168170
*/
169171
struct FogOptions {
170172
/**
@@ -183,7 +185,7 @@ struct FogOptions {
183185
float cutOffDistance = INFINITY;
184186

185187
/**
186-
* fog's maximum opacity between 0 and 1
188+
* fog's maximum opacity between 0 and 1. Ignored in `linearFog` mode.
187189
*/
188190
float maximumOpacity = 1.0f;
189191

@@ -193,12 +195,15 @@ struct FogOptions {
193195
float height = 0.0f;
194196

195197
/**
196-
* How fast the fog dissipates with altitude. heightFalloff has a unit of [1/m].
198+
* How fast the fog dissipates with the altitude. heightFalloff has a unit of [1/m].
197199
* It can be expressed as 1/H, where H is the altitude change in world units [m] that causes a
198200
* factor 2.78 (e) change in fog density.
199201
*
200202
* A falloff of 0 means the fog density is constant everywhere and may result is slightly
201203
* faster computations.
204+
*
205+
* In `linearFog` mode, only use to compute the slope of the linear equation. Completely
206+
* ignored if set to 0.
202207
*/
203208
float heightFalloff = 1.0f;
204209

@@ -220,7 +225,7 @@ struct FogOptions {
220225
LinearColor color = { 1.0f, 1.0f, 1.0f };
221226

222227
/**
223-
* Extinction factor in [1/m] at altitude 'height'. The extinction factor controls how much
228+
* Extinction factor in [1/m] at an altitude 'height'. The extinction factor controls how much
224229
* light is absorbed and out-scattered per unit of distance. Each unit of extinction reduces
225230
* the incoming light to 37% of its original value.
226231
*
@@ -229,11 +234,16 @@ struct FogOptions {
229234
* the composition of the fog/atmosphere.
230235
*
231236
* For historical reason this parameter is called `density`.
237+
*
238+
* In `linearFog` mode this is the slope of the linear equation if heightFalloff is set to 0.
239+
* Otherwise, heightFalloff affects the slope calculation such that it matches the slope of
240+
* the standard equation at the camera height.
232241
*/
233242
float density = 0.1f;
234243

235244
/**
236245
* Distance in world units [m] from the camera where the Sun in-scattering starts.
246+
* Ignored in `linearFog` mode.
237247
*/
238248
float inScatteringStart = 0.0f;
239249

@@ -242,6 +252,7 @@ struct FogOptions {
242252
* is scattered (by the fog) towards the camera.
243253
* Size of the Sun in-scattering (>0 to activate). Good values are >> 1 (e.g. ~10 - 100).
244254
* Smaller values result is a larger scattering size.
255+
* Ignored in `linearFog` mode.
245256
*/
246257
float inScatteringSize = -1.0f;
247258

@@ -269,6 +280,8 @@ struct FogOptions {
269280
*
270281
* `fogColorFromIbl` is ignored when skyTexture is specified.
271282
*
283+
* In `linearFog` mode mipmap level 0 is always used.
284+
*
272285
* @see Texture
273286
* @see fogColorFromIbl
274287
*/
@@ -283,7 +296,7 @@ struct FogOptions {
283296
/**
284297
* Options to control Depth of Field (DoF) effect in the scene.
285298
*
286-
* cocScale can be used to set the depth of field blur independently from the camera
299+
* cocScale can be used to set the depth of field blur independently of the camera
287300
* aperture, e.g. for artistic reasons. This can be achieved by setting:
288301
* cocScale = cameraAperture / desiredDoFAperture
289302
*

filament/src/ds/ColorPassDescriptorSet.cpp

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919

2020
#include "Froxelizer.h"
2121
#include "PerViewDescriptorSetUtils.h"
22-
#include "HwDescriptorSetLayoutFactory.h"
23-
#include "ShadowMapManager.h"
2422
#include "TypedUniformBuffer.h"
2523

2624
#include "components/LightManager.h"
@@ -30,10 +28,8 @@
3028
#include "details/IndirectLight.h"
3129
#include "details/Texture.h"
3230

33-
#include <filament/Engine.h>
3431
#include <filament/Exposure.h>
3532
#include <filament/Options.h>
36-
#include <filament/TextureSampler.h>
3733
#include <filament/MaterialEnums.h>
3834
#include <filament/Viewport.h>
3935

@@ -56,9 +52,11 @@
5652
#include <algorithm>
5753
#include <array>
5854
#include <cmath>
55+
#include <cstring>
56+
#include <cstddef>
57+
#include <limits>
5958
#include <random>
6059

61-
#include <stddef.h>
6260
#include <stdint.h>
6361

6462
namespace filament {
@@ -243,6 +241,22 @@ void ColorPassDescriptorSet::prepareFog(FEngine& engine, const CameraInfo& camer
243241
.filterMin = SamplerMinFilter::LINEAR_MIPMAP_LINEAR
244242
});
245243

244+
// Fog calculation details:
245+
// Optical path: (
246+
// f = heightFalloff
247+
// Te(y, z) = z * density * (exp(-f * eye_y) - exp(-f * eye_y - f * y)) / (f * y)
248+
// Transmittance:
249+
// t(y , z) = exp(-Te(y, z))
250+
251+
// In Linear Mode, formally the slope of the linear equation is: dt(y,z)/dz(0, eye_y)
252+
// (the derivative of the transmittance at distance 0 and camera height). When the height
253+
// falloff is disabled, the density parameter exactly represents this value.
254+
constexpr double EPSILON = std::numeric_limits<float>::epsilon();
255+
double const f = heightFalloff;
256+
double const eye = userCameraPosition.y - options.height;
257+
double const dt = options.density * (f <= EPSILON ? 1.0 : (std::exp(-f * eye) - std::exp(-2.0 * f * eye)) / (f * eye));
258+
float const fogEndLinear = float(1.0 / dt);
259+
246260
s.fogStart = options.distance;
247261
s.fogMaxOpacity = options.maximumOpacity;
248262
s.fogHeightFalloff = heightFalloff;
@@ -253,6 +267,8 @@ void ColorPassDescriptorSet::prepareFog(FEngine& engine, const CameraInfo& camer
253267
s.fogInscatteringSize = options.inScatteringSize;
254268
s.fogColorFromIbl = fogColorTextureHandle ? 1.0f : 0.0f;
255269
s.fogFromWorldMatrix = mat3f{ cof(fogFromWorld) };
270+
s.fogLinearParams = { 1.0f / (fogEndLinear - options.distance),
271+
-options.distance / (fogEndLinear - options.distance) };
256272
}
257273

258274
void ColorPassDescriptorSet::prepareSSAO(Handle<HwTexture> ssao,
@@ -332,7 +348,7 @@ void ColorPassDescriptorSet::prepareDirectionalLight(FEngine& engine,
332348
}
333349
}
334350

335-
void ColorPassDescriptorSet::prepareAmbientLight(FEngine& engine, FIndirectLight const& ibl,
351+
void ColorPassDescriptorSet::prepareAmbientLight(FEngine const& engine, FIndirectLight const& ibl,
336352
float const intensity, float const exposure) noexcept {
337353
auto& s = mUniforms.edit();
338354

filament/src/ds/ColorPassDescriptorSet.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ class ColorPassDescriptorSet {
115115
void prepareDirectionalLight(FEngine& engine, float exposure,
116116
math::float3 const& sceneSpaceDirection, LightManagerInstance instance) noexcept;
117117

118-
void prepareAmbientLight(FEngine& engine,
118+
void prepareAmbientLight(FEngine const& engine,
119119
FIndirectLight const& ibl, float intensity, float exposure) noexcept;
120120

121121
void prepareDynamicLights(Froxelizer& froxelizer) noexcept;

libs/filabridge/include/private/filament/UibStructs.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,8 @@ struct PerViewUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
177177
float fogOneOverFarMinusNear;
178178
float fogNearOverFarMinusNear;
179179
std140::mat33 fogFromWorldMatrix;
180+
math::float2 fogLinearParams; // { 1/(end-start), -start/(end-start) }
181+
math::float2 fogReserved[1];
180182

181183
// --------------------------------------------------------------------------------------------
182184
// Screen-space reflections [variant: SSR (i.e.: VSM | SRE)]
@@ -202,7 +204,7 @@ struct PerViewUib { // NOLINT(cppcoreguidelines-pro-type-member-init)
202204
float es2Reserved2;
203205

204206
// bring PerViewUib to 2 KiB
205-
math::float4 reserved[40];
207+
math::float4 reserved[39];
206208
};
207209

208210
// 2 KiB == 128 float4s

libs/filamat/include/filamat/MaterialBuilder.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,9 @@ class UTILS_PUBLIC MaterialBuilder : public MaterialBuilderBase {
532532
//! Enable / disable flipping of the Y coordinate of UV attributes, enabled by default.
533533
MaterialBuilder& flipUV(bool flipUV) noexcept;
534534

535+
//! Enable / disable the cheapest linear fog, disabled by default.
536+
MaterialBuilder& linearFog(bool enabled) noexcept;
537+
535538
//! Enable / disable multi-bounce ambient occlusion, disabled by default on mobile.
536539
MaterialBuilder& multiBounceAmbientOcclusion(bool multiBounceAO) noexcept;
537540

@@ -948,6 +951,7 @@ class UTILS_PUBLIC MaterialBuilder : public MaterialBuilderBase {
948951
bool mClearCoatIorChange = true;
949952

950953
bool mFlipUV = true;
954+
bool mLinearFog = false;
951955

952956
bool mMultiBounceAO = false;
953957
bool mMultiBounceAOSet = false;

libs/filamat/src/MaterialBuilder.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,11 @@ MaterialBuilder& MaterialBuilder::flipUV(bool const flipUV) noexcept {
539539
return *this;
540540
}
541541

542+
MaterialBuilder& MaterialBuilder::linearFog(bool const enabled) noexcept {
543+
mLinearFog = enabled;
544+
return *this;
545+
}
546+
542547
MaterialBuilder& MaterialBuilder::customSurfaceShading(bool const customSurfaceShading) noexcept {
543548
mCustomSurfaceShading = customSurfaceShading;
544549
return *this;
@@ -708,6 +713,7 @@ void MaterialBuilder::prepareToBuild(MaterialInfo& info) noexcept {
708713
info.specularAntiAliasing = mSpecularAntiAliasing;
709714
info.clearCoatIorChange = mClearCoatIorChange;
710715
info.flipUV = mFlipUV;
716+
info.linearFog = mLinearFog;
711717
info.requiredAttributes = mRequiredAttributes;
712718
info.blendingMode = mBlendingMode;
713719
info.postLightingBlendingMode = mPostLightingBlendingMode;

libs/filamat/src/shaders/CodeGenerator.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,8 @@ utils::io::sstream& CodeGenerator::generateCommonProlog(utils::io::sstream& out,
250250
CodeGenerator::generateDefine(out, "LEGACY_MORPHING", material.useLegacyMorphing);
251251
}
252252
if (stage == ShaderStage::FRAGMENT) {
253+
CodeGenerator::generateDefine(out, "FILAMENT_LINEAR_FOG",
254+
material.linearFog);
253255
CodeGenerator::generateDefine(out, "MATERIAL_HAS_CUSTOM_DEPTH",
254256
material.userMaterialHasCustomDepth);
255257
}

0 commit comments

Comments
 (0)