Bladeren bron

More GI work

Panagiotis Christopoulos Charitos 6 jaren geleden
bovenliggende
commit
81c3ad902f

+ 11 - 0
samples/sponza/assets/scene.lua

@@ -140,6 +140,17 @@ trf:setRotation(rot)
 trf:setScale(1)
 node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
 
+node = scene:newGlobalIlluminationProbeNode("giprobe0")
+comp = node:getSceneNodeBase():getGlobalIlluminationProbeComponent()
+comp:setBoundingBox(Vec4.new(-35.1133, -16.4224, -22.1445, 0), Vec4.new(35.1133, 16.4224, 22.1445, 0))
+trf = Transform.new()
+trf:setOrigin(Vec4.new(-0.294456, 13.2902, 0, 0))
+rot = Mat3x4.new()
+rot:setAll(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0)
+trf:setRotation(rot)
+trf:setScale(1)
+node:getSceneNodeBase():getMoveComponent():setLocalTransform(trf)
+
 node = scene:newModelNode("sponza_277leaf-materialnone0", "assets/sponza_277leaf-material.ankimdl")
 trf = Transform.new()
 trf:setOrigin(Vec4.new(-10.8267, 3.02038, -4.74626, 0))

+ 17 - 15
shaders/IrradianceDice.glslp

@@ -3,13 +3,15 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-// Compute the irradiance given an environment map. The irradiance will be stored in an ambient dice.
+// Compute the irradiance given a light shading result. The irradiance will be stored in an ambient dice.
 
-#pragma anki input const U32 ENV_TEX_TILE_SIZE
+#pragma anki input const U32 INPUT_TEXTURES_HEIGHT
 
 #pragma anki start comp
 
 #include <shaders/Functions.glsl>
+#include <shaders/Pack.glsl>
+#include <shaders/LightFunctions.glsl>
 
 layout(local_size_x = 6, local_size_y = 1, local_size_z = 1) in;
 
@@ -30,7 +32,7 @@ shared Vec3 s_diceColors[6];
 
 void main()
 {
-	const F32 ENV_TEX_TILE_SIZE_F = F32(ENV_TEX_TILE_SIZE);
+	const F32 INPUT_TEXTURES_HEIGHT_F = F32(INPUT_TEXTURES_HEIGHT);
 	const U32 diceFace = gl_LocalInvocationID.x;
 
 	// Get the r coordinate of the current direction of the dice
@@ -40,12 +42,12 @@ void main()
 	Vec3 irradiance = Vec3(0.0);
 	ANKI_LOOP for(U32 f = 0u; f < 6u; ++f)
 	{
-		ANKI_LOOP for(U32 i = 0u; i < ENV_TEX_TILE_SIZE; ++i)
+		ANKI_LOOP for(U32 i = 0u; i < INPUT_TEXTURES_HEIGHT; ++i)
 		{
-			ANKI_LOOP for(U32 j = 0u; j < ENV_TEX_TILE_SIZE; ++j)
+			ANKI_LOOP for(U32 j = 0u; j < INPUT_TEXTURES_HEIGHT; ++j)
 			{
-				const Vec2 uv =
-					Vec2(j + f * ENV_TEX_TILE_SIZE_F, i) / Vec2(6.0 * ENV_TEX_TILE_SIZE_F, ENV_TEX_TILE_SIZE_F);
+				const Vec2 uv = Vec2(j + f * INPUT_TEXTURES_HEIGHT_F, i)
+								/ Vec2(6.0 * INPUT_TEXTURES_HEIGHT_F, INPUT_TEXTURES_HEIGHT_F);
 				const Vec2 ndc = UV_TO_NDC(uv);
 
 				const Vec3 r = getCubemapDirection(ndc, f);
@@ -54,7 +56,7 @@ void main()
 				if(lambert > 0.0)
 				{
 					const Vec3 lightShading = textureLod(u_lightShadingTex, u_nearestAnyClampSampler, uv, 0.0).rgb;
-					irradiance += lightShading * lambert * cubeCoordSolidAngle(ndc, ENV_TEX_TILE_SIZE_F);
+					irradiance += lightShading * lambert * cubeCoordSolidAngle(ndc, INPUT_TEXTURES_HEIGHT_F);
 				}
 			}
 		}
@@ -68,12 +70,12 @@ void main()
 	irradiance = Vec3(0.0);
 	ANKI_LOOP for(U32 f = 0u; f < 6u; ++f)
 	{
-		ANKI_LOOP for(U32 i = 0u; i < ENV_TEX_TILE_SIZE; ++i)
+		ANKI_LOOP for(U32 i = 0u; i < INPUT_TEXTURES_HEIGHT; ++i)
 		{
-			ANKI_LOOP for(U32 j = 0u; j < ENV_TEX_TILE_SIZE; ++j)
+			ANKI_LOOP for(U32 j = 0u; j < INPUT_TEXTURES_HEIGHT; ++j)
 			{
-				const Vec2 uv =
-					Vec2(j + f * ENV_TEX_TILE_SIZE_F, i) / Vec2(6.0 * ENV_TEX_TILE_SIZE_F, ENV_TEX_TILE_SIZE_F);
+				const Vec2 uv = Vec2(j + f * INPUT_TEXTURES_HEIGHT_F, i)
+								/ Vec2(6.0 * INPUT_TEXTURES_HEIGHT_F, INPUT_TEXTURES_HEIGHT_F);
 				const Vec2 ndc = UV_TO_NDC(uv);
 
 				const Vec3 r = getCubemapDirection(ndc, f);
@@ -98,8 +100,8 @@ void main()
 
 					// Compute 2nd bounce
 					const Vec3 lightShading = textureLod(u_lightShadingTex, u_nearestAnyClampSampler, uv, 0.0).rgb;
-					irradiance +=
-						firstBounceIrradiance + lightShading * lambert * cubeCoordSolidAngle(ndc, ENV_TEX_TILE_SIZE_F);
+					irradiance += firstBounceIrradiance
+								  + lightShading * lambert * cubeCoordSolidAngle(ndc, INPUT_TEXTURES_HEIGHT_F);
 				}
 			}
 		}
@@ -109,7 +111,7 @@ void main()
 	irradiance *= (1.0 / PI);
 
 	// Store the result
-	imageStore(u_irradianceVolumes[nonUniformEXT(diceFace)], u_volumeTexel, Vec4(irradiance, 0.0));
+	imageStore(u_irradianceVolumes[nonuniformEXT(diceFace)], u_volumeTexel, Vec4(irradiance, 0.0));
 }
 
 #pragma anki end

+ 1 - 0
src/anki/Renderer.h

@@ -30,5 +30,6 @@
 #include <anki/renderer/RendererObject.h>
 #include <anki/renderer/Bloom.h>
 #include <anki/renderer/VolumetricLightingAccumulation.h>
+#include <anki/renderer/GlobalIllumination.h>
 
 /// @defgroup renderer Renderering system

+ 12 - 4
src/anki/gr/vulkan/DescriptorSet.cpp

@@ -277,8 +277,9 @@ void DSThreadAllocator::writeSet(const Array<AnyBindingExtended, MAX_BINDINGS_PE
 	{
 		if(m_layoutEntry->m_activeBindings.get(bindingIdx))
 		{
-			for(U arrIdx = 0; arrIdx < bindings[bindingIdx].m_arraySize; ++arrIdx)
+			for(U arrIdx = 0; arrIdx < m_layoutEntry->m_bindingArraySize[bindingIdx]; ++arrIdx)
 			{
+				ANKI_ASSERT(bindings[bindingIdx].m_arraySize >= m_layoutEntry->m_bindingArraySize[bindingIdx]);
 				const AnyBinding& b = (bindings[bindingIdx].m_arraySize == 1) ? bindings[bindingIdx].m_single
 																			  : bindings[bindingIdx].m_array[arrIdx];
 
@@ -346,7 +347,7 @@ void DSThreadAllocator::writeSet(const Array<AnyBindingExtended, MAX_BINDINGS_PE
 	{
 		if(m_layoutEntry->m_activeBindings.get(bindingIdx))
 		{
-			for(U arrIdx = 0; arrIdx < bindings[bindingIdx].m_arraySize; ++arrIdx)
+			for(U arrIdx = 0; arrIdx < m_layoutEntry->m_bindingArraySize[bindingIdx]; ++arrIdx)
 			{
 				const AnyBinding& b = (bindings[bindingIdx].m_arraySize == 1) ? bindings[bindingIdx].m_single
 																			  : bindings[bindingIdx].m_array[arrIdx];
@@ -445,7 +446,7 @@ Error DSLayoutCacheEntry::init(const DescriptorBinding* bindings, U bindingCount
 		{
 			if(m_poolSizesCreateInf[j].type == convertDescriptorType(bindings[i].m_type))
 			{
-				++m_poolSizesCreateInf[j].descriptorCount;
+				m_poolSizesCreateInf[j].descriptorCount += bindings[i].m_arraySizeMinusOne + 1;
 				break;
 			}
 		}
@@ -453,7 +454,7 @@ Error DSLayoutCacheEntry::init(const DescriptorBinding* bindings, U bindingCount
 		if(j == poolSizeCount)
 		{
 			m_poolSizesCreateInf[poolSizeCount].type = convertDescriptorType(bindings[i].m_type);
-			m_poolSizesCreateInf[poolSizeCount].descriptorCount = 1;
+			m_poolSizesCreateInf[poolSizeCount].descriptorCount = bindings[i].m_arraySizeMinusOne + 1;
 			++poolSizeCount;
 		}
 	}
@@ -979,6 +980,13 @@ Error BindlessDescriptorSet::initDeviceFeatures(
 
 	vkGetPhysicalDeviceFeatures2(pdev, &features);
 
+	if(!indexingFeatures.shaderSampledImageArrayNonUniformIndexing
+		|| !indexingFeatures.shaderStorageImageArrayNonUniformIndexing)
+	{
+		ANKI_VK_LOGE("Non uniform indexing is not supported by the device");
+		return Error::FUNCTION_FAILED;
+	}
+
 	if(!indexingFeatures.descriptorBindingSampledImageUpdateAfterBind
 		|| !indexingFeatures.descriptorBindingStorageImageUpdateAfterBind)
 	{

+ 1 - 0
src/anki/renderer/Common.h

@@ -38,6 +38,7 @@ class TemporalAA;
 class UiStage;
 class Ssr;
 class VolumetricLightingAccumulation;
+class GlobalIllumination;
 
 class RenderingContext;
 class DebugDrawer;

+ 15 - 8
src/anki/renderer/GlobalIllumination.cpp

@@ -29,7 +29,8 @@ static Vec3 computeProbeCellPosition(U cellIdx, const GlobalIlluminationProbeQue
 	const Vec3 cellSize = (probe.m_aabbMax - probe.m_aabbMin)
 						  / Vec3(probe.m_cellCounts.x(), probe.m_cellCounts.y(), probe.m_cellCounts.z());
 	const Vec3 halfCellSize = cellSize / 2.0f;
-	const Vec3 cellPos = Vec3(cellCoords.x(), cellCoords.y(), cellCoords.z()) * cellSize + halfCellSize;
+	const Vec3 cellPos =
+		Vec3(cellCoords.x(), cellCoords.y(), cellCoords.z()) * cellSize + halfCellSize + probe.m_aabbMin;
 
 	return cellPos;
 }
@@ -49,6 +50,12 @@ public:
 	RenderTargetHandle m_lightShadingRt;
 };
 
+GlobalIllumination::~GlobalIllumination()
+{
+	m_cacheEntries.destroy(getAllocator());
+	m_probeUuidToCacheEntryIdx.destroy(getAllocator());
+}
+
 Error GlobalIllumination::init(const ConfigSet& cfg)
 {
 	ANKI_R_LOGI("Initializing global illumination");
@@ -174,7 +181,7 @@ Error GlobalIllumination::initIrradiance(const ConfigSet& cfg)
 	ANKI_CHECK(m_r->getResourceManager().loadResource("shaders/IrradianceDice.glslp", m_irradiance.m_prog));
 
 	ShaderProgramResourceConstantValueInitList<1> consts(m_irradiance.m_prog);
-	consts.add("INPUT_TEXTURES_SIZE", U32(m_tileSize));
+	consts.add("INPUT_TEXTURES_HEIGHT", U32(m_tileSize));
 
 	const ShaderProgramResourceVariant* variant;
 	m_irradiance.m_prog->getOrCreateVariant(consts.get(), variant);
@@ -450,9 +457,9 @@ void GlobalIllumination::prepareProbes(RenderingContext& ctx,
 			TextureInitInfo texInit;
 			texInit.m_type = TextureType::_3D;
 			texInit.m_format = Format::B10G11R11_UFLOAT_PACK32;
-			texInit.m_width = probeToUpdateThisFrame->m_cellCounts.x();
-			texInit.m_height = probeToUpdateThisFrame->m_cellCounts.y();
-			texInit.m_depth = probeToUpdateThisFrame->m_cellCounts.z();
+			texInit.m_width = probe.m_cellCounts.x();
+			texInit.m_height = probe.m_cellCounts.y();
+			texInit.m_depth = probe.m_cellCounts.z();
 			texInit.m_usage = TextureUsageBit::ALL_COMPUTE | TextureUsageBit::SAMPLED_ALL;
 			texInit.m_initialUsage = TextureUsageBit::SAMPLED_FRAGMENT;
 
@@ -462,9 +469,6 @@ void GlobalIllumination::prepareProbes(RenderingContext& ctx,
 			}
 		}
 
-		// Inform the caller
-		probeToUpdateThisFrame = &newListOfProbes[newListOfProbeCount];
-
 		// Compute the render position
 		const U cellToRender = entry.m_renderedCells++;
 		ANKI_ASSERT(cellToRender < probe.m_totalCellCount);
@@ -491,6 +495,7 @@ void GlobalIllumination::prepareProbes(RenderingContext& ctx,
 		}
 
 		// Push the probe to the new list
+		probeToUpdateThisFrame = &newListOfProbes[newListOfProbeCount];
 		newListOfProbes[newListOfProbeCount++] = probe;
 
 		for(U i = 0; i < 6; i++)
@@ -644,6 +649,8 @@ void GlobalIllumination::runIrradiance(RenderPassWorkContext& rgraphCtx, Interna
 	ANKI_ASSERT(giCtx.m_probe);
 	const GlobalIlluminationProbeQueueElement& probe = *giCtx.m_probe;
 
+	cmdb->bindShaderProgram(m_irradiance.m_grProg);
+
 	// Bind resources
 	U binding = 0;
 	cmdb->bindSampler(0, binding++, m_r->getSamplers().m_nearestNearestClamp);

+ 5 - 0
src/anki/renderer/Renderer.cpp

@@ -28,6 +28,7 @@
 #include <anki/renderer/UiStage.h>
 #include <anki/renderer/Ssr.h>
 #include <anki/renderer/VolumetricLightingAccumulation.h>
+#include <anki/renderer/GlobalIllumination.h>
 #include <shaders/glsl_cpp_common/ClusteredShading.h>
 
 namespace anki
@@ -117,6 +118,9 @@ Error Renderer::initInternal(const ConfigSet& config)
 	m_volLighting.reset(m_alloc.newInstance<VolumetricLightingAccumulation>(this));
 	ANKI_CHECK(m_volLighting->init(config));
 
+	m_gi.reset(m_alloc.newInstance<GlobalIllumination>(this));
+	ANKI_CHECK(m_gi->init(config));
+
 	m_indirect.reset(m_alloc.newInstance<Indirect>(this));
 	ANKI_CHECK(m_indirect->init(config));
 
@@ -286,6 +290,7 @@ Error Renderer::populateRenderGraph(RenderingContext& ctx)
 
 	// Populate render graph. WARNING Watch the order
 	m_shadowMapping->populateRenderGraph(ctx);
+	m_gi->populateRenderGraph(ctx);
 	m_indirect->populateRenderGraph(ctx);
 	m_volLighting->populateRenderGraph(ctx);
 	m_gbuffer->populateRenderGraph(ctx);

+ 1 - 0
src/anki/renderer/Renderer.h

@@ -367,6 +367,7 @@ private:
 	/// @name Rendering stages
 	/// @{
 	UniquePtr<VolumetricLightingAccumulation> m_volLighting;
+	UniquePtr<GlobalIllumination> m_gi;
 	UniquePtr<Indirect> m_indirect;
 	UniquePtr<ShadowMapping> m_shadowMapping; ///< Shadow mapping.
 	UniquePtr<GBuffer> m_gbuffer; ///< Material rendering stage

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

@@ -83,7 +83,8 @@ Error CameraNode::init(FrustumType frustumType)
 		| FrustumComponentVisibilityTestFlag::LENS_FLARE_COMPONENTS
 		| FrustumComponentVisibilityTestFlag::REFLECTION_PROBES | FrustumComponentVisibilityTestFlag::REFLECTION_PROXIES
 		| FrustumComponentVisibilityTestFlag::OCCLUDERS | FrustumComponentVisibilityTestFlag::DECALS
-		| FrustumComponentVisibilityTestFlag::FOG_DENSITY_COMPONENTS | FrustumComponentVisibilityTestFlag::EARLY_Z
+		| FrustumComponentVisibilityTestFlag::FOG_DENSITY_COMPONENTS
+		| FrustumComponentVisibilityTestFlag::GLOBAL_ILLUMINATION_PROBES | FrustumComponentVisibilityTestFlag::EARLY_Z
 		| FrustumComponentVisibilityTestFlag::ALL_SHADOWS_ENABLED);
 
 	// Feedback component #2

+ 2 - 1
src/anki/scene/GlobalIlluminationProbeNode.cpp

@@ -139,7 +139,8 @@ void GlobalIlluminationProbeNode::onShapeUpdateOrProbeNeedsRendering()
 {
 	GlobalIlluminationProbeComponent& gic = getComponent<GlobalIlluminationProbeComponent>();
 
-	// Update the frustum component if the shape was updated or the probe needs rendering
+	// Update the frustum component if the shape needs rendering
+	if(gic.getMarkedForRendering())
 	{
 		// Compute effective distance
 		F32 effectiveDistance = gic.getAlignedBoundingBoxMax().x() - gic.getAlignedBoundingBoxMin().x();

+ 31 - 0
src/anki/scene/Visibility.cpp

@@ -15,6 +15,7 @@
 #include <anki/scene/components/FogDensityComponent.h>
 #include <anki/scene/components/LightComponent.h>
 #include <anki/scene/components/SpatialComponent.h>
+#include <anki/scene/components/GlobalIlluminationProbeComponent.h>
 #include <anki/renderer/MainRenderer.h>
 #include <anki/util/Logger.h>
 #include <anki/util/ThreadHive.h>
@@ -246,6 +247,9 @@ void VisibilityTestTask::test(ThreadHive& hive, U32 taskId)
 	const Bool wantsFogDensityComponents =
 		testedFrc.visibilityTestsEnabled(FrustumComponentVisibilityTestFlag::FOG_DENSITY_COMPONENTS);
 
+	const Bool wantsGiProbeCoponents =
+		testedFrc.visibilityTestsEnabled(FrustumComponentVisibilityTestFlag::GLOBAL_ILLUMINATION_PROBES);
+
 	const Bool wantsEarlyZ = testedFrc.visibilityTestsEnabled(FrustumComponentVisibilityTestFlag::EARLY_Z)
 							 && m_frcCtx->m_visCtx->m_earlyZDist > 0.0f;
 
@@ -286,6 +290,9 @@ void VisibilityTestTask::test(ThreadHive& hive, U32 taskId)
 		const FogDensityComponent* fogc = nullptr;
 		wantNode |= wantsFogDensityComponents && (fogc = node.tryGetComponent<FogDensityComponent>());
 
+		GlobalIlluminationProbeComponent* giprobec = nullptr;
+		wantNode |= wantsGiProbeCoponents && (giprobec = node.tryGetComponent<GlobalIlluminationProbeComponent>());
+
 		if(ANKI_UNLIKELY(!wantNode))
 		{
 			// Skip node
@@ -541,6 +548,29 @@ void VisibilityTestTask::test(ThreadHive& hive, U32 taskId)
 			fogc->setupFogDensityQueueElement(*el);
 		}
 
+		if(giprobec)
+		{
+			GlobalIlluminationProbeQueueElement* el = result.m_giProbes.newElement(alloc);
+			giprobec->setupGlobalIlluminationProbeQueueElement(*el);
+
+			if(giprobec->getMarkedForRendering())
+			{
+				RenderQueue* a = alloc.newArray<RenderQueue>(6);
+				nextQueues = WeakArray<RenderQueue>(a, 6);
+
+				el->m_renderQueues[0] = &nextQueues[0];
+				el->m_renderQueues[1] = &nextQueues[1];
+				el->m_renderQueues[2] = &nextQueues[2];
+				el->m_renderQueues[3] = &nextQueues[3];
+				el->m_renderQueues[4] = &nextQueues[4];
+				el->m_renderQueues[5] = &nextQueues[5];
+			}
+			else
+			{
+				el->m_renderQueues = {{nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}};
+			}
+		}
+
 		// Add more frustums to the list
 		if(nextQueues.getSize() > 0)
 		{
@@ -625,6 +655,7 @@ void CombineResultsTask::combine()
 	ANKI_VIS_COMBINE(LensFlareQueueElement, m_lensFlares);
 	ANKI_VIS_COMBINE(DecalQueueElement, m_decals);
 	ANKI_VIS_COMBINE(FogDensityQueueElement, m_fogDensityVolumes);
+	ANKI_VIS_COMBINE(GlobalIlluminationProbeQueueElement, m_giProbes);
 
 	for(U i = 0; i < threadCount; ++i)
 	{

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

@@ -115,6 +115,7 @@ public:
 	TRenderQueueElementStorage<LensFlareQueueElement> m_lensFlares;
 	TRenderQueueElementStorage<DecalQueueElement> m_decals;
 	TRenderQueueElementStorage<FogDensityQueueElement> m_fogDensityVolumes;
+	TRenderQueueElementStorage<GlobalIlluminationProbeQueueElement> m_giProbes;
 
 	Timestamp m_timestamp = 0;
 

+ 10 - 12
src/anki/scene/components/FrustumComponent.cpp

@@ -19,9 +19,6 @@ FrustumComponent::FrustumComponent(SceneNode* node, FrustumType frustumType)
 	ANKI_ASSERT(node);
 	ANKI_ASSERT(frustumType < FrustumType::COUNT);
 
-	m_flags.set(SHAPE_MARKED_FOR_UPDATE | TRANSFORM_MARKED_FOR_UPDATE);
-	setEnabledVisibilityTests(FrustumComponentVisibilityTestFlag::NONE);
-
 	// Set some default values
 	if(frustumType == FrustumType::PERSPECTIVE)
 	{
@@ -48,7 +45,7 @@ Bool FrustumComponent::updateInternal()
 	m_prevViewProjMat = m_viewProjMat;
 
 	// Update the shape
-	if(m_flags.get(SHAPE_MARKED_FOR_UPDATE))
+	if(m_shapeMarkedForUpdate)
 	{
 		updated = true;
 
@@ -105,7 +102,7 @@ Bool FrustumComponent::updateInternal()
 	}
 
 	// Update transform related things
-	if(m_flags.get(TRANSFORM_MARKED_FOR_UPDATE))
+	if(m_trfMarkedForUpdate)
 	{
 		updated = true;
 		m_viewMat = Mat4(m_trf.getInverse());
@@ -115,7 +112,8 @@ Bool FrustumComponent::updateInternal()
 	if(updated)
 	{
 		m_viewProjMat = m_projMat * m_viewMat;
-		m_flags.unset(SHAPE_MARKED_FOR_UPDATE | TRANSFORM_MARKED_FOR_UPDATE);
+		m_shapeMarkedForUpdate = false;
+		m_trfMarkedForUpdate = false;
 
 		if(m_frustumType == FrustumType::PERSPECTIVE)
 		{
@@ -156,15 +154,15 @@ void FrustumComponent::fillCoverageBufferCallback(void* userData, F32* depthValu
 
 void FrustumComponent::setEnabledVisibilityTests(FrustumComponentVisibilityTestFlag bits)
 {
-	m_flags.unset(FrustumComponentVisibilityTestFlag::ALL);
-	m_flags.set(bits, true);
+	m_flags = FrustumComponentVisibilityTestFlag::NONE;
+	m_flags |= bits;
 
 #if ANKI_ASSERTS_ENABLED
-	if(m_flags.get(FrustumComponentVisibilityTestFlag::RENDER_COMPONENTS)
-		|| m_flags.get(FrustumComponentVisibilityTestFlag::SHADOW_CASTERS))
+	if(!!(m_flags & FrustumComponentVisibilityTestFlag::RENDER_COMPONENTS)
+		|| !!(m_flags & FrustumComponentVisibilityTestFlag::SHADOW_CASTERS))
 	{
-		if(m_flags.get(FrustumComponentVisibilityTestFlag::RENDER_COMPONENTS)
-			== m_flags.get(FrustumComponentVisibilityTestFlag::SHADOW_CASTERS))
+		if((m_flags & FrustumComponentVisibilityTestFlag::RENDER_COMPONENTS)
+			== (m_flags & FrustumComponentVisibilityTestFlag::SHADOW_CASTERS))
 		{
 			ANKI_ASSERT(0 && "Cannot have them both");
 		}

+ 16 - 19
src/anki/scene/components/FrustumComponent.h

@@ -36,13 +36,15 @@ enum class FrustumComponentVisibilityTestFlag : U16
 	OCCLUDERS = 1 << 10,
 	DECALS = 1 << 11,
 	FOG_DENSITY_COMPONENTS = 1 << 12,
-	EARLY_Z = 1 << 13,
+	GLOBAL_ILLUMINATION_PROBES = 1 << 13,
+	EARLY_Z = 1 << 14,
 
 	LAST = EARLY_Z,
 
 	ALL = RENDER_COMPONENTS | LIGHT_COMPONENTS | LENS_FLARE_COMPONENTS | SHADOW_CASTERS | POINT_LIGHT_SHADOWS_ENABLED
 		  | SPOT_LIGHT_SHADOWS_ENABLED | DIRECTIONAL_LIGHT_SHADOWS_ALL_CASCADES | DIRECTIONAL_LIGHT_SHADOWS_1_CASCADE
-		  | REFLECTION_PROBES | REFLECTION_PROXIES | OCCLUDERS | DECALS | FOG_DENSITY_COMPONENTS | EARLY_Z,
+		  | REFLECTION_PROBES | REFLECTION_PROXIES | OCCLUDERS | DECALS | FOG_DENSITY_COMPONENTS
+		  | GLOBAL_ILLUMINATION_PROBES | EARLY_Z,
 
 	ALL_SHADOWS_ENABLED =
 		POINT_LIGHT_SHADOWS_ENABLED | SPOT_LIGHT_SHADOWS_ENABLED | DIRECTIONAL_LIGHT_SHADOWS_ALL_CASCADES
@@ -78,7 +80,7 @@ public:
 		m_perspective.m_far = far;
 		m_perspective.m_fovX = fovX;
 		m_perspective.m_fovY = fovY;
-		m_flags.set(SHAPE_MARKED_FOR_UPDATE);
+		m_shapeMarkedForUpdate = true;
 	}
 
 	void setOrthographic(F32 near, F32 far, F32 right, F32 left, F32 top, F32 bottom)
@@ -92,13 +94,13 @@ public:
 		m_ortho.m_left = left;
 		m_ortho.m_top = top;
 		m_ortho.m_bottom = bottom;
-		m_flags.set(SHAPE_MARKED_FOR_UPDATE);
+		m_shapeMarkedForUpdate = true;
 	}
 
 	void setNear(F32 near)
 	{
 		m_common.m_near = near;
-		m_flags.set(SHAPE_MARKED_FOR_UPDATE);
+		m_shapeMarkedForUpdate = true;
 	}
 
 	F32 getNear() const
@@ -109,7 +111,7 @@ public:
 	void setFar(F32 far)
 	{
 		m_common.m_far = far;
-		m_flags.set(SHAPE_MARKED_FOR_UPDATE);
+		m_shapeMarkedForUpdate = true;
 	}
 
 	F32 getFar() const
@@ -120,7 +122,7 @@ public:
 	void setFovX(F32 fovx)
 	{
 		ANKI_ASSERT(m_frustumType == FrustumType::PERSPECTIVE);
-		m_flags.set(SHAPE_MARKED_FOR_UPDATE);
+		m_shapeMarkedForUpdate = true;
 		m_perspective.m_fovX = fovx;
 	}
 
@@ -133,7 +135,7 @@ public:
 	void setFovY(F32 fovy)
 	{
 		ANKI_ASSERT(m_frustumType == FrustumType::PERSPECTIVE);
-		m_flags.set(SHAPE_MARKED_FOR_UPDATE);
+		m_shapeMarkedForUpdate = true;
 		m_perspective.m_fovY = fovy;
 	}
 
@@ -156,7 +158,7 @@ public:
 	void setTransform(const Transform& trf)
 	{
 		m_trf = trf;
-		m_flags.set(TRANSFORM_MARKED_FOR_UPDATE);
+		m_trfMarkedForUpdate = true;
 	}
 
 	const Mat4& getProjectionMatrix() const
@@ -205,12 +207,12 @@ public:
 
 	Bool visibilityTestsEnabled(FrustumComponentVisibilityTestFlag bits) const
 	{
-		return m_flags.get(bits);
+		return !!(m_flags & bits);
 	}
 
 	Bool anyVisibilityTestEnabled() const
 	{
-		return m_flags.getAny(FrustumComponentVisibilityTestFlag::ALL);
+		return !!(m_flags & FrustumComponentVisibilityTestFlag::ALL);
 	}
 
 	/// The type is FillCoverageBufferCallback.
@@ -267,13 +269,6 @@ public:
 	}
 
 private:
-	enum Flags : U16
-	{
-		SHAPE_MARKED_FOR_UPDATE = static_cast<U16>(FrustumComponentVisibilityTestFlag::LAST) << 1,
-		TRANSFORM_MARKED_FOR_UPDATE = static_cast<U16>(FrustumComponentVisibilityTestFlag::LAST) << 2,
-	};
-	ANKI_ENUM_ALLOW_NUMERIC_OPERATIONS(Flags, friend)
-
 	class Common
 	{
 	public:
@@ -334,7 +329,9 @@ private:
 		U32 m_depthMapHeight = 0;
 	} m_coverageBuff; ///< Coverage buffer for extra visibility tests.
 
-	BitMask<U16> m_flags = {0};
+	FrustumComponentVisibilityTestFlag m_flags = FrustumComponentVisibilityTestFlag::NONE;
+	Bool m_shapeMarkedForUpdate = true;
+	Bool m_trfMarkedForUpdate = true;
 
 	Bool updateInternal();
 };

+ 1 - 1
src/anki/scene/components/GlobalIlluminationProbeComponent.h

@@ -30,7 +30,7 @@ public:
 	/// Set the bounding box in world coordinates.
 	void setBoundingBox(const Vec4& min, const Vec4& max)
 	{
-		ANKI_ASSERT(min < max);
+		ANKI_ASSERT(min.xyz() < max.xyz());
 		m_aabbMin = min.xyz();
 		m_aabbMax = max.xyz();
 		updateMembers();

+ 31 - 21
tools/blender_anki_additions.patch

@@ -1,8 +1,21 @@
+diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh
+index 6cd725494b3..6ce61b8c7d6 100755
+--- a/build_files/build_environment/install_deps.sh
++++ b/build_files/build_environment/install_deps.sh
+@@ -340,7 +340,7 @@ LLVM_FORCE_REBUILD=false
+ LLVM_SKIP=false
+ 
+ # OSL needs to be compiled for now!
+-OSL_VERSION="1.7.5"
++OSL_VERSION="1.8.10"
+ OSL_VERSION_MIN=$OSL_VERSION
+ OSL_FORCE_BUILD=false
+ OSL_FORCE_REBUILD=false
 diff --git a/source/blender/collada/EffectExporter.cpp b/source/blender/collada/EffectExporter.cpp
-index 76b5114..11ea02e 100644
+index d33ce725e58..bf36943b324 100644
 --- a/source/blender/collada/EffectExporter.cpp
 +++ b/source/blender/collada/EffectExporter.cpp
-@@ -47,7 +47,9 @@ extern "C" {
+@@ -46,7 +46,9 @@ extern "C" {
  	#include "BKE_customdata.h"
  	#include "BKE_mesh.h"
  	#include "BKE_material.h"
@@ -10,9 +23,9 @@ index 76b5114..11ea02e 100644
  }
 +#include <sstream>
  
- // OB_MESH is assumed
- static std::string getActiveUVLayerName(Object *ob)
-@@ -170,6 +172,26 @@ void EffectsExporter::writeTextures(COLLADASW::EffectProfile &ep,
+ EffectsExporter::EffectsExporter(COLLADASW::StreamWriter *sw, const ExportSettings *export_settings) : COLLADASW::LibraryEffects(sw), export_settings(export_settings) {
+ }
+@@ -196,6 +198,26 @@ void EffectsExporter::writeTextures(
  		texture.setChildElementName("bump");
  		ep.addExtraTechniqueColorOrTexture(COLLADASW::ColorOrTexture(texture));
  	}
@@ -22,7 +35,7 @@ index 76b5114..11ea02e 100644
 +		texture.setTexcoord(uvname);
 +		texture.setSampler(*sampler);
 +		texture.setProfileName("blender");
-+		texture.setChildElementName("roughness");
++		texture.setChildElementName("roughness_tex");
 +		ep.addExtraTechniqueColorOrTexture(COLLADASW::ColorOrTexture(texture));
 +	}
 +	if (t->mapto & MAP_DISPLACE) {
@@ -39,8 +52,8 @@ index 76b5114..11ea02e 100644
  }
  
  void EffectsExporter::operator()(Material *ma, Object *ob)
-@@ -398,6 +420,68 @@ void EffectsExporter::operator()(Material *ma, Object *ob)
- 		}
+@@ -358,6 +380,68 @@ void EffectsExporter::operator()(Material *ma, Object *ob)
+ 		writeTextures(ep, key, sampler, t, ima, uvname);
  	}
  
 +	// AnKi: Export extra properties
@@ -109,7 +122,7 @@ index 76b5114..11ea02e 100644
  	ep.addProfileElements();
  	bool twoSided = false;
 diff --git a/source/blender/collada/GeometryExporter.cpp b/source/blender/collada/GeometryExporter.cpp
-index 7c7c57f..b02ba47 100644
+index 4b693332715..b554d7e2422 100644
 --- a/source/blender/collada/GeometryExporter.cpp
 +++ b/source/blender/collada/GeometryExporter.cpp
 @@ -47,6 +47,7 @@ extern "C" {
@@ -120,12 +133,10 @@ index 7c7c57f..b02ba47 100644
  }
  
  #include "collada_internal.h"
-@@ -143,13 +144,133 @@ void GeometryExporter::operator()(Object *ob)
- 			createPolylist(0, has_uvs, has_color, ob, me, geom_id, norind);
+@@ -154,12 +155,133 @@ void GeometryExporter::operator()(Object *ob)
  		}
  	}
--	
-+
+ 
 +	// AnKi: Export mesh properties
 +	{
 +		static const char *property_names[] = {
@@ -136,6 +147,7 @@ index 7c7c57f..b02ba47 100644
 +			"lod1",
 +			"skip",
 +			"reflection_probe",
++			"gi_probe",
 +			"reflection_proxy",
 +			"occluder",
 +			"collision_mesh",
@@ -204,7 +216,7 @@ index 7c7c57f..b02ba47 100644
 +	}
 +
  	closeMesh();
- 	
+ 
  	if (me->flag & ME_TWOSIDED) {
  		mSW->appendTextBlock("<extra><technique profile=\"MAYA\"><double_sided>1</double_sided></technique></extra>");
  	}
@@ -256,7 +268,7 @@ index 7c7c57f..b02ba47 100644
  
  	if (this->export_settings->include_shapekeys) {
 diff --git a/source/blender/collada/LightExporter.cpp b/source/blender/collada/LightExporter.cpp
-index ff50abf..205f687 100644
+index 02c5438ec47..6db17d8d082 100644
 --- a/source/blender/collada/LightExporter.cpp
 +++ b/source/blender/collada/LightExporter.cpp
 @@ -31,6 +31,9 @@
@@ -277,12 +289,10 @@ index ff50abf..205f687 100644
  		addLight(cla);
  	}
  	// lamp
-@@ -190,6 +194,49 @@ bool LightsExporter::exportBlenderProfile(COLLADASW::Light &cla, Lamp *la)
- 	cla.addExtraTechniqueParameter("blender", "skyblendfac", la->skyblendfac);
+@@ -191,5 +195,48 @@ bool LightsExporter::exportBlenderProfile(COLLADASW::Light &cla, Lamp *la)
  	cla.addExtraTechniqueParameter("blender", "sky_exposure", la->sky_exposure);
  	cla.addExtraTechniqueParameter("blender", "sky_colorspace", la->sky_colorspace);
--	
-+
+ 
 +	// AnKi: Export properties
 +	static const char *property_names[] = {
 +		"lens_flare",
@@ -329,7 +339,7 @@ index ff50abf..205f687 100644
  	return true;
  }
 diff --git a/source/blender/collada/SceneExporter.cpp b/source/blender/collada/SceneExporter.cpp
-index 30cd6dd..17563dd 100644
+index 4e08548449f..4eb2580dd6b 100644
 --- a/source/blender/collada/SceneExporter.cpp
 +++ b/source/blender/collada/SceneExporter.cpp
 @@ -28,6 +28,7 @@ extern "C" {
@@ -340,7 +350,7 @@ index 30cd6dd..17563dd 100644
  }
  
  #include "SceneExporter.h"
-@@ -234,6 +235,14 @@ void SceneExporter::writeNodes(Object *ob, Scene *sce)
+@@ -232,6 +233,14 @@ void SceneExporter::writeNodes(bContext *C, Object *ob, Scene *sce)
  		}
  	}
  

+ 1 - 1
tools/blender_anki_additions_readme.txt

@@ -4,4 +4,4 @@ Follow the blender build instuctions. Use the following to build the external:
 
 The command above will give CMAKE options. Add this as well -DOPENCOLLADA_ROOT_DIR
 
-Commit the patch is based upon: c05363e8895a8cd6daa2241706d357c47ed4a83e
+Commit the patch is based upon: 78a8d3685bd3487eb0b5dd55793f94fe7235e377

+ 38 - 1
tools/scene/Exporter.cpp

@@ -833,6 +833,23 @@ void Exporter::visitNode(const aiNode* ainode)
 
 				special = true;
 			}
+			else if(prop.first == "gi_probe" && prop.second == "true")
+			{
+				GiProbe probe;
+				aiMatrix4x4 trf = toAnkiMatrix(ainode->mTransformation);
+				probe.m_position = aiVector3D(trf.a4, trf.b4, trf.c4);
+
+				aiVector3D scale(trf.a1, trf.b2, trf.c3);
+				assert(scale.x > 0.0f && scale.y > 0.0f && scale.z > 0.0f);
+
+				aiVector3D half = scale;
+				probe.m_aabbMin = probe.m_position - half - probe.m_position;
+				probe.m_aabbMax = probe.m_position + half - probe.m_position;
+
+				m_giProbes.push_back(probe);
+
+				special = true;
+			}
 			else if(prop.first == "reflection_proxy" && prop.second == "true")
 			{
 				ReflectionProxy proxy;
@@ -1015,7 +1032,7 @@ void Exporter::exportAll()
 	}
 
 	//
-	// Export probes
+	// Export refl probes
 	//
 	i = 0;
 	for(const ReflectionProbe& probe : m_reflectionProbes)
@@ -1032,6 +1049,26 @@ void Exporter::exportAll()
 		++i;
 	}
 
+	//
+	// Export GI probes
+	//
+	i = 0;
+	for(const GiProbe& probe : m_giProbes)
+	{
+		std::string name = "giprobe" + std::to_string(i);
+		file << "\nnode = scene:newGlobalIlluminationProbeNode(\"" << name << "\")\n";
+
+		file << "comp = node:getSceneNodeBase():getGlobalIlluminationProbeComponent()\n";
+		file << "comp:setBoundingBox(Vec4.new(" << probe.m_aabbMin.x << ", " << probe.m_aabbMin.y << ", "
+			 << probe.m_aabbMin.z << ", 0), Vec4.new(" << probe.m_aabbMax.x << ", " << probe.m_aabbMax.y << ", "
+			 << probe.m_aabbMax.z << ", 0))\n";
+
+		aiMatrix4x4 trf;
+		aiMatrix4x4::Translation(probe.m_position, trf);
+		writeNodeTransform("node", trf);
+		++i;
+	}
+
 	//
 	// Export proxies
 	//

+ 3 - 0
tools/scene/Exporter.h

@@ -72,6 +72,8 @@ public:
 	aiVector3D m_aabbMax;
 };
 
+using GiProbe = ReflectionProbe;
+
 class ReflectionProxy
 {
 public:
@@ -122,6 +124,7 @@ public:
 	std::vector<StaticCollisionNode> m_staticCollisionNodes;
 	std::vector<ParticleEmitter> m_particleEmitters;
 	std::vector<ReflectionProbe> m_reflectionProbes;
+	std::vector<GiProbe> m_giProbes;
 	std::vector<ReflectionProxy> m_reflectionProxies;
 	std::vector<OccluderNode> m_occluders;
 	std::vector<DecalNode> m_decals;