Kaynağa Gözat

Renderer can now properly handle multiple material techniques

BearishSun 9 yıl önce
ebeveyn
işleme
86e7a688a6

+ 4 - 1
Source/BansheeCore/Include/BsMaterial.h

@@ -116,7 +116,10 @@ namespace BansheeEngine
 		UINT32 getNumTechniques() const { return (UINT32)mTechniques.size(); }
 
 		/** Attempts to find a technique with the supported tag. Returns an index of the technique, or -1 if not found. */
-		UINT32 findTechnique(const StringID& tag);
+		UINT32 findTechnique(const StringID& tag) const;
+
+		/** Finds the index of the default (primary) technique to use. */
+		UINT32 getDefaultTechnique() const;
 
 		/** 
 		 * Returns the number of passes that are used by the technique at the specified index. 

+ 3 - 0
Source/BansheeCore/Include/BsTechnique.h

@@ -25,6 +25,9 @@ namespace BansheeEngine
 		/** Checks if the technique has the specified tag. */
 		bool hasTag(const StringID& tag);
 
+		/** Checks if the technique has any tags. */
+		UINT32 hasTags() const { return !mTags.empty(); }
+
 	protected:
 		StringID mRenderAPI;
 		StringID mRenderer;

+ 14 - 2
Source/BansheeCore/Source/BsMaterial.cpp

@@ -62,7 +62,7 @@ namespace BansheeEngine
 	}
 
 	template<bool Core>
-	UINT32 TMaterial<Core>::findTechnique(const StringID& tag)
+	UINT32 TMaterial<Core>::findTechnique(const StringID& tag) const
 	{
 		for(UINT32 i = 0; i < (UINT32)mTechniques.size(); i++)
 		{
@@ -70,7 +70,19 @@ namespace BansheeEngine
 				return i;
 		}
 
-		return -1;
+		return (UINT32)-1;
+	}
+
+	template<bool Core>
+	UINT32 TMaterial<Core>::getDefaultTechnique() const
+	{
+		for (UINT32 i = 0; i < (UINT32)mTechniques.size(); i++)
+		{
+			if (!mTechniques[i]->hasTags())
+				return i;
+		}
+
+		return 0;
 	}
 
 	template<bool Core>

+ 2 - 1
Source/BansheeEngine/Include/BsRendererUtility.h

@@ -34,10 +34,11 @@ namespace BansheeEngine
 		 *
 		 * @param[in]	material		Material containing the pass.
 		 * @param[in]	passIdx			Index of the pass in the material.
+		 * @param[in]	techniqueIdx	Index of the technique the pass belongs to, if the material has multiple techniques.
 		 *
 		 * @note	Core thread.
 		 */
-		void setPass(const SPtr<MaterialCore>& material, UINT32 passIdx = 0);
+		void setPass(const SPtr<MaterialCore>& material, UINT32 passIdx = 0, UINT32 techniqueIdx = 0);
 
 		/**
 		 * Activates the specified material pass for compute. Any further dispatch calls will be executed using this pass.

+ 1 - 1
Source/BansheeEngine/Source/BsRendererUtility.cpp

@@ -117,7 +117,7 @@ namespace BansheeEngine
 
 	}
 
-	void RendererUtility::setPass(const SPtr<MaterialCore>& material, UINT32 passIdx)
+	void RendererUtility::setPass(const SPtr<MaterialCore>& material, UINT32 passIdx, UINT32 techniqueIdx)
 	{
 		RenderAPICore& rapi = RenderAPICore::instance();
 

+ 5 - 2
Source/RenderBeast/Include/BsRenderBeast.h

@@ -27,6 +27,9 @@ namespace BansheeEngine
 	static StringID RPS_GBufferDepth = "GBufferDepth";
 	static StringID RPS_BoneMatrices = "BoneMatrices";
 
+	/** Technique tags. */
+	static StringID RTag_Animated = "Animated";
+
 	/**
 	 * Default renderer for Banshee. Performs frustum culling, sorting and renders objects in custom ways determine by
 	 * renderable handlers.
@@ -205,7 +208,7 @@ namespace BansheeEngine
 		// Core thread only fields
 		Vector<RendererRenderTarget> mRenderTargets;
 		UnorderedMap<const CameraCore*, RendererCamera> mCameras;
-		UnorderedMap<SPtr<MaterialCore>, MaterialSamplerOverrides*> mSamplerOverrides;
+		UnorderedMap<SamplerOverrideKey, MaterialSamplerOverrides*> mSamplerOverrides;
 
 		Vector<RendererObject> mRenderables;
 		Vector<RenderableShaderData> mRenderableShaderData;
@@ -230,4 +233,4 @@ namespace BansheeEngine
 	};
 
 	/** @} */
-}
+}

+ 3 - 0
Source/RenderBeast/Include/BsRendererObject.h

@@ -36,6 +36,9 @@ namespace BansheeEngine
 		/** Identifier of the animation running on the renderable's mesh. -1 if no animation. */
 		UINT64 animationId;
 
+		/** Index of the technique in the material to render the element with. */
+		UINT32 techniqueIdx;
+
 		/** 
 		 * Parameter for setting global bone pose transforms used for an element with skeletal animation, null otherwise. 
 		 */

+ 43 - 1
Source/RenderBeast/Include/BsSamplerOverrides.h

@@ -42,6 +42,27 @@ namespace BansheeEngine
 		UINT32 refCount;
 	};
 
+	/** Key used for uniquely identifying a sampler override entry. */
+	struct SamplerOverrideKey
+	{
+		SamplerOverrideKey(const SPtr<MaterialCore>& material, UINT32 techniqueIdx)
+			:material(material), techniqueIdx(techniqueIdx)
+		{ }
+
+		bool operator== (const SamplerOverrideKey& rhs) const
+		{ 
+			return material == rhs.material && techniqueIdx == rhs.techniqueIdx;
+		}
+
+		bool operator!= (const SamplerOverrideKey& rhs) const 
+		{ 
+			return !(*this == rhs); 
+		}
+
+		SPtr<MaterialCore> material;
+		UINT32 techniqueIdx;
+	};
+
 	/**	Helper class for generating sampler overrides. */
 	class BS_BSRND_EXPORT SamplerOverrideUtility
 	{
@@ -74,4 +95,25 @@ namespace BansheeEngine
 	};
 
 	/** @} */
-}
+}
+
+/** @cond STDLIB */
+
+namespace std
+{
+	/** Hash value generator for SamplerOverrideKey. */
+	template<>
+	struct hash<BansheeEngine::SamplerOverrideKey>
+	{
+		size_t operator()(const BansheeEngine::SamplerOverrideKey& key) const
+		{
+			size_t hash = 0;
+			BansheeEngine::hash_combine(hash, key.material);
+			BansheeEngine::hash_combine(hash, key.techniqueIdx);
+
+			return hash;
+		}
+	};
+}
+
+/** @endcond */

+ 28 - 15
Source/RenderBeast/Source/BsRenderBeast.cpp

@@ -174,38 +174,49 @@ namespace BansheeEngine
 				if (renElement.material == nullptr)
 					renElement.material = mDefaultMaterial->getMaterial();
 
+				// Determine which technique to use
+				UINT32 techniqueIdx = -1;
+				if(renderable->isAnimated())
+					techniqueIdx = renElement.material->findTechnique(RTag_Animated);
+
+				if (techniqueIdx == (UINT32)-1)
+					techniqueIdx = renElement.material->getDefaultTechnique();
+
+				renElement.techniqueIdx = techniqueIdx;
+
 				// Generate or assigned renderer specific data for the material
 				Any materialInfo = renElement.material->getRendererData();
 				if(materialInfo.empty())
 				{
 					RendererMaterial matInfo;
-					matInfo.params.resize(1);
-					matInfo.params[0] = renElement.material->createParamsSet(0);
+					matInfo.params.resize(techniqueIdx + 1);
+					matInfo.params[techniqueIdx] = renElement.material->createParamsSet(techniqueIdx);
 					matInfo.matVersion = renElement.material->getVersion();
 
-					renElement.material->updateParamsSet(matInfo.params[0], 0, true);
+					renElement.material->updateParamsSet(matInfo.params[techniqueIdx], techniqueIdx, true);
 					renElement.material->setRendererData(matInfo);
-					renElement.params = matInfo.params[0];
+					renElement.params = matInfo.params[techniqueIdx];
 				}
 				else
 				{
 					RendererMaterial& matInfo = any_cast_ref<RendererMaterial>(materialInfo);
 					if(matInfo.matVersion != renElement.material->getVersion())
 					{
-						if (matInfo.params.size() < 1)
-							matInfo.params.resize(1);
+						if (matInfo.params.size() <= techniqueIdx)
+							matInfo.params.resize(techniqueIdx + 1);
 
-						matInfo.params[0] = renElement.material->createParamsSet(0);
+						matInfo.params[techniqueIdx] = renElement.material->createParamsSet(techniqueIdx);
 						matInfo.matVersion = renElement.material->getVersion();
 
-						renElement.material->updateParamsSet(matInfo.params[0], 0, true);
+						renElement.material->updateParamsSet(matInfo.params[techniqueIdx], techniqueIdx, true);
 					}
 
-					renElement.params = matInfo.params[0];
+					renElement.params = matInfo.params[techniqueIdx];
 				}
 
 				// Generate or assign sampler state overrides
-				auto iterFind = mSamplerOverrides.find(renElement.material);
+				SamplerOverrideKey samplerKey(renElement.material, techniqueIdx);
+				auto iterFind = mSamplerOverrides.find(samplerKey);
 				if (iterFind != mSamplerOverrides.end())
 				{
 					renElement.samplerOverrides = iterFind->second;
@@ -217,7 +228,7 @@ namespace BansheeEngine
 					MaterialSamplerOverrides* samplerOverrides = SamplerOverrideUtility::generateSamplerOverrides(shader,
 						renElement.material->_getInternalParams(), renElement.params, mCoreOptions);
 
-					mSamplerOverrides[renElement.material] = samplerOverrides;
+					mSamplerOverrides[samplerKey] = samplerOverrides;
 
 					renElement.samplerOverrides = samplerOverrides;
 					samplerOverrides->refCount++;
@@ -237,7 +248,9 @@ namespace BansheeEngine
 		Vector<BeastRenderableElement>& elements = mRenderables[renderableId].elements;
 		for (auto& element : elements)
 		{
-			auto iterFind = mSamplerOverrides.find(element.material);
+			SamplerOverrideKey samplerKey(element.material, element.techniqueIdx);
+
+			auto iterFind = mSamplerOverrides.find(samplerKey);
 			assert(iterFind != mSamplerOverrides.end());
 
 			MaterialSamplerOverrides* samplerOverrides = iterFind->second;
@@ -788,10 +801,10 @@ namespace BansheeEngine
 		}
 
 		mObjectRenderer->setPerObjectParams(element, mRenderableShaderData[rendererId], worldViewProjMatrix, boneMatrices);
-		material->updateParamsSet(element.params);
+		material->updateParamsSet(element.params, element.techniqueIdx);
 
 		if (bindPass)
-			RendererUtility::instance().setPass(material, passIdx);
+			RendererUtility::instance().setPass(material, passIdx, element.techniqueIdx);
 
 		if (element.samplerOverrides != nullptr)
 			setPassParams(element.params, element.samplerOverrides, passIdx);
@@ -805,7 +818,7 @@ namespace BansheeEngine
 	{
 		for (auto& entry : mSamplerOverrides)
 		{
-			SPtr<MaterialParamsCore> materialParams = entry.first->_getInternalParams();
+			SPtr<MaterialParamsCore> materialParams = entry.first.material->_getInternalParams();
 
 			MaterialSamplerOverrides* materialOverrides = entry.second;
 			for(UINT32 i = 0; i < materialOverrides->numOverrides; i++)