浏览代码

Re-enable decals

Panagiotis Christopoulos Charitos 9 月之前
父节点
当前提交
eeae4a63bc

+ 7 - 7
AnKi/Importer/GltfImporter.cpp

@@ -802,29 +802,29 @@ Error GltfImporter::visitNode(const cgltf_node& node, const Transform& parentTrf
 			ANKI_CHECK(m_sceneFile.writeTextf("\nnode = scene:newSceneNode(\"%s\")\n", getNodeName(node).cstr()));
 			ANKI_CHECK(m_sceneFile.writeText("comp = node:newDecalComponent()\n"));
 
-			ANKI_CHECK(getExtra(extras, "decal_diffuse_atlas", extraValueStr, extraFound));
+			ANKI_CHECK(getExtra(extras, "decal_diffuse", extraValueStr, extraFound));
 			if(extraFound)
 			{
 				ANKI_CHECK(getExtra(extras, "decal_diffuse_factor", extraValuef, extraFound));
 
 				ANKI_CHECK(
-					m_sceneFile.writeTextf("comp:loadDiffuseImageResource(\"%s\", %f)\n", extraValueStr.cstr(), (extraFound) ? extraValuef : -1.0f));
+					m_sceneFile.writeTextf("comp:loadDiffuseImageResource(\"%s\", %f)\n", extraValueStr.cstr(), (extraFound) ? extraValuef : 1.0f));
 			}
 
-			ANKI_CHECK(getExtra(extras, "decal_diffuse_sub_texture", extraValueStr, extraFound));
+			ANKI_CHECK(getExtra(extras, "decal_metal_roughness", extraValueStr, extraFound));
 			if(extraFound)
 			{
-				ANKI_CHECK(getExtra(extras, "decal_specular_roughness_metallic_factor", extraValuef, extraFound));
+				ANKI_CHECK(getExtra(extras, "decal_metal_roughness_factor", extraValuef, extraFound));
 
-				ANKI_CHECK(m_sceneFile.writeTextf("comp:loadRoughnessMetallnessTexture(\"%s\", %f)\n", extraValueStr.cstr(),
-												  (extraFound) ? extraValuef : -1.0f));
+				ANKI_CHECK(m_sceneFile.writeTextf("comp:loadMetalRoughnessImageResource(\"%s\", %f)\n", extraValueStr.cstr(),
+												  (extraFound) ? extraValuef : 1.0f));
 			}
 
 			Vec3 tsl;
 			Mat3 rot;
 			Vec3 scale;
 			getNodeTransform(node, tsl, rot, scale);
-			const Transform localTrf = Transform(tsl.xyz0(), Mat3x4(Vec3(0.0f), rot), Vec4(1.0f, 1.0f, 1.0f, 0.0f));
+			const Transform localTrf = Transform(tsl, rot, scale);
 			ANKI_CHECK(writeTransform(parentTrf.combineTransformations(localTrf)));
 		}
 		else

+ 1 - 1
AnKi/Importer/ImageImporter.h

@@ -33,7 +33,7 @@ public:
 	UVec2 m_astcBlockSize = UVec2(8u);
 	Bool m_sRgbToLinear = false;
 	Bool m_linearToSRgb = false;
-	Bool m_flipImage = true;
+	Bool m_flipImage = false;
 };
 
 /// Converts images to AnKi's specific format.

+ 17 - 32
AnKi/Renderer/GBufferPost.cpp

@@ -23,54 +23,39 @@ void GBufferPost::populateRenderGraph(RenderingContext& ctx)
 
 	if(GpuSceneArrays::Decal::getSingleton().getElementCount() == 0)
 	{
-		// If there are no decals don't bother
 		return;
 	}
 
 	RenderGraphBuilder& rgraph = ctx.m_renderGraphDescr;
 
-	// Create pass
-	GraphicsRenderPass& rpass = rgraph.newGraphicsRenderPass("GBuffPost");
+	NonGraphicsRenderPass& rpass = rgraph.newNonGraphicsRenderPass("GBuffPost");
 
-	rpass.setWork([this, &ctx](RenderPassWorkContext& rgraphCtx) {
-		CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
+	rpass.newTextureDependency(getRenderer().getGBuffer().getColorRt(0), TextureUsageBit::kUavCompute);
+	rpass.newTextureDependency(getRenderer().getGBuffer().getColorRt(1), TextureUsageBit::kUavCompute);
+	rpass.newTextureDependency(getRenderer().getGBuffer().getColorRt(2), TextureUsageBit::kUavCompute);
+	rpass.newTextureDependency(getRenderer().getGBuffer().getDepthRt(), TextureUsageBit::kSrvCompute);
 
-		cmdb.setViewport(0, 0, getRenderer().getInternalResolution().x(), getRenderer().getInternalResolution().y());
-		cmdb.bindShaderProgram(m_grProg.get());
+	rpass.newBufferDependency(getRenderer().getClusterBinning().getDependency(), BufferUsageBit::kSrvCompute);
 
-		cmdb.setBlendFactors(0, BlendFactor::kOne, BlendFactor::kSrcAlpha, BlendFactor::kZero, BlendFactor::kOne);
-		cmdb.setBlendFactors(1, BlendFactor::kOne, BlendFactor::kSrcAlpha, BlendFactor::kZero, BlendFactor::kOne);
+	rpass.setWork([this, &ctx](RenderPassWorkContext& rgraphCtx) {
+		CommandBuffer& cmdb = *rgraphCtx.m_commandBuffer;
 
-		// Bind all
-		cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_nearestNearestClamp.get());
+		rgraphCtx.bindUav(0, 0, getRenderer().getGBuffer().getColorRt(0));
+		rgraphCtx.bindUav(1, 0, getRenderer().getGBuffer().getColorRt(1));
+		rgraphCtx.bindUav(2, 0, getRenderer().getGBuffer().getColorRt(2));
 
 		rgraphCtx.bindSrv(0, 0, getRenderer().getGBuffer().getDepthRt());
-
-		cmdb.bindSampler(1, 0, getRenderer().getSamplers().m_trilinearRepeat.get());
+		cmdb.bindSrv(1, 0, getRenderer().getClusterBinning().getPackedObjectsBuffer(GpuSceneNonRenderableObjectType::kDecal));
+		cmdb.bindSrv(2, 0, getRenderer().getClusterBinning().getClustersBuffer());
 
 		cmdb.bindConstantBuffer(0, 0, ctx.m_globalRenderingConstantsBuffer);
-		cmdb.bindSrv(0, 0, getRenderer().getClusterBinning().getPackedObjectsBuffer(GpuSceneNonRenderableObjectType::kDecal));
-		cmdb.bindSrv(1, 0, getRenderer().getClusterBinning().getClustersBuffer());
 
-		// Draw
-		cmdb.draw(PrimitiveTopology::kTriangles, 3);
+		cmdb.bindSampler(0, 0, getRenderer().getSamplers().m_trilinearClamp.get());
 
-		// Restore state
-		cmdb.setBlendFactors(0, BlendFactor::kOne, BlendFactor::kZero);
-		cmdb.setBlendFactors(1, BlendFactor::kOne, BlendFactor::kZero);
-	});
-
-	GraphicsRenderPassTargetDesc rt0(getRenderer().getGBuffer().getColorRt(0));
-	rt0.m_loadOperation = RenderTargetLoadOperation::kLoad;
-	GraphicsRenderPassTargetDesc rt1(getRenderer().getGBuffer().getColorRt(1));
-	rt1.m_loadOperation = RenderTargetLoadOperation::kLoad;
-	rpass.setRenderpassInfo({rt0, rt1});
-
-	rpass.newTextureDependency(getRenderer().getGBuffer().getColorRt(0), TextureUsageBit::kAllRtvDsv);
-	rpass.newTextureDependency(getRenderer().getGBuffer().getColorRt(1), TextureUsageBit::kAllRtvDsv);
-	rpass.newTextureDependency(getRenderer().getGBuffer().getDepthRt(), TextureUsageBit::kSrvPixel);
+		cmdb.bindShaderProgram(m_grProg.get());
 
-	rpass.newBufferDependency(getRenderer().getClusterBinning().getDependency(), BufferUsageBit::kSrvPixel);
+		dispatchPPCompute(cmdb, 8, 8, getRenderer().getInternalResolution().x(), getRenderer().getInternalResolution().y());
+	});
 }
 
 } // end namespace anki

+ 1 - 1
AnKi/Renderer/GBufferPost.h

@@ -12,7 +12,7 @@ namespace anki {
 /// @addtogroup renderer
 /// @{
 
-/// Applies SSAO and decals to the GBuffer. It's a seperate pass because it requres the depth buffer.
+/// Applies decals to the GBuffer. It's a seperate pass because it requres the depth buffer.
 class GBufferPost : public RendererObject
 {
 public:

+ 3 - 184
AnKi/Resource/ImageLoader.cpp

@@ -231,161 +231,6 @@ public:
 	}
 };
 
-Error ImageLoader::loadUncompressedTga(FileInterface& fs, U32& width, U32& height, U32& bpp,
-									   DynamicArray<U8, MemoryPoolPtrWrapper<BaseMemoryPool>, PtrSize>& data)
-{
-	Array<U8, 6> header6;
-
-	// Read the info from header
-	ANKI_CHECK(fs.read(&header6[0], sizeof(header6)));
-
-	width = header6[1] * 256 + header6[0];
-	height = header6[3] * 256 + header6[2];
-	bpp = header6[4];
-
-	if((width == 0) || (height == 0) || ((bpp != 24) && (bpp != 32)))
-	{
-		ANKI_RESOURCE_LOGE("Invalid image information");
-		return Error::kUserData;
-	}
-
-	// Read the data
-	const PtrSize bytesPerPxl = (bpp / 8);
-	const PtrSize imageSize = bytesPerPxl * width * height;
-	data.resize(imageSize);
-
-	ANKI_CHECK(fs.read(reinterpret_cast<char*>(&data[0]), imageSize));
-
-	// Swap red with blue
-	for(PtrSize i = 0; i < imageSize; i += bytesPerPxl)
-	{
-		const U8 temp = data[i];
-		data[i] = data[i + 2];
-		data[i + 2] = temp;
-	}
-
-	return Error::kNone;
-}
-
-Error ImageLoader::loadCompressedTga(FileInterface& fs, U32& width, U32& height, U32& bpp,
-									 DynamicArray<U8, MemoryPoolPtrWrapper<BaseMemoryPool>, PtrSize>& data)
-{
-	Array<U8, 6> header6;
-	ANKI_CHECK(fs.read(&header6[0], sizeof(header6)));
-
-	width = header6[1] * 256 + header6[0];
-	height = header6[3] * 256 + header6[2];
-	bpp = header6[4];
-
-	if((width <= 0) || (height <= 0) || ((bpp != 24) && (bpp != 32)))
-	{
-		ANKI_RESOURCE_LOGE("Invalid image information");
-		return Error::kUserData;
-	}
-
-	const PtrSize bytesPerPxl = (bpp / 8);
-	const PtrSize imageSize = bytesPerPxl * width * height;
-	data.resize(imageSize);
-
-	const PtrSize pixelCount = height * width;
-	PtrSize currentPixel = 0;
-	PtrSize currentByte = 0;
-	Array<U8, 4> colorbuffer;
-
-	do
-	{
-		U8 chunkheader = 0;
-
-		ANKI_CHECK(fs.read(&chunkheader, sizeof(U8)));
-
-		if(chunkheader < 128)
-		{
-			chunkheader++;
-			for(U8 counter = 0; counter < chunkheader; counter++)
-			{
-				ANKI_CHECK(fs.read(&colorbuffer[0], bytesPerPxl));
-
-				data[currentByte] = colorbuffer[2];
-				data[currentByte + 1] = colorbuffer[1];
-				data[currentByte + 2] = colorbuffer[0];
-
-				if(bytesPerPxl == 4)
-				{
-					data[currentByte + 3] = colorbuffer[3];
-				}
-
-				currentByte += bytesPerPxl;
-				currentPixel++;
-
-				if(currentPixel > pixelCount)
-				{
-					ANKI_RESOURCE_LOGE("Too many pixels read");
-					return Error::kUserData;
-				}
-			}
-		}
-		else
-		{
-			chunkheader = U8(chunkheader - 127);
-			ANKI_CHECK(fs.read(&colorbuffer[0], bytesPerPxl));
-
-			for(U8 counter = 0; counter < chunkheader; counter++)
-			{
-				data[currentByte] = colorbuffer[2];
-				data[currentByte + 1] = colorbuffer[1];
-				data[currentByte + 2] = colorbuffer[0];
-
-				if(bytesPerPxl == 4)
-				{
-					data[currentByte + 3] = colorbuffer[3];
-				}
-
-				currentByte += bytesPerPxl;
-				currentPixel++;
-
-				if(currentPixel > pixelCount)
-				{
-					ANKI_RESOURCE_LOGE("Too many pixels read");
-					data.destroy();
-					return Error::kUserData;
-				}
-			}
-		}
-	} while(currentPixel < pixelCount);
-
-	return Error::kNone;
-}
-
-Error ImageLoader::loadTga(FileInterface& fs, U32& width, U32& height, U32& bpp,
-						   DynamicArray<U8, MemoryPoolPtrWrapper<BaseMemoryPool>, PtrSize>& data)
-{
-	Array<Char, 12> myTgaHeader;
-
-	ANKI_CHECK(fs.read(&myTgaHeader[0], sizeof(myTgaHeader)));
-
-	if(memcmp(kTgaHeaderUncompressed, &myTgaHeader[0], sizeof(myTgaHeader)) == 0)
-	{
-		ANKI_CHECK(loadUncompressedTga(fs, width, height, bpp, data));
-	}
-	else if(std::memcmp(kTgaHeaderCompressed, &myTgaHeader[0], sizeof(myTgaHeader)) == 0)
-	{
-		ANKI_CHECK(loadCompressedTga(fs, width, height, bpp, data));
-	}
-	else
-	{
-		ANKI_RESOURCE_LOGE("Invalid image header");
-		return Error::kUserData;
-	}
-
-	if(bpp != 32 && bpp != 24)
-	{
-		ANKI_RESOURCE_LOGE("Invalid bpp");
-		return Error::kUserData;
-	}
-
-	return Error::kNone;
-}
-
 Error ImageLoader::loadAnkiImage(FileInterface& file, U32 maxImageSize, ImageBinaryDataCompression& preferredCompression,
 								 DynamicArray<ImageLoaderSurface, MemoryPoolPtrWrapper<BaseMemoryPool>>& surfaces,
 								 DynamicArray<ImageLoaderVolume, MemoryPoolPtrWrapper<BaseMemoryPool>>& volumes, U32& width, U32& height, U32& depth,
@@ -639,7 +484,7 @@ Error ImageLoader::loadStb(Bool isFloat, FileInterface& fs, U32& width, U32& hei
 
 	// Use STB to read the image
 	int stbw, stbh, comp;
-	stbi_set_flip_vertically_on_load_thread(true);
+	stbi_set_flip_vertically_on_load_thread(false);
 	U8* stbdata;
 	if(isFloat)
 	{
@@ -715,33 +560,7 @@ Error ImageLoader::loadInternal(FileInterface& file, const CString& filename, U3
 	m_imageType = ImageBinaryType::k2D;
 	m_compression = ImageBinaryDataCompression::kRaw;
 
-	if(ext == "tga")
-	{
-		m_surfaces.resize(1, pool);
-
-		m_mipmapCount = 1;
-		m_depth = 1;
-		m_layerCount = 1;
-		U32 bpp = 0;
-		ANKI_CHECK(loadTga(file, m_surfaces[0].m_width, m_surfaces[0].m_height, bpp, m_surfaces[0].m_data));
-
-		m_width = m_surfaces[0].m_width;
-		m_height = m_surfaces[0].m_height;
-
-		if(bpp == 32)
-		{
-			m_colorFormat = ImageBinaryColorFormat::kRgba8;
-		}
-		else if(bpp == 24)
-		{
-			m_colorFormat = ImageBinaryColorFormat::kRgb8;
-		}
-		else
-		{
-			ANKI_ASSERT(0);
-		}
-	}
-	else if(ext == "ankitex")
+	if(ext == "ankitex")
 	{
 #if ANKI_PLATFORM_MOBILE
 		m_compression = ImageBinaryDataCompression::kAstc;
@@ -752,7 +571,7 @@ Error ImageLoader::loadInternal(FileInterface& file, const CString& filename, U3
 		ANKI_CHECK(loadAnkiImage(file, maxImageSize, m_compression, m_surfaces, m_volumes, m_width, m_height, m_depth, m_layerCount, m_mipmapCount,
 								 m_imageType, m_colorFormat, m_astcBlockSize));
 	}
-	else if(ext == "png" || ext == "jpg")
+	else if(ext == "png" || ext == "jpg" || ext == "tga")
 	{
 		m_surfaces.resize(1, pool);
 

+ 0 - 8
AnKi/Resource/ImageLoader.h

@@ -141,14 +141,6 @@ private:
 
 	void destroy();
 
-	static Error loadUncompressedTga(FileInterface& fs, U32& width, U32& height, U32& bpp,
-									 DynamicArray<U8, MemoryPoolPtrWrapper<BaseMemoryPool>, PtrSize>& data);
-
-	static Error loadCompressedTga(FileInterface& fs, U32& width, U32& height, U32& bpp,
-								   DynamicArray<U8, MemoryPoolPtrWrapper<BaseMemoryPool>, PtrSize>& data);
-
-	static Error loadTga(FileInterface& fs, U32& width, U32& height, U32& bpp, DynamicArray<U8, MemoryPoolPtrWrapper<BaseMemoryPool>, PtrSize>& data);
-
 	static Error loadStb(Bool isFloat, FileInterface& fs, U32& width, U32& height,
 						 DynamicArray<U8, MemoryPoolPtrWrapper<BaseMemoryPool>, PtrSize>& data);
 

+ 26 - 31
AnKi/Scene/Components/DecalComponent.cpp

@@ -15,6 +15,7 @@ DecalComponent::DecalComponent(SceneNode* node)
 	: SceneComponent(node, kClassType)
 {
 	m_gpuSceneDecal.allocate();
+	loadDiffuseImageResource("EngineAssets/DefaultDecal.png", 0.9f);
 }
 
 DecalComponent::~DecalComponent()
@@ -26,9 +27,7 @@ void DecalComponent::setLayer(CString fname, F32 blendFactor, LayerType type)
 	Layer& l = m_layers[type];
 
 	ImageResourcePtr rsrc;
-
-	const Error err = ResourceManager::getSingleton().loadResource(fname, rsrc);
-	if(err)
+	if(ResourceManager::getSingleton().loadResource(fname, rsrc))
 	{
 		ANKI_SCENE_LOGE("Failed to load image");
 		return;
@@ -38,49 +37,45 @@ void DecalComponent::setLayer(CString fname, F32 blendFactor, LayerType type)
 
 	l.m_image = std::move(rsrc);
 	l.m_bindlessTextureIndex = l.m_image->getTexture().getOrCreateBindlessTextureIndex(TextureSubresourceDesc::all());
-	l.m_blendFactor = blendFactor;
+	l.m_blendFactor = clamp(blendFactor, 0.0f, 1.0f);
 }
 
 Error DecalComponent::update(SceneComponentUpdateInfo& info, Bool& updated)
 {
 	updated = m_dirty || info.m_node->movedThisFrame();
 
-	if(updated)
+	if(!updated) [[likely]]
 	{
-		m_dirty = false;
-
-		const Vec3 halfBoxSize = m_boxSize / 2.0f;
+		return Error::kNone;
+	}
 
-		// Calculate the texture matrix
-		const Mat4 worldTransform(info.m_node->getWorldTransform());
+	m_dirty = false;
 
-		const Mat4 viewMat = worldTransform.invert();
+	const Vec3 halfBoxSize = info.m_node->getWorldTransform().getScale().xyz();
 
-		const Mat4 projMat = Mat4::calculateOrthographicProjectionMatrix(halfBoxSize.x(), -halfBoxSize.x(), halfBoxSize.y(), -halfBoxSize.y(),
-																		 kClusterObjectFrustumNearPlane, m_boxSize.z());
+	// Calculate the texture matrix
+	Transform trf = info.m_node->getWorldTransform();
+	trf.setScale(Vec3(1.0f));
+	const Mat4 viewMat = Mat4(trf).invert();
 
-		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 projMat = Mat4::calculateOrthographicProjectionMatrix(halfBoxSize.x(), -halfBoxSize.x(), halfBoxSize.y(), -halfBoxSize.y(),
+																	 -halfBoxSize.z(), halfBoxSize.z());
 
-		m_biasProjViewMat = biasMat4 * projMat * viewMat;
+	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);
 
-		// Update the spatial
-		const Vec4 center(0.0f, 0.0f, -halfBoxSize.z(), 0.0f);
-		const Vec4 extend(halfBoxSize.x(), halfBoxSize.y(), halfBoxSize.z(), 0.0f);
-		const Obb obbL(center, Mat3x4::getIdentity(), extend);
-		const Obb obbW = obbL.getTransformed(info.m_node->getWorldTransform());
+	const Mat4 biasedProjViewMat = biasMat4 * projMat * viewMat;
 
-		// Upload to the GPU scene
-		GpuSceneDecal gpuDecal;
-		gpuDecal.m_diffuseTexture = m_layers[LayerType::kDiffuse].m_bindlessTextureIndex;
-		gpuDecal.m_roughnessMetalnessTexture = m_layers[LayerType::kRoughnessMetalness].m_bindlessTextureIndex;
-		gpuDecal.m_diffuseBlendFactor = m_layers[LayerType::kDiffuse].m_blendFactor;
-		gpuDecal.m_roughnessMetalnessFactor = m_layers[LayerType::kRoughnessMetalness].m_blendFactor;
-		gpuDecal.m_textureMatrix = m_biasProjViewMat;
-		gpuDecal.m_sphereCenter = obbW.getCenter().xyz();
-		gpuDecal.m_sphereRadius = obbW.getExtend().length();
+	// Upload to the GPU scene
+	GpuSceneDecal gpuDecal;
+	gpuDecal.m_diffuseTexture = m_layers[LayerType::kDiffuse].m_bindlessTextureIndex;
+	gpuDecal.m_roughnessMetalnessTexture = m_layers[LayerType::kRoughnessMetalness].m_bindlessTextureIndex;
+	gpuDecal.m_diffuseBlendFactor = m_layers[LayerType::kDiffuse].m_blendFactor;
+	gpuDecal.m_roughnessMetalnessFactor = m_layers[LayerType::kRoughnessMetalness].m_blendFactor;
+	gpuDecal.m_textureMatrix = biasedProjViewMat;
+	gpuDecal.m_sphereCenter = info.m_node->getWorldTransform().getOrigin().xyz();
+	gpuDecal.m_sphereRadius = halfBoxSize.length();
 
-		m_gpuSceneDecal.uploadToGpuScene(gpuDecal);
-	}
+	m_gpuSceneDecal.uploadToGpuScene(gpuDecal);
 
 	return Error::kNone;
 }

+ 2 - 16
AnKi/Scene/Components/DecalComponent.h

@@ -38,23 +38,11 @@ public:
 		setLayer(fname, blendFactor, LayerType::kDiffuse);
 	}
 
-	void loadRoughnessMetalnessImageResource(CString fname, F32 blendFactor)
+	void loadMetalRoughnessImageResource(CString fname, F32 blendFactor)
 	{
 		setLayer(fname, blendFactor, LayerType::kRoughnessMetalness);
 	}
 
-	/// Update the internal structures.
-	void setBoxVolumeSize(const Vec3& sizeXYZ)
-	{
-		m_boxSize = sizeXYZ;
-		m_dirty = true;
-	}
-
-	const Vec3& getBoxVolumeSize() const
-	{
-		return m_boxSize;
-	}
-
 private:
 	enum class LayerType : U8
 	{
@@ -67,13 +55,11 @@ private:
 	{
 	public:
 		ImageResourcePtr m_image;
-		F32 m_blendFactor = 0.0f;
+		F32 m_blendFactor = 1.0f;
 		U32 m_bindlessTextureIndex = kMaxU32;
 	};
 
 	Array<Layer, U(LayerType::kCount)> m_layers;
-	Mat4 m_biasProjViewMat = Mat4::getIdentity();
-	Vec3 m_boxSize = Vec3(1.0f);
 
 	GpuSceneArrays::Decal::Allocation m_gpuSceneDecal;
 

+ 33 - 82
AnKi/Script/Scene.cpp

@@ -60,7 +60,7 @@ static EventManager* getEventManager(lua_State* l)
 
 using WeakArraySceneNodePtr = WeakArray<SceneNode*>;
 
-LuaUserDataTypeInfo luaUserDataTypeInfoLightComponentType = {-4512355469057060026, "LightComponentType", 0, nullptr, nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoLightComponentType = {9161731750228934784, "LightComponentType", 0, nullptr, nullptr};
 
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<LightComponentType>()
@@ -95,7 +95,8 @@ static inline void wrapLightComponentType(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoBodyComponentCollisionShapeType = {671847876503904514, "BodyComponentCollisionShapeType", 0, nullptr, nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoBodyComponentCollisionShapeType = {-7069966657913140379, "BodyComponentCollisionShapeType", 0, nullptr,
+																		  nullptr};
 
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<BodyComponentCollisionShapeType>()
@@ -139,7 +140,7 @@ static inline void wrapBodyComponentCollisionShapeType(lua_State* l)
 }
 
 LuaUserDataTypeInfo luaUserDataTypeInfoWeakArraySceneNodePtr = {
-	8481773792182469546, "WeakArraySceneNodePtr", LuaUserData::computeSizeForGarbageCollected<WeakArraySceneNodePtr>(), nullptr, nullptr};
+	1283006476289129714, "WeakArraySceneNodePtr", LuaUserData::computeSizeForGarbageCollected<WeakArraySceneNodePtr>(), nullptr, nullptr};
 
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<WeakArraySceneNodePtr>()
@@ -257,7 +258,7 @@ static inline void wrapWeakArraySceneNodePtr(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoLightComponent = {7400372163853045267, "LightComponent",
+LuaUserDataTypeInfo luaUserDataTypeInfoLightComponent = {8699100876815061903, "LightComponent",
 														 LuaUserData::computeSizeForGarbageCollected<LightComponent>(), nullptr, nullptr};
 
 template<>
@@ -868,7 +869,7 @@ static inline void wrapLightComponent(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoDecalComponent = {-1523454534072154881, "DecalComponent",
+LuaUserDataTypeInfo luaUserDataTypeInfoDecalComponent = {-6169088492441751862, "DecalComponent",
 														 LuaUserData::computeSizeForGarbageCollected<DecalComponent>(), nullptr, nullptr};
 
 template<>
@@ -929,8 +930,8 @@ static int wrapDecalComponentloadDiffuseImageResource(lua_State* l)
 	return 0;
 }
 
-/// Pre-wrap method DecalComponent::loadRoughnessMetalnessImageResource.
-static inline int pwrapDecalComponentloadRoughnessMetalnessImageResource(lua_State* l)
+/// Pre-wrap method DecalComponent::loadMetalRoughnessImageResource.
+static inline int pwrapDecalComponentloadMetalRoughnessImageResource(lua_State* l)
 {
 	[[maybe_unused]] LuaUserData* ud;
 	[[maybe_unused]] void* voidp;
@@ -963,64 +964,15 @@ static inline int pwrapDecalComponentloadRoughnessMetalnessImageResource(lua_Sta
 	}
 
 	// Call the method
-	self->loadRoughnessMetalnessImageResource(arg0, arg1);
+	self->loadMetalRoughnessImageResource(arg0, arg1);
 
 	return 0;
 }
 
-/// Wrap method DecalComponent::loadRoughnessMetalnessImageResource.
-static int wrapDecalComponentloadRoughnessMetalnessImageResource(lua_State* l)
+/// Wrap method DecalComponent::loadMetalRoughnessImageResource.
+static int wrapDecalComponentloadMetalRoughnessImageResource(lua_State* l)
 {
-	int res = pwrapDecalComponentloadRoughnessMetalnessImageResource(l);
-	if(res >= 0)
-	{
-		return res;
-	}
-
-	lua_error(l);
-	return 0;
-}
-
-/// Pre-wrap method DecalComponent::setBoxVolumeSize.
-static inline int pwrapDecalComponentsetBoxVolumeSize(lua_State* l)
-{
-	[[maybe_unused]] LuaUserData* ud;
-	[[maybe_unused]] void* voidp;
-	[[maybe_unused]] PtrSize size;
-
-	if(LuaBinder::checkArgsCount(l, 2)) [[unlikely]]
-	{
-		return -1;
-	}
-
-	// Get "this" as "self"
-	if(LuaBinder::checkUserData(l, 1, luaUserDataTypeInfoDecalComponent, ud))
-	{
-		return -1;
-	}
-
-	DecalComponent* self = ud->getData<DecalComponent>();
-
-	// Pop arguments
-	extern LuaUserDataTypeInfo luaUserDataTypeInfoVec3;
-	if(LuaBinder::checkUserData(l, 2, luaUserDataTypeInfoVec3, ud)) [[unlikely]]
-	{
-		return -1;
-	}
-
-	Vec3* iarg0 = ud->getData<Vec3>();
-	const Vec3& arg0(*iarg0);
-
-	// Call the method
-	self->setBoxVolumeSize(arg0);
-
-	return 0;
-}
-
-/// Wrap method DecalComponent::setBoxVolumeSize.
-static int wrapDecalComponentsetBoxVolumeSize(lua_State* l)
-{
-	int res = pwrapDecalComponentsetBoxVolumeSize(l);
+	int res = pwrapDecalComponentloadMetalRoughnessImageResource(l);
 	if(res >= 0)
 	{
 		return res;
@@ -1035,12 +987,11 @@ static inline void wrapDecalComponent(lua_State* l)
 {
 	LuaBinder::createClass(l, &luaUserDataTypeInfoDecalComponent);
 	LuaBinder::pushLuaCFuncMethod(l, "loadDiffuseImageResource", wrapDecalComponentloadDiffuseImageResource);
-	LuaBinder::pushLuaCFuncMethod(l, "loadRoughnessMetalnessImageResource", wrapDecalComponentloadRoughnessMetalnessImageResource);
-	LuaBinder::pushLuaCFuncMethod(l, "setBoxVolumeSize", wrapDecalComponentsetBoxVolumeSize);
+	LuaBinder::pushLuaCFuncMethod(l, "loadMetalRoughnessImageResource", wrapDecalComponentloadMetalRoughnessImageResource);
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoLensFlareComponent = {8598672267166371667, "LensFlareComponent",
+LuaUserDataTypeInfo luaUserDataTypeInfoLensFlareComponent = {4995731539995318563, "LensFlareComponent",
 															 LuaUserData::computeSizeForGarbageCollected<LensFlareComponent>(), nullptr, nullptr};
 
 template<>
@@ -1203,7 +1154,7 @@ static inline void wrapLensFlareComponent(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoBodyComponent = {2044205211571264187, "BodyComponent",
+LuaUserDataTypeInfo luaUserDataTypeInfoBodyComponent = {8099732141277801003, "BodyComponent",
 														LuaUserData::computeSizeForGarbageCollected<BodyComponent>(), nullptr, nullptr};
 
 template<>
@@ -1513,7 +1464,7 @@ static inline void wrapBodyComponent(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoTriggerComponent = {-1002454183054442233, "TriggerComponent",
+LuaUserDataTypeInfo luaUserDataTypeInfoTriggerComponent = {6598736644455803043, "TriggerComponent",
 														   LuaUserData::computeSizeForGarbageCollected<TriggerComponent>(), nullptr, nullptr};
 
 template<>
@@ -1627,7 +1578,7 @@ static inline void wrapTriggerComponent(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoFogDensityComponent = {7977204644763908597, "FogDensityComponent",
+LuaUserDataTypeInfo luaUserDataTypeInfoFogDensityComponent = {1558360313688010235, "FogDensityComponent",
 															  LuaUserData::computeSizeForGarbageCollected<FogDensityComponent>(), nullptr, nullptr};
 
 template<>
@@ -1733,7 +1684,7 @@ static inline void wrapFogDensityComponent(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoCameraComponent = {-8282685180682550393, "CameraComponent",
+LuaUserDataTypeInfo luaUserDataTypeInfoCameraComponent = {7240058762383993623, "CameraComponent",
 														  LuaUserData::computeSizeForGarbageCollected<CameraComponent>(), nullptr, nullptr};
 
 template<>
@@ -1815,8 +1766,8 @@ static inline void wrapCameraComponent(lua_State* l)
 }
 
 LuaUserDataTypeInfo luaUserDataTypeInfoGlobalIlluminationProbeComponent = {
-	-7197282717727299465, "GlobalIlluminationProbeComponent", LuaUserData::computeSizeForGarbageCollected<GlobalIlluminationProbeComponent>(),
-	nullptr, nullptr};
+	7786098780583308602, "GlobalIlluminationProbeComponent", LuaUserData::computeSizeForGarbageCollected<GlobalIlluminationProbeComponent>(), nullptr,
+	nullptr};
 
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<GlobalIlluminationProbeComponent>()
@@ -2012,7 +1963,7 @@ static inline void wrapGlobalIlluminationProbeComponent(lua_State* l)
 }
 
 LuaUserDataTypeInfo luaUserDataTypeInfoReflectionProbeComponent = {
-	-454570398619495788, "ReflectionProbeComponent", LuaUserData::computeSizeForGarbageCollected<ReflectionProbeComponent>(), nullptr, nullptr};
+	3728015256035918590, "ReflectionProbeComponent", LuaUserData::computeSizeForGarbageCollected<ReflectionProbeComponent>(), nullptr, nullptr};
 
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<ReflectionProbeComponent>()
@@ -2028,7 +1979,7 @@ static inline void wrapReflectionProbeComponent(lua_State* l)
 }
 
 LuaUserDataTypeInfo luaUserDataTypeInfoParticleEmitterComponent = {
-	6715294256872600072, "ParticleEmitterComponent", LuaUserData::computeSizeForGarbageCollected<ParticleEmitterComponent>(), nullptr, nullptr};
+	8545543429504863184, "ParticleEmitterComponent", LuaUserData::computeSizeForGarbageCollected<ParticleEmitterComponent>(), nullptr, nullptr};
 
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<ParticleEmitterComponent>()
@@ -2090,7 +2041,7 @@ static inline void wrapParticleEmitterComponent(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoModelComponent = {587971086225739631, "ModelComponent",
+LuaUserDataTypeInfo luaUserDataTypeInfoModelComponent = {2794397331070110609, "ModelComponent",
 														 LuaUserData::computeSizeForGarbageCollected<ModelComponent>(), nullptr, nullptr};
 
 template<>
@@ -2153,7 +2104,7 @@ static inline void wrapModelComponent(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoSkinComponent = {1179936923048810307, "SkinComponent",
+LuaUserDataTypeInfo luaUserDataTypeInfoSkinComponent = {6453635927704179480, "SkinComponent",
 														LuaUserData::computeSizeForGarbageCollected<SkinComponent>(), nullptr, nullptr};
 
 template<>
@@ -2216,7 +2167,7 @@ static inline void wrapSkinComponent(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoSkyboxComponent = {-2081978872066799593, "SkyboxComponent",
+LuaUserDataTypeInfo luaUserDataTypeInfoSkyboxComponent = {9078636318267408065, "SkyboxComponent",
 														  LuaUserData::computeSizeForGarbageCollected<SkyboxComponent>(), nullptr, nullptr};
 
 template<>
@@ -2707,7 +2658,7 @@ static inline void wrapSkyboxComponent(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoSceneNode = {251828223337137303, "SceneNode", LuaUserData::computeSizeForGarbageCollected<SceneNode>(),
+LuaUserDataTypeInfo luaUserDataTypeInfoSceneNode = {8924349910587267929, "SceneNode", LuaUserData::computeSizeForGarbageCollected<SceneNode>(),
 													nullptr, nullptr};
 
 template<>
@@ -4550,7 +4501,7 @@ static inline void wrapSceneNode(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoSceneGraph = {-9132673623641199223, "SceneGraph", LuaUserData::computeSizeForGarbageCollected<SceneGraph>(),
+LuaUserDataTypeInfo luaUserDataTypeInfoSceneGraph = {-7992083750500404459, "SceneGraph", LuaUserData::computeSizeForGarbageCollected<SceneGraph>(),
 													 nullptr, nullptr};
 
 template<>
@@ -4736,7 +4687,7 @@ static inline void wrapSceneGraph(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoEvent = {287676937276190166, "Event", LuaUserData::computeSizeForGarbageCollected<Event>(), nullptr, nullptr};
+LuaUserDataTypeInfo luaUserDataTypeInfoEvent = {4634393106419300120, "Event", LuaUserData::computeSizeForGarbageCollected<Event>(), nullptr, nullptr};
 
 template<>
 const LuaUserDataTypeInfo& LuaUserData::getDataTypeInfoFor<Event>()
@@ -4800,7 +4751,7 @@ static inline void wrapEvent(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoLightEvent = {797031557305127058, "LightEvent", LuaUserData::computeSizeForGarbageCollected<LightEvent>(),
+LuaUserDataTypeInfo luaUserDataTypeInfoLightEvent = {5654906403086349064, "LightEvent", LuaUserData::computeSizeForGarbageCollected<LightEvent>(),
 													 nullptr, nullptr};
 
 template<>
@@ -4919,7 +4870,7 @@ static inline void wrapLightEvent(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoScriptEvent = {-6936063156053602985, "ScriptEvent", LuaUserData::computeSizeForGarbageCollected<ScriptEvent>(),
+LuaUserDataTypeInfo luaUserDataTypeInfoScriptEvent = {2884793170545449902, "ScriptEvent", LuaUserData::computeSizeForGarbageCollected<ScriptEvent>(),
 													  nullptr, nullptr};
 
 template<>
@@ -4935,7 +4886,7 @@ static inline void wrapScriptEvent(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoJitterMoveEvent = {7031214453544803829, "JitterMoveEvent",
+LuaUserDataTypeInfo luaUserDataTypeInfoJitterMoveEvent = {-7337813253077277960, "JitterMoveEvent",
 														  LuaUserData::computeSizeForGarbageCollected<JitterMoveEvent>(), nullptr, nullptr};
 
 template<>
@@ -5010,7 +4961,7 @@ static inline void wrapJitterMoveEvent(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoAnimationEvent = {1582028356070398946, "AnimationEvent",
+LuaUserDataTypeInfo luaUserDataTypeInfoAnimationEvent = {-6138247333310671375, "AnimationEvent",
 														 LuaUserData::computeSizeForGarbageCollected<AnimationEvent>(), nullptr, nullptr};
 
 template<>
@@ -5026,7 +4977,7 @@ static inline void wrapAnimationEvent(lua_State* l)
 	lua_settop(l, 0);
 }
 
-LuaUserDataTypeInfo luaUserDataTypeInfoEventManager = {-3459184637522950091, "EventManager",
+LuaUserDataTypeInfo luaUserDataTypeInfoEventManager = {9107446086384125482, "EventManager",
 													   LuaUserData::computeSizeForGarbageCollected<EventManager>(), nullptr, nullptr};
 
 template<>

+ 1 - 6
AnKi/Script/Scene.xml

@@ -161,17 +161,12 @@ using WeakArraySceneNodePtr = WeakArray<SceneNode*>;
 						<arg>F32</arg>
 					</args>
 				</method>
-				<method name="loadRoughnessMetalnessImageResource">
+				<method name="loadMetalRoughnessImageResource">
 					<args>
 						<arg>CString</arg>
 						<arg>F32</arg>
 					</args>
 				</method>
-				<method name="setBoxVolumeSize">
-					<args>
-						<arg>const Vec3&amp;</arg>
-					</args>
-				</method>
 			</methods>
 		</class>
 

+ 32 - 15
AnKi/Shaders/ClusteredShadingFunctions.hlsl

@@ -69,40 +69,57 @@ U32 computeTileClusterIndexFragCoord(Vec2 fragCoord, U32 tileCountX)
 }
 
 /// Merge the tiles with z splits into a single cluster.
+template<Bool kDynamicallyUniform = false>
 Cluster mergeClusters(Cluster tileCluster, Cluster zCluster)
 {
-//#define ANKI_OR_MASKS(x) WaveActiveBitOr(x)
-#define ANKI_OR_MASKS(x) (x)
-
 	Cluster outCluster;
 
-	[unroll] for(U32 i = 0; i < kMaxVisibleLights / 32; ++i)
+	if(kDynamicallyUniform)
 	{
-		outCluster.m_pointLightsMask[i] = ANKI_OR_MASKS(tileCluster.m_pointLightsMask[i] & zCluster.m_pointLightsMask[i]);
-		outCluster.m_spotLightsMask[i] = ANKI_OR_MASKS(tileCluster.m_spotLightsMask[i] & zCluster.m_spotLightsMask[i]);
-	}
+		[unroll] for(U32 i = 0; i < kMaxVisibleLights / 32; ++i)
+		{
+			outCluster.m_pointLightsMask[i] = WaveActiveBitOr(tileCluster.m_pointLightsMask[i] & zCluster.m_pointLightsMask[i]);
+			outCluster.m_spotLightsMask[i] = WaveActiveBitOr(tileCluster.m_spotLightsMask[i] & zCluster.m_spotLightsMask[i]);
+		}
 
-	[unroll] for(U32 i = 0; i < kMaxVisibleDecals / 32; ++i)
-	{
-		outCluster.m_decalsMask[i] = ANKI_OR_MASKS(tileCluster.m_decalsMask[i] & zCluster.m_decalsMask[i]);
+		[unroll] for(U32 i = 0; i < kMaxVisibleDecals / 32; ++i)
+		{
+			outCluster.m_decalsMask[i] = WaveActiveBitOr(tileCluster.m_decalsMask[i] & zCluster.m_decalsMask[i]);
+		}
+
+		outCluster.m_fogDensityVolumesMask = WaveActiveBitOr(tileCluster.m_fogDensityVolumesMask & zCluster.m_fogDensityVolumesMask);
+		outCluster.m_reflectionProbesMask = WaveActiveBitOr(tileCluster.m_reflectionProbesMask & zCluster.m_reflectionProbesMask);
+		outCluster.m_giProbesMask = WaveActiveBitOr(tileCluster.m_giProbesMask & zCluster.m_giProbesMask);
 	}
+	else
+	{
+		[unroll] for(U32 i = 0; i < kMaxVisibleLights / 32; ++i)
+		{
+			outCluster.m_pointLightsMask[i] = (tileCluster.m_pointLightsMask[i] & zCluster.m_pointLightsMask[i]);
+			outCluster.m_spotLightsMask[i] = (tileCluster.m_spotLightsMask[i] & zCluster.m_spotLightsMask[i]);
+		}
 
-	outCluster.m_fogDensityVolumesMask = ANKI_OR_MASKS(tileCluster.m_fogDensityVolumesMask & zCluster.m_fogDensityVolumesMask);
-	outCluster.m_reflectionProbesMask = ANKI_OR_MASKS(tileCluster.m_reflectionProbesMask & zCluster.m_reflectionProbesMask);
-	outCluster.m_giProbesMask = ANKI_OR_MASKS(tileCluster.m_giProbesMask & zCluster.m_giProbesMask);
+		[unroll] for(U32 i = 0; i < kMaxVisibleDecals / 32; ++i)
+		{
+			outCluster.m_decalsMask[i] = (tileCluster.m_decalsMask[i] & zCluster.m_decalsMask[i]);
+		}
 
-#undef ANKI_OR_MASKS
+		outCluster.m_fogDensityVolumesMask = (tileCluster.m_fogDensityVolumesMask & zCluster.m_fogDensityVolumesMask);
+		outCluster.m_reflectionProbesMask = (tileCluster.m_reflectionProbesMask & zCluster.m_reflectionProbesMask);
+		outCluster.m_giProbesMask = (tileCluster.m_giProbesMask & zCluster.m_giProbesMask);
+	}
 
 	return outCluster;
 }
 
 /// Get the final cluster after ORing and ANDing the masks.
+template<Bool kDynamicallyUniform = false>
 Cluster getClusterFragCoord(StructuredBuffer<Cluster> clusters, GlobalRendererConstants consts, Vec3 fragCoord)
 {
 	const Cluster tileCluster = clusters[computeTileClusterIndexFragCoord(fragCoord.xy, consts.m_tileCounts.x)];
 	const Cluster zCluster = clusters[computeZSplitClusterIndex(fragCoord.z, consts.m_zSplitCount, consts.m_zSplitMagic.x, consts.m_zSplitMagic.y)
 									  + consts.m_tileCounts.x * consts.m_tileCounts.y];
-	return mergeClusters(tileCluster, zCluster);
+	return mergeClusters<kDynamicallyUniform>(tileCluster, zCluster);
 }
 
 U32 iteratePointLights(inout Cluster cluster)

+ 72 - 67
AnKi/Shaders/GBufferPost.ankiprog

@@ -3,52 +3,44 @@
 // Code licensed under the BSD License.
 // http://www.anki3d.org/LICENSE
 
-#pragma anki technique vert pixel
+#pragma anki 16bit
 
-#include <AnKi/Shaders/QuadVert.hlsl>
+#pragma anki technique comp
 
-#if ANKI_PIXEL_SHADER
-#	include <AnKi/Shaders/PackFunctions.hlsl>
-#	include <AnKi/Shaders/Functions.hlsl>
-#	include <AnKi/Shaders/ClusteredShadingFunctions.hlsl>
-#	include <AnKi/Shaders/Include/MiscRendererTypes.h>
+#include <AnKi/Shaders/PackFunctions.hlsl>
+#include <AnKi/Shaders/Functions.hlsl>
+#include <AnKi/Shaders/ClusteredShadingFunctions.hlsl>
+#include <AnKi/Shaders/Include/MiscRendererTypes.h>
 
-SamplerState g_nearestAnyClampSampler : register(s0);
-Texture2D g_depthTex : register(t0);
-SamplerState g_trilinearRepeatSampler : register(s1);
+RWTexture2D<Vec4> g_gbuffer0Tex : register(u0);
+RWTexture2D<Vec4> g_gbuffer1Tex : register(u1);
+RWTexture2D<Vec4> g_gbuffer2Tex : register(u2);
 
-ConstantBuffer<GlobalRendererConstants> g_globalConstants : register(b0);
+Texture2D<Vec4> g_depthTex : register(t0);
 StructuredBuffer<Decal> g_decals : register(t1);
 StructuredBuffer<Cluster> g_clusters : register(t2);
 
-struct PixelOut
-{
-	RVec4 m_diffuse : SV_TARGET0;
-	RVec4 m_roughnessAndOther : SV_TARGET1;
-};
-
-PixelOut main(VertOut input)
-{
-	const Vec2 uv = input.m_uv;
+ConstantBuffer<GlobalRendererConstants> g_globalConstants : register(b0);
 
-	// This code blends the diffuse and the specular+rougness of the decals with GBuffer render targets.
-	// Normaly the blending is being done ('D' is the decal diffuse and 'f' is decal blend factor):
-	// d=gbuffer.diff
-	// 1st decal: d'=d*(1-f)+D*f
-	// 2nd decal: d''=d'*(1-f')+D'*f' <=> d''=d*(1-f)*(1-f')+D*f*(1-f')+D'*f'
-	// By looking at the trend we will have to multiply the gbuffer.diff with: (1-f)*(1-f') ... (1-f'''')
+SamplerState g_linearClampAnySampler : register(s0);
 
-	RVec4 diffuse = Vec4(0.0, 0.0, 0.0, 1.0);
-	RVec4 roughnessAndOther = Vec4(0.0, 0.0, 0.0, 1.0);
+[NumThreads(8, 8, 1)] void main(UVec2 svDispatchThreadId : SV_DispatchThreadID)
+{
+	UVec2 viewportSize;
+	g_depthTex.GetDimensions(viewportSize.x, viewportSize.y);
+	if(any(svDispatchThreadId >= viewportSize))
+	{
+		return;
+	}
 
 	// Get worldPos
-	const F32 depth = g_depthTex.SampleLevel(g_nearestAnyClampSampler, uv, 0.0).r;
-	const Vec2 ndc = uvToNdc(uv);
+	const F32 depth = g_depthTex[svDispatchThreadId].r;
+	const Vec2 ndc = uvToNdc(Vec2(svDispatchThreadId) / Vec2(viewportSize));
 	const Vec4 worldPos4 = mul(g_globalConstants.m_matrices.m_invertedViewProjectionJitter, Vec4(ndc, depth, 1.0));
 	const Vec3 worldPos = worldPos4.xyz / worldPos4.w;
 
-	// Get the cluster
-	Cluster cluster = getClusterFragCoord(g_clusters, g_globalConstants, Vec3(input.m_svPosition.xy, depth));
+	// Get the cluster. Make sure it's dynamically uniform because we are accessing bindless textures later on
+	Cluster cluster = getClusterFragCoord<true>(g_clusters, g_globalConstants, Vec3(svDispatchThreadId, depth));
 
 	// Make the decalsMask uniform across the wave because we are accessing bindless textures later on
 	U32 decalsMask = cluster.m_decalsMask[0];
@@ -57,11 +49,18 @@ PixelOut main(VertOut input)
 		decalsMask |= cluster.m_decalsMask[i];
 	}
 
-	if(WaveActiveAllTrue(decalsMask == 0))
+	if(decalsMask == 0)
 	{
-		discard;
+		return;
 	}
 
+	GbufferInfo<F16> gbuffer = (GbufferInfo<F16>)0;
+	unpackGBufferNoVelocity<F16>(g_gbuffer0Tex[svDispatchThreadId], g_gbuffer1Tex[svDispatchThreadId], g_gbuffer2Tex[svDispatchThreadId], gbuffer);
+
+	HVec3 diffuse = gbuffer.m_diffuse;
+	F16 roughness = gbuffer.m_roughness;
+	F16 metalness = gbuffer.m_metallic;
+
 	U32 idx;
 	[loop] while((idx = iterateDecals(cluster)) != kMaxU32)
 	{
@@ -69,52 +68,58 @@ PixelOut main(VertOut input)
 
 		// Project pos to decal space
 		const Vec4 texCoords4 = mul(decal.m_textureMatrix, Vec4(worldPos, 1.0));
-		if(texCoords4.w <= 0.7)
+
+		const F32 depth = texCoords4.z / texCoords4.w;
+		const Vec2 uv = texCoords4.xy / texCoords4.w;
+
+		if(any(Vec3(uv, depth) < 0.0) || any(Vec3(uv, depth) > 1.0))
 		{
-			// Behind the decal, skip
+			// Outside the volume
 			continue;
 		}
 
-		const Vec2 uv = saturate(texCoords4.xy / texCoords4.w);
+		// Fade a bit when approaching depth 0 or 1
+		const F16 edgeFactor = 1.0 - pow(abs(2.0 * depth - 1.0), 8.0);
 
-		// Read textures
-		RVec4 diff;
+		F16 factor = edgeFactor;
+
+		// Do diffuse
 		if(decal.m_diffuseTexture != kMaxU32)
 		{
-			diff = getBindlessTexture2DVec4(decal.m_diffuseTexture).Sample(g_trilinearRepeatSampler, uv);
-		}
-		else
-		{
-			diff = 0.0f;
+			const HVec4 col = getBindlessTexture2DVec4(decal.m_diffuseTexture).SampleLevel(g_linearClampAnySampler, uv, 0.0);
+
+			factor *= col.a;
+			diffuse = lerp(diffuse, col.rgb, factor * decal.m_diffuseBlendFactor);
 		}
 
-		RVec2 roughnessMetalness;
-		RF32 roughnessMetalnessFactor;
+		// Do metal roughness
 		if(decal.m_roughnessMetalnessTexture != kMaxU32)
 		{
-			roughnessMetalness = getBindlessTexture2DVec4(decal.m_roughnessMetalnessTexture).Sample(g_trilinearRepeatSampler, uv).gb;
-			roughnessMetalnessFactor = diff.a;
-		}
-		else
-		{
-			roughnessMetalness = 0.0f;
-			roughnessMetalnessFactor = 0.0f;
-		}
+			const HVec3 col = getBindlessTexture2DVec4(decal.m_roughnessMetalnessTexture).SampleLevel(g_linearClampAnySampler, uv, 0.0).gba;
 
-		// Update diffuse
-		RF32 f = diff.a * decal.m_diffuseBlendFactor;
-		diffuse.rgb = diffuse.rgb * (1.0 - f) + diff.rgb * f;
-		diffuse.a *= (1.0 - f);
+			if(decal.m_diffuseTexture == kMaxU32)
+			{
+				// Can't use the diffuse tex for alpha. Try the alpha from the roughness/metal texture
+				factor *= col.z;
+			}
 
-		// Update only roughness for now. Metalness is weirdly packed
-		f = roughnessMetalnessFactor * decal.m_roughnessMetalnessFactor;
-		roughnessAndOther.r = roughnessMetalness.r * (1.0 - f) + roughnessMetalness.r * f;
-		roughnessAndOther.a *= (1.0 - f);
+			roughness = lerp(roughness, col.x, factor * decal.m_roughnessMetalnessFactor);
+			metalness = lerp(metalness, col.y, factor * decal.m_roughnessMetalnessFactor);
+		}
 	}
 
-	PixelOut output;
-	output.m_diffuse = diffuse;
-	output.m_roughnessAndOther = roughnessAndOther;
-	return output;
+	if(any(diffuse != gbuffer.m_diffuse) || roughness != gbuffer.m_roughness || metalness != gbuffer.m_metallic)
+	{
+		gbuffer.m_diffuse = diffuse;
+		gbuffer.m_roughness = roughness;
+		gbuffer.m_metallic = metalness;
+
+		HVec4 rt0, rt1, rt2;
+		Vec2 rt3;
+		packGBuffer(gbuffer, rt0, rt1, rt2, rt3);
+
+		g_gbuffer0Tex[svDispatchThreadId] = rt0;
+		g_gbuffer1Tex[svDispatchThreadId] = rt1;
+		g_gbuffer2Tex[svDispatchThreadId] = rt2;
+	}
 }
-#endif // ANKI_PIXEL_SHADER

二进制
EngineAssets/DefaultDecal.png


+ 2 - 2
Samples/Common/SampleApp.cpp

@@ -63,8 +63,8 @@ Error SampleApp::userMainLoop(Bool& quit, Second elapsedTime)
 
 	if(in.getKey(KeyCode::kY) == 1)
 	{
-		// renderer.setCurrentDebugRenderTarget((renderer.getCurrentDebugRenderTarget() == "GBufferAlbedo") ? "" : "GBufferAlbedo");
-		g_shadowMappingPcssCVar = !g_shadowMappingPcssCVar;
+		renderer.setCurrentDebugRenderTarget((renderer.getCurrentDebugRenderTarget() == "GBufferAlbedo") ? "" : "GBufferAlbedo");
+		// g_shadowMappingPcssCVar = !g_shadowMappingPcssCVar;
 	}
 
 	if(in.getKey(KeyCode::kU) == 1)

+ 68 - 0
Samples/Sponza/Assets/Scene.lua

@@ -16,6 +16,30 @@ trf:setRotation(rot)
 trf:setScale(Vec3.new(1.000000, 1.000000, 1.000000))
 node:setLocalTransform(trf)
 
+node = scene:newSceneNode("Cube.017")
+comp = node:newDecalComponent()
+comp:loadDiffuseImageResource("Assets/blood_decal_albedo.ankitex", 1.000000)
+comp:loadMetalRoughnessImageResource("Assets/blood_decal_metal_roughness.ankitex", 1.000000)
+trf = Transform.new()
+trf:setOrigin(Vec3.new(-7.248238, -0.031180, 2.810158))
+rot = Mat3.new()
+rot:setAll(1.000000, 0.000000, 0.000000, 0.000000, -0.000000, -1.000000, 0.000000, 1.000000, -0.000000)
+trf:setRotation(rot)
+trf:setScale(Vec3.new(1.467957, 1.360810, 0.082817))
+node:setLocalTransform(trf)
+
+node = scene:newSceneNode("Cube.018")
+comp = node:newDecalComponent()
+comp:loadDiffuseImageResource("Assets/blood_decal_albedo.ankitex", 1.000000)
+comp:loadMetalRoughnessImageResource("Assets/blood_decal_metal_roughness.ankitex", 1.000000)
+trf = Transform.new()
+trf:setOrigin(Vec3.new(-7.248238, 1.820668, 3.320379))
+rot = Mat3.new()
+rot:setAll(-0.724110, -0.689684, -0.000000, -0.689684, 0.724110, -0.000000, 0.000000, 0.000000, -1.000000)
+trf:setRotation(rot)
+trf:setScale(Vec3.new(1.467957, 1.360810, 0.164461))
+node:setLocalTransform(trf)
+
 node = scene:newSceneNode("Cube.011")
 comp = node:newGlobalIlluminationProbeComponent()
 trf = Transform.new()
@@ -2903,5 +2927,49 @@ trf:setRotation(rot)
 trf:setScale(Vec3.new(0.845972, 0.845972, 0.845972))
 node:setLocalTransform(trf)
 
+node = scene:newSceneNode("decal")
+comp = node:newDecalComponent()
+comp:loadDiffuseImageResource("Assets/torch_burn_decal.ankitex", 1.000000)
+trf = Transform.new()
+trf:setOrigin(Vec3.new(8.551484, 3.596614, -4.380483))
+rot = Mat3.new()
+rot:setAll(1.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.000000, 1.000000)
+trf:setRotation(rot)
+trf:setScale(Vec3.new(0.664928, 1.646613, 0.265592))
+node:setLocalTransform(trf)
+
+node = scene:newSceneNode("decal.001")
+comp = node:newDecalComponent()
+comp:loadDiffuseImageResource("Assets/torch_burn_decal.ankitex", 1.000000)
+trf = Transform.new()
+trf:setOrigin(Vec3.new(-10.791684, 3.596614, -4.380483))
+rot = Mat3.new()
+rot:setAll(1.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.000000, 1.000000)
+trf:setRotation(rot)
+trf:setScale(Vec3.new(0.664928, 1.646613, 0.265592))
+node:setLocalTransform(trf)
+
+node = scene:newSceneNode("decal.002")
+comp = node:newDecalComponent()
+comp:loadDiffuseImageResource("Assets/torch_burn_decal.ankitex", 1.000000)
+trf = Transform.new()
+trf:setOrigin(Vec3.new(-10.791684, 3.596614, 3.085766))
+rot = Mat3.new()
+rot:setAll(-1.000000, 0.000000, -0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.000000, -1.000000)
+trf:setRotation(rot)
+trf:setScale(Vec3.new(0.664928, 1.646613, 0.265592))
+node:setLocalTransform(trf)
+
+node = scene:newSceneNode("decal.003")
+comp = node:newDecalComponent()
+comp:loadDiffuseImageResource("Assets/torch_burn_decal.ankitex", 1.000000)
+trf = Transform.new()
+trf:setOrigin(Vec3.new(8.552687, 3.596614, 3.085766))
+rot = Mat3.new()
+rot:setAll(-1.000000, 0.000000, -0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.000000, -1.000000)
+trf:setRotation(rot)
+trf:setScale(Vec3.new(0.664928, 1.646613, 0.265592))
+node:setLocalTransform(trf)
+
 node = scene:tryFindSceneNode("Suzanne")
 getEventManager():newAnimationEvent("Assets/SuzanneAction_a8e545711d9aeca3.ankianim", "Suzanne", node)

二进制
Samples/Sponza/Assets/blood_decal_albedo.ankitex


二进制
Samples/Sponza/Assets/blood_decal_metal_roughness.ankitex


二进制
Samples/Sponza/Assets/torch_burn_decal.ankitex


+ 1 - 1
Tools/Image/ImageImporterMain.cpp

@@ -32,7 +32,7 @@ Options:
 -v                     : Verbose log
 -to-linear             : Convert sRGB to linear
 -to-srgb               : Convert linear to sRGB
--flip-image <0|1>      : Flip the image. Default is 1
+-flip-image <0|1>      : Flip the image. Default is 0
 -hdr-scale <3 floats>  : Apply some scale to HDR images. Default is {1 1 1}
 -hdr-bias <3 floats>   : Apply some bias to HDR images. Default is {0 0 0}
 )";