diff --git a/NEW_RELEASE_NOTES.md b/NEW_RELEASE_NOTES.md
index 9de5125d89..c256dabadb 100644
--- a/NEW_RELEASE_NOTES.md
+++ b/NEW_RELEASE_NOTES.md
@@ -9,3 +9,4 @@ appropriate header in [RELEASE_NOTES.md](./RELEASE_NOTES.md).
## Release notes for next branch cut
- engine: a new feature to set a transform on the global-scale fog [⚠️ **Recompile materials**]
+- engine: large-scale fog can now be opted-out on a per-renderable basis
\ No newline at end of file
diff --git a/android/filament-android/src/main/cpp/RenderableManager.cpp b/android/filament-android/src/main/cpp/RenderableManager.cpp
index 74c3c7dece..2713dffa0b 100644
--- a/android/filament-android/src/main/cpp/RenderableManager.cpp
+++ b/android/filament-android/src/main/cpp/RenderableManager.cpp
@@ -201,12 +201,19 @@ Java_com_google_android_filament_RenderableManager_nBuilderSkinning(JNIEnv*, jcl
}
extern "C" JNIEXPORT void JNICALL
-Java_com_google_android_filament_RenderableManager_nEnableSkinningBuffers(JNIEnv*, jclass,
+Java_com_google_android_filament_RenderableManager_nBuilderEnableSkinningBuffers(JNIEnv*, jclass,
jlong nativeBuilder, jboolean enabled) {
RenderableManager::Builder *builder = (RenderableManager::Builder *) nativeBuilder;
builder->enableSkinningBuffers(enabled);
}
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_android_filament_RenderableManager_nBuilderFog(JNIEnv*, jclass,
+ jlong nativeBuilder, jboolean enabled) {
+ RenderableManager::Builder *builder = (RenderableManager::Builder *) nativeBuilder;
+ builder->fog(enabled);
+}
+
extern "C" JNIEXPORT jint JNICALL
Java_com_google_android_filament_RenderableManager_nBuilderSkinningBones(JNIEnv* env, jclass,
jlong nativeBuilder, jint boneCount, jobject bones, jint remaining) {
@@ -360,6 +367,20 @@ Java_com_google_android_filament_RenderableManager_nSetCulling(JNIEnv*, jclass,
rm->setCulling((RenderableManager::Instance) i, enabled);
}
+extern "C" JNIEXPORT void JNICALL
+Java_com_google_android_filament_RenderableManager_nSetFogEnabled(JNIEnv*, jclass,
+ jlong nativeRenderableManager, jint i, jboolean enabled) {
+ RenderableManager *rm = (RenderableManager *) nativeRenderableManager;
+ rm->setFogEnabled((RenderableManager::Instance) i, enabled);
+}
+
+extern "C" JNIEXPORT jboolean JNICALL
+Java_com_google_android_filament_RenderableManager_nGetFogEnabled(JNIEnv*, jclass,
+ jlong nativeRenderableManager, jint i) {
+ RenderableManager *rm = (RenderableManager *) nativeRenderableManager;
+ return (jboolean)rm->getFogEnabled((RenderableManager::Instance) i);
+}
+
extern "C" JNIEXPORT void JNICALL
Java_com_google_android_filament_RenderableManager_nSetCastShadows(JNIEnv*, jclass,
jlong nativeRenderableManager, jint i, jboolean enabled) {
diff --git a/android/filament-android/src/main/java/com/google/android/filament/RenderableManager.java b/android/filament-android/src/main/java/com/google/android/filament/RenderableManager.java
index 0b8a50b142..a3c8f1ff1c 100644
--- a/android/filament-android/src/main/java/com/google/android/filament/RenderableManager.java
+++ b/android/filament-android/src/main/java/com/google/android/filament/RenderableManager.java
@@ -417,7 +417,19 @@ public class RenderableManager {
*/
@NonNull
public Builder enableSkinningBuffers(boolean enabled) {
- nEnableSkinningBuffers(mNativeBuilder, enabled);
+ nBuilderEnableSkinningBuffers(mNativeBuilder, enabled);
+ return this;
+ }
+
+ /**
+ * Controls if this renderable is affected by the large-scale fog.
+ * @param enabled If true, enables large-scale fog on this object. Disables it otherwise.
+ * True by default.
+ * @return this Builder object for chaining calls
+ */
+ @NonNull
+ public Builder fog(boolean enabled) {
+ nBuilderFog(mNativeBuilder, enabled);
return this;
}
@@ -729,6 +741,23 @@ public class RenderableManager {
nSetCulling(mNativeObject, i, enabled);
}
+ /**
+ * Changes whether or not the large-scale fog is applied to this renderable
+ * @see Builder#fog
+ */
+ public void setFogEnabled(@EntityInstance int i, boolean enabled) {
+ nSetFogEnabled(mNativeObject, i, enabled);
+ }
+
+ /**
+ * Returns whether large-scale fog is enabled for this renderable.
+ * @return True if fog is enabled for this renderable.
+ * @see Builder#fog
+ */
+ public boolean getFogEnabled(@EntityInstance int i) {
+ return nGetFogEnabled(mNativeObject, i);
+ }
+
/**
* Enables or disables a light channel.
* Light channel 0 is enabled by default.
@@ -951,7 +980,8 @@ public class RenderableManager {
private static native void nBuilderSkinningBuffer(long nativeBuilder, long nativeSkinningBuffer, int boneCount, int offset);
private static native void nBuilderMorphing(long nativeBuilder, int targetCount);
private static native void nBuilderSetMorphTargetBufferAt(long nativeBuilder, int level, int primitiveIndex, long nativeMorphTargetBuffer, int offset, int count);
- private static native void nEnableSkinningBuffers(long nativeBuilder, boolean enabled);
+ private static native void nBuilderEnableSkinningBuffers(long nativeBuilder, boolean enabled);
+ private static native void nBuilderFog(long nativeBuilder, boolean enabled);
private static native void nBuilderLightChannel(long nativeRenderableManager, int channel, boolean enable);
private static native void nBuilderInstances(long nativeRenderableManager, int instances);
@@ -966,6 +996,8 @@ public class RenderableManager {
private static native void nSetPriority(long nativeRenderableManager, int i, int priority);
private static native void nSetChannel(long nativeRenderableManager, int i, int channel);
private static native void nSetCulling(long nativeRenderableManager, int i, boolean enabled);
+ private static native void nSetFogEnabled(long nativeRenderableManager, int i, boolean enabled);
+ private static native boolean nGetFogEnabled(long nativeRenderableManager, int i);
private static native void nSetLightChannel(long nativeRenderableManager, int i, int channel, boolean enable);
private static native boolean nGetLightChannel(long nativeRenderableManager, int i, int channel);
private static native void nSetCastShadows(long nativeRenderableManager, int i, boolean enabled);
diff --git a/filament/include/filament/RenderableManager.h b/filament/include/filament/RenderableManager.h
index 10b78d3201..0f5cf929eb 100644
--- a/filament/include/filament/RenderableManager.h
+++ b/filament/include/filament/RenderableManager.h
@@ -303,6 +303,14 @@ public:
*/
Builder& enableSkinningBuffers(bool enabled = true) noexcept;
+ /**
+ * Controls if this renderable is affected by the large-scale fog.
+ * @param enabled If true, enables large-scale fog on this object. Disables it otherwise.
+ * True by default.
+ * @return A reference to this Builder for chaining calls.
+ */
+ Builder& fog(bool enabled = true) noexcept;
+
/**
* Enables GPU vertex skinning for up to 255 bones, 0 by default.
*
@@ -536,6 +544,19 @@ public:
*/
void setCulling(Instance instance, bool enable) noexcept;
+ /**
+ * Changes whether or not the large-scale fog is applied to this renderable
+ * @see Builder::fog()
+ */
+ void setFogEnabled(Instance instance, bool enable) noexcept;
+
+ /**
+ * Returns whether large-scale fog is enabled for this renderable.
+ * @return True if fog is enabled for this renderable.
+ * @see Builder::fog()
+ */
+ bool getFogEnabled(Instance instance) const noexcept;
+
/**
* Enables or disables a light channel.
* Light channel 0 is enabled by default.
diff --git a/filament/src/RenderPass.cpp b/filament/src/RenderPass.cpp
index 994a9b30cc..9d2eade3ac 100644
--- a/filament/src/RenderPass.cpp
+++ b/filament/src/RenderPass.cpp
@@ -431,7 +431,7 @@ UTILS_NOINLINE
RenderPass::Command* RenderPass::generateCommandsImpl(uint32_t extraFlags,
Command* UTILS_RESTRICT curr,
FScene::RenderableSoa const& UTILS_RESTRICT soa, Range range,
- Variant variant, RenderFlags renderFlags, FScene::VisibleMaskType visibilityMask,
+ Variant const variant, RenderFlags renderFlags, FScene::VisibleMaskType visibilityMask,
float3 cameraPosition, float3 cameraForward) noexcept {
// generateCommands() writes both the draw and depth commands simultaneously such that
@@ -479,6 +479,8 @@ RenderPass::Command* RenderPass::generateCommandsImpl(uint32_t extraFlags,
continue;
}
+ Variant renderableVariant = variant;
+
// Signed distance from camera plane to object's center. Positive distances are in front of
// the camera. Some objects with a center behind the camera can still be visible
// so their distance will be negative (this happens a lot for the shadow map).
@@ -523,9 +525,9 @@ RenderPass::Command* RenderPass::generateCommandsImpl(uint32_t extraFlags,
// if we are already an SSR variant, the SRE bit is already set,
// there is no harm setting it again
static_assert(Variant::SPECIAL_SSR & Variant::SRE);
- variant.setShadowReceiver(
+ renderableVariant.setShadowReceiver(
Variant::isSSRVariant(variant) || (soaVisibility[i].receiveShadows & hasShadowing));
- variant.setSkinning(hasSkinningOrMorphing);
+ renderableVariant.setSkinning(hasSkinningOrMorphing);
if constexpr (isDepthPass) {
cmdDepth.key = uint64_t(Pass::DEPTH);
@@ -540,6 +542,9 @@ RenderPass::Command* RenderPass::generateCommandsImpl(uint32_t extraFlags,
cmdDepth.primitive.materialVariant.setSkinning(hasSkinningOrMorphing);
cmdDepth.primitive.rasterState.inverseFrontFaces = inverseFrontFaces;
}
+ if constexpr (isColorPass) {
+ renderableVariant.setFog(soaVisibility[i].fog && Variant::isFogVariant(variant));
+ }
const bool shadowCaster = soaVisibility[i].castShadows & hasShadowing;
const bool writeDepthForShadowCasters = depthContainsShadowCasters & shadowCaster;
@@ -560,7 +565,7 @@ RenderPass::Command* RenderPass::generateCommandsImpl(uint32_t extraFlags,
if constexpr (isColorPass) {
cmdColor.primitive.primitiveHandle = primitive.getHwHandle();
- RenderPass::setupColorCommand(cmdColor, variant, mi, inverseFrontFaces);
+ RenderPass::setupColorCommand(cmdColor, renderableVariant, mi, inverseFrontFaces);
cmdColor.primitive.skinningHandle = skinning.handle;
cmdColor.primitive.skinningOffset = skinning.offset;
diff --git a/filament/src/RenderableManager.cpp b/filament/src/RenderableManager.cpp
index 5a16d8d63a..bc1240415d 100644
--- a/filament/src/RenderableManager.cpp
+++ b/filament/src/RenderableManager.cpp
@@ -165,4 +165,12 @@ bool RenderableManager::getLightChannel(Instance instance, unsigned int channel)
return downcast(this)->getLightChannel(instance, channel);
}
+void RenderableManager::setFogEnabled(RenderableManager::Instance instance, bool enable) noexcept {
+ downcast(this)->setFogEnabled(instance, enable);
+}
+
+bool RenderableManager::getFogEnabled(RenderableManager::Instance instance) const noexcept {
+ return downcast(this)->getFogEnabled(instance);
+}
+
} // namespace filament
diff --git a/filament/src/components/RenderableManager.cpp b/filament/src/components/RenderableManager.cpp
index 1edddec32a..b2b59ea2db 100644
--- a/filament/src/components/RenderableManager.cpp
+++ b/filament/src/components/RenderableManager.cpp
@@ -60,6 +60,7 @@ struct RenderableManager::BuilderDetails {
bool mReceiveShadows : 1;
bool mScreenSpaceContactShadows : 1;
bool mSkinningBufferMode : 1;
+ bool mFogEnabled : 1;
size_t mSkinningBoneCount = 0;
size_t mMorphTargetCount = 0;
Bone const* mUserBones = nullptr;
@@ -70,7 +71,7 @@ struct RenderableManager::BuilderDetails {
explicit BuilderDetails(size_t count)
: mEntries(count), mCulling(true), mCastShadows(false), mReceiveShadows(true),
- mScreenSpaceContactShadows(false), mSkinningBufferMode(false) {
+ mScreenSpaceContactShadows(false), mSkinningBufferMode(false), mFogEnabled(true) {
}
// this is only needed for the explicit instantiation below
BuilderDetails() = default;
@@ -204,6 +205,11 @@ RenderableManager::Builder& RenderableManager::Builder::enableSkinningBuffers(bo
return *this;
}
+RenderableManager::Builder& RenderableManager::Builder::fog(bool enabled) noexcept {
+ mImpl->mFogEnabled = enabled;
+ return *this;
+}
+
RenderableManager::Builder& RenderableManager::Builder::morphing(size_t targetCount) noexcept {
mImpl->mMorphTargetCount = targetCount;
return *this;
@@ -373,6 +379,7 @@ void FRenderableManager::create(
setCulling(ci, builder->mCulling);
setSkinning(ci, false);
setMorphing(ci, builder->mMorphTargetCount);
+ setFogEnabled(ci, builder->mFogEnabled);
mManager[ci].channels = builder->mLightChannels;
InstancesInfo& instances = manager[ci].instances;
diff --git a/filament/src/components/RenderableManager.h b/filament/src/components/RenderableManager.h
index ee6b1e7b3d..648ccdaeb5 100644
--- a/filament/src/components/RenderableManager.h
+++ b/filament/src/components/RenderableManager.h
@@ -64,6 +64,7 @@ public:
bool morphing : 1;
bool screenSpaceContactShadows : 1;
bool reversedWindingOrder : 1;
+ bool fog : 1;
};
static_assert(sizeof(Visibility) == sizeof(uint16_t), "Visibility should be 16 bits");
@@ -114,6 +115,8 @@ public:
inline void setReceiveShadows(Instance instance, bool enable) noexcept;
inline void setScreenSpaceContactShadows(Instance instance, bool enable) noexcept;
inline void setCulling(Instance instance, bool enable) noexcept;
+ inline void setFogEnabled(Instance instance, bool enable) noexcept;
+ inline bool getFogEnabled(Instance instance) const noexcept;
inline void setPrimitives(Instance instance, utils::Slice const& primitives) noexcept;
@@ -339,6 +342,17 @@ void FRenderableManager::setCulling(Instance instance, bool enable) noexcept {
}
}
+void FRenderableManager::setFogEnabled(Instance instance, bool enable) noexcept {
+ if (instance) {
+ Visibility& visibility = mManager[instance].visibility;
+ visibility.fog = enable;
+ }
+}
+
+bool FRenderableManager::getFogEnabled(RenderableManager::Instance instance) const noexcept {
+ return getVisibility(instance).fog;
+}
+
void FRenderableManager::setSkinning(Instance instance, bool enable) noexcept {
if (instance) {
Visibility& visibility = mManager[instance].visibility;
diff --git a/web/filament-js/jsbindings.cpp b/web/filament-js/jsbindings.cpp
index 60ca4a5e7b..4a36aaedf9 100644
--- a/web/filament-js/jsbindings.cpp
+++ b/web/filament-js/jsbindings.cpp
@@ -905,12 +905,23 @@ class_("RenderableManager$Builder")
.BUILDER_FUNCTION("culling", RenderableBuilder, (RenderableBuilder* builder, bool enable), {
return &builder->culling(enable); })
+ .BUILDER_FUNCTION("lightChannel", RenderableBuilder,
+ (RenderableBuilder* builder, unsigned int channel, bool enable), {
+ return &builder->lightChannel(channel, enable); })
+
.BUILDER_FUNCTION("castShadows", RenderableBuilder, (RenderableBuilder* builder, bool enable), {
return &builder->castShadows(enable); })
.BUILDER_FUNCTION("receiveShadows", RenderableBuilder, (RenderableBuilder* builder, bool enable), {
return &builder->receiveShadows(enable); })
+ .BUILDER_FUNCTION("screenSpaceContactShadows", RenderableBuilder,
+ (RenderableBuilder* builder, bool enable), {
+ return &builder->screenSpaceContactShadows(enable); })
+
+ .BUILDER_FUNCTION("fog", RenderableBuilder, (RenderableBuilder* builder, bool enable), {
+ return &builder->fog(enable); })
+
.BUILDER_FUNCTION("skinning", RenderableBuilder, (RenderableBuilder* builder, size_t boneCount), {
return &builder->skinning(boneCount); })
@@ -945,9 +956,9 @@ class_("RenderableManager$Builder")
(RenderableBuilder* builder, size_t index, bool enabled), {
return &builder->globalBlendOrderEnabled(index, enabled); })
- .BUILDER_FUNCTION("lightChannel", RenderableBuilder,
- (RenderableBuilder* builder, unsigned int channel, bool enable), {
- return &builder->lightChannel(channel, enable); })
+ .BUILDER_FUNCTION("instances", RenderableBuilder,
+ (RenderableBuilder* builder, size_t instanceCount), {
+ return &builder->instances(instanceCount); })
.function("_build", EMBIND_LAMBDA(int, (RenderableBuilder* builder,
Engine* engine, utils::Entity entity), {
@@ -978,6 +989,8 @@ class_("RenderableManager")
.function("isShadowReceiver", &RenderableManager::isShadowReceiver)
.function("setLightChannel", &RenderableManager::setLightChannel)
.function("getLightChannel", &RenderableManager::getLightChannel)
+ .function("setFogEnabled", &RenderableManager::setFogEnabled)
+ .function("getFogEnabled", &RenderableManager::getFogEnabled)
.function("setBones", EMBIND_LAMBDA(void, (RenderableManager* self,
RenderableManager::Instance instance, emscripten::val transforms, size_t offset), {