瀏覽代碼

Move to DX coordinate system. What a pain...

Panagiotis Christopoulos Charitos 1 年之前
父節點
當前提交
bf7937f356

+ 1 - 0
AnKi/Core/GpuMemory/GpuSceneBuffer.h

@@ -8,6 +8,7 @@
 #include <AnKi/Core/Common.h>
 #include <AnKi/Core/Common.h>
 #include <AnKi/Gr/Utils/SegregatedListsGpuMemoryPool.h>
 #include <AnKi/Gr/Utils/SegregatedListsGpuMemoryPool.h>
 #include <AnKi/Resource/ShaderProgramResource.h>
 #include <AnKi/Resource/ShaderProgramResource.h>
+#include <AnKi/Gr/GrManager.h>
 
 
 namespace anki {
 namespace anki {
 
 

+ 1 - 0
AnKi/Core/GpuMemory/RebarTransientMemoryPool.h

@@ -7,6 +7,7 @@
 
 
 #include <AnKi/Core/Common.h>
 #include <AnKi/Core/Common.h>
 #include <AnKi/Gr/Buffer.h>
 #include <AnKi/Gr/Buffer.h>
+#include <AnKi/Gr/GrManager.h>
 
 
 namespace anki {
 namespace anki {
 
 

+ 2 - 16
AnKi/Gr/BackendCommon/GraphicsStateTracker.h

@@ -273,12 +273,7 @@ public:
 		}
 		}
 	}
 	}
 
 
-	void beginRenderPass(ConstWeakArray<Format> colorFormats, Format depthStencilFormat, UVec2 rtsSize
-#if ANKI_GR_BACKEND_VULKAN
-						 ,
-						 Bool rendersToSwapchain
-#endif
-	)
+	void beginRenderPass(ConstWeakArray<Format> colorFormats, Format depthStencilFormat, UVec2 rtsSize)
 	{
 	{
 		m_staticState.m_misc.m_colorRtFormats.fill(Format::kNone);
 		m_staticState.m_misc.m_colorRtFormats.fill(Format::kNone);
 		m_staticState.m_misc.m_colorRtMask.unsetAll();
 		m_staticState.m_misc.m_colorRtMask.unsetAll();
@@ -292,11 +287,7 @@ public:
 
 
 		m_hashes.m_misc = 0; // Always mark it dirty because calling beginRenderPass is a rare occurance and we want to avoid extra checks
 		m_hashes.m_misc = 0; // Always mark it dirty because calling beginRenderPass is a rare occurance and we want to avoid extra checks
 
 
-		if(m_rtsSize != rtsSize
-#if ANKI_GR_BACKEND_VULKAN
-		   || m_staticState.m_misc.m_rendersToSwapchain != rendersToSwapchain
-#endif
-		)
+		if(m_rtsSize != rtsSize)
 		{
 		{
 			m_rtsSize = rtsSize;
 			m_rtsSize = rtsSize;
 
 
@@ -304,10 +295,6 @@ public:
 			m_dynState.m_scissorDirty = true;
 			m_dynState.m_scissorDirty = true;
 			m_dynState.m_viewportDirty = true;
 			m_dynState.m_viewportDirty = true;
 		}
 		}
-
-#if ANKI_GR_BACKEND_VULKAN
-		m_staticState.m_misc.m_rendersToSwapchain = rendersToSwapchain;
-#endif
 	}
 	}
 
 
 	void bindShaderProgram(ShaderProgram* prog)
 	void bindShaderProgram(ShaderProgram* prog)
@@ -558,7 +545,6 @@ private:
 			BitSet<kMaxColorRenderTargets> m_colorRtMask = {false};
 			BitSet<kMaxColorRenderTargets> m_colorRtMask = {false};
 
 
 #if ANKI_GR_BACKEND_VULKAN
 #if ANKI_GR_BACKEND_VULKAN
-			Bool m_rendersToSwapchain = false;
 			Bool m_pipelineStatisticsEnabled = false;
 			Bool m_pipelineStatisticsEnabled = false;
 #endif
 #endif
 		} m_misc;
 		} m_misc;

+ 2 - 1
AnKi/Gr/D3D/D3DDescriptor.h

@@ -194,7 +194,8 @@ public:
 	U32 getBindlessIndex(const DescriptorHeapHandle& handle) const
 	U32 getBindlessIndex(const DescriptorHeapHandle& handle) const
 	{
 	{
 		handle.validate();
 		handle.validate();
-		ANKI_ASSERT(handle.m_cpuHandle.ptr == m_gpuPersistent.m_cbvSrvUav.m_cpuHeapStart.ptr);
+		ANKI_ASSERT(handle.m_heapCpuStart.ptr == m_gpuPersistent.m_cbvSrvUav.m_cpuHeapStart.ptr);
+		ANKI_ASSERT(handle.m_heapGpuStart.ptr == m_gpuPersistent.m_cbvSrvUav.m_gpuHeapStart.ptr);
 		const PtrSize idx = (handle.m_cpuHandle.ptr - m_gpuPersistent.m_cbvSrvUav.m_cpuHeapStart.ptr) / m_gpuPersistent.m_cbvSrvUav.m_descriptorSize;
 		const PtrSize idx = (handle.m_cpuHandle.ptr - m_gpuPersistent.m_cbvSrvUav.m_cpuHeapStart.ptr) / m_gpuPersistent.m_cbvSrvUav.m_descriptorSize;
 		return U32(idx);
 		return U32(idx);
 	}
 	}

+ 2 - 0
AnKi/Gr/D3D/D3DTexture.cpp

@@ -33,6 +33,8 @@ U32 Texture::getOrCreateBindlessTextureIndex(const TextureSubresourceDesc& subre
 	if(view.m_bindlessIndex == kMaxU32)
 	if(view.m_bindlessIndex == kMaxU32)
 	{
 	{
 		view.m_bindlessHandle = DescriptorFactory::getSingleton().allocatePersistent(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, true);
 		view.m_bindlessHandle = DescriptorFactory::getSingleton().allocatePersistent(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV, true);
+		getDevice().CopyDescriptorsSimple(1, view.m_bindlessHandle.getCpuOffset(), view.m_handle.getCpuOffset(),
+										  D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV);
 		view.m_bindlessIndex = DescriptorFactory::getSingleton().getBindlessIndex(view.m_bindlessHandle);
 		view.m_bindlessIndex = DescriptorFactory::getSingleton().getBindlessIndex(view.m_bindlessHandle);
 	}
 	}
 
 

+ 2 - 7
AnKi/Gr/Vulkan/VkCommandBuffer.cpp

@@ -468,7 +468,6 @@ void CommandBuffer::beginRenderPass(ConstWeakArray<RenderTarget> colorRts, Rende
 	// Set the render area
 	// Set the render area
 	ANKI_ASSERT(minx < fbWidth && miny < fbHeight);
 	ANKI_ASSERT(minx < fbWidth && miny < fbHeight);
 
 
-	const Bool flipViewport = drawsToSwapchain;
 	const U32 maxx = min<U32>(minx + width, fbWidth);
 	const U32 maxx = min<U32>(minx + width, fbWidth);
 	const U32 maxy = min<U32>(miny + height, fbHeight);
 	const U32 maxy = min<U32>(miny + height, fbHeight);
 	width = maxx - minx;
 	width = maxx - minx;
@@ -476,16 +475,12 @@ void CommandBuffer::beginRenderPass(ConstWeakArray<RenderTarget> colorRts, Rende
 	ANKI_ASSERT(minx + width <= fbWidth && miny + height <= fbHeight);
 	ANKI_ASSERT(minx + width <= fbWidth && miny + height <= fbHeight);
 
 
 	info.renderArea.offset.x = minx;
 	info.renderArea.offset.x = minx;
-	if(flipViewport)
-	{
-		ANKI_ASSERT(height <= fbHeight);
-	}
-	info.renderArea.offset.y = (flipViewport) ? fbHeight - (miny + height) : miny;
+	info.renderArea.offset.y = miny;
 	info.renderArea.extent.width = width;
 	info.renderArea.extent.width = width;
 	info.renderArea.extent.height = height;
 	info.renderArea.extent.height = height;
 
 
 	// State bookkeeping
 	// State bookkeeping
-	self.m_graphicsState.beginRenderPass({colorFormats.getBegin(), colorRts.getSize()}, dsFormat, UVec2(fbWidth, fbHeight), drawsToSwapchain);
+	self.m_graphicsState.beginRenderPass({colorFormats.getBegin(), colorRts.getSize()}, dsFormat, UVec2(fbWidth, fbHeight));
 	if(drawsToSwapchain)
 	if(drawsToSwapchain)
 	{
 	{
 		self.m_renderedToDefaultFb = true;
 		self.m_renderedToDefaultFb = true;

+ 7 - 18
AnKi/Gr/Vulkan/VkGraphicsState.cpp

@@ -14,7 +14,7 @@ namespace anki {
 static NumericCVar<PtrSize> g_diskShaderCacheMaxSizeCVar(CVarSubsystem::kGr, "DiskShaderCacheMaxSize", 128_MB, 1_MB, 1_GB,
 static NumericCVar<PtrSize> g_diskShaderCacheMaxSizeCVar(CVarSubsystem::kGr, "DiskShaderCacheMaxSize", 128_MB, 1_MB, 1_GB,
 														 "Max size of the pipeline cache file");
 														 "Max size of the pipeline cache file");
 
 
-static VkViewport computeViewport(U32* viewport, U32 fbWidth, U32 fbHeight, Bool flipvp)
+static VkViewport computeViewport(U32* viewport, U32 fbWidth, U32 fbHeight)
 {
 {
 	const U32 minx = viewport[0];
 	const U32 minx = viewport[0];
 	const U32 miny = viewport[1];
 	const U32 miny = viewport[1];
@@ -24,17 +24,12 @@ static VkViewport computeViewport(U32* viewport, U32 fbWidth, U32 fbHeight, Bool
 	ANKI_ASSERT(minx + width <= fbWidth);
 	ANKI_ASSERT(minx + width <= fbWidth);
 	ANKI_ASSERT(miny + height <= fbHeight);
 	ANKI_ASSERT(miny + height <= fbHeight);
 
 
-	const VkViewport s = {.x = F32(minx),
-						  .y = (flipvp) ? F32(fbHeight - miny) : F32(miny), // Move to the bottom
-						  .width = F32(width),
-						  .height = (flipvp) ? -F32(height) : F32(height),
-						  .minDepth = 0.0f,
-						  .maxDepth = 1.0f};
+	const VkViewport s = {.x = F32(minx), .y = F32(height + miny), .width = F32(width), .height = -F32(height), .minDepth = 0.0f, .maxDepth = 1.0f};
 
 
 	return s;
 	return s;
 }
 }
 
 
-static VkRect2D computeScissor(U32* scissor, U32 fbWidth, U32 fbHeight, Bool flipvp)
+static VkRect2D computeScissor(U32* scissor, U32 fbWidth, U32 fbHeight)
 {
 {
 	const U32 minx = scissor[0];
 	const U32 minx = scissor[0];
 	const U32 miny = scissor[1];
 	const U32 miny = scissor[1];
@@ -48,7 +43,7 @@ static VkRect2D computeScissor(U32* scissor, U32 fbWidth, U32 fbHeight, Bool fli
 	out.extent.width = width;
 	out.extent.width = width;
 	out.extent.height = height;
 	out.extent.height = height;
 	out.offset.x = minx;
 	out.offset.x = minx;
-	out.offset.y = (flipvp) ? (fbHeight - (miny + height)) : miny;
+	out.offset.y = fbHeight - (miny + height);
 
 
 	return out;
 	return out;
 }
 }
@@ -140,20 +135,14 @@ void GraphicsPipelineFactory::flushState(GraphicsStateTracker& state, VkCommandB
 	{
 	{
 		ANKI_ASSERT(dynState.m_viewport[2] != 0 && dynState.m_viewport[3] != 0);
 		ANKI_ASSERT(dynState.m_viewport[2] != 0 && dynState.m_viewport[3] != 0);
 		dynState.m_viewportDirty = false;
 		dynState.m_viewportDirty = false;
-
-		const Bool flipVp = staticState.m_misc.m_rendersToSwapchain;
-		const VkViewport vp = computeViewport(dynState.m_viewport.getBegin(), state.m_rtsSize.x(), state.m_rtsSize.y(), flipVp);
-
+		const VkViewport vp = computeViewport(dynState.m_viewport.getBegin(), state.m_rtsSize.x(), state.m_rtsSize.y());
 		vkCmdSetViewport(cmdb, 0, 1, &vp);
 		vkCmdSetViewport(cmdb, 0, 1, &vp);
 	}
 	}
 
 
 	if(dynState.m_scissorDirty)
 	if(dynState.m_scissorDirty)
 	{
 	{
 		dynState.m_scissorDirty = false;
 		dynState.m_scissorDirty = false;
-
-		const Bool flipVp = staticState.m_misc.m_rendersToSwapchain;
-		const VkRect2D rect = computeScissor(dynState.m_scissor.getBegin(), state.m_rtsSize.x(), state.m_rtsSize.y(), flipVp);
-
+		const VkRect2D rect = computeScissor(dynState.m_scissor.getBegin(), state.m_rtsSize.x(), state.m_rtsSize.y());
 		vkCmdSetScissor(cmdb, 0, 1, &rect);
 		vkCmdSetScissor(cmdb, 0, 1, &rect);
 	}
 	}
 
 
@@ -258,7 +247,7 @@ void GraphicsPipelineFactory::flushState(GraphicsStateTracker& state, VkCommandB
 	rastCi.rasterizerDiscardEnable = false;
 	rastCi.rasterizerDiscardEnable = false;
 	rastCi.polygonMode = convertFillMode(staticState.m_rast.m_fillMode);
 	rastCi.polygonMode = convertFillMode(staticState.m_rast.m_fillMode);
 	rastCi.cullMode = convertCullMode(staticState.m_rast.m_cullMode);
 	rastCi.cullMode = convertCullMode(staticState.m_rast.m_cullMode);
-	rastCi.frontFace = (!staticState.m_misc.m_rendersToSwapchain) ? VK_FRONT_FACE_CLOCKWISE : VK_FRONT_FACE_COUNTER_CLOCKWISE; // For viewport flip
+	rastCi.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
 	rastCi.depthBiasEnable = staticState.m_rast.m_depthBiasEnabled;
 	rastCi.depthBiasEnable = staticState.m_rast.m_depthBiasEnabled;
 	rastCi.lineWidth = 1.0f;
 	rastCi.lineWidth = 1.0f;
 	ci.pRasterizationState = &rastCi;
 	ci.pRasterizationState = &rastCi;

+ 2 - 2
AnKi/Renderer/IndirectDiffuseProbes.cpp

@@ -402,7 +402,7 @@ void IndirectDiffuseProbes::populateRenderGraph(RenderingContext& rctx)
 
 
 					if(doShadows)
 					if(doShadows)
 					{
 					{
-						const Mat4 biasMat4(0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
+						const Mat4 biasMat4(0.5f, 0.0f, 0.0f, 0.5f, 0.0f, -0.5f, 0.0f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
 						dsInfo.m_dirLightMatrix = biasMat4 * cascadeViewProjMat;
 						dsInfo.m_dirLightMatrix = biasMat4 * cascadeViewProjMat;
 					}
 					}
 					else
 					else
@@ -468,7 +468,7 @@ void IndirectDiffuseProbes::populateRenderGraph(RenderingContext& rctx)
 				U32 x, y, z;
 				U32 x, y, z;
 				unflatten3dArrayIndex(probeToRefresh->getCellCountsPerDimension().x(), probeToRefresh->getCellCountsPerDimension().y(),
 				unflatten3dArrayIndex(probeToRefresh->getCellCountsPerDimension().x(), probeToRefresh->getCellCountsPerDimension().y(),
 									  probeToRefresh->getCellCountsPerDimension().z(), cellIdx, x, y, z);
 									  probeToRefresh->getCellCountsPerDimension().z(), cellIdx, x, y, z);
-				consts.m_volumeTexel = IVec3(x, y, z);
+				consts.m_volumeTexel = IVec3(x, probeToRefresh->getCellCountsPerDimension().y() - y - 1, z);
 
 
 				consts.m_nextTexelOffsetInU = probeToRefresh->getCellCountsPerDimension().x();
 				consts.m_nextTexelOffsetInU = probeToRefresh->getCellCountsPerDimension().x();
 				cmdb.setFastConstants(&consts, sizeof(consts));
 				cmdb.setFastConstants(&consts, sizeof(consts));

+ 1 - 1
AnKi/Renderer/ProbeReflections.cpp

@@ -385,7 +385,7 @@ void ProbeReflections::populateRenderGraph(RenderingContext& rctx)
 				dsInfo.m_viewport = UVec4(0, 0, m_lightShading.m_tileSize, m_lightShading.m_tileSize);
 				dsInfo.m_viewport = UVec4(0, 0, m_lightShading.m_tileSize, m_lightShading.m_tileSize);
 				dsInfo.m_effectiveShadowDistance = probeToRefresh->getShadowsRenderRadius();
 				dsInfo.m_effectiveShadowDistance = probeToRefresh->getShadowsRenderRadius();
 
 
-				const Mat4 biasMat4(0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
+				const Mat4 biasMat4(0.5f, 0.0f, 0.0f, 0.5f, 0.0f, -0.5f, 0.0f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
 				dsInfo.m_dirLightMatrix = biasMat4 * cascadeViewProjMat;
 				dsInfo.m_dirLightMatrix = biasMat4 * cascadeViewProjMat;
 
 
 				dsInfo.m_visibleLightsBuffer = visResult;
 				dsInfo.m_visibleLightsBuffer = visResult;

+ 1 - 1
AnKi/Renderer/ShadowMapping.cpp

@@ -135,7 +135,7 @@ Mat4 ShadowMapping::createSpotLightTextureMatrix(const UVec4& viewport) const
 	ANKI_ASSERT(viewport[2] == viewport[3]);
 	ANKI_ASSERT(viewport[2] == viewport[3]);
 	const F32 sizeTextureSpace = F32(viewport[2]) / atlasSize;
 	const F32 sizeTextureSpace = F32(viewport[2]) / atlasSize;
 
 
-	const Mat4 biasMat4(0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
+	const Mat4 biasMat4(0.5f, 0.0f, 0.0f, 0.5f, 0.0f, -0.5f, 0.0f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
 
 
 	return Mat4(sizeTextureSpace, 0.0f, 0.0f, uv.x(), 0.0f, sizeTextureSpace, 0.0f, uv.y(), 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
 	return Mat4(sizeTextureSpace, 0.0f, 0.0f, uv.x(), 0.0f, sizeTextureSpace, 0.0f, uv.y(), 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f)
 		   * biasMat4;
 		   * biasMat4;

+ 1 - 1
AnKi/Renderer/Utils/GpuVisibility.cpp

@@ -549,7 +549,7 @@ void GpuVisibility::populateRenderGraphInternal(Bool distanceBased, BaseGpuVisib
 		NonGraphicsRenderPass& pass = rgraph.newNonGraphicsRenderPass(generateTempPassName("GPU vis zero: %s", in.m_passesName.cstr()));
 		NonGraphicsRenderPass& pass = rgraph.newNonGraphicsRenderPass(generateTempPassName("GPU vis zero: %s", in.m_passesName.cstr()));
 		pass.newBufferDependency(zeroMemDep, BufferUsageBit::kCopyDestination);
 		pass.newBufferDependency(zeroMemDep, BufferUsageBit::kCopyDestination);
 
 
-		pass.setWork([stage1Mem, stage2Mem, stage3Mem, this](RenderPassWorkContext& rpass) {
+		pass.setWork([stage1Mem, stage2Mem, stage3Mem](RenderPassWorkContext& rpass) {
 			CommandBuffer& cmdb = *rpass.m_commandBuffer;
 			CommandBuffer& cmdb = *rpass.m_commandBuffer;
 
 
 			constexpr Bool debugZeroing = false; // For debugging purposes zero everything
 			constexpr Bool debugZeroing = false; // For debugging purposes zero everything

+ 1 - 1
AnKi/Resource/ImageResource.cpp

@@ -113,7 +113,7 @@ Error ImageResource::load(const ResourceFilename& filename, Bool async)
 			init.m_format = Format::kR8G8B8_Unorm;
 			init.m_format = Format::kR8G8B8_Unorm;
 			break;
 			break;
 		case ImageBinaryDataCompression::kS3tc:
 		case ImageBinaryDataCompression::kS3tc:
-			init.m_format = Format::kBC1_Rgb_Unorm_Block;
+			init.m_format = Format::kBC1_Rgba_Unorm_Block;
 			break;
 			break;
 		case ImageBinaryDataCompression::kAstc:
 		case ImageBinaryDataCompression::kAstc:
 			if(loader.getAstcBlockSize() == UVec2(4u))
 			if(loader.getAstcBlockSize() == UVec2(4u))

+ 1 - 1
AnKi/Scene/Components/DecalComponent.cpp

@@ -59,7 +59,7 @@ Error DecalComponent::update(SceneComponentUpdateInfo& info, Bool& updated)
 		const Mat4 projMat = Mat4::calculateOrthographicProjectionMatrix(halfBoxSize.x(), -halfBoxSize.x(), halfBoxSize.y(), -halfBoxSize.y(),
 		const Mat4 projMat = Mat4::calculateOrthographicProjectionMatrix(halfBoxSize.x(), -halfBoxSize.x(), halfBoxSize.y(), -halfBoxSize.y(),
 																		 kClusterObjectFrustumNearPlane, m_boxSize.z());
 																		 kClusterObjectFrustumNearPlane, m_boxSize.z());
 
 
-		const Mat4 biasMat4(0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
+		const Mat4 biasMat4(0.5f, 0.0f, 0.0f, 0.5f, 0.0f, -0.5f, 0.0f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
 
 
 		m_biasProjViewMat = biasMat4 * projMat * viewMat;
 		m_biasProjViewMat = biasMat4 * projMat * viewMat;
 
 

+ 1 - 1
AnKi/Scene/Components/LightComponent.cpp

@@ -171,7 +171,7 @@ Error LightComponent::update(SceneComponentUpdateInfo& info, Bool& updated)
 
 
 		if(reallyShadow)
 		if(reallyShadow)
 		{
 		{
-			const Mat4 biasMat4(0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
+			const Mat4 biasMat4(0.5f, 0.0f, 0.0f, 0.5f, 0.0f, -0.5f, 0.0f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f);
 			const Mat4 proj = Mat4::calculatePerspectiveProjectionMatrix(m_spot.m_outerAngle, m_spot.m_outerAngle, kClusterObjectFrustumNearPlane,
 			const Mat4 proj = Mat4::calculatePerspectiveProjectionMatrix(m_spot.m_outerAngle, m_spot.m_outerAngle, kClusterObjectFrustumNearPlane,
 																		 m_spot.m_distance);
 																		 m_spot.m_distance);
 			const Mat4 uvToAtlas(m_shadowAtlasUvViewports[0].z(), 0.0f, 0.0f, m_shadowAtlasUvViewports[0].x(), 0.0f, m_shadowAtlasUvViewports[0].w(),
 			const Mat4 uvToAtlas(m_shadowAtlasUvViewports[0].z(), 0.0f, 0.0f, m_shadowAtlasUvViewports[0].x(), 0.0f, m_shadowAtlasUvViewports[0].w(),

+ 6 - 6
AnKi/Scene/Frustum.cpp

@@ -8,12 +8,12 @@
 
 
 namespace anki {
 namespace anki {
 
 
-Array<Mat3x4, 6> Frustum::m_omnidirectionalRotations = {Mat3x4(Vec3(0.0f), Mat3(Euler(0.0f, -kPi / 2.0f, 0.0f)) * Mat3(Euler(0.0f, 0.0f, kPi))),
-														Mat3x4(Vec3(0.0f), Mat3(Euler(0.0f, kPi / 2.0f, 0.0f)) * Mat3(Euler(0.0f, 0.0f, kPi))),
-														Mat3x4(Vec3(0.0f), Mat3(Euler(kPi / 2.0f, 0.0f, 0.0f))),
-														Mat3x4(Vec3(0.0f), Mat3(Euler(-kPi / 2.0f, 0.0f, 0.0f))),
-														Mat3x4(Vec3(0.0f), Mat3(Euler(0.0f, kPi, 0.0f)) * Mat3(Euler(0.0f, 0.0f, kPi))),
-														Mat3x4(Vec3(0.0f), Mat3(Euler(0.0f, 0.0f, kPi)))};
+Array<Mat3x4, 6> Frustum::m_omnidirectionalRotations = {Mat3x4(Vec3(0.0f), Mat3(Euler(0.0f, -kPi / 2.0f, 0.0f))), // +x
+														Mat3x4(Vec3(0.0f), Mat3(Euler(0.0f, kPi / 2.0f, 0.0f))), // -x
+														Mat3x4(Vec3(0.0f), Mat3(Euler(kPi / 2.0f, 0.0f, 0.0f))), // +y
+														Mat3x4(Vec3(0.0f), Mat3(Euler(-kPi / 2.0f, 0.0f, 0.0f))), // -y
+														Mat3x4(Vec3(0.0f), Mat3::getIdentity()), // -z
+														Mat3x4(Vec3(0.0f), Mat3(Euler(0.0f, kPi, 0.0f)))}; // +z
 
 
 Frustum::Frustum()
 Frustum::Frustum()
 {
 {

+ 2 - 2
AnKi/Shaders/ApplyIrradianceToReflection.ankiprog

@@ -23,7 +23,7 @@ RWTexture2D<RVec4> g_cubeTex[6u] : register(u0); // RWTexture2D because there is
 	const UVec2 dispatchThreadId = min(svDispatchThreadId.xy, cubeSizeu - 1u);
 	const UVec2 dispatchThreadId = min(svDispatchThreadId.xy, cubeSizeu - 1u);
 
 
 	const Vec2 uv = (Vec2(dispatchThreadId) + 0.5) / Vec2(cubeSize);
 	const Vec2 uv = (Vec2(dispatchThreadId) + 0.5) / Vec2(cubeSize);
-	const Vec3 sampleUv = getCubemapDirection(uvToNdc(uv), faceIdx);
+	const Vec3 sampleUv = getCubemapDirection(uv, faceIdx);
 
 
 	// Read the gbuffer
 	// Read the gbuffer
 	GbufferInfo gbuffer = (GbufferInfo)0;
 	GbufferInfo gbuffer = (GbufferInfo)0;
@@ -33,7 +33,7 @@ RWTexture2D<RVec4> g_cubeTex[6u] : register(u0); // RWTexture2D because there is
 
 
 	// Sample
 	// Sample
 	const RVec3 irradiance = sampleAmbientDice(g_irradianceDice[0u].xyz, g_irradianceDice[1u].xyz, g_irradianceDice[2u].xyz, g_irradianceDice[3u].xyz,
 	const RVec3 irradiance = sampleAmbientDice(g_irradianceDice[0u].xyz, g_irradianceDice[1u].xyz, g_irradianceDice[2u].xyz, g_irradianceDice[3u].xyz,
-											   g_irradianceDice[4u].xyz, g_irradianceDice[5u].xyz, gbuffer.m_normal);
+											   g_irradianceDice[4u].xyz, g_irradianceDice[5u].xyz, gbuffer.m_normal * Vec3(1.0, 1.0, -1.0));
 
 
 	// Compute the indirect term
 	// Compute the indirect term
 	const RVec3 indirect = gbuffer.m_diffuse * irradiance;
 	const RVec3 indirect = gbuffer.m_diffuse * irradiance;

+ 8 - 4
AnKi/Shaders/Common.hlsl

@@ -72,15 +72,19 @@
 ANKI_BINDLESS3()
 ANKI_BINDLESS3()
 
 
 template<typename T>
 template<typename T>
-T uvToNdc(T x)
+T uvToNdc(T uv)
 {
 {
-	return x * 2.0f - 1.0f;
+	T ndc = uv * 2.0f - 1.0f;
+	ndc.y *= -1.0f;
+	return ndc;
 }
 }
 
 
 template<typename T>
 template<typename T>
-T ndcToUv(T x)
+T ndcToUv(T ndc)
 {
 {
-	return x * 0.5f + 0.5f;
+	T uv = ndc * 0.5f + 0.5f;
+	uv.y = 1.0f - uv.y;
+	return uv;
 }
 }
 
 
 // Define min3, max3, min4, max4 functions
 // Define min3, max3, min4, max4 functions

+ 41 - 51
AnKi/Shaders/Functions.hlsl

@@ -225,9 +225,16 @@ Vec4 bilateralUpsample(Texture2D depthHigh, Texture2D depthLow, Texture2D colorL
 	return sum / normalize;
 	return sum / normalize;
 }
 }
 
 
-/// Compute the UV that can be passed to a cube texture. The norm is in [-1, 1].
-Vec3 getCubemapDirection(const Vec2 norm, const U32 faceIdx)
-{
+/// Compute the UV that can be passed to a cube texture.
+/// (0.5, 0) returns {1, 0, 0}
+/// (0.5, 1) returns {-1, 0, 0}
+/// (0.5, 2) returns {0, 1, 0}
+/// (0.5, 3) returns {0, -1, 0}
+/// (0.5, 4) returns {0, 0, 1}
+/// (0.5, 5) returns {0, 0, -1}
+Vec3 getCubemapDirection(const Vec2 uv, const U32 faceIdx)
+{
+	const Vec2 norm = uv * 2.0 - 1.0;
 	Vec3 zDir = Vec3((faceIdx <= 1u) ? 1 : 0, (faceIdx & 2u) >> 1u, (faceIdx & 4u) >> 2u);
 	Vec3 zDir = Vec3((faceIdx <= 1u) ? 1 : 0, (faceIdx & 2u) >> 1u, (faceIdx & 4u) >> 2u);
 	zDir *= (((faceIdx & 1u) == 1u) ? -1.0 : 1.0);
 	zDir *= (((faceIdx & 1u) == 1u) ? -1.0 : 1.0);
 	const Vec3 yDir = (faceIdx == 2u) ? Vec3(0.0, 0.0, 1.0) : (faceIdx == 3u) ? Vec3(0.0, 0.0, -1.0) : Vec3(0.0, -1.0, 0.0);
 	const Vec3 yDir = (faceIdx == 2u) ? Vec3(0.0, 0.0, 1.0) : (faceIdx == 3u) ? Vec3(0.0, 0.0, -1.0) : Vec3(0.0, -1.0, 0.0);
@@ -235,62 +242,44 @@ Vec3 getCubemapDirection(const Vec2 norm, const U32 faceIdx)
 	return normalize(norm.x * xDir + norm.y * yDir + zDir);
 	return normalize(norm.x * xDir + norm.y * yDir + zDir);
 }
 }
 
 
-// Convert 3D cubemap coordinates to 2D plus face index. v doesn't need to be normalized.
-Vec2 convertCubeUvs(const Vec3 v, out F32 faceIndex)
-{
-	const Vec3 absV = abs(v);
-	F32 mag;
-	Vec2 uv;
-
-	if(absV.z >= absV.x && absV.z >= absV.y)
-	{
-		faceIndex = (v.z < 0.0) ? 5.0 : 4.0;
-		uv = Vec2((v.z < 0.0) ? -v.x : v.x, -v.y);
-		mag = absV.z;
-	}
-	else if(absV.y >= absV.x)
-	{
-		faceIndex = (v.y < 0.0) ? 3.0 : 2.0;
-		uv = Vec2(v.x, (v.y < 0.0) ? -v.z : v.z);
-		mag = absV.y;
-	}
-	else
-	{
-		faceIndex = (v.x < 0.0) ? 1.0 : 0.0;
-		uv = Vec2((v.x < 0.0) ? v.z : -v.z, -v.y);
-		mag = absV.x;
-	}
-
-	return 0.5 / mag * uv + 0.5;
-}
-
-// Same as convertCubeUvs but it returns the faceIndex as unsigned I32.
-Vec2 convertCubeUvsu(const Vec3 v, out U32 faceIndex)
-{
-	const Vec3 absV = abs(v);
-	F32 mag;
-	Vec2 uv;
-
-	if(absV.z >= absV.x && absV.z >= absV.y)
+/// Convert 3D cubemap coordinates to 2D plus face index. vec doesn't need to be normalized. It's the opposite of getCubemapDirection.
+/// This is the exact same thing AMD is doing (v_cubeid and co) with a small difference. AMD for some reason adds 1.5 to the final result instead of
+/// 0.5.
+template<typename T>
+Vec2 convertCubeUvs(const Vec3 vec, out T faceIndex)
+{
+	F32 u, v;
+	const F32 x = vec.x;
+	const F32 y = vec.y;
+	const F32 z = vec.z;
+	const F32 ax = abs(vec.x);
+	const F32 ay = abs(vec.y);
+	const F32 az = abs(vec.z);
+	F32 major;
+
+	if(az >= ax && az >= ay)
 	{
 	{
-		faceIndex = (v.z < 0.0) ? 5u : 4u;
-		uv = Vec2((v.z < 0.0) ? -v.x : v.x, -v.y);
-		mag = absV.z;
+		major = az;
+		u = (z < 0.0f) ? -x : x;
+		v = -y;
+		faceIndex = (z < 0.0f) ? (T)5 : (T)4;
 	}
 	}
-	else if(absV.y >= absV.x)
+	else if(ay >= ax)
 	{
 	{
-		faceIndex = (v.y < 0.0) ? 3u : 2u;
-		uv = Vec2(v.x, (v.y < 0.0) ? -v.z : v.z);
-		mag = absV.y;
+		major = ay;
+		u = x;
+		v = (y < 0.0f) ? -z : z;
+		faceIndex = (y < 0.0f) ? (T)3 : (T)2;
 	}
 	}
 	else
 	else
 	{
 	{
-		faceIndex = (v.x < 0.0) ? 1u : 0u;
-		uv = Vec2((v.x < 0.0) ? v.z : -v.z, -v.y);
-		mag = absV.x;
+		major = ax;
+		u = (x < 0.0f) ? z : -z;
+		v = -y;
+		faceIndex = (x < 0.0f) ? (T)1 : (T)0;
 	}
 	}
 
 
-	return 0.5 / mag * uv + 0.5;
+	return Vec2(u, v) / (major * 2.0f) + 0.5f;
 }
 }
 
 
 template<typename T>
 template<typename T>
@@ -703,6 +692,7 @@ vector<T, 3> filmGrain(vector<T, 3> color, Vec2 uv, T strength, F32 time)
 
 
 /// Perturb normal, see http://www.thetenthplanet.de/archives/1180
 /// Perturb normal, see http://www.thetenthplanet.de/archives/1180
 /// Does normal mapping in the fragment shader. It assumes that green is up. viewDir and geometricNormal need to be in the same space.
 /// Does normal mapping in the fragment shader. It assumes that green is up. viewDir and geometricNormal need to be in the same space.
+/// viewDir is the -(eye - vertexPos)
 RVec3 perturbNormal(RVec3 tangentNormal, Vec3 viewDir, Vec2 uv, Vec3 geometricNormal)
 RVec3 perturbNormal(RVec3 tangentNormal, Vec3 viewDir, Vec2 uv, Vec3 geometricNormal)
 {
 {
 	tangentNormal.y = -tangentNormal.y; // Green is up
 	tangentNormal.y = -tangentNormal.y; // Green is up

+ 2 - 6
AnKi/Shaders/GBufferGeneric.ankiprog

@@ -59,10 +59,6 @@
 #define SW_MESHLETS (ANKI_TECHNIQUE_GBufferSwMeshletRendering || ANKI_TECHNIQUE_ShadowsSwMeshletRendering)
 #define SW_MESHLETS (ANKI_TECHNIQUE_GBufferSwMeshletRendering || ANKI_TECHNIQUE_ShadowsSwMeshletRendering)
 
 
 #define VISUALIZE_MESHLETS (0 && GBUFFER)
 #define VISUALIZE_MESHLETS (0 && GBUFFER)
-#define MESHLET_BACKFACE_CULLING 0
-#define MESHLET_OUTSIDE_OF_SCREEN_CULLING 1
-#define MESHLET_NO_SAMPLING_POINT_CULLING 1
-#define MESHLET_HZB_CULLING 1
 #define PRIMITIVE_BACKFACE_CULLING 1
 #define PRIMITIVE_BACKFACE_CULLING 1
 #define PRIMITIVE_NO_SAMPLING_POINTS_CULLING 1
 #define PRIMITIVE_NO_SAMPLING_POINTS_CULLING 1
 #define PRIMITIVE_ANY_CULLING (PRIMITIVE_BACKFACE_CULLING || PRIMITIVE_NO_SAMPLING_POINTS_CULLING)
 #define PRIMITIVE_ANY_CULLING (PRIMITIVE_BACKFACE_CULLING || PRIMITIVE_NO_SAMPLING_POINTS_CULLING)
@@ -414,7 +410,7 @@ main(U32 svGroupId : SV_GROUPID, U32 svGroupIndex : SV_GROUPINDEX, out vertices
 			const Vec2 eb = c - a;
 			const Vec2 eb = c - a;
 			const Vec2 ec = b - a;
 			const Vec2 ec = b - a;
 
 
-			cull = cull || (eb.x * ec.y >= eb.y * ec.x);
+			cull = cull || (eb.x * ec.y < eb.y * ec.x);
 #	endif
 #	endif
 
 
 #	if PRIMITIVE_NO_SAMPLING_POINTS_CULLING
 #	if PRIMITIVE_NO_SAMPLING_POINTS_CULLING
@@ -537,7 +533,7 @@ PixelOut main(
 
 
 #		if NORMAL_TEX
 #		if NORMAL_TEX
 	const RVec3 nAtTangentspace = normalize((BINDLESS(localConstants.m_normalTex).Sample(g_globalSampler, uv).rgb - 0.5) * 2.0);
 	const RVec3 nAtTangentspace = normalize((BINDLESS(localConstants.m_normalTex).Sample(g_globalSampler, uv).rgb - 0.5) * 2.0);
-	const Vec3 viewDir = normalize(g_globalConstants.m_cameraTransform.getTranslationPart() - vertInput.m_worldPos);
+	const Vec3 viewDir = -normalize(g_globalConstants.m_cameraTransform.getTranslationPart() - vertInput.m_worldPos);
 	const RVec3 normal = perturbNormal(nAtTangentspace, viewDir, uv, normalize(vertInput.m_normal));
 	const RVec3 normal = perturbNormal(nAtTangentspace, viewDir, uv, normalize(vertInput.m_normal));
 #		else
 #		else
 	const RVec3 normal = normalize(vertInput.m_normal);
 	const RVec3 normal = normalize(vertInput.m_normal);

+ 1 - 1
AnKi/Shaders/HzbMaxDepthProject.ankiprog

@@ -53,7 +53,7 @@ Vec4 main(U32 svVertexId : SV_VERTEXID, U32 svInstanceId : SV_INSTANCEID) : SV_P
 
 
 	// Y
 	// Y
 	ndc.y = F32(tileY);
 	ndc.y = F32(tileY);
-	if(svVertexId == 3 || svVertexId == 2 || svVertexId == 7 || svVertexId == 6)
+	if(svVertexId == 0 || svVertexId == 1 || svVertexId == 4 || svVertexId == 5)
 	{
 	{
 		// Top side, move the point
 		// Top side, move the point
 		ndc.y += 1.0f;
 		ndc.y += 1.0f;

+ 10 - 12
AnKi/Shaders/IrradianceDice.ankiprog

@@ -46,14 +46,13 @@ RWStructuredBuffer<BufferOut> g_irradianceDisceResults : register(u0);
 #endif
 #endif
 
 
 constexpr U32 kMinWaveSize = 8u;
 constexpr U32 kMinWaveSize = 8u;
-groupshared Vec3 s_integrationResults[6u][kThreadgroupSize / kMinWaveSize];
+groupshared Vec3 s_integrationResults[6u][kThreadgroupSize / kMinWaveSize]; // In cube coords
 groupshared U32 s_waveIndexInsideThreadGroup;
 groupshared U32 s_waveIndexInsideThreadGroup;
 
 
 RVec3 sampleLightShadingTexture(const U32 face, UVec3 svGroupThreadId)
 RVec3 sampleLightShadingTexture(const U32 face, UVec3 svGroupThreadId)
 {
 {
 	const Vec2 uv = (Vec2(svGroupThreadId.x, svGroupThreadId.y) + 0.5) / F32(THREDGROUP_SIZE_SQRT);
 	const Vec2 uv = (Vec2(svGroupThreadId.x, svGroupThreadId.y) + 0.5) / F32(THREDGROUP_SIZE_SQRT);
-	const Vec2 ndc = uvToNdc(uv);
-	const Vec3 cubeUvw = getCubemapDirection(ndc, face);
+	const Vec3 cubeUvw = getCubemapDirection(uv, face);
 
 
 	return g_lightShadingTexCube.SampleLevel(g_nearestAnyClampSampler, cubeUvw, 0.0).rgb;
 	return g_lightShadingTexCube.SampleLevel(g_nearestAnyClampSampler, cubeUvw, 0.0).rgb;
 }
 }
@@ -67,21 +66,20 @@ RVec3 sampleLightShadingTexture(const U32 face, UVec3 svGroupThreadId)
 
 
 	// Compute the NDC used in cubeCoordSolidAngle
 	// Compute the NDC used in cubeCoordSolidAngle
 	const Vec2 faceUv = (Vec2(svGroupThreadId.xy) + 0.5) / threadgroupSizeSqrtf;
 	const Vec2 faceUv = (Vec2(svGroupThreadId.xy) + 0.5) / threadgroupSizeSqrtf;
-	const Vec2 ndc = uvToNdc(faceUv);
 
 
 	// Compute result for a pixel
 	// Compute result for a pixel
 	Vec3 resultFaces[6u];
 	Vec3 resultFaces[6u];
 	for(U32 f = 0u; f < 6u; ++f)
 	for(U32 f = 0u; f < 6u; ++f)
 	{
 	{
 		// Get the direction of the dice face
 		// Get the direction of the dice face
-		const Vec3 diceDir = getCubemapDirection(Vec2(0.0, 0.0), f);
+		const Vec3 diceDir = getCubemapDirection(0.5, f) * Vec3(1.0, 1.0, -1.0);
 
 
-		const Vec3 r = getCubemapDirection(ndc, f);
+		const Vec3 r = getCubemapDirection(faceUv, f) * Vec3(1.0, 1.0, -1.0);
 
 
 		// Compute integral part
 		// Compute integral part
 		const RF32 lambert = max(0.0, dot(r, diceDir));
 		const RF32 lambert = max(0.0, dot(r, diceDir));
 		const RVec3 lightShading = sampleLightShadingTexture(f, svGroupThreadId);
 		const RVec3 lightShading = sampleLightShadingTexture(f, svGroupThreadId);
-		const RVec3 irradiance = lightShading * lambert * cubeCoordSolidAngle(ndc, threadgroupSizeSqrtf);
+		const RVec3 irradiance = lightShading * lambert * cubeCoordSolidAngle(uvToNdc(faceUv), threadgroupSizeSqrtf);
 
 
 		// Store
 		// Store
 		resultFaces[f] = irradiance;
 		resultFaces[f] = irradiance;
@@ -122,15 +120,15 @@ RVec3 sampleLightShadingTexture(const U32 face, UVec3 svGroupThreadId)
 	for(U32 f = 0u; f < 6u; ++f)
 	for(U32 f = 0u; f < 6u; ++f)
 	{
 	{
 		// Get the direction of the dice face
 		// Get the direction of the dice face
-		const Vec3 diceDir = getCubemapDirection(Vec2(0.0, 0.0), f);
+		const Vec3 diceDir = getCubemapDirection(0.5, f) * Vec3(1.0, 1.0, -1.0);
 
 
-		const Vec3 r = getCubemapDirection(ndc, f);
+		const Vec3 r = getCubemapDirection(faceUv, f) * Vec3(1.0, 1.0, -1.0);
 
 
 		// Compute integral part
 		// Compute integral part
 		const RF32 lambert = max(0.0, dot(r, diceDir));
 		const RF32 lambert = max(0.0, dot(r, diceDir));
 
 
 		// Read the gbuffer
 		// Read the gbuffer
-		const Vec3 gbufferUv = getCubemapDirection(ndc, f);
+		const Vec3 gbufferUv = getCubemapDirection(faceUv, f);
 		GbufferInfo gbuffer = (GbufferInfo)0;
 		GbufferInfo gbuffer = (GbufferInfo)0;
 		unpackGBufferNoVelocity(g_gbufferTex[0u].SampleLevel(g_nearestAnyClampSampler, gbufferUv, 0.0),
 		unpackGBufferNoVelocity(g_gbufferTex[0u].SampleLevel(g_nearestAnyClampSampler, gbufferUv, 0.0),
 								g_gbufferTex[1u].SampleLevel(g_nearestAnyClampSampler, gbufferUv, 0.0),
 								g_gbufferTex[1u].SampleLevel(g_nearestAnyClampSampler, gbufferUv, 0.0),
@@ -139,12 +137,12 @@ RVec3 sampleLightShadingTexture(const U32 face, UVec3 svGroupThreadId)
 		// Sample irradiance
 		// Sample irradiance
 		RVec3 firstBounceIrradiance =
 		RVec3 firstBounceIrradiance =
 			sampleAmbientDice(s_integrationResults[0][0], s_integrationResults[1][0], s_integrationResults[2][0], s_integrationResults[3][0],
 			sampleAmbientDice(s_integrationResults[0][0], s_integrationResults[1][0], s_integrationResults[2][0], s_integrationResults[3][0],
-							  s_integrationResults[4][0], s_integrationResults[5][0], gbuffer.m_normal);
+							  s_integrationResults[4][0], s_integrationResults[5][0], gbuffer.m_normal * Vec3(1.0, 1.0, -1.0));
 		firstBounceIrradiance = gbuffer.m_diffuse * firstBounceIrradiance;
 		firstBounceIrradiance = gbuffer.m_diffuse * firstBounceIrradiance;
 
 
 		// Compute 2nd bounce
 		// Compute 2nd bounce
 		const RVec3 lightShading = sampleLightShadingTexture(f, svGroupThreadId);
 		const RVec3 lightShading = sampleLightShadingTexture(f, svGroupThreadId);
-		const RVec3 irradiance = (firstBounceIrradiance + lightShading * lambert) * cubeCoordSolidAngle(ndc, threadgroupSizeSqrtf);
+		const RVec3 irradiance = (firstBounceIrradiance + lightShading * lambert) * cubeCoordSolidAngle(uvToNdc(faceUv), threadgroupSizeSqrtf);
 
 
 		// Store
 		// Store
 		resultFaces[f] = irradiance;
 		resultFaces[f] = irradiance;

+ 5 - 2
AnKi/Shaders/LightFunctions.hlsl

@@ -178,7 +178,7 @@ RF32 computeShadowFactorPointLightGeneric(PointLight light, Vec3 frag2Light, Tex
 
 
 	// Convert cube coords
 	// Convert cube coords
 	U32 faceIdxu;
 	U32 faceIdxu;
-	Vec2 uv = convertCubeUvsu(dir, faceIdxu);
+	Vec2 uv = convertCubeUvs(dir * Vec3(1.0, 1.0, -1.0), faceIdxu);
 
 
 	// Get the atlas offset
 	// Get the atlas offset
 	const Vec2 atlasOffset = light.m_shadowAtlasTileOffsets[faceIdxu].xy;
 	const Vec2 atlasOffset = light.m_shadowAtlasTileOffsets[faceIdxu].xy;
@@ -396,8 +396,9 @@ F32 computeProbeBlendWeight(Vec3 fragPos, // Doesn't need to be inside the AABB
 // https://www.shadertoy.com/view/XtcBDB
 // https://www.shadertoy.com/view/XtcBDB
 RVec3 sampleAmbientDice(RVec3 posx, RVec3 negx, RVec3 posy, RVec3 negy, RVec3 posz, RVec3 negz, RVec3 normal)
 RVec3 sampleAmbientDice(RVec3 posx, RVec3 negx, RVec3 posy, RVec3 negy, RVec3 posz, RVec3 negz, RVec3 normal)
 {
 {
+	normal.z *= -1.0f;
 	const RVec3 axisWeights = normal * normal;
 	const RVec3 axisWeights = normal * normal;
-	const RVec3 uv = ndcToUv(normal);
+	const RVec3 uv = normal * 0.5f + 0.5f;
 
 
 	RVec3 col = lerp(negx, posx, uv.x) * axisWeights.x;
 	RVec3 col = lerp(negx, posx, uv.x) * axisWeights.x;
 	col += lerp(negy, posy, uv.y) * axisWeights.y;
 	col += lerp(negy, posy, uv.y) * axisWeights.y;
@@ -415,6 +416,8 @@ RVec3 sampleGlobalIllumination(const Vec3 worldPos, const Vec3 normal, const Glo
 {
 {
 	// Find the UVW
 	// Find the UVW
 	Vec3 uvw = (worldPos - probe.m_aabbMin) / (probe.m_aabbMax - probe.m_aabbMin);
 	Vec3 uvw = (worldPos - probe.m_aabbMin) / (probe.m_aabbMax - probe.m_aabbMin);
+	uvw = saturate(uvw);
+	uvw.y = 1.0f - uvw.y;
 
 
 	// The U contains the 6 directions so divide
 	// The U contains the 6 directions so divide
 	uvw.x /= 6.0;
 	uvw.x /= 6.0;

+ 4 - 2
AnKi/Shaders/LightShading.ankiprog

@@ -144,7 +144,8 @@ RVec3 main(VertOut input) : SV_TARGET0
 				const ReflectionProbe probe = g_reflectionProbes[firstbitlow2(cluster.m_reflectionProbesMask)];
 				const ReflectionProbe probe = g_reflectionProbes[firstbitlow2(cluster.m_reflectionProbesMask)];
 
 
 				// Sample
 				// Sample
-				const Vec3 cubeUv = intersectProbe(worldPos, reflDir, probe.m_aabbMin, probe.m_aabbMax, probe.m_position);
+				Vec3 cubeUv = intersectProbe(worldPos, reflDir, probe.m_aabbMin, probe.m_aabbMax, probe.m_position);
+				cubeUv.z = -cubeUv.z;
 				probeColor = getBindlessTextureCubeRVec4(probe.m_cubeTexture).SampleLevel(g_trilinearClampSampler, cubeUv, reflLod).rgb;
 				probeColor = getBindlessTextureCubeRVec4(probe.m_cubeTexture).SampleLevel(g_trilinearClampSampler, cubeUv, reflLod).rgb;
 			}
 			}
 			else
 			else
@@ -165,7 +166,8 @@ RVec3 main(VertOut input) : SV_TARGET0
 					totalBlendWeight += blendWeight;
 					totalBlendWeight += blendWeight;
 
 
 					// Sample reflections
 					// Sample reflections
-					const Vec3 cubeUv = intersectProbe(worldPos, reflDir, probe.m_aabbMin, probe.m_aabbMax, probe.m_position);
+					Vec3 cubeUv = intersectProbe(worldPos, reflDir, probe.m_aabbMin, probe.m_aabbMax, probe.m_position);
+					cubeUv.z = -cubeUv.z;
 					const Vec3 c =
 					const Vec3 c =
 						getBindlessTextureNonUniformIndexCubeRVec4(probe.m_cubeTexture).SampleLevel(g_trilinearClampSampler, cubeUv, reflLod).rgb;
 						getBindlessTextureNonUniformIndexCubeRVec4(probe.m_cubeTexture).SampleLevel(g_trilinearClampSampler, cubeUv, reflLod).rgb;
 					probeColor += c * blendWeight;
 					probeColor += c * blendWeight;

+ 1 - 3
AnKi/Shaders/MotionVectors.ankiprog

@@ -10,8 +10,6 @@
 #if ANKI_COMPUTE_SHADER || ANKI_PIXEL_SHADER
 #if ANKI_COMPUTE_SHADER || ANKI_PIXEL_SHADER
 #	include <AnKi/Shaders/Functions.hlsl>
 #	include <AnKi/Shaders/Functions.hlsl>
 
 
-constexpr F32 kMaxRejectionDistance = 0.1; // In meters
-
 SamplerState g_nearesetAnyClampSampler : register(s0);
 SamplerState g_nearesetAnyClampSampler : register(s0);
 Texture2D g_currentDepthTex : register(t0);
 Texture2D g_currentDepthTex : register(t0);
 Texture2D g_velocityTex : register(t1);
 Texture2D g_velocityTex : register(t1);
@@ -69,7 +67,7 @@ PixelOut main(VertOut input)
 		Vec4 prevClipPos = mul(g_consts.m_prevViewProjMat, Vec4(worldPos, 1.0));
 		Vec4 prevClipPos = mul(g_consts.m_prevViewProjMat, Vec4(worldPos, 1.0));
 		prevClipPos.xy /= prevClipPos.w;
 		prevClipPos.xy /= prevClipPos.w;
 
 
-		const Vec2 diff = (prevClipPos.xy - clipPos.xy) * 0.5f; // aka uvToNdc(prevClipPos.xy) - uvToNdc(clipPos.xy)
+		const Vec2 diff = ndcToUv(prevClipPos.xy) - ndcToUv(clipPos.xy);
 		historyUv = uv + diff;
 		historyUv = uv + diff;
 	}
 	}
 
 

+ 4 - 3
AnKi/Shaders/QuadVert.hlsl

@@ -18,10 +18,11 @@ struct VertOut
 #if ANKI_VERTEX_SHADER
 #if ANKI_VERTEX_SHADER
 VertOut main(U32 vertId : SV_VERTEXID)
 VertOut main(U32 vertId : SV_VERTEXID)
 {
 {
-	VertOut output;
-	output.m_uv = Vec2(vertId & 1, vertId >> 1) * 2.0;
+	const Vec2 coord = Vec2(vertId >> 1, vertId & 1);
 
 
-	output.m_svPosition = Vec4(output.m_uv * 2.0 - 1.0, CUSTOM_DEPTH, 1.0);
+	VertOut output;
+	output.m_svPosition = Vec4(coord * Vec2(4.0, -4.0) + Vec2(-1.0, 1.0), CUSTOM_DEPTH, 1.0);
+	output.m_uv = coord * 2.0f;
 
 
 	return output;
 	return output;
 }
 }

+ 9 - 6
AnKi/Shaders/Sky.ankiprog

@@ -75,7 +75,8 @@ Vec3 getValFromTLut(Texture2D<Vec4> tex, SamplerState linearAnyClampSampler, Vec
 	const F32 height = length(pos);
 	const F32 height = length(pos);
 	const Vec3 up = pos / height;
 	const Vec3 up = pos / height;
 	const F32 sunCosZenithAngle = dot(dirToSun, up);
 	const F32 sunCosZenithAngle = dot(dirToSun, up);
-	const Vec2 uv = Vec2(saturate(0.5f + 0.5f * sunCosZenithAngle), saturate((height - kGroundRadiusMM) / (kAtmosphereRadiusMM - kGroundRadiusMM)));
+	const Vec2 uv =
+		Vec2(saturate(0.5f + 0.5f * sunCosZenithAngle), 1.0 - saturate((height - kGroundRadiusMM) / (kAtmosphereRadiusMM - kGroundRadiusMM)));
 	return tex.SampleLevel(linearAnyClampSampler, uv, 0.0f).xyz;
 	return tex.SampleLevel(linearAnyClampSampler, uv, 0.0f).xyz;
 }
 }
 
 
@@ -86,7 +87,7 @@ Vec3 getValFromTLut(Texture2D<Vec4> tex, Vec3 pos, Vec3 dirToSun)
 	const Vec3 up = pos / height;
 	const Vec3 up = pos / height;
 	const F32 sunCosZenithAngle = dot(dirToSun, up);
 	const F32 sunCosZenithAngle = dot(dirToSun, up);
 
 
-	const Vec2 uv = Vec2(0.5f + 0.5f * sunCosZenithAngle, (height - kGroundRadiusMM) / (kAtmosphereRadiusMM - kGroundRadiusMM));
+	const Vec2 uv = Vec2(0.5f + 0.5f * sunCosZenithAngle, 1.0 - (height - kGroundRadiusMM) / (kAtmosphereRadiusMM - kGroundRadiusMM));
 
 
 	Vec2 texSize;
 	Vec2 texSize;
 	tex.GetDimensions(texSize.x, texSize.y);
 	tex.GetDimensions(texSize.x, texSize.y);
@@ -100,7 +101,8 @@ Vec3 getValFromMultiScattLut(Texture2D<Vec4> tex, SamplerState linearAnyClampSam
 	const F32 height = length(pos);
 	const F32 height = length(pos);
 	const Vec3 up = pos / height;
 	const Vec3 up = pos / height;
 	const F32 sunCosZenithAngle = dot(dirToSun, up);
 	const F32 sunCosZenithAngle = dot(dirToSun, up);
-	const Vec2 uv = Vec2(saturate(0.5 + 0.5 * sunCosZenithAngle), saturate((height - kGroundRadiusMM) / (kAtmosphereRadiusMM - kGroundRadiusMM)));
+	const Vec2 uv =
+		Vec2(saturate(0.5 + 0.5 * sunCosZenithAngle), 1.0 - saturate((height - kGroundRadiusMM) / (kAtmosphereRadiusMM - kGroundRadiusMM)));
 	return tex.SampleLevel(linearAnyClampSampler, uv, 0.0f).xyz;
 	return tex.SampleLevel(linearAnyClampSampler, uv, 0.0f).xyz;
 }
 }
 
 
@@ -181,7 +183,7 @@ Vec3 getSunTransmittance(Vec3 pos, Vec3 dirToSun)
 
 
 	const F32 sunCosTheta = 2.0f * uv.x - 1.0f;
 	const F32 sunCosTheta = 2.0f * uv.x - 1.0f;
 	const F32 sunTheta = safeacos(sunCosTheta);
 	const F32 sunTheta = safeacos(sunCosTheta);
-	const F32 height = lerp(kGroundRadiusMM, kAtmosphereRadiusMM, uv.y);
+	const F32 height = lerp(kGroundRadiusMM, kAtmosphereRadiusMM, 1.0 - uv.y);
 
 
 	const Vec3 pos = Vec3(0.0f, height, 0.0f);
 	const Vec3 pos = Vec3(0.0f, height, 0.0f);
 	const Vec3 dirToSun = normalize(Vec3(0.0f, sunCosTheta, -sin(sunTheta)));
 	const Vec3 dirToSun = normalize(Vec3(0.0f, sunCosTheta, -sin(sunTheta)));
@@ -301,7 +303,7 @@ void getMulScattValues(Vec3 pos, Vec3 dirToSun, out Vec3 lumTotal, out Vec3 fms)
 
 
 	const F32 sunCosTheta = 2.0f * uv.x - 1.0f;
 	const F32 sunCosTheta = 2.0f * uv.x - 1.0f;
 	const F32 sunTheta = safeacos(sunCosTheta);
 	const F32 sunTheta = safeacos(sunCosTheta);
-	const F32 height = lerp(kGroundRadiusMM, kAtmosphereRadiusMM, uv.y);
+	const F32 height = lerp(kGroundRadiusMM, kAtmosphereRadiusMM, 1.0 - uv.y);
 
 
 	const Vec3 pos = Vec3(0.0f, height, 0.0f);
 	const Vec3 pos = Vec3(0.0f, height, 0.0f);
 	const Vec3 dirToSun = normalize(Vec3(0.0f, sunCosTheta, -sin(sunTheta)));
 	const Vec3 dirToSun = normalize(Vec3(0.0f, sunCosTheta, -sin(sunTheta)));
@@ -378,7 +380,8 @@ Vec3 raymarchScattering(Vec3 pos, Vec3 rayDir, Vec3 dirToSun, F32 tMax, F32 numS
 	Vec2 lutSize;
 	Vec2 lutSize;
 	g_skyLutStorageTex.GetDimensions(lutSize.x, lutSize.y);
 	g_skyLutStorageTex.GetDimensions(lutSize.x, lutSize.y);
 
 
-	const Vec2 uv = (Vec2(svDispatchThreadId) + 0.5f) / lutSize;
+	Vec2 uv = (Vec2(svDispatchThreadId) + 0.5f) / lutSize;
+	uv.y = 1.0f - uv.y;
 
 
 	const F32 azimuthAngle = (uv.x - 0.5f) * 2.0f * kPi;
 	const F32 azimuthAngle = (uv.x - 0.5f) * 2.0f * kPi;
 	// Non-linear mapping of altitude. See Section 5.3 of the paper.
 	// Non-linear mapping of altitude. See Section 5.3 of the paper.

+ 1 - 1
AnKi/Shaders/Sky.hlsl

@@ -42,7 +42,7 @@ Vec3 getValFromSkyLut(Texture2D<Vec4> skyLut, SamplerState linearAnyClampSampler
 
 
 	// Non-linear mapping of altitude angle. See Section 5.3 of the paper.
 	// Non-linear mapping of altitude angle. See Section 5.3 of the paper.
 	const F32 v = 0.5 + 0.5 * sign(altitudeAngle) * sqrt(abs(altitudeAngle) * 2.0 / kPi);
 	const F32 v = 0.5 + 0.5 * sign(altitudeAngle) * sqrt(abs(altitudeAngle) * 2.0 / kPi);
-	const Vec2 uv = Vec2(azimuthAngle / (2.0f * kPi), v);
+	const Vec2 uv = Vec2(azimuthAngle / (2.0f * kPi), 1.0 - v);
 
 
 	return skyLut.SampleLevel(linearAnyClampSampler, uv, 0.0f).xyz;
 	return skyLut.SampleLevel(linearAnyClampSampler, uv, 0.0f).xyz;
 }
 }

+ 1 - 1
AnKi/Shaders/Ssr.ankiprog

@@ -128,7 +128,7 @@ RVec4 main(VertOut input) : SV_TARGET0
 		const RF32 oppositeLen = tan(coneAngle / 2.0f) * adjacentLen;
 		const RF32 oppositeLen = tan(coneAngle / 2.0f) * adjacentLen;
 		const Vec3 projectedOpposite =
 		const Vec3 projectedOpposite =
 			cheapPerspectiveProjection(g_consts.m_projMat00_11_22_23, Vec4(hitPointViewSpace + Vec3(oppositeLen, 0.0f, 0.0f), 1.0f));
 			cheapPerspectiveProjection(g_consts.m_projMat00_11_22_23, Vec4(hitPointViewSpace + Vec3(oppositeLen, 0.0f, 0.0f), 1.0f));
-		const F32 uvDistance = abs(ndcToUv(projectedOpposite.x) - hitPoint.x);
+		const F32 uvDistance = abs((projectedOpposite.x * 0.5f + 0.5f) - hitPoint.x);
 		const RF32 mip = max(0.0f, log2(uvDistance * lightShadingTexSize.x + kEpsilonF32));
 		const RF32 mip = max(0.0f, log2(uvDistance * lightShadingTexSize.x + kEpsilonF32));
 
 
 		// Reproject the hit point because you are reading the previous frame
 		// Reproject the hit point because you are reading the previous frame

+ 5 - 2
AnKi/Shaders/VisibilityAndCollisionFunctions.hlsl

@@ -225,8 +225,11 @@ Bool cullHzb(Vec2 aabbMinNdc, Vec2 aabbMaxNdc, F32 aabbMinDepth, Texture2D<Vec4>
 	F32 mipCount;
 	F32 mipCount;
 	hzb.GetDimensions(0, texSize.x, texSize.y, mipCount);
 	hzb.GetDimensions(0, texSize.x, texSize.y, mipCount);
 
 
-	const Vec2 minUv = saturate(ndcToUv(aabbMinNdc));
-	const Vec2 maxUv = saturate(ndcToUv(aabbMaxNdc));
+	const Vec2 uva = saturate(ndcToUv(aabbMinNdc));
+	const Vec2 uvb = saturate(ndcToUv(aabbMaxNdc));
+
+	const Vec2 minUv = Vec2(uva.x, uvb.y);
+	const Vec2 maxUv = Vec2(uvb.x, uva.y);
 	const Vec2 sizeXY = (maxUv - minUv) * texSize;
 	const Vec2 sizeXY = (maxUv - minUv) * texSize;
 	F32 mip = ceil(log2(max(sizeXY.x, sizeXY.y)));
 	F32 mip = ceil(log2(max(sizeXY.x, sizeXY.y)));
 
 

+ 22 - 0
AnKi/Util/Functions.h

@@ -201,6 +201,28 @@ inline void alignRoundDown(TAlignment alignment, TValue& value)
 	value = getAlignedRoundDown(alignment, value);
 	value = getAlignedRoundDown(alignment, value);
 }
 }
 
 
+/// Given two alignments compute a new alignment that satisfies both
+template<typename T>
+T computeCompoundAlignment(const T alignment1, const T alignment2)
+{
+	ANKI_ASSERT(alignment1 && alignment2);
+
+	// Compute greatest common divisor
+	T greatestCommonDivisor = alignment1;
+	T alignment2_ = alignment2;
+	while(alignment2_ != 0)
+	{
+		const auto temp = alignment2_;
+		alignment2_ = greatestCommonDivisor % alignment2_;
+		greatestCommonDivisor = temp;
+	}
+
+	// Calculate the least common multiple (LCM) of the two alignments
+	const auto lcmAlignment = alignment1 * (alignment2 / greatestCommonDivisor);
+
+	return lcmAlignment;
+}
+
 /// Check if a number is aligned
 /// Check if a number is aligned
 template<typename Type>
 template<typename Type>
 inline constexpr Bool isAligned(PtrSize alignment, Type value)
 inline constexpr Bool isAligned(PtrSize alignment, Type value)

+ 8 - 4
Sandbox/Main.cpp

@@ -165,6 +165,14 @@ Error MyApp::userMainLoop(Bool& quit, Second elapsedTime)
 		mousePosOn1stClick = in.getMousePosition();
 		mousePosOn1stClick = in.getMousePosition();
 	}
 	}
 
 
+	if(in.getKey(KeyCode::kF2) == 1)
+	{
+		mover->setLocalRotation(
+			Mat3x4(-0.600323, -0.173433, 0.780726, 0.000000, 0.000000, 0.976203, 0.216857, 0.000000, -0.799758, 0.130185, -0.586037, 0.000000));
+
+		// printf("%s | %s\n", mover->getWorldTransform().getRotation().toString().cstr(), mover->getWorldTransform().getOrigin().toString().cstr());
+	}
+
 	if(in.getMouseButton(MouseButton::kRight) || in.hasTouchDevice())
 	if(in.getMouseButton(MouseButton::kRight) || in.hasTouchDevice())
 	{
 	{
 		constexpr F32 ROTATE_ANGLE = toRad(2.5f);
 		constexpr F32 ROTATE_ANGLE = toRad(2.5f);
@@ -198,10 +206,6 @@ Error MyApp::userMainLoop(Bool& quit, Second elapsedTime)
 				renderer.getDbg().setDitheredDepthTestEnabled(true);
 				renderer.getDbg().setDitheredDepthTestEnabled(true);
 			}
 			}
 		}
 		}
-		if(in.getKey(KeyCode::kF2) == 1)
-		{
-			// renderer.getDbg().flipFlags(DbgFlag::SPATIAL_COMPONENT);
-		}
 
 
 		if(in.getKey(KeyCode::kUp))
 		if(in.getKey(KeyCode::kUp))
 		{
 		{

+ 2 - 2
Tests/Gr/Gr.cpp

@@ -440,6 +440,7 @@ float4 main(float4 svPosition : SV_POSITION, float2 uv : TEXCOORDS, uint svPrimI
 
 
 		const U kIterationCount = 100;
 		const U kIterationCount = 100;
 		U iterations = kIterationCount;
 		U iterations = kIterationCount;
+		const Vec4 viewport(10.0f, 10.0f, F32(NativeWindow::getSingleton().getWidth() - 20), F32(NativeWindow::getSingleton().getHeight() - 30));
 		while(iterations--)
 		while(iterations--)
 		{
 		{
 			HighRezTimer timer;
 			HighRezTimer timer;
@@ -451,7 +452,7 @@ float4 main(float4 svPosition : SV_POSITION, float2 uv : TEXCOORDS, uint svPrimI
 			cinit.m_flags = CommandBufferFlag::kGeneralWork;
 			cinit.m_flags = CommandBufferFlag::kGeneralWork;
 			CommandBufferPtr cmdb = GrManager::getSingleton().newCommandBuffer(cinit);
 			CommandBufferPtr cmdb = GrManager::getSingleton().newCommandBuffer(cinit);
 
 
-			cmdb->setViewport(0, 0, NativeWindow::getSingleton().getWidth(), NativeWindow::getSingleton().getHeight());
+			cmdb->setViewport(U32(viewport.x()), U32(viewport.y()), U32(viewport.z()), U32(viewport.w()));
 			cmdb->bindShaderProgram(prog.get());
 			cmdb->bindShaderProgram(prog.get());
 
 
 			const TextureBarrierInfo barrier = {TextureView(presentTex.get(), TextureSubresourceDesc::all()), TextureUsageBit::kNone,
 			const TextureBarrierInfo barrier = {TextureView(presentTex.get(), TextureSubresourceDesc::all()), TextureUsageBit::kNone,
@@ -460,7 +461,6 @@ float4 main(float4 svPosition : SV_POSITION, float2 uv : TEXCOORDS, uint svPrimI
 
 
 			cmdb->beginRenderPass({TextureView(presentTex.get(), TextureSubresourceDesc::firstSurface())});
 			cmdb->beginRenderPass({TextureView(presentTex.get(), TextureSubresourceDesc::firstSurface())});
 
 
-			const Vec4 viewport(0.0f, 0.0f, F32(NativeWindow::getSingleton().getWidth()), F32(NativeWindow::getSingleton().getHeight()));
 			cmdb->setFastConstants(&viewport, sizeof(viewport));
 			cmdb->setFastConstants(&viewport, sizeof(viewport));
 
 
 			cmdb->bindSrv(0, 0, TextureView(tex.get(), TextureSubresourceDesc::all()));
 			cmdb->bindSrv(0, 0, TextureView(tex.get(), TextureSubresourceDesc::all()));