Explorar o código

Properly render skinned mesh even when no animation is running

BearishSun %!s(int64=9) %!d(string=hai) anos
pai
achega
472f4c82b3

+ 72 - 0
Source/BansheeCore/Include/BsMaterialParam.h

@@ -48,6 +48,12 @@ namespace BansheeEngine
 		/** @copydoc TGpuDataParam::get */
 		T get(UINT32 arrayIdx = 0) const;
 
+		/** Checks if param is initialized. */
+		bool operator==(const nullptr_t& nullval) const
+		{
+			return mGPUParams == nullptr;
+		}
+
 	protected:
 		UINT32 mParamIndex;
 		UINT32 mArraySize;
@@ -69,6 +75,12 @@ namespace BansheeEngine
 		/** @copydoc TGpuDataParam::get */
 		T get(UINT32 arrayIdx = 0) const;
 
+		/** Checks if param is initialized. */
+		bool operator==(const nullptr_t& nullval) const
+		{
+			return mParams == nullptr;
+		}
+
 	protected:
 		SPtr<Vector<TGpuDataParam<T, true>>> mParams;
 	};
@@ -96,6 +108,12 @@ namespace BansheeEngine
 		/** @copydoc TGpuParamStruct::getElementSize */
 		UINT32 getElementSize() const;
 
+		/** Checks if param is initialized. */
+		bool operator==(const nullptr_t& nullval) const
+		{
+			return mGPUParams == nullptr;
+		}
+
 	protected:
 		UINT32 mParamIndex;
 		UINT32 mArraySize;
@@ -120,6 +138,12 @@ namespace BansheeEngine
 		/** @copydoc TGpuParamStruct::getElementSize */
 		UINT32 getElementSize() const;
 
+		/** Checks if param is initialized. */
+		bool operator==(const nullptr_t& nullval) const
+		{
+			return mParams == nullptr;
+		}
+
 	protected:
 		SPtr<Vector<TGpuParamStruct<true>>> mParams;
 	};
@@ -144,6 +168,12 @@ namespace BansheeEngine
 		/** @copydoc GpuParamTexture::get */
 		HTexture get() const;
 
+		/** Checks if param is initialized. */
+		bool operator==(const nullptr_t& nullval) const
+		{
+			return mGPUParams == nullptr;
+		}
+
 	protected:
 		UINT32 mParamIndex;
 		SPtr<MaterialParams> mMaterialParams;
@@ -164,6 +194,12 @@ namespace BansheeEngine
 		/** @copydoc GpuParamTexture::get */
 		SPtr<TextureCore> get() const;
 
+		/** Checks if param is initialized. */
+		bool operator==(const nullptr_t& nullval) const
+		{
+			return mParams == nullptr;
+		}
+
 	protected:
 		SPtr<Vector<TGpuParamTexture<true>>> mParams;
 	};
@@ -188,6 +224,12 @@ namespace BansheeEngine
 		/** @copydoc GpuParamLoadStoreTexture::get */
 		HTexture get() const;
 
+		/** Checks if param is initialized. */
+		bool operator==(const nullptr_t& nullval) const
+		{
+			return mGPUParams == nullptr;
+		}
+
 	protected:
 		UINT32 mParamIndex;
 		SPtr<MaterialParams> mMaterialParams;
@@ -209,6 +251,12 @@ namespace BansheeEngine
 		/** @copydoc GpuParamLoadStoreTexture::get */
 		SPtr<TextureCore> get() const;
 
+		/** Checks if param is initialized. */
+		bool operator==(const nullptr_t& nullval) const
+		{
+			return mParams == nullptr;
+		}
+
 	protected:
 		SPtr<Vector<TGpuParamLoadStoreTexture<true>>> mParams;
 	};
@@ -233,6 +281,12 @@ namespace BansheeEngine
 		/** @copydoc GpuParamBuffer::get */
 		SPtr<GpuBuffer> get() const;
 
+		/** Checks if param is initialized. */
+		bool operator==(const nullptr_t& nullval) const
+		{
+			return mGPUParams == nullptr;
+		}
+
 	protected:
 		UINT32 mParamIndex;
 		SPtr<MaterialParams> mMaterialParams;
@@ -253,6 +307,12 @@ namespace BansheeEngine
 		/** @copydoc GpuParamBuffer::get */
 		SPtr<GpuBufferCore> get() const;
 
+		/** Checks if param is initialized. */
+		bool operator==(const nullptr_t& nullval) const
+		{
+			return mParams == nullptr;
+		}
+
 	protected:
 		SPtr<Vector<TGpuParamBuffer<true>>> mParams;
 	};
@@ -277,6 +337,12 @@ namespace BansheeEngine
 		/** @copydoc GpuParamSampState::get */
 		SPtr<SamplerState> get() const;
 
+		/** Checks if param is initialized. */
+		bool operator==(const nullptr_t& nullval) const
+		{
+			return mGPUParams == nullptr;
+		}
+
 	protected:
 		UINT32 mParamIndex;
 		SPtr<MaterialParams> mMaterialParams;
@@ -297,6 +363,12 @@ namespace BansheeEngine
 		/** @copydoc GpuParamSampState::get */
 		SPtr<SamplerStateCore> get() const;
 
+		/** Checks if param is initialized. */
+		bool operator==(const nullptr_t& nullval) const
+		{
+			return mParams == nullptr;
+		}
+
 	protected:
 		SPtr<Vector<TGpuParamSampState<true>>> mParams;
 	};

+ 3 - 2
Source/MBansheeEngine/Animation/Animation.cs

@@ -117,8 +117,9 @@ namespace BansheeEngine
 
         /// <summary>
         /// Determines the default clip to play as soon as the component is enabled. If more control over playing clips is
-        /// needed use the <see cref="Play"/>, <see cref="Blend"/> and <see cref="CrossFade"/> methods to queue clips for
-        /// playback manually, and <see cref="SetState"/> method for modify their states individually.
+        /// needed use the <see cref="Play"/>, <see cref="Blend1D"/>, <see cref="Blend2D"/> and <see cref="CrossFade"/> 
+        /// methods to queue clips for playback manually, and <see cref="SetState"/> method for modify their states 
+        /// individually.
         /// </summary>
         public AnimationClip DefaultClip
         {

+ 6 - 2
Source/MBansheeEngine/Animation/AnimationClip.cs

@@ -8,7 +8,11 @@ namespace BansheeEngine
     /** @addtogroup Animation
      *  @{
      */
-     
+
+    /// <summary>
+    /// Contains animation curves for translation/rotation/scale of scene objects/skeleton bones, as well as curves for
+    /// generic property animation.
+    /// </summary>
     public class AnimationClip : Resource
     {
         /// <summary>
@@ -19,4 +23,4 @@ namespace BansheeEngine
     }
 
     /** @} */
-}
+}

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

@@ -37,6 +37,9 @@ namespace BansheeEngine
 		 * Parameter for setting global bone pose transforms used for an element with skeletal animation, null otherwise. 
 		 */
 		MaterialParamBufferCore boneMatricesParam;
+
+		/** GPU buffer containing element's bone matrices, if it requires any. */
+		SPtr<GpuBufferCore> boneMatrixBuffer;
 	};
 
 	 /** Contains information about a Renderable, used by the Renderer. */

+ 30 - 3
Source/RenderBeast/Source/BsObjectRendering.cpp

@@ -5,6 +5,9 @@
 #include "BsGpuParams.h"
 #include "BsRenderBeast.h"
 #include "BsMaterial.h"
+#include "BsMesh.h"
+#include "BsSkeleton.h"
+#include "BsGpuBuffer.h"
 
 namespace BansheeEngine
 {
@@ -50,8 +53,33 @@ namespace BansheeEngine
 		element.material->setParamBlockBuffer(perCameraBlockName, mPerCameraParams.getBuffer());
 		element.material->setParamBlockBuffer(perObjectBlockName, mPerObjectParams.getBuffer());
 
-		if(!boneMatricesParamName.empty())
+		if (!boneMatricesParamName.empty())
+		{
+			// Note: Bone matrices should be shared between all sub-meshes, so maybe it's better to create this buffer
+			// on a per-Renderable basis, rather than per-element?
 			element.boneMatricesParam = element.material->getParamBuffer(boneMatricesParamName);
+
+			SPtr<Skeleton> skeleton = element.mesh->getSkeleton();
+			UINT32 numBones = skeleton != nullptr ? skeleton->getNumBones() : 0;
+
+			if (numBones > 0)
+			{
+				SPtr<GpuBufferCore> buffer = GpuBufferCore::create(numBones * 3, 0, GBT_STANDARD, BF_32X4F, GBU_DYNAMIC);
+				UINT8* dest = (UINT8*)buffer->lock(0, numBones * 3 * sizeof(Vector4), GBL_WRITE_ONLY_DISCARD);
+
+				// Initialize bone transforms to identity, so the object renders properly even if no animation is animating it
+				for (UINT32 i = 0; i < numBones; i++)
+				{
+					memcpy(dest, &Matrix4::IDENTITY, 12 * sizeof(float)); // Assuming row-major format
+
+					dest += 12 * sizeof(float);
+				}
+
+				buffer->unlock();
+
+				element.boneMatrixBuffer = buffer;
+			}
+		}
 	}
 
 	void ObjectRenderer::setParamFrameParams(float time)
@@ -87,8 +115,7 @@ namespace BansheeEngine
 		mPerObjectParams.gWorldDeterminantSign.set(data.worldDeterminantSign);
 		mPerObjectParams.gMatWorldViewProj.set(wvpMatrix);
 
-		if(element.animationId != (UINT64)-1)
-			element.boneMatricesParam.set(boneMatrices);
+		element.boneMatricesParam.set(boneMatrices);
 	}
 
 	void DefaultMaterial::_initDefines(ShaderDefines& defines)

+ 4 - 5
Source/RenderBeast/Source/BsRenderBeast.cpp

@@ -26,6 +26,7 @@
 #include "BsRenderTargets.h"
 #include "BsRendererUtility.h"
 #include "BsAnimationManager.h"
+#include "BsSkeleton.h"
 #include "BsGpuBuffer.h"
 
 using namespace std::placeholders;
@@ -725,11 +726,11 @@ namespace BansheeEngine
 		UINT32 rendererId = element.renderableId;
 		Matrix4 worldViewProjMatrix = viewProj * mRenderableShaderData[rendererId].worldTransform;
 
-		SPtr<GpuBufferCore> boneMatrices;
+		SPtr<GpuBufferCore> boneMatrices = element.boneMatrixBuffer;
 		if(element.animationId != (UINT64)-1)
 		{
-			// Note: If multiple elements are using the same animation (not possible atm), this buffer should be created
-			// earlier and then shared by all elements
+			// Note: If multiple elements are using the same animation (not possible atm), this buffer should be shared by
+			// all such elements
 
 			const RendererAnimationData& animData = frameInfo.animData;
 
@@ -738,9 +739,7 @@ namespace BansheeEngine
 			{
 				const RendererAnimationData::PoseInfo& poseInfo = iterFind->second;
 
-				boneMatrices = GpuBufferCore::create(poseInfo.numBones * 3, 0, GBT_STANDARD, BF_32X4F, GBU_STATIC);
 				UINT8* dest = (UINT8*)boneMatrices->lock(0, poseInfo.numBones * 3 * sizeof(Vector4), GBL_WRITE_ONLY_DISCARD);
-
 				for(UINT32 i = 0; i < poseInfo.numBones; i++)
 				{
 					const Matrix4& transform = animData.transforms[poseInfo.startIdx + i];