Browse Source

Scripting work

Panagiotis Christopoulos Charitos 7 years ago
parent
commit
72f8b1b587

+ 2 - 1
src/anki/renderer/RenderQueue.h

@@ -252,9 +252,10 @@ public:
 	WeakArray<ReflectionProbeQueueElement> m_reflectionProbes;
 	WeakArray<LensFlareQueueElement> m_lensFlares;
 	WeakArray<DecalQueueElement> m_decals;
+	WeakArray<FogDensityQueueElement> m_fogDensityVolumes;
 	WeakArray<UiQueueElement> m_uis;
 
-	/// Applies only if the RenderQueue holds shadow casters. It's the timesamp that modified
+	/// Applies only if the RenderQueue holds shadow casters. It's the max timesamp of all shadow casters
 	Timestamp m_shadowRenderablesLastUpdateTimestamp = 0;
 
 	F32 m_cameraNear;

+ 1 - 1
src/anki/scene/CameraNode.cpp

@@ -79,7 +79,7 @@ Error CameraNode::init(Frustum* frustum)
 		| FrustumComponentVisibilityTestFlag::LENS_FLARE_COMPONENTS
 		| FrustumComponentVisibilityTestFlag::REFLECTION_PROBES | FrustumComponentVisibilityTestFlag::REFLECTION_PROXIES
 		| FrustumComponentVisibilityTestFlag::OCCLUDERS | FrustumComponentVisibilityTestFlag::DECALS
-		| FrustumComponentVisibilityTestFlag::EARLY_Z);
+		| FrustumComponentVisibilityTestFlag::FOG_DENSITY_COMPONENTS | FrustumComponentVisibilityTestFlag::EARLY_Z);
 
 	// Feedback component #2
 	newComponent<CameraFrustumFeedbackComponent>();

+ 52 - 39
src/anki/scene/Visibility.cpp

@@ -12,8 +12,9 @@
 #include <anki/scene/components/ReflectionProxyComponent.h>
 #include <anki/scene/components/OccluderComponent.h>
 #include <anki/scene/components/DecalComponent.h>
-#include <anki/scene/LightNode.h>
 #include <anki/scene/components/MoveComponent.h>
+#include <anki/scene/components/FogDensityComponent.h>
+#include <anki/scene/components/LightComponent.h>
 #include <anki/renderer/MainRenderer.h>
 #include <anki/util/Logger.h>
 #include <anki/util/ThreadHive.h>
@@ -221,6 +222,9 @@ void VisibilityTestTask::test(ThreadHive& hive, U32 taskId)
 
 	const Bool wantsDecals = testedFrc.visibilityTestsEnabled(FrustumComponentVisibilityTestFlag::DECALS);
 
+	const Bool wantsFogDensityComponents =
+		testedFrc.visibilityTestsEnabled(FrustumComponentVisibilityTestFlag::FOG_DENSITY_COMPONENTS);
+
 	const Bool wantsEarlyZ = testedFrc.visibilityTestsEnabled(FrustumComponentVisibilityTestFlag::EARLY_Z)
 							 && m_frcCtx->m_visCtx->m_earlyZDist > 0.0f;
 
@@ -241,43 +245,49 @@ void VisibilityTestTask::test(ThreadHive& hive, U32 taskId)
 		// Check what components the frustum needs
 		Bool wantNode = false;
 
-		const RenderComponent* rc = node.tryGetComponent<RenderComponent>();
-		if(rc && wantsRenderComponents)
+		const RenderComponent* rc = nullptr;
+		if(wantsRenderComponents && (rc = node.tryGetComponent<RenderComponent>()))
+		{
+			wantNode = true;
+		}
+
+		if(wantsShadowCasters && (rc = node.tryGetComponent<RenderComponent>()) && rc->getCastsShadow())
 		{
 			wantNode = true;
 		}
 
-		if(rc && rc->getCastsShadow() && wantsShadowCasters)
+		const LightComponent* lc = nullptr;
+		if(wantsLightComponents && (lc = node.tryGetComponent<LightComponent>()))
 		{
 			wantNode = true;
 		}
 
-		const LightComponent* lc = node.tryGetComponent<LightComponent>();
-		if(lc && wantsLightComponents)
+		const LensFlareComponent* lfc = nullptr;
+		if(wantsFlareComponents && (lfc = node.tryGetComponent<LensFlareComponent>()))
 		{
 			wantNode = true;
 		}
 
-		const LensFlareComponent* lfc = node.tryGetComponent<LensFlareComponent>();
-		if(lfc && wantsFlareComponents)
+		const ReflectionProbeComponent* reflc = nullptr;
+		if(wantsReflectionProbes && (reflc = node.tryGetComponent<ReflectionProbeComponent>()))
 		{
 			wantNode = true;
 		}
 
-		const ReflectionProbeComponent* reflc = node.tryGetComponent<ReflectionProbeComponent>();
-		if(reflc && wantsReflectionProbes)
+		const ReflectionProxyComponent* proxyc = nullptr;
+		if(wantsReflectionProxies && (proxyc = node.tryGetComponent<ReflectionProxyComponent>()))
 		{
 			wantNode = true;
 		}
 
-		const ReflectionProxyComponent* proxyc = node.tryGetComponent<ReflectionProxyComponent>();
-		if(proxyc && wantsReflectionProxies)
+		DecalComponent* decalc = nullptr;
+		if(wantsDecals && (decalc = node.tryGetComponent<DecalComponent>()))
 		{
 			wantNode = true;
 		}
 
-		DecalComponent* decalc = node.tryGetComponent<DecalComponent>();
-		if(decalc && wantsDecals)
+		const FogDensityComponent* fogc = nullptr;
+		if(wantsFogDensityComponents && (fogc = node.tryGetComponent<FogDensityComponent>()))
 		{
 			wantNode = true;
 		}
@@ -336,34 +346,30 @@ void VisibilityTestTask::test(ThreadHive& hive, U32 taskId)
 
 		if(rc)
 		{
-			if(wantsRenderComponents || (wantsShadowCasters && rc->getCastsShadow()))
+			RenderableQueueElement* el;
+			if(rc->isForwardShading())
 			{
-				RenderableQueueElement* el;
-				if(rc->isForwardShading())
-				{
-					el = result.m_forwardShadingRenderables.newElement(alloc);
-				}
-				else
-				{
-					el = result.m_renderables.newElement(alloc);
-				}
+				el = result.m_forwardShadingRenderables.newElement(alloc);
+			}
+			else
+			{
+				el = result.m_renderables.newElement(alloc);
+			}
 
-				rc->setupRenderableQueueElement(*el);
+			rc->setupRenderableQueueElement(*el);
 
-				// Compute distance from the frustum
-				const Plane& nearPlane = testedFrc.getFrustum().getPlanesWorldSpace()[FrustumPlaneType::NEAR];
-				el->m_distanceFromCamera = max(0.0f, sps[0].m_sp->getAabb().testPlane(nearPlane));
+			// Compute distance from the frustum
+			const Plane& nearPlane = testedFrc.getFrustum().getPlanesWorldSpace()[FrustumPlaneType::NEAR];
+			el->m_distanceFromCamera = max(0.0f, sps[0].m_sp->getAabb().testPlane(nearPlane));
 
-				if(wantsEarlyZ && el->m_distanceFromCamera < m_frcCtx->m_visCtx->m_earlyZDist
-					&& !rc->isForwardShading())
-				{
-					RenderableQueueElement* el2 = result.m_earlyZRenderables.newElement(alloc);
-					*el2 = *el;
-				}
+			if(wantsEarlyZ && el->m_distanceFromCamera < m_frcCtx->m_visCtx->m_earlyZDist && !rc->isForwardShading())
+			{
+				RenderableQueueElement* el2 = result.m_earlyZRenderables.newElement(alloc);
+				*el2 = *el;
 			}
 		}
 
-		if(lc && wantsLightComponents)
+		if(lc)
 		{
 			switch(lc->getLightComponentType())
 			{
@@ -420,13 +426,13 @@ void VisibilityTestTask::test(ThreadHive& hive, U32 taskId)
 			}
 		}
 
-		if(lfc && wantsFlareComponents)
+		if(lfc)
 		{
 			LensFlareQueueElement* el = result.m_lensFlares.newElement(alloc);
 			lfc->setupLensFlareQueueElement(*el);
 		}
 
-		if(reflc && wantsReflectionProbes)
+		if(reflc)
 		{
 			ReflectionProbeQueueElement* el = result.m_reflectionProbes.newElement(alloc);
 			reflc->setupReflectionProbeQueueElement(*el);
@@ -449,17 +455,23 @@ void VisibilityTestTask::test(ThreadHive& hive, U32 taskId)
 			}
 		}
 
-		if(proxyc && wantsReflectionProxies)
+		if(proxyc)
 		{
 			ANKI_ASSERT(!"TODO");
 		}
 
-		if(decalc && wantsDecals)
+		if(decalc)
 		{
 			DecalQueueElement* el = result.m_decals.newElement(alloc);
 			decalc->setupDecalQueueElement(*el);
 		}
 
+		if(fogc)
+		{
+			FogDensityQueueElement* el = result.m_fogDensityVolumes.newElement(alloc);
+			fogc->setupFogDensityQueueElement(*el);
+		}
+
 		// Add more frustums to the list
 		if(nextQueues.getSize() > 0)
 		{
@@ -532,6 +544,7 @@ void CombineResultsTask::combine()
 	ANKI_VIS_COMBINE(ReflectionProbeQueueElement, m_reflectionProbes);
 	ANKI_VIS_COMBINE(LensFlareQueueElement, m_lensFlares);
 	ANKI_VIS_COMBINE(DecalQueueElement, m_decals);
+	ANKI_VIS_COMBINE(FogDensityQueueElement, m_fogDensityVolumes);
 
 #undef ANKI_VIS_COMBINE
 #undef ANKI_VIS_COMBINE_AND_PTR

+ 1 - 0
src/anki/scene/VisibilityInternal.h

@@ -113,6 +113,7 @@ public:
 	TRenderQueueElementStorage<ReflectionProbeQueueElement> m_reflectionProbes;
 	TRenderQueueElementStorage<LensFlareQueueElement> m_lensFlares;
 	TRenderQueueElementStorage<DecalQueueElement> m_decals;
+	TRenderQueueElementStorage<FogDensityQueueElement> m_fogDensityVolumes;
 
 	Timestamp m_timestamp = 0;
 };

+ 5 - 4
src/anki/scene/components/FrustumComponent.h

@@ -30,10 +30,11 @@ enum class FrustumComponentVisibilityTestFlag : U16
 	REFLECTION_PROXIES = 1 << 5,
 	OCCLUDERS = 1 << 6,
 	DECALS = 1 << 7,
-	EARLY_Z = 1 << 8,
+	FOG_DENSITY_COMPONENTS = 1 << 8,
+	EARLY_Z = 1 << 9,
 
 	ALL_TESTS = RENDER_COMPONENTS | LIGHT_COMPONENTS | LENS_FLARE_COMPONENTS | SHADOW_CASTERS | REFLECTION_PROBES
-				| REFLECTION_PROXIES | DECALS | EARLY_Z
+				| REFLECTION_PROXIES | DECALS | FOG_DENSITY_COMPONENTS | EARLY_Z
 };
 ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(FrustumComponentVisibilityTestFlag, inline)
 
@@ -184,8 +185,8 @@ public:
 private:
 	enum Flags
 	{
-		SHAPE_MARKED_FOR_UPDATE = 1 << 9,
-		TRANSFORM_MARKED_FOR_UPDATE = 1 << 10,
+		SHAPE_MARKED_FOR_UPDATE = 1 << 10,
+		TRANSFORM_MARKED_FOR_UPDATE = 1 << 12,
 	};
 	ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(Flags, friend)
 

+ 354 - 0
src/anki/script/Scene.cpp

@@ -1634,6 +1634,233 @@ static inline void wrapTriggerComponent(lua_State* l)
 	lua_settop(l, 0);
 }
 
+LuaUserDataTypeInfo luaUserDataTypeInfoFogDensityComponent = {3433641273323722630,
+	"FogDensityComponent",
+	LuaUserData::computeSizeForGarbageCollected<FogDensityComponent>(),
+	nullptr,
+	nullptr};
+
+template<>
+const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<FogDensityComponent>()
+{
+	return luaUserDataTypeInfoFogDensityComponent;
+}
+
+/// Pre-wrap method FogDensityComponent::setBoundingBox.
+static inline int pwrapFogDensityComponentsetBoundingBox(lua_State* l)
+{
+	LuaUserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	PtrSize size;
+	(void)size;
+
+	if(ANKI_UNLIKELY(LuaBinder::checkArgsCount(l, 3)))
+	{
+		return -1;
+	}
+
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, luaUserDataTypeInfoFogDensityComponent, ud))
+	{
+		return -1;
+	}
+
+	FogDensityComponent* self = ud->getData<FogDensityComponent>();
+
+	// Pop arguments
+	extern LuaUserDataTypeInfo luaUserDataTypeInfoVec4;
+	if(ANKI_UNLIKELY(LuaBinder::checkUserData(l, 2, luaUserDataTypeInfoVec4, ud)))
+	{
+		return -1;
+	}
+
+	Vec4* iarg0 = ud->getData<Vec4>();
+	const Vec4& arg0(*iarg0);
+
+	extern LuaUserDataTypeInfo luaUserDataTypeInfoVec4;
+	if(ANKI_UNLIKELY(LuaBinder::checkUserData(l, 3, luaUserDataTypeInfoVec4, ud)))
+	{
+		return -1;
+	}
+
+	Vec4* iarg1 = ud->getData<Vec4>();
+	const Vec4& arg1(*iarg1);
+
+	// Call the method
+	self->setBoundingBox(arg0, arg1);
+
+	return 0;
+}
+
+/// Wrap method FogDensityComponent::setBoundingBox.
+static int wrapFogDensityComponentsetBoundingBox(lua_State* l)
+{
+	int res = pwrapFogDensityComponentsetBoundingBox(l);
+	if(res >= 0)
+	{
+		return res;
+	}
+
+	lua_error(l);
+	return 0;
+}
+
+/// Pre-wrap method FogDensityComponent::setSphere.
+static inline int pwrapFogDensityComponentsetSphere(lua_State* l)
+{
+	LuaUserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	PtrSize size;
+	(void)size;
+
+	if(ANKI_UNLIKELY(LuaBinder::checkArgsCount(l, 2)))
+	{
+		return -1;
+	}
+
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, luaUserDataTypeInfoFogDensityComponent, ud))
+	{
+		return -1;
+	}
+
+	FogDensityComponent* self = ud->getData<FogDensityComponent>();
+
+	// Pop arguments
+	F32 arg0;
+	if(ANKI_UNLIKELY(LuaBinder::checkNumber(l, 2, arg0)))
+	{
+		return -1;
+	}
+
+	// Call the method
+	self->setSphere(arg0);
+
+	return 0;
+}
+
+/// Wrap method FogDensityComponent::setSphere.
+static int wrapFogDensityComponentsetSphere(lua_State* l)
+{
+	int res = pwrapFogDensityComponentsetSphere(l);
+	if(res >= 0)
+	{
+		return res;
+	}
+
+	lua_error(l);
+	return 0;
+}
+
+/// Pre-wrap method FogDensityComponent::setDensity.
+static inline int pwrapFogDensityComponentsetDensity(lua_State* l)
+{
+	LuaUserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	PtrSize size;
+	(void)size;
+
+	if(ANKI_UNLIKELY(LuaBinder::checkArgsCount(l, 2)))
+	{
+		return -1;
+	}
+
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, luaUserDataTypeInfoFogDensityComponent, ud))
+	{
+		return -1;
+	}
+
+	FogDensityComponent* self = ud->getData<FogDensityComponent>();
+
+	// Pop arguments
+	F32 arg0;
+	if(ANKI_UNLIKELY(LuaBinder::checkNumber(l, 2, arg0)))
+	{
+		return -1;
+	}
+
+	// Call the method
+	self->setDensity(arg0);
+
+	return 0;
+}
+
+/// Wrap method FogDensityComponent::setDensity.
+static int wrapFogDensityComponentsetDensity(lua_State* l)
+{
+	int res = pwrapFogDensityComponentsetDensity(l);
+	if(res >= 0)
+	{
+		return res;
+	}
+
+	lua_error(l);
+	return 0;
+}
+
+/// Pre-wrap method FogDensityComponent::getDensity.
+static inline int pwrapFogDensityComponentgetDensity(lua_State* l)
+{
+	LuaUserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	PtrSize size;
+	(void)size;
+
+	if(ANKI_UNLIKELY(LuaBinder::checkArgsCount(l, 1)))
+	{
+		return -1;
+	}
+
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, luaUserDataTypeInfoFogDensityComponent, ud))
+	{
+		return -1;
+	}
+
+	FogDensityComponent* self = ud->getData<FogDensityComponent>();
+
+	// Call the method
+	F32 ret = self->getDensity();
+
+	// Push return value
+	lua_pushnumber(l, ret);
+
+	return 1;
+}
+
+/// Wrap method FogDensityComponent::getDensity.
+static int wrapFogDensityComponentgetDensity(lua_State* l)
+{
+	int res = pwrapFogDensityComponentgetDensity(l);
+	if(res >= 0)
+	{
+		return res;
+	}
+
+	lua_error(l);
+	return 0;
+}
+
+/// Wrap class FogDensityComponent.
+static inline void wrapFogDensityComponent(lua_State* l)
+{
+	LuaBinder::createClass(l, &luaUserDataTypeInfoFogDensityComponent);
+	LuaBinder::pushLuaCFuncMethod(l, "setBoundingBox", wrapFogDensityComponentsetBoundingBox);
+	LuaBinder::pushLuaCFuncMethod(l, "setSphere", wrapFogDensityComponentsetSphere);
+	LuaBinder::pushLuaCFuncMethod(l, "setDensity", wrapFogDensityComponentsetDensity);
+	LuaBinder::pushLuaCFuncMethod(l, "getDensity", wrapFogDensityComponentgetDensity);
+	lua_settop(l, 0);
+}
+
 LuaUserDataTypeInfo luaUserDataTypeInfoSceneNode = {
 	-2220074417980276571, "SceneNode", LuaUserData::computeSizeForGarbageCollected<SceneNode>(), nullptr, nullptr};
 
@@ -2057,6 +2284,61 @@ static int wrapSceneNodegetTriggerComponent(lua_State* l)
 	return 0;
 }
 
+/// Pre-wrap method SceneNode::tryGetComponent<FogDensityComponent>.
+static inline int pwrapSceneNodegetFogDensityComponent(lua_State* l)
+{
+	LuaUserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	PtrSize size;
+	(void)size;
+
+	if(ANKI_UNLIKELY(LuaBinder::checkArgsCount(l, 1)))
+	{
+		return -1;
+	}
+
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, luaUserDataTypeInfoSceneNode, ud))
+	{
+		return -1;
+	}
+
+	SceneNode* self = ud->getData<SceneNode>();
+
+	// Call the method
+	FogDensityComponent* ret = self->tryGetComponent<FogDensityComponent>();
+
+	// Push return value
+	if(ANKI_UNLIKELY(ret == nullptr))
+	{
+		lua_pushstring(l, "Glue code returned nullptr");
+		return -1;
+	}
+
+	voidp = lua_newuserdata(l, sizeof(LuaUserData));
+	ud = static_cast<LuaUserData*>(voidp);
+	luaL_setmetatable(l, "FogDensityComponent");
+	extern LuaUserDataTypeInfo luaUserDataTypeInfoFogDensityComponent;
+	ud->initPointed(&luaUserDataTypeInfoFogDensityComponent, const_cast<FogDensityComponent*>(ret));
+
+	return 1;
+}
+
+/// Wrap method SceneNode::tryGetComponent<FogDensityComponent>.
+static int wrapSceneNodegetFogDensityComponent(lua_State* l)
+{
+	int res = pwrapSceneNodegetFogDensityComponent(l);
+	if(res >= 0)
+	{
+		return res;
+	}
+
+	lua_error(l);
+	return 0;
+}
+
 /// Wrap class SceneNode.
 static inline void wrapSceneNode(lua_State* l)
 {
@@ -2069,6 +2351,7 @@ static inline void wrapSceneNode(lua_State* l)
 	LuaBinder::pushLuaCFuncMethod(l, "getLensFlareComponent", wrapSceneNodegetLensFlareComponent);
 	LuaBinder::pushLuaCFuncMethod(l, "getDecalComponent", wrapSceneNodegetDecalComponent);
 	LuaBinder::pushLuaCFuncMethod(l, "getTriggerComponent", wrapSceneNodegetTriggerComponent);
+	LuaBinder::pushLuaCFuncMethod(l, "getFogDensityComponent", wrapSceneNodegetFogDensityComponent);
 	lua_settop(l, 0);
 }
 
@@ -2949,6 +3232,75 @@ static inline void wrapTriggerNode(lua_State* l)
 	lua_settop(l, 0);
 }
 
+LuaUserDataTypeInfo luaUserDataTypeInfoFogDensityNode = {-2463430472135938886,
+	"FogDensityNode",
+	LuaUserData::computeSizeForGarbageCollected<FogDensityNode>(),
+	nullptr,
+	nullptr};
+
+template<>
+const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<FogDensityNode>()
+{
+	return luaUserDataTypeInfoFogDensityNode;
+}
+
+/// Pre-wrap method FogDensityNode::getSceneNodeBase.
+static inline int pwrapFogDensityNodegetSceneNodeBase(lua_State* l)
+{
+	LuaUserData* ud;
+	(void)ud;
+	void* voidp;
+	(void)voidp;
+	PtrSize size;
+	(void)size;
+
+	if(ANKI_UNLIKELY(LuaBinder::checkArgsCount(l, 1)))
+	{
+		return -1;
+	}
+
+	// Get "this" as "self"
+	if(LuaBinder::checkUserData(l, 1, luaUserDataTypeInfoFogDensityNode, ud))
+	{
+		return -1;
+	}
+
+	FogDensityNode* self = ud->getData<FogDensityNode>();
+
+	// Call the method
+	SceneNode& ret = *self;
+
+	// Push return value
+	voidp = lua_newuserdata(l, sizeof(LuaUserData));
+	ud = static_cast<LuaUserData*>(voidp);
+	luaL_setmetatable(l, "SceneNode");
+	extern LuaUserDataTypeInfo luaUserDataTypeInfoSceneNode;
+	ud->initPointed(&luaUserDataTypeInfoSceneNode, const_cast<SceneNode*>(&ret));
+
+	return 1;
+}
+
+/// Wrap method FogDensityNode::getSceneNodeBase.
+static int wrapFogDensityNodegetSceneNodeBase(lua_State* l)
+{
+	int res = pwrapFogDensityNodegetSceneNodeBase(l);
+	if(res >= 0)
+	{
+		return res;
+	}
+
+	lua_error(l);
+	return 0;
+}
+
+/// Wrap class FogDensityNode.
+static inline void wrapFogDensityNode(lua_State* l)
+{
+	LuaBinder::createClass(l, &luaUserDataTypeInfoFogDensityNode);
+	LuaBinder::pushLuaCFuncMethod(l, "getSceneNodeBase", wrapFogDensityNodegetSceneNodeBase);
+	lua_settop(l, 0);
+}
+
 LuaUserDataTypeInfo luaUserDataTypeInfoSceneGraph = {
 	-7754439619132389154, "SceneGraph", LuaUserData::computeSizeForGarbageCollected<SceneGraph>(), nullptr, nullptr};
 
@@ -4167,6 +4519,7 @@ void wrapModuleScene(lua_State* l)
 	wrapDecalComponent(l);
 	wrapLensFlareComponent(l);
 	wrapTriggerComponent(l);
+	wrapFogDensityComponent(l);
 	wrapSceneNode(l);
 	wrapModelNode(l);
 	wrapPerspectiveCameraNode(l);
@@ -4179,6 +4532,7 @@ void wrapModuleScene(lua_State* l)
 	wrapOccluderNode(l);
 	wrapDecalNode(l);
 	wrapTriggerNode(l);
+	wrapFogDensityNode(l);
 	wrapSceneGraph(l);
 	wrapEvent(l);
 	wrapLightEvent(l);

+ 34 - 0
src/anki/script/Scene.xml

@@ -215,6 +215,29 @@ using WeakArraySceneNodePtr = WeakArray<SceneNode*>;
 				</method>
 			</methods>
 		</class>
+		<class name="FogDensityComponent">
+			<methods>
+				<method name="setBoundingBox">
+					<args>
+						<arg>const Vec4&amp;</arg>
+						<arg>const Vec4&amp;</arg>
+					</args>
+				</method>
+				<method name="setSphere">
+					<args>
+						<arg>F32</arg>
+					</args>
+				</method>
+				<method name="setDensity">
+					<args>
+						<arg>F32</arg>
+					</args>
+				</method>
+				<method name="getDensity">
+					<return>F32</return>
+				</method>
+			</methods>
+		</class>
 
 		<!-- Nodes -->
 		<class name="SceneNode">
@@ -243,6 +266,9 @@ using WeakArraySceneNodePtr = WeakArray<SceneNode*>;
 				<method name="tryGetComponent&lt;TriggerComponent&gt;" alias="getTriggerComponent">
 					<return>TriggerComponent*</return>
 				</method>
+				<method name="tryGetComponent&lt;FogDensityComponent&gt;" alias="getFogDensityComponent">
+					<return>FogDensityComponent*</return>
+				</method>
 			</methods>
 		</class>
 		<class name="ModelNode">
@@ -347,6 +373,14 @@ using WeakArraySceneNodePtr = WeakArray<SceneNode*>;
 				</method>
 			</methods>
 		</class>
+		<class name="FogDensityNode">
+			<methods>
+				<method name="getSceneNodeBase">
+					<overrideCall>SceneNode&amp; ret = *self;</overrideCall>
+					<return>SceneNode&amp;</return>
+				</method>
+			</methods>
+		</class>
 		<class name="SceneGraph">
 			<methods>
 				<method name="newPerspectiveCameraNode">