浏览代码

Add some debug drawing on some scene components

Panagiotis Christopoulos Charitos 6 年之前
父节点
当前提交
e99cf7d620

二进制
engine_data/GreenDecal.ankitex


二进制
engine_data/LightBulb.ankitex


二进制
engine_data/Mirror.ankitex


二进制
engine_data/SpotLight.ankitex


+ 2 - 1
shaders/FinalComposite.glslp

@@ -104,7 +104,8 @@ void main()
 #endif
 
 #if DBG_ENABLED
-	out_color += textureLod(u_dbgRt, u_linearAnyClampSampler, uv, 0.0).rgb;
+	const Vec4 dbg = textureLod(u_dbgRt, u_linearAnyClampSampler, uv, 0.0);
+	out_color = mix(out_color, dbg.rgb, dbg.a);
 #endif
 }
 

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

@@ -105,7 +105,7 @@ const Format LIGHT_SHADING_COLOR_ATTACHMENT_PIXEL_FORMAT = Format::B10G11R11_UFL
 
 const Format FORWARD_SHADING_COLOR_ATTACHMENT_PIXEL_FORMAT = Format::R16G16B16A16_SFLOAT;
 
-const Format DBG_COLOR_ATTACHMENT_PIXEL_FORMAT = Format::R8G8B8_UNORM;
+const Format DBG_COLOR_ATTACHMENT_PIXEL_FORMAT = Format::R8G8B8A8_UNORM;
 
 const Format SHADOW_DEPTH_PIXEL_FORMAT = Format::D32_SFLOAT;
 const Format SHADOW_COLOR_PIXEL_FORMAT = Format::R16_UNORM;

+ 33 - 2
src/anki/renderer/Dbg.cpp

@@ -66,6 +66,8 @@ void Dbg::run(RenderPassWorkContext& rgraphCtx, const RenderingContext& ctx)
 
 	rgraphCtx.bindTexture(0, 1, m_r->getGBuffer().getDepthRt(), TextureSubresourceInfo(DepthStencilAspectBit::DEPTH));
 
+	cmdb->setBlendFactors(0, BlendFactor::SRC_ALPHA, BlendFactor::ONE_MINUS_SRC_ALPHA);
+
 	// Set the context
 	RenderQueueDrawContext dctx;
 	dctx.m_viewMatrix = ctx.m_renderQueue->m_viewMatrix;
@@ -73,6 +75,7 @@ void Dbg::run(RenderPassWorkContext& rgraphCtx, const RenderingContext& ctx)
 	dctx.m_projectionMatrix = ctx.m_renderQueue->m_projectionMatrix;
 	dctx.m_cameraTransform = ctx.m_renderQueue->m_viewMatrix.getInverse();
 	dctx.m_stagingGpuAllocator = &m_r->getStagingGpuMemoryManager();
+	dctx.m_frameAllocator = ctx.m_tempAllocator;
 	dctx.m_commandBuffer = cmdb;
 	dctx.m_sampler = m_r->getSamplers().m_trilinearRepeatAniso;
 	dctx.m_key = RenderingKey(Pass::FS, 0, 1, false, false);
@@ -90,7 +93,7 @@ void Dbg::run(RenderPassWorkContext& rgraphCtx, const RenderingContext& ctx)
 	{
 		const RenderableQueueElement& el = ctx.m_renderQueue->m_renderables[i];
 		Array<void*, 1> a = {{const_cast<void*>(el.m_userData)}};
-		el.m_callback(dctx, a);
+		// el.m_callback(dctx, a);
 	}
 
 	// Draw probes
@@ -98,7 +101,35 @@ void Dbg::run(RenderPassWorkContext& rgraphCtx, const RenderingContext& ctx)
 	{
 		for(const GlobalIlluminationProbeQueueElement& el : ctx.m_renderQueue->m_giProbes)
 		{
-			Array<void*, 1> a = {{const_cast<void*>(el.m_userData)}};
+			Array<void*, 1> a = {{const_cast<void*>(el.m_debugDrawCallbackUserData)}};
+			el.m_debugDrawCallback(dctx, a);
+		}
+	}
+
+	// Draw lights
+	if(threadId == 0)
+	{
+		U count = ctx.m_renderQueue->m_pointLights.getSize();
+		while(count--)
+		{
+			const PointLightQueueElement& el = ctx.m_renderQueue->m_pointLights[count];
+			Array<void*, 1> a = {{const_cast<void*>(el.m_debugDrawCallbackUserData)}};
+			el.m_debugDrawCallback(dctx, a);
+		}
+
+		for(const SpotLightQueueElement& el : ctx.m_renderQueue->m_spotLights)
+		{
+			Array<void*, 1> a = {{const_cast<void*>(el.m_debugDrawCallbackUserData)}};
+			el.m_debugDrawCallback(dctx, a);
+		}
+	}
+
+	// Decals
+	if(threadId == 0)
+	{
+		for(const DecalQueueElement& el : ctx.m_renderQueue->m_decals)
+		{
+			Array<void*, 1> a = {{const_cast<void*>(el.m_debugDrawCallbackUserData)}};
 			el.m_debugDrawCallback(dctx, a);
 		}
 	}

+ 3 - 3
src/anki/renderer/GlobalIllumination.cpp

@@ -478,7 +478,7 @@ void GlobalIllumination::prepareProbes(InternalContext& giCtx)
 
 			const U cellToRender = (cacheEntryDirty) ? 0 : entry.m_renderedCells;
 			const Vec3 cellPos = computeProbeCellPosition(cellToRender, probe);
-			probe.m_feedbackCallback(true, probe.m_userData, cellPos.xyz0());
+			probe.m_feedbackCallback(true, probe.m_feedbackCallbackUserData, cellPos.xyz0());
 			continue;
 		}
 		else if(!canUpdateThisFrame)
@@ -533,14 +533,14 @@ void GlobalIllumination::prepareProbes(InternalContext& giCtx)
 		if(entry.m_renderedCells == probe.m_totalCellCount)
 		{
 			// Don't gather renderables next frame if it's done
-			probe.m_feedbackCallback(false, probe.m_userData, Vec4(0.0f));
+			probe.m_feedbackCallback(false, probe.m_feedbackCallbackUserData, Vec4(0.0f));
 		}
 		else if(!foundProbeToUpdateNextFrame)
 		{
 			// Gather rendederables from the same probe next frame
 			foundProbeToUpdateNextFrame = true;
 			const Vec3 cellPos = computeProbeCellPosition(entry.m_renderedCells, probe);
-			probe.m_feedbackCallback(true, probe.m_userData, cellPos.xyz0());
+			probe.m_feedbackCallback(true, probe.m_feedbackCallbackUserData, cellPos.xyz0());
 		}
 
 		// Push the probe to the new list

+ 10 - 8
src/anki/renderer/RenderQueue.h

@@ -42,6 +42,7 @@ public:
 	CommandBufferPtr m_commandBuffer;
 	SamplerPtr m_sampler; ///< A trilinear sampler with anisotropy.
 	StagingGpuMemoryManager* m_stagingGpuAllocator ANKI_DEBUG_CODE(= nullptr);
+	StackAllocator<U8> m_frameAllocator;
 	Bool m_debugDraw; ///< If true the drawcall should be drawing some kind of debug mesh.
 	BitSet<U(RenderQueueDebugDrawFlag::COUNT), U32> m_debugDrawFlags = {false};
 };
@@ -106,8 +107,8 @@ public:
 	F32 m_radius;
 	Vec3 m_diffuseColor;
 	Array<RenderQueue*, 6> m_shadowRenderQueues;
-	const void* m_userData;
-	RenderQueueDrawCallback m_drawCallback;
+	RenderQueueDrawCallback m_debugDrawCallback;
+	const void* m_debugDrawCallbackUserData;
 
 	Array<Vec2, 6> m_shadowAtlasTileOffsets; ///< Renderer internal.
 	F32 m_shadowAtlasTileSize; ///< Renderer internal.
@@ -137,8 +138,8 @@ public:
 	F32 m_innerAngle;
 	Vec3 m_diffuseColor;
 	RenderQueue* m_shadowRenderQueue;
-	const void* m_userData;
-	RenderQueueDrawCallback m_drawCallback;
+	RenderQueueDrawCallback m_debugDrawCallback;
+	const void* m_debugDrawCallbackUserData;
 
 	SpotLightQueueElement()
 	{
@@ -158,8 +159,8 @@ class DirectionalLightQueueElement final
 public:
 	Array<Mat4, MAX_SHADOW_CASCADES> m_textureMatrices;
 	Array<RenderQueue*, MAX_SHADOW_CASCADES> m_shadowRenderQueues;
-	const void* m_userData;
 	RenderQueueDrawCallback m_drawCallback;
+	const void* m_drawCallbackUserData;
 	U64 m_uuid; ///< Zero means that there is no dir light
 	Vec3 m_diffuseColor;
 	Vec3 m_direction;
@@ -210,8 +211,9 @@ class GlobalIlluminationProbeQueueElement final
 public:
 	U64 m_uuid;
 	GlobalIlluminationProbeQueueElementFeedbackCallback m_feedbackCallback;
+	void* m_feedbackCallbackUserData;
 	RenderQueueDrawCallback m_debugDrawCallback;
-	void* m_userData;
+	const void* m_debugDrawCallbackUserData;
 	Array<RenderQueue*, 6> m_renderQueues;
 	Vec3 m_aabbMin;
 	Vec3 m_aabbMax;
@@ -263,8 +265,8 @@ static_assert(std::is_trivially_destructible<LensFlareQueueElement>::value == tr
 class DecalQueueElement final
 {
 public:
-	const void* m_userData;
-	RenderQueueDrawCallback m_drawCallback;
+	RenderQueueDrawCallback m_debugDrawCallback;
+	const void* m_debugDrawCallbackUserData;
 	/// Totaly unsafe but we can't have a smart ptr in here since there will be no deletion.
 	TextureView* m_diffuseAtlas;
 	/// Totaly unsafe but we can't have a smart ptr in here since there will be no deletion.

+ 168 - 0
src/anki/scene/DebugDrawer.cpp

@@ -293,4 +293,172 @@ void allocateAndPopulateDebugBox(StagingGpuMemoryManager& stagingGpuAllocator,
 	indexCount = INDEX_COUNT;
 }
 
+Error DebugDrawer2::init(ResourceManager* rsrcManager)
+{
+	return rsrcManager->loadResource("shaders/SceneDebug.glslp", m_prog);
+}
+
+void DebugDrawer2::drawCubes(ConstWeakArray<Mat4> mvps,
+	const Vec4& color,
+	F32 lineSize,
+	Bool ditherFailedDepth,
+	F32 cubeSideSize,
+	StagingGpuMemoryManager& stagingGpuAllocator,
+	CommandBufferPtr& cmdb) const
+{
+	StagingGpuMemoryToken vertsToken;
+	StagingGpuMemoryToken indicesToken;
+
+	Vec3* verts = static_cast<Vec3*>(
+		stagingGpuAllocator.allocateFrame(sizeof(Vec3) * 8, StagingGpuMemoryType::VERTEX, vertsToken));
+
+	const F32 size = cubeSideSize / 2.0f;
+	verts[0] = Vec3(size, size, size); // front top right
+	verts[1] = Vec3(-size, size, size); // front top left
+	verts[2] = Vec3(-size, -size, size); // front bottom left
+	verts[3] = Vec3(size, -size, size); // front bottom right
+	verts[4] = Vec3(size, size, -size); // back top right
+	verts[5] = Vec3(-size, size, -size); // back top left
+	verts[6] = Vec3(-size, -size, -size); // back bottom left
+	verts[7] = Vec3(size, -size, -size); // back bottom right
+
+	const U INDEX_COUNT = 12 * 2;
+	U16* indices = static_cast<U16*>(
+		stagingGpuAllocator.allocateFrame(sizeof(U16) * INDEX_COUNT, StagingGpuMemoryType::VERTEX, indicesToken));
+
+	U indexCount = 0;
+	indices[indexCount++] = 0;
+	indices[indexCount++] = 1;
+	indices[indexCount++] = 1;
+	indices[indexCount++] = 2;
+	indices[indexCount++] = 2;
+	indices[indexCount++] = 3;
+	indices[indexCount++] = 3;
+	indices[indexCount++] = 0;
+
+	indices[indexCount++] = 4;
+	indices[indexCount++] = 5;
+	indices[indexCount++] = 5;
+	indices[indexCount++] = 6;
+	indices[indexCount++] = 6;
+	indices[indexCount++] = 7;
+	indices[indexCount++] = 7;
+	indices[indexCount++] = 4;
+
+	indices[indexCount++] = 0;
+	indices[indexCount++] = 4;
+	indices[indexCount++] = 1;
+	indices[indexCount++] = 5;
+	indices[indexCount++] = 2;
+	indices[indexCount++] = 6;
+	indices[indexCount++] = 3;
+	indices[indexCount++] = 7;
+
+	// Set the uniforms
+	StagingGpuMemoryToken unisToken;
+	Mat4* pmvps = static_cast<Mat4*>(stagingGpuAllocator.allocateFrame(
+		sizeof(Mat4) * mvps.getSize() + sizeof(Vec4), StagingGpuMemoryType::UNIFORM, unisToken));
+
+	memcpy(pmvps, &mvps[0], mvps.getSizeInBytes());
+
+	Vec4* pcolor = reinterpret_cast<Vec4*>(pmvps + mvps.getSize());
+	*pcolor = color;
+
+	// Setup state
+	ShaderProgramResourceMutationInitList<2> mutators(m_prog);
+	mutators.add("COLOR_TEXTURE", 0);
+	mutators.add("DITHERED_DEPTH_TEST", U(ditherFailedDepth != 0));
+	ShaderProgramResourceConstantValueInitList<1> consts(m_prog);
+	consts.add("INSTANCE_COUNT", U32(mvps.getSize()));
+	const ShaderProgramResourceVariant* variant;
+	m_prog->getOrCreateVariant(mutators.get(), consts.get(), variant);
+	cmdb->bindShaderProgram(variant->getProgram());
+
+	cmdb->setVertexAttribute(0, 0, Format::R32G32B32_SFLOAT, 0);
+	cmdb->bindVertexBuffer(0, vertsToken.m_buffer, vertsToken.m_offset, sizeof(Vec3));
+	cmdb->bindIndexBuffer(indicesToken.m_buffer, indicesToken.m_offset, IndexType::U16);
+
+	cmdb->bindUniformBuffer(1, 0, unisToken.m_buffer, unisToken.m_offset, unisToken.m_range);
+
+	cmdb->setLineWidth(lineSize);
+	cmdb->drawElements(PrimitiveTopology::LINES, indexCount, mvps.getSize());
+}
+
+void DebugDrawer2::drawBillboardTextures(const Mat4& projMat,
+	const Mat4& viewMat,
+	ConstWeakArray<Vec3> positions,
+	const Vec4& color,
+	Bool ditherFailedDepth,
+	TextureViewPtr tex,
+	SamplerPtr sampler,
+	Vec2 billboardSize,
+	StagingGpuMemoryManager& stagingGpuAllocator,
+	CommandBufferPtr& cmdb) const
+{
+	StagingGpuMemoryToken positionsToken;
+	Vec3* verts = static_cast<Vec3*>(
+		stagingGpuAllocator.allocateFrame(sizeof(Vec3) * 4, StagingGpuMemoryType::VERTEX, positionsToken));
+
+	verts[0] = Vec3(-0.5f, -0.5f, 0.0f);
+	verts[1] = Vec3(+0.5f, -0.5f, 0.0f);
+	verts[2] = Vec3(-0.5f, +0.5f, 0.0f);
+	verts[3] = Vec3(+0.5f, +0.5f, 0.0f);
+
+	StagingGpuMemoryToken uvsToken;
+	Vec2* uvs =
+		static_cast<Vec2*>(stagingGpuAllocator.allocateFrame(sizeof(Vec2) * 4, StagingGpuMemoryType::VERTEX, uvsToken));
+
+	uvs[0] = Vec2(0.0f, 0.0f);
+	uvs[1] = Vec2(1.0f, 0.0f);
+	uvs[2] = Vec2(0.0f, 1.0f);
+	uvs[3] = Vec2(1.0f, 1.0f);
+
+	// Set the uniforms
+	StagingGpuMemoryToken unisToken;
+	Mat4* pmvps = static_cast<Mat4*>(stagingGpuAllocator.allocateFrame(
+		sizeof(Mat4) * positions.getSize() + sizeof(Vec4), StagingGpuMemoryType::UNIFORM, unisToken));
+
+	const Mat4 camTrf = viewMat.getInverse();
+	const Vec3 zAxis = camTrf.getZAxis().xyz().getNormalized();
+	Vec3 yAxis = Vec3(0.0f, 1.0f, 0.0f);
+	const Vec3 xAxis = yAxis.cross(zAxis).getNormalized();
+	yAxis = zAxis.cross(xAxis).getNormalized();
+	Mat3 rot;
+	rot.setColumns(xAxis, yAxis, zAxis);
+
+	for(const Vec3& pos : positions)
+	{
+		Mat3 scale = Mat3::getIdentity();
+		scale(0, 0) *= billboardSize.x();
+		scale(1, 1) *= billboardSize.y();
+
+		*pmvps = projMat * viewMat * Mat4(pos.xyz1(), rot * scale, 1.0f);
+		++pmvps;
+	}
+
+	Vec4* pcolor = reinterpret_cast<Vec4*>(pmvps);
+	*pcolor = color;
+
+	// Setup state
+	ShaderProgramResourceMutationInitList<2> mutators(m_prog);
+	mutators.add("COLOR_TEXTURE", 1);
+	mutators.add("DITHERED_DEPTH_TEST", U(ditherFailedDepth != 0));
+	ShaderProgramResourceConstantValueInitList<1> consts(m_prog);
+	consts.add("INSTANCE_COUNT", U32(positions.getSize()));
+	const ShaderProgramResourceVariant* variant;
+	m_prog->getOrCreateVariant(mutators.get(), consts.get(), variant);
+	cmdb->bindShaderProgram(variant->getProgram());
+
+	cmdb->setVertexAttribute(0, 0, Format::R32G32B32_SFLOAT, 0);
+	cmdb->setVertexAttribute(1, 1, Format::R32G32_SFLOAT, 0);
+	cmdb->bindVertexBuffer(0, positionsToken.m_buffer, positionsToken.m_offset, sizeof(Vec3));
+	cmdb->bindVertexBuffer(1, uvsToken.m_buffer, uvsToken.m_offset, sizeof(Vec2));
+
+	cmdb->bindUniformBuffer(1, 0, unisToken.m_buffer, unisToken.m_offset, unisToken.m_range);
+	cmdb->bindSampler(1, 1, sampler);
+	cmdb->bindTexture(1, 2, tex, TextureUsageBit::SAMPLED_FRAGMENT);
+
+	cmdb->drawArrays(PrimitiveTopology::TRIANGLE_STRIP, 4, positions.getSize());
+}
+
 } // end namespace anki

+ 64 - 0
src/anki/scene/DebugDrawer.h

@@ -126,6 +126,70 @@ void allocateAndPopulateDebugBox(StagingGpuMemoryManager& stagingGpuAllocator,
 	StagingGpuMemoryToken& vertsToken,
 	StagingGpuMemoryToken& indicesToken,
 	U32& indexCount);
+
+/// Debug drawer.
+class DebugDrawer2
+{
+public:
+	ANKI_USE_RESULT Error init(ResourceManager* rsrcManager);
+
+	void drawCubes(ConstWeakArray<Mat4> mvps,
+		const Vec4& color,
+		F32 lineSize,
+		Bool ditherFailedDepth,
+		F32 cubeSideSize,
+		StagingGpuMemoryManager& stagingGpuAllocator,
+		CommandBufferPtr& cmdb) const;
+
+	void drawCube(const Mat4& mvp,
+		const Vec4& color,
+		F32 lineSize,
+		Bool ditherFailedDepth,
+		F32 cubeSideSize,
+		StagingGpuMemoryManager& stagingGpuAllocator,
+		CommandBufferPtr& cmdb) const
+	{
+		drawCubes(
+			ConstWeakArray<Mat4>(&mvp, 1), color, lineSize, ditherFailedDepth, cubeSideSize, stagingGpuAllocator, cmdb);
+	}
+
+	void drawBillboardTextures(const Mat4& projMat,
+		const Mat4& viewMat,
+		ConstWeakArray<Vec3> positions,
+		const Vec4& color,
+		Bool ditherFailedDepth,
+		TextureViewPtr tex,
+		SamplerPtr sampler,
+		Vec2 billboardSize,
+		StagingGpuMemoryManager& stagingGpuAllocator,
+		CommandBufferPtr& cmdb) const;
+
+	void drawBillboardTexture(const Mat4& projMat,
+		const Mat4& viewMat,
+		Vec3 position,
+		const Vec4& color,
+		Bool ditherFailedDepth,
+		TextureViewPtr tex,
+		SamplerPtr sampler,
+		Vec2 billboardSize,
+		StagingGpuMemoryManager& stagingGpuAllocator,
+		CommandBufferPtr& cmdb) const
+	{
+		drawBillboardTextures(projMat,
+			viewMat,
+			ConstWeakArray<Vec3>(&position, 1),
+			color,
+			ditherFailedDepth,
+			tex,
+			sampler,
+			billboardSize,
+			stagingGpuAllocator,
+			cmdb);
+	}
+
+private:
+	ShaderProgramResourcePtr m_prog;
+};
 /// @}
 
 } // end namespace anki

+ 63 - 0
src/anki/scene/DecalNode.cpp

@@ -7,6 +7,7 @@
 #include <anki/scene/components/DecalComponent.h>
 #include <anki/scene/components/MoveComponent.h>
 #include <anki/scene/components/SpatialComponent.h>
+#include <anki/resource/ResourceManager.h>
 
 namespace anki
 {
@@ -68,9 +69,13 @@ Error DecalNode::init()
 	newComponent<MoveComponent>();
 	newComponent<MoveFeedbackComponent>();
 	DecalComponent* decalc = newComponent<DecalComponent>(this);
+	decalc->setDrawCallback(drawCallback, this);
 	newComponent<ShapeFeedbackComponent>();
 	newComponent<SpatialComponent>(this, &decalc->getBoundingVolume());
 
+	ANKI_CHECK(m_dbgDrawer.init(&getResourceManager()));
+	ANKI_CHECK(getResourceManager().loadResource("engine_data/GreenDecal.ankitex", m_dbgTex));
+
 	return Error::NONE;
 }
 
@@ -90,4 +95,62 @@ void DecalNode::onDecalUpdated()
 	sc.markForUpdate();
 }
 
+void DecalNode::drawCallback(RenderQueueDrawContext& ctx, ConstWeakArray<void*> userData)
+{
+	Mat4* const mvps = ctx.m_frameAllocator.newArray<Mat4>(userData.getSize());
+	Vec3* const positions = ctx.m_frameAllocator.newArray<Vec3>(userData.getSize());
+	for(U i = 0; i < userData.getSize(); ++i)
+	{
+		const DecalNode& self = *static_cast<const DecalNode*>(userData[i]);
+		const DecalComponent& decalComp = self.getComponent<DecalComponent>();
+
+		Mat3 rot = decalComp.getBoundingVolume().getRotation().getRotationPart();
+		const Vec4 tsl = decalComp.getBoundingVolume().getCenter().xyz1();
+		const Vec3 scale = decalComp.getBoundingVolume().getExtend().xyz();
+
+		rot(0, 0) *= scale.x();
+		rot(1, 1) *= scale.y();
+		rot(2, 2) *= scale.z();
+
+		mvps[i] = ctx.m_viewProjectionMatrix * Mat4(tsl, rot, 1.0f);
+		positions[i] = tsl.xyz();
+	}
+
+	const Bool enableDepthTest = ctx.m_debugDrawFlags.get(RenderQueueDebugDrawFlag::DEPTH_TEST_ON);
+	if(enableDepthTest)
+	{
+		ctx.m_commandBuffer->setDepthCompareOperation(CompareOperation::LESS);
+	}
+	else
+	{
+		ctx.m_commandBuffer->setDepthCompareOperation(CompareOperation::ALWAYS);
+	}
+
+	const DecalNode& self = *static_cast<const DecalNode*>(userData[0]);
+	self.m_dbgDrawer.drawCubes(ConstWeakArray<Mat4>(mvps, userData.getSize()),
+		Vec4(0.0f, 1.0f, 0.0f, 1.0f),
+		1.0f,
+		ctx.m_debugDrawFlags.get(RenderQueueDebugDrawFlag::DITHERED_DEPTH_TEST_ON),
+		2.0f,
+		*ctx.m_stagingGpuAllocator,
+		ctx.m_commandBuffer);
+
+	self.m_dbgDrawer.drawBillboardTextures(ctx.m_projectionMatrix,
+		ctx.m_viewMatrix,
+		ConstWeakArray<Vec3>(positions, userData.getSize()),
+		Vec4(1.0f),
+		ctx.m_debugDrawFlags.get(RenderQueueDebugDrawFlag::DITHERED_DEPTH_TEST_ON),
+		self.m_dbgTex->getGrTextureView(),
+		ctx.m_sampler,
+		Vec2(0.75f),
+		*ctx.m_stagingGpuAllocator,
+		ctx.m_commandBuffer);
+
+	// Restore state
+	if(!enableDepthTest)
+	{
+		ctx.m_commandBuffer->setDepthCompareOperation(CompareOperation::LESS);
+	}
+}
+
 } // end namespace anki

+ 6 - 0
src/anki/scene/DecalNode.h

@@ -6,6 +6,7 @@
 #pragma once
 
 #include <anki/scene/SceneNode.h>
+#include <anki/scene/DebugDrawer.h>
 #include <anki/collision/Obb.h>
 
 namespace anki
@@ -31,8 +32,13 @@ private:
 	class MoveFeedbackComponent;
 	class ShapeFeedbackComponent;
 
+	DebugDrawer2 m_dbgDrawer;
+	TextureResourcePtr m_dbgTex;
+
 	void onMove(MoveComponent& movec);
 	void onDecalUpdated();
+
+	static void drawCallback(RenderQueueDrawContext& ctx, ConstWeakArray<void*> userData);
 };
 /// @}
 

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

@@ -82,8 +82,9 @@ Error GlobalIlluminationProbeNode::init()
 	// GI probe comp
 	GlobalIlluminationProbeComponent* giprobec =
 		newComponent<GlobalIlluminationProbeComponent>(getSceneGraph().getNewUuid());
-	ANKI_CHECK(giprobec->init(getResourceManager()));
+	ANKI_CHECK(giprobec->init());
 	giprobec->setBoundingBox(m_spatialAabb.getMin(), m_spatialAabb.getMax());
+	giprobec->setDrawCallback(debugDrawCallback, this);
 
 	// Second feedback component
 	newComponent<ShapeFeedbackComponent>();
@@ -123,6 +124,8 @@ Error GlobalIlluminationProbeNode::init()
 	SpatialComponent* spatialc = newComponent<SpatialComponent>(this, &m_spatialAabb);
 	spatialc->setUpdateOctreeBounds(false);
 
+	ANKI_CHECK(m_dbgDrawer.init(&getResourceManager()));
+
 	return Error::NONE;
 }
 
@@ -199,4 +202,50 @@ Error GlobalIlluminationProbeNode::frameUpdate(Second prevUpdateTime, Second crn
 	return Error::NONE;
 }
 
+void GlobalIlluminationProbeNode::debugDrawCallback(RenderQueueDrawContext& ctx, ConstWeakArray<void*> userData)
+{
+	Mat4* const mvps = ctx.m_frameAllocator.newArray<Mat4>(userData.getSize());
+	for(U i = 0; i < userData.getSize(); ++i)
+	{
+		const GlobalIlluminationProbeNode& self = *static_cast<const GlobalIlluminationProbeNode*>(userData[i]);
+		const GlobalIlluminationProbeComponent& giComp = self.getComponent<GlobalIlluminationProbeComponent>();
+
+		const Vec3 tsl = (giComp.getAlignedBoundingBoxMin().xyz() + giComp.getAlignedBoundingBoxMax().xyz()) / 2.0f;
+		const Vec3 scale = (tsl - giComp.getAlignedBoundingBoxMin().xyz());
+
+		// Set non uniform scale.
+		Mat3 rot = Mat3::getIdentity();
+		rot(0, 0) *= scale.x();
+		rot(1, 1) *= scale.y();
+		rot(2, 2) *= scale.z();
+
+		mvps[i] = ctx.m_viewProjectionMatrix * Mat4(tsl.xyz1(), rot, 1.0f);
+	}
+
+	const Bool enableDepthTest = ctx.m_debugDrawFlags.get(RenderQueueDebugDrawFlag::DEPTH_TEST_ON);
+	if(enableDepthTest)
+	{
+		ctx.m_commandBuffer->setDepthCompareOperation(CompareOperation::LESS);
+	}
+	else
+	{
+		ctx.m_commandBuffer->setDepthCompareOperation(CompareOperation::ALWAYS);
+	}
+
+	static_cast<const GlobalIlluminationProbeNode*>(userData[0])
+		->m_dbgDrawer.drawCubes(ConstWeakArray<Mat4>(mvps, userData.getSize()),
+			Vec4(0.729f, 0.635f, 0.196f, 1.0f),
+			1.0f,
+			ctx.m_debugDrawFlags.get(RenderQueueDebugDrawFlag::DITHERED_DEPTH_TEST_ON),
+			2.0f,
+			*ctx.m_stagingGpuAllocator,
+			ctx.m_commandBuffer);
+
+	// Restore state
+	if(!enableDepthTest)
+	{
+		ctx.m_commandBuffer->setDepthCompareOperation(CompareOperation::LESS);
+	}
+}
+
 } // end namespace anki

+ 4 - 0
src/anki/scene/GlobalIlluminationProbeNode.h

@@ -6,6 +6,7 @@
 #pragma once
 
 #include <anki/scene/SceneNode.h>
+#include <anki/scene/DebugDrawer.h>
 #include <anki/collision/Aabb.h>
 
 namespace anki
@@ -36,9 +37,12 @@ private:
 	Array<Transform, 6> m_cubeFaceTransforms;
 	Aabb m_spatialAabb = Aabb(Vec3(-1.0f), Vec3(1.0f));
 	Vec4 m_previousPosition = Vec4(0.0f);
+	DebugDrawer2 m_dbgDrawer;
 
 	void onMoveUpdate(MoveComponent& move);
 	void onShapeUpdateOrProbeNeedsRendering();
+
+	static void debugDrawCallback(RenderQueueDrawContext& ctx, ConstWeakArray<void*> userData);
 };
 /// @}
 

+ 71 - 3
src/anki/scene/LightNode.cpp

@@ -9,6 +9,7 @@
 #include <anki/scene/components/MoveComponent.h>
 #include <anki/scene/components/SpatialComponent.h>
 #include <anki/scene/components/FrustumComponent.h>
+#include <anki/resource/ResourceManager.h>
 #include <shaders/glsl_cpp_common/ClusteredShading.h>
 
 namespace anki
@@ -71,6 +72,25 @@ LightNode::~LightNode()
 {
 }
 
+Error LightNode::initCommon(LightComponentType lightType)
+{
+	CString texFname;
+	switch(lightType)
+	{
+	case LightComponentType::POINT:
+		texFname = "engine_data/LightBulb.ankitex";
+		break;
+	case LightComponentType::SPOT:
+		texFname = "engine_data/SpotLight.ankitex";
+		break;
+	default:
+		ANKI_ASSERT(0);
+	}
+	ANKI_CHECK(getResourceManager().loadResource(texFname, m_dbgTex));
+
+	return m_dbgDrawer.init(&getResourceManager());
+}
+
 void LightNode::frameUpdateCommon()
 {
 	// Update frustum comps shadow info
@@ -126,6 +146,45 @@ Error LightNode::loadLensFlare(const CString& filename)
 	return Error::NONE;
 }
 
+void LightNode::drawCallback(RenderQueueDrawContext& ctx, ConstWeakArray<void*> userData)
+{
+	for(const void* plight : userData)
+	{
+		const LightNode& self = *static_cast<const LightNode*>(plight);
+		const LightComponent& lcomp = self.getComponent<LightComponent>();
+
+		const Bool enableDepthTest = ctx.m_debugDrawFlags.get(RenderQueueDebugDrawFlag::DEPTH_TEST_ON);
+		if(enableDepthTest)
+		{
+			ctx.m_commandBuffer->setDepthCompareOperation(CompareOperation::LESS);
+		}
+		else
+		{
+			ctx.m_commandBuffer->setDepthCompareOperation(CompareOperation::ALWAYS);
+		}
+
+		Vec3 color = lcomp.getDiffuseColor().xyz();
+		color /= max(max(color.x(), color.y()), color.z());
+
+		self.m_dbgDrawer.drawBillboardTexture(ctx.m_projectionMatrix,
+			ctx.m_viewMatrix,
+			lcomp.getTransform().getOrigin().xyz(),
+			color.xyz1(),
+			ctx.m_debugDrawFlags.get(RenderQueueDebugDrawFlag::DITHERED_DEPTH_TEST_ON),
+			self.m_dbgTex->getGrTextureView(),
+			ctx.m_sampler,
+			Vec2(0.75f),
+			*ctx.m_stagingGpuAllocator,
+			ctx.m_commandBuffer);
+
+		// Restore state
+		if(!enableDepthTest)
+		{
+			ctx.m_commandBuffer->setDepthCompareOperation(CompareOperation::LESS);
+		}
+	}
+}
+
 PointLightNode::PointLightNode(SceneGraph* scene, CString name)
 	: LightNode(scene, name)
 {
@@ -138,6 +197,8 @@ PointLightNode::~PointLightNode()
 
 Error PointLightNode::init()
 {
+	ANKI_CHECK(initCommon(LightComponentType::POINT));
+
 	// Move component
 	newComponent<MoveComponent>();
 
@@ -145,7 +206,8 @@ Error PointLightNode::init()
 	newComponent<MovedFeedbackComponent>();
 
 	// Light component
-	newComponent<LightComponent>(LightComponentType::POINT, getSceneGraph().getNewUuid());
+	LightComponent* lc = newComponent<LightComponent>(LightComponentType::POINT, getSceneGraph().getNewUuid());
+	lc->setDrawCallback(drawCallback, static_cast<LightNode*>(this));
 
 	// Feedback component
 	newComponent<LightChangedFeedbackComponent>();
@@ -237,6 +299,8 @@ SpotLightNode::SpotLightNode(SceneGraph* scene, CString name)
 
 Error SpotLightNode::init()
 {
+	ANKI_CHECK(initCommon(LightComponentType::SPOT));
+
 	// Move component
 	newComponent<MoveComponent>();
 
@@ -244,7 +308,8 @@ Error SpotLightNode::init()
 	newComponent<MovedFeedbackComponent>();
 
 	// Light component
-	newComponent<LightComponent>(LightComponentType::SPOT, getSceneGraph().getNewUuid());
+	LightComponent* lc = newComponent<LightComponent>(LightComponentType::SPOT, getSceneGraph().getNewUuid());
+	lc->setDrawCallback(drawCallback, static_cast<LightNode*>(this));
 
 	// Feedback component
 	newComponent<LightChangedFeedbackComponent>();
@@ -324,7 +389,10 @@ Error DirectionalLightNode::init()
 {
 	newComponent<MoveComponent>();
 	newComponent<FeedbackComponent>();
-	newComponent<LightComponent>(LightComponentType::DIRECTIONAL, getSceneGraph().getNewUuid());
+
+	LightComponent* lc = newComponent<LightComponent>(LightComponentType::DIRECTIONAL, getSceneGraph().getNewUuid());
+	lc->setDrawCallback(drawCallback, this);
+
 	SpatialComponent* spatialc = newComponent<SpatialComponent>(this, &m_boundingBox);
 
 	// Make the bounding box large enough so it will always be visible. Because of that don't update the octree bounds

+ 14 - 0
src/anki/scene/LightNode.h

@@ -7,6 +7,7 @@
 
 #include <anki/scene/SceneNode.h>
 #include <anki/scene/Forward.h>
+#include <anki/scene/DebugDrawer.h>
 #include <anki/scene/components/LightComponent.h>
 #include <anki/resource/TextureResource.h>
 #include <anki/Collision.h>
@@ -31,6 +32,8 @@ protected:
 	class MovedFeedbackComponent;
 	class LightChangedFeedbackComponent;
 
+	ANKI_USE_RESULT Error initCommon(LightComponentType lightType);
+
 	/// Called when moved
 	void onMoveUpdateCommon(const MoveComponent& move);
 
@@ -39,6 +42,12 @@ protected:
 	virtual void onMoveUpdate(const MoveComponent& move) = 0;
 
 	virtual void onShapeUpdate(LightComponent& light) = 0;
+
+	static void drawCallback(RenderQueueDrawContext& ctx, ConstWeakArray<void*> userData);
+
+private:
+	DebugDrawer2 m_dbgDrawer;
+	TextureResourcePtr m_dbgTex;
 };
 
 /// Point light
@@ -93,6 +102,11 @@ private:
 	class FeedbackComponent;
 
 	Aabb m_boundingBox;
+
+	static void drawCallback(RenderQueueDrawContext& ctx, ConstWeakArray<void*> userData)
+	{
+		// TODO
+	}
 };
 /// @}
 

+ 10 - 34
src/anki/scene/ModelNode.cpp

@@ -54,7 +54,7 @@ Error ModelNode::init(ModelResourcePtr resource, U32 modelPatchIdx)
 {
 	ANKI_ASSERT(modelPatchIdx < resource->getModelPatches().getSize());
 
-	ANKI_CHECK(getResourceManager().loadResource("shaders/SceneDebug.glslp", m_dbgProg));
+	ANKI_CHECK(m_dbgDrawer.init(&getResourceManager()));
 	m_model = resource;
 	m_modelPatchIdx = modelPatchIdx;
 
@@ -204,16 +204,7 @@ void ModelNode::draw(RenderQueueDrawContext& ctx, ConstWeakArray<void*> userData
 	{
 		// Draw the bounding volumes
 
-		// Allocate staging memory
-		StagingGpuMemoryToken vertToken, indicesToken;
-		U32 indexCount;
-		allocateAndPopulateDebugBox(*ctx.m_stagingGpuAllocator, vertToken, indicesToken, indexCount);
-
-		// Set the uniforms
-		StagingGpuMemoryToken unisToken;
-		Mat4* mvps = static_cast<Mat4*>(ctx.m_stagingGpuAllocator->allocateFrame(
-			sizeof(Mat4) * userData.getSize() + sizeof(Vec4), StagingGpuMemoryType::UNIFORM, unisToken));
-
+		Mat4* const mvps = ctx.m_frameAllocator.newArray<Mat4>(userData.getSize());
 		for(U i = 0; i < userData.getSize(); ++i)
 		{
 			const ModelNode& self2 = *static_cast<const ModelNode*>(userData[i]);
@@ -228,23 +219,9 @@ void ModelNode::draw(RenderQueueDrawContext& ctx, ConstWeakArray<void*> userData
 			rot(1, 1) *= scale.y() * MARGIN;
 			rot(2, 2) *= scale.z() * MARGIN;
 
-			*mvps = ctx.m_viewProjectionMatrix * Mat4(tsl, rot, 1.0f);
-			++mvps;
+			mvps[i] = ctx.m_viewProjectionMatrix * Mat4(tsl, rot, 1.0f);
 		}
 
-		Vec4* color = reinterpret_cast<Vec4*>(mvps);
-		*color = Vec4(1.0f, 0.0f, 1.0f, 1.0f);
-
-		// Setup state
-		ShaderProgramResourceMutationInitList<2> mutators(m_dbgProg);
-		mutators.add("COLOR_TEXTURE", 0);
-		mutators.add("DITHERED_DEPTH_TEST", ctx.m_debugDrawFlags.get(RenderQueueDebugDrawFlag::DITHERED_DEPTH_TEST_ON));
-		ShaderProgramResourceConstantValueInitList<1> consts(m_dbgProg);
-		consts.add("INSTANCE_COUNT", U32(userData.getSize()));
-		const ShaderProgramResourceVariant* variant;
-		m_dbgProg->getOrCreateVariant(mutators.get(), consts.get(), variant);
-		cmdb->bindShaderProgram(variant->getProgram());
-
 		const Bool enableDepthTest = ctx.m_debugDrawFlags.get(RenderQueueDebugDrawFlag::DEPTH_TEST_ON);
 		if(enableDepthTest)
 		{
@@ -255,14 +232,13 @@ void ModelNode::draw(RenderQueueDrawContext& ctx, ConstWeakArray<void*> userData
 			cmdb->setDepthCompareOperation(CompareOperation::ALWAYS);
 		}
 
-		cmdb->setVertexAttribute(0, 0, Format::R32G32B32_SFLOAT, 0);
-		cmdb->bindVertexBuffer(0, vertToken.m_buffer, vertToken.m_offset, sizeof(Vec3));
-		cmdb->bindIndexBuffer(indicesToken.m_buffer, indicesToken.m_offset, IndexType::U16);
-
-		cmdb->bindUniformBuffer(1, 0, unisToken.m_buffer, unisToken.m_offset, unisToken.m_range);
-
-		cmdb->setLineWidth(1.0f);
-		cmdb->drawElements(PrimitiveTopology::LINES, indexCount, userData.getSize());
+		m_dbgDrawer.drawCubes(ConstWeakArray<Mat4>(mvps, userData.getSize()),
+			Vec4(1.0f, 0.0f, 1.0f, 1.0f),
+			1.0f,
+			ctx.m_debugDrawFlags.get(RenderQueueDebugDrawFlag::DITHERED_DEPTH_TEST_ON),
+			2.0f,
+			*ctx.m_stagingGpuAllocator,
+			cmdb);
 
 		// Restore state
 		if(!enableDepthTest)

+ 2 - 1
src/anki/scene/ModelNode.h

@@ -8,6 +8,7 @@
 #include <anki/scene/SceneNode.h>
 #include <anki/scene/components/MoveComponent.h>
 #include <anki/scene/components/SpatialComponent.h>
+#include <anki/scene/DebugDrawer.h>
 #include <anki/resource/ModelResource.h>
 #include <anki/collision/Obb.h>
 #include <anki/renderer/RenderQueue.h>
@@ -46,7 +47,7 @@ private:
 	U64 m_mergeKey = 0;
 	U32 m_modelPatchIdx = 0;
 
-	ShaderProgramResourcePtr m_dbgProg;
+	DebugDrawer2 m_dbgDrawer;
 
 	void onMoveComponentUpdate(const MoveComponent& move);
 

+ 10 - 7
src/anki/scene/components/DecalComponent.h

@@ -71,6 +71,12 @@ public:
 		m_markedForUpdate = true;
 	}
 
+	void setDrawCallback(RenderQueueDrawCallback callback, const void* userData)
+	{
+		m_drawCallback = callback;
+		m_drawCallbackUserData = userData;
+	}
+
 	/// Implements SceneComponent::update.
 	ANKI_USE_RESULT Error update(SceneNode& node, Second, Second, Bool& updated) override
 	{
@@ -132,8 +138,8 @@ public:
 		el.m_obbCenter = m_obb.getCenter().xyz();
 		el.m_obbExtend = m_obb.getExtend().xyz();
 		el.m_obbRotation = m_obb.getRotation().getRotationPart();
-		el.m_userData = this;
-		el.m_drawCallback = debugDrawCallback;
+		el.m_debugDrawCallback = m_drawCallback;
+		el.m_debugDrawCallbackUserData = m_drawCallbackUserData;
 	}
 
 private:
@@ -153,6 +159,8 @@ private:
 	};
 
 	SceneNode* m_node;
+	RenderQueueDrawCallback m_drawCallback = nullptr;
+	const void* m_drawCallbackUserData = nullptr;
 	Array<Layer, U(LayerType::COUNT)> m_layers;
 	Mat4 m_biasProjViewMat;
 	Vec3 m_sizes = Vec3(1.0f);
@@ -163,11 +171,6 @@ private:
 	ANKI_USE_RESULT Error setLayer(CString texAtlasFname, CString texAtlasSubtexName, F32 blendFactor, LayerType type);
 
 	void updateInternal();
-
-	static void debugDrawCallback(RenderQueueDrawContext& ctx, ConstWeakArray<void*> userData)
-	{
-		// TODO
-	}
 };
 /// @}
 

+ 0 - 76
src/anki/scene/components/GlobalIlluminationProbeComponent.cpp

@@ -10,80 +10,4 @@
 namespace anki
 {
 
-Error GlobalIlluminationProbeComponent::init(ResourceManager& rsrc)
-{
-	return rsrc.loadResource("shaders/SceneDebug.glslp", m_dbgProg);
-}
-
-void GlobalIlluminationProbeComponent::debugDraw(RenderQueueDrawContext& ctx, ConstWeakArray<void*> userData)
-{
-	StagingGpuMemoryToken vertToken, indicesToken;
-	U32 indexCount;
-	allocateAndPopulateDebugBox(*ctx.m_stagingGpuAllocator, vertToken, indicesToken, indexCount);
-
-	// Set the uniforms
-	StagingGpuMemoryToken unisToken;
-	Mat4* mvps = static_cast<Mat4*>(ctx.m_stagingGpuAllocator->allocateFrame(
-		sizeof(Mat4) * userData.getSize() + sizeof(Vec4), StagingGpuMemoryType::UNIFORM, unisToken));
-
-	for(U i = 0; i < userData.getSize(); ++i)
-	{
-		const GlobalIlluminationProbeComponent& self =
-			*static_cast<const GlobalIlluminationProbeComponent*>(userData[i]);
-
-		const Vec3 tsl = (self.m_aabbMin + self.m_aabbMax) / 2.0f;
-		const Vec3 scale = (tsl - self.m_aabbMin);
-
-		// Set non uniform scale.
-		Mat3 rot = Mat3::getIdentity();
-		rot(0, 0) *= scale.x();
-		rot(1, 1) *= scale.y();
-		rot(2, 2) *= scale.z();
-
-		*mvps = ctx.m_viewProjectionMatrix * Mat4(tsl.xyz1(), rot, 1.0f);
-		++mvps;
-	}
-
-	Vec4* color = reinterpret_cast<Vec4*>(mvps);
-	*color = Vec4(0.729f, 0.635f, 0.196f, 1.0f);
-
-	// Setup state
-	const GlobalIlluminationProbeComponent& self = *static_cast<const GlobalIlluminationProbeComponent*>(userData[0]);
-	ShaderProgramResourceMutationInitList<2> mutators(self.m_dbgProg);
-	mutators.add("COLOR_TEXTURE", 0);
-	mutators.add("DITHERED_DEPTH_TEST", ctx.m_debugDrawFlags.get(RenderQueueDebugDrawFlag::DITHERED_DEPTH_TEST_ON));
-	ShaderProgramResourceConstantValueInitList<1> consts(self.m_dbgProg);
-	consts.add("INSTANCE_COUNT", U32(userData.getSize()));
-	const ShaderProgramResourceVariant* variant;
-	self.m_dbgProg->getOrCreateVariant(mutators.get(), consts.get(), variant);
-
-	CommandBufferPtr& cmdb = ctx.m_commandBuffer;
-	cmdb->bindShaderProgram(variant->getProgram());
-
-	const Bool enableDepthTest = ctx.m_debugDrawFlags.get(RenderQueueDebugDrawFlag::DEPTH_TEST_ON);
-	if(enableDepthTest)
-	{
-		cmdb->setDepthCompareOperation(CompareOperation::LESS);
-	}
-	else
-	{
-		cmdb->setDepthCompareOperation(CompareOperation::ALWAYS);
-	}
-
-	cmdb->setVertexAttribute(0, 0, Format::R32G32B32_SFLOAT, 0);
-	cmdb->bindVertexBuffer(0, vertToken.m_buffer, vertToken.m_offset, sizeof(Vec3));
-	cmdb->bindIndexBuffer(indicesToken.m_buffer, indicesToken.m_offset, IndexType::U16);
-
-	cmdb->bindUniformBuffer(1, 0, unisToken.m_buffer, unisToken.m_offset, unisToken.m_range);
-
-	cmdb->setLineWidth(1.0f);
-	cmdb->drawElements(PrimitiveTopology::LINES, indexCount, userData.getSize());
-
-	// Restore state
-	if(!enableDepthTest)
-	{
-		cmdb->setDepthCompareOperation(CompareOperation::LESS);
-	}
-}
-
 } // end namespace anki

+ 15 - 11
src/anki/scene/components/GlobalIlluminationProbeComponent.h

@@ -27,7 +27,10 @@ public:
 		ANKI_ASSERT(uuid > 0);
 	}
 
-	ANKI_USE_RESULT Error init(ResourceManager& rsrc);
+	ANKI_USE_RESULT Error init()
+	{
+		return Error::NONE;
+	}
 
 	/// Set the bounding box in world coordinates.
 	void setBoundingBox(const Vec4& min, const Vec4& max)
@@ -88,12 +91,19 @@ public:
 		return m_renderPosition.xyz0();
 	}
 
+	void setDrawCallback(RenderQueueDrawCallback callback, const void* userData)
+	{
+		m_drawCallback = callback;
+		m_drawCallbackUserData = userData;
+	}
+
 	void setupGlobalIlluminationProbeQueueElement(GlobalIlluminationProbeQueueElement& el)
 	{
 		el.m_uuid = m_uuid;
 		el.m_feedbackCallback = giProbeQueueElementFeedbackCallback;
-		el.m_debugDrawCallback = debugDrawCallback;
-		el.m_userData = this;
+		el.m_feedbackCallbackUserData = this;
+		el.m_debugDrawCallback = m_drawCallback;
+		el.m_debugDrawCallbackUserData = m_drawCallbackUserData;
 		el.m_renderQueues = {};
 		el.m_aabbMin = m_aabbMin;
 		el.m_aabbMax = m_aabbMax;
@@ -111,7 +121,8 @@ public:
 	}
 
 private:
-	ShaderProgramResourcePtr m_dbgProg;
+	RenderQueueDrawCallback m_drawCallback = nullptr;
+	const void* m_drawCallbackUserData = nullptr;
 	U64 m_uuid;
 	Vec3 m_aabbMin = Vec3(-1.0f);
 	Vec3 m_aabbMax = Vec3(+1.0f);
@@ -132,13 +143,6 @@ private:
 		self.m_renderPosition = eyeWorldPosition.xyz();
 	}
 
-	static void debugDrawCallback(RenderQueueDrawContext& ctx, ConstWeakArray<void*> userData)
-	{
-		debugDraw(ctx, userData);
-	}
-
-	static void debugDraw(RenderQueueDrawContext& ctx, ConstWeakArray<void*> userData);
-
 	/// Recalc come values.
 	void updateMembers()
 	{

+ 2 - 2
src/anki/scene/components/LightComponent.cpp

@@ -83,8 +83,8 @@ void LightComponent::setupDirectionalLightQueueElement(const FrustumComponent& f
 
 	const U shadowCascadeCount = cascadeFrustumComponents.getSize();
 
-	el.m_userData = this;
-	el.m_drawCallback = derectionalLightDebugDrawCallback;
+	el.m_drawCallback = m_drawCallback;
+	el.m_drawCallbackUserData = m_drawCallbackUserData;
 	el.m_uuid = m_uuid;
 	el.m_diffuseColor = m_diffColor.xyz();
 	el.m_direction = -m_trf.getRotation().getZAxis().xyz();

+ 17 - 19
src/anki/scene/components/LightComponent.h

@@ -122,6 +122,17 @@ public:
 		m_flags.set(SHADOW, x);
 	}
 
+	void setDrawCallback(RenderQueueDrawCallback callback, const void* userData)
+	{
+		m_drawCallback = callback;
+		m_drawCallbackUserData = userData;
+	}
+
+	const Transform& getTransform() const
+	{
+		return m_trf;
+	}
+
 	ANKI_USE_RESULT Error update(SceneNode& node, Second prevTime, Second crntTime, Bool& updated) override;
 
 	void setupPointLightQueueElement(PointLightQueueElement& el) const
@@ -131,8 +142,8 @@ public:
 		el.m_worldPosition = m_trf.getOrigin().xyz();
 		el.m_radius = m_point.m_radius;
 		el.m_diffuseColor = m_diffColor.xyz();
-		el.m_userData = this;
-		el.m_drawCallback = pointLightDebugDrawCallback;
+		el.m_debugDrawCallback = m_drawCallback;
+		el.m_debugDrawCallbackUserData = m_drawCallbackUserData;
 	}
 
 	void setupSpotLightQueueElement(SpotLightQueueElement& el) const
@@ -145,8 +156,8 @@ public:
 		el.m_outerAngle = m_spot.m_outerAngle;
 		el.m_innerAngle = m_spot.m_innerAngle;
 		el.m_diffuseColor = m_diffColor.xyz();
-		el.m_userData = this;
-		el.m_drawCallback = spotLightDebugDrawCallback;
+		el.m_debugDrawCallback = m_drawCallback;
+		el.m_debugDrawCallbackUserData = m_drawCallbackUserData;
 	}
 
 	/// Setup a directional queue element.
@@ -162,6 +173,8 @@ private:
 	U64 m_uuid;
 	Vec4 m_diffColor = Vec4(0.5f);
 	Transform m_trf = Transform::getIdentity();
+	RenderQueueDrawCallback m_drawCallback = nullptr;
+	const void* m_drawCallbackUserData = nullptr;
 
 	struct Point
 	{
@@ -200,21 +213,6 @@ private:
 
 	LightComponentType m_type;
 	BitMask<U8> m_flags = BitMask<U8>(DIRTY | TRF_DIRTY);
-
-	static void pointLightDebugDrawCallback(RenderQueueDrawContext& ctx, ConstWeakArray<void*> userData)
-	{
-		// TODO
-	}
-
-	static void spotLightDebugDrawCallback(RenderQueueDrawContext& ctx, ConstWeakArray<void*> userData)
-	{
-		// TODO
-	}
-
-	static void derectionalLightDebugDrawCallback(RenderQueueDrawContext& ctx, ConstWeakArray<void*> userData)
-	{
-		// TODO
-	}
 };
 /// @}