Browse Source

During FBX import account for original units and scale to meters
Import scale is now properly applied to bind poses
Local transform will no longer be applied twice to animated SOs
Fix issue with SO transform feedback where animation would keep updating the SO, and the SO would keep updating the animation, every frame

BearishSun 9 years ago
parent
commit
25df5b2afa

+ 3 - 1
Source/BansheeCore/Source/BsAnimation.cpp

@@ -1079,7 +1079,7 @@ namespace BansheeEngine
 		// Write TRS animation results to relevant SceneObjects
 		for(UINT32 i = 0; i < mAnimProxy->numSceneObjects; i++)
 		{
-			const AnimatedSceneObjectInfo& soInfo = mAnimProxy->sceneObjectInfos[i];
+			AnimatedSceneObjectInfo& soInfo = mAnimProxy->sceneObjectInfos[i];
 
 			auto iterFind = mSceneObjects.find(soInfo.id);
 			if (iterFind == mSceneObjects.end())
@@ -1101,6 +1101,8 @@ namespace BansheeEngine
 				so->setRotation(mAnimProxy->sceneObjectPose.rotations[i]);
 				so->setScale(mAnimProxy->sceneObjectPose.scales[i]);
 			}
+
+			soInfo.hash = so->getTransformHash();
 		}
 
 		// Must ensure that clip in the proxy and current primary clip are the same

+ 3 - 3
Source/BansheeEngine/Include/BsCRenderable.h

@@ -55,12 +55,12 @@ namespace BansheeEngine
 		/** Returns the internal renderable that is used for majority of operations by this component. */
 		SPtr<Renderable> _getRenderable() const { return mInternal; }
 
+		/** Attaches an animation that will be used for animating the renderable's mesh. */
+		void _setAnimation(const SPtr<Animation>& animation);
+
 		/** @} */
 
 	private:
-		/**	Updates the world transform if the SceneObject transform changed. */
-		void updateTransform() const;
-
 		mutable SPtr<Renderable> mInternal;
 
 		/************************************************************************/

+ 3 - 0
Source/BansheeEngine/Include/BsRenderable.h

@@ -199,6 +199,9 @@ namespace BansheeEngine
 		/**	Sets the hash value that can be used to identify if the internal data needs an update. */
 		void _setLastModifiedHash(UINT32 hash) { mLastUpdateHash = hash; }
 
+		/** Updates the transfrom from the provided scene object, if the scene object's data is detected to be dirty. */
+		void _updateTransform(const HSceneObject& so, bool force = false);
+
 		/**	Creates a new renderable handler instance. */
 		static SPtr<Renderable> create();
 

+ 1 - 4
Source/BansheeEngine/Source/BsCAnimation.cpp

@@ -146,10 +146,7 @@ namespace BansheeEngine
 		if (renderableComponent == nullptr)
 			return;
 
-		SPtr<Renderable> renderable = renderableComponent->_getRenderable();
-
-		if(renderable != nullptr)
-			renderable->setAnimation(mInternal);
+		renderableComponent->_setAnimation(mInternal);
 	}
 
 	void CAnimation::destroyInternal()

+ 9 - 10
Source/BansheeEngine/Source/BsCRenderable.cpp

@@ -29,14 +29,13 @@ namespace BansheeEngine
 		gSceneManager()._registerRenderable(mInternal, sceneObject());
 
 		HAnimation animationComponent = SO()->getComponent<CAnimation>();
-		if(animationComponent != nullptr)
-			mInternal->setAnimation(animationComponent->_getInternal());
+		if (animationComponent != nullptr)
+			_setAnimation(animationComponent->_getInternal());
 	}
 
 	Bounds CRenderable::getBounds() const
 	{
-		updateTransform();
-
+		mInternal->_updateTransform(mThisHandle);
 		return mInternal->getBounds();
 	}
 
@@ -47,15 +46,15 @@ namespace BansheeEngine
 		return true;
 	}
 
-	void CRenderable::updateTransform() const
+	void CRenderable::_setAnimation(const SPtr<Animation>& animation)
 	{
-		UINT32 curHash = SO()->getTransformHash();
-		if (curHash != mInternal->_getLastModifiedHash())
+		if (mInternal != nullptr)
 		{
-			Matrix4 transformNoScale = Matrix4::TRS(SO()->getWorldPosition(), SO()->getWorldRotation(), Vector3::ONE);
+			mInternal->setAnimation(animation);
 
-			mInternal->setTransform(SO()->getWorldTfrm(), transformNoScale);
-			mInternal->_setLastModifiedHash(curHash);
+			// Need to update transform because animated renderables handle local transforms through bones, so it shouldn't
+			// be included in the renderable's transform.
+			mInternal->_updateTransform(mThisHandle, true);
 		}
 	}
 

+ 28 - 0
Source/BansheeEngine/Source/BsRenderable.cpp

@@ -281,6 +281,34 @@ namespace BansheeEngine
 		}
 	}
 
+	void Renderable::_updateTransform(const HSceneObject& so, bool force)
+	{
+		UINT32 curHash = so->getTransformHash();
+		if (curHash != _getLastModifiedHash() || force)
+		{
+			if (mAnimation != nullptr)
+			{
+				// Note: Technically we're checking child's hash but using parent's transform. Ideally we check the parent's
+				// hash to reduce the number of required updates.
+				HSceneObject parentSO = so->getParent();
+				if (parentSO != nullptr)
+				{
+					Matrix4 transformNoScale = Matrix4::TRS(parentSO->getWorldPosition(), parentSO->getWorldRotation(), Vector3::ONE);
+					setTransform(parentSO->getWorldTfrm(), transformNoScale);
+				}
+				else
+					setTransform(Matrix4::IDENTITY, Matrix4::IDENTITY);
+			}
+			else
+			{
+				Matrix4 transformNoScale = Matrix4::TRS(so->getWorldPosition(), so->getWorldRotation(), Vector3::ONE);
+				setTransform(so->getWorldTfrm(), transformNoScale);
+			}
+
+			_setLastModifiedHash(curHash);
+		}
+	}
+
 	void Renderable::_markCoreDirty(RenderableDirtyFlag flag)
 	{
 		markCoreDirty((UINT32)flag);

+ 4 - 13
Source/BansheeEngine/Source/BsSceneManager.cpp

@@ -80,22 +80,13 @@ namespace BansheeEngine
 	{
 		for (auto& renderablePair : mRenderables)
 		{
-			SPtr<Renderable> handler = renderablePair.second.renderable;
+			SPtr<Renderable> renderable = renderablePair.second.renderable;
 			HSceneObject so = renderablePair.second.sceneObject;
 
-			UINT32 curHash = so->getTransformHash();
-			if (curHash != handler->_getLastModifiedHash())
-			{
-				Matrix4 transformNoScale = Matrix4::TRS(so->getWorldPosition(), so->getWorldRotation(), Vector3::ONE);
-
-				handler->setTransform(so->getWorldTfrm(), transformNoScale);
-				handler->_setLastModifiedHash(curHash);
-			}
+			renderable->_updateTransform(so);
 
-			if (so->getActive() != handler->getIsActive())
-			{
-				handler->setIsActive(so->getActive());
-			}
+			if (so->getActive() != renderable->getIsActive())
+				renderable->setIsActive(so->getActive());
 		}
 
 		for (auto& cameraPair : mCameras)

+ 12 - 9
Source/BansheeFBXImporter/Source/BsFBXImporter.cpp

@@ -319,6 +319,13 @@ namespace BansheeEngine
 
 	void FBXImporter::parseScene(FbxScene* scene, const FBXImportOptions& options, FBXImportScene& outputScene)
 	{
+		float importScale = 1.0f;
+		if (options.importScale > 0.0001f)
+			importScale = options.importScale;
+
+		FbxSystemUnit scaledMeters(100.0f / importScale);
+		scaledMeters.ConvertScene(scene);
+
 		outputScene.rootNode = createImportNode(outputScene, scene->GetRootNode(), nullptr);
 
 		Stack<FbxNode*> todo;
@@ -523,8 +530,6 @@ namespace BansheeEngine
 	SPtr<RendererMeshData> FBXImporter::generateMeshData(const FBXImportScene& scene, const FBXImportOptions& options, 
 		Vector<SubMesh>& outputSubMeshes, SPtr<Skeleton>& outputSkeleton)
 	{
-		Matrix4 importScale = Matrix4::scaling(options.importScale);
-
 		Vector<SPtr<MeshData>> allMeshData;
 		Vector<Vector<SubMesh>> allSubMeshes;
 		Vector<BONE_DESC> allBones;
@@ -597,7 +602,7 @@ namespace BansheeEngine
 			UINT32 numIndices = (UINT32)mesh->indices.size();
 			for (auto& node : mesh->referencedBy)
 			{
-				Matrix4 worldTransform = node->worldTransform * importScale;
+				Matrix4 worldTransform = node->worldTransform;
 				Matrix4 worldTransformIT = worldTransform.transpose();
 				worldTransformIT = worldTransformIT.inverse();
 
@@ -1247,14 +1252,12 @@ namespace BansheeEngine
 		Matrix4 invBakedTransform;
 		if (mesh.referencedBy.size() > 0)
 		{
-			Matrix4 importScale = Matrix4::scaling(options.importScale);
-			Matrix4 bakedTransform = mesh.referencedBy[0]->worldTransform * importScale;
-
+			Matrix4 bakedTransform = mesh.referencedBy[0]->worldTransform;
 			invBakedTransform = bakedTransform.inverseAffine();
 		}
 		else
 			invBakedTransform = Matrix4::IDENTITY;
-		
+
 		UnorderedSet<FbxNode*> existingBones;
 		UINT32 boneCount = (UINT32)skin->GetClusterCount();
 		for (UINT32 i = 0; i < boneCount; i++)
@@ -1503,8 +1506,8 @@ namespace BansheeEngine
 				eulerAnimation = reduceKeyframes(eulerAnimation);
 			}
 
-			if (importOptions.importScale != 1.0f)
-				boneAnim.translation = scaleKeyframes(boneAnim.translation, importOptions.importScale);
+			//if (importOptions.importScale != 1.0f)
+			//	boneAnim.translation = scaleKeyframes(boneAnim.translation, importOptions.importScale);
 
 			boneAnim.rotation = AnimationUtility::eulerToQuaternionCurve(eulerAnimation);
 		}

+ 1 - 1
Source/BansheeMono/Include/BsMonoProperty.h

@@ -92,7 +92,7 @@ namespace BansheeEngine
 		::MonoMethod* mGetMethod;
 		::MonoMethod* mSetMethod;
 
-		mutable MonoClass* mGetReturnType;
+		mutable MonoClass* mReturnType;
 		mutable bool mIsIndexed;
 		mutable bool mIsFullyInitialized;
 	};

+ 11 - 3
Source/BansheeMono/Source/BsMonoProperty.cpp

@@ -10,7 +10,7 @@
 namespace BansheeEngine
 {
 	MonoProperty::MonoProperty(::MonoProperty* monoProp)
-		:mProperty(monoProp), mGetReturnType(nullptr), mIsIndexed(false), mIsFullyInitialized(false)
+		:mProperty(monoProp), mReturnType(nullptr), mIsIndexed(false), mIsFullyInitialized(false)
 	{
 		mGetMethod = mono_property_get_get_method(mProperty);
 		mSetMethod = mono_property_get_set_method(mProperty);
@@ -64,7 +64,7 @@ namespace BansheeEngine
 		if (!mIsFullyInitialized)
 			initializeDeferred();
 
-		return mGetReturnType;
+		return mReturnType;
 	}
 
 	bool MonoProperty::hasAttribute(MonoClass* monoClass)
@@ -132,7 +132,7 @@ namespace BansheeEngine
 			{
 				::MonoClass* returnClass = mono_class_from_mono_type(returnType);
 				if (returnClass != nullptr)
-					mGetReturnType = MonoManager::instance().findClass(returnClass);
+					mReturnType = MonoManager::instance().findClass(returnClass);
 			}
 
 			UINT32 numParams = mono_signature_get_param_count(signature);
@@ -142,6 +142,14 @@ namespace BansheeEngine
 		{
 			MonoMethodSignature* signature = mono_method_signature(mSetMethod);
 
+			MonoType* returnType = mono_signature_get_return_type(signature);
+			if (returnType != nullptr)
+			{
+				::MonoClass* returnClass = mono_class_from_mono_type(returnType);
+				if (returnClass != nullptr)
+					mReturnType = MonoManager::instance().findClass(returnClass);
+			}
+
 			UINT32 numParams = mono_signature_get_param_count(signature);
 			mIsIndexed = numParams == 2;
 		}

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

@@ -583,9 +583,7 @@ namespace BansheeEngine
             if (renderable == null)
                 return;
 
-            NativeRenderable nativeRenderable = renderable.Native;
-            if (nativeRenderable != null)
-                nativeRenderable.Animation = _native;
+            renderable.NativeAnimation = _native;
         }
 
         /// <summary>

+ 3 - 3
Source/MBansheeEngine/Interop/NativeRenderable.cs

@@ -109,9 +109,9 @@ namespace BansheeEngine
             Internal_SetMaterial(mCachedPtr, materialPtr, index);
         }
 
-        internal void UpdateTransform(SceneObject sceneObject)
+        internal void UpdateTransform(SceneObject sceneObject, bool force)
         {
-            Internal_UpdateTransform(mCachedPtr, sceneObject.mCachedPtr);
+            Internal_UpdateTransform(mCachedPtr, sceneObject.mCachedPtr, force);
         }
         
         internal void OnDestroy()
@@ -126,7 +126,7 @@ namespace BansheeEngine
         private static extern void Internal_SetAnimation(IntPtr thisPtr, IntPtr animation);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_UpdateTransform(IntPtr thisPtr, IntPtr parentSO);
+        private static extern void Internal_UpdateTransform(IntPtr thisPtr, IntPtr parentSO, bool force);
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetMesh(IntPtr thisPtr, IntPtr mesh);

+ 20 - 2
Source/MBansheeEngine/Rendering/Renderable.cs

@@ -28,6 +28,24 @@ namespace BansheeEngine
             get { return _native; }
         }
 
+        /// <summary>
+        /// Attaches an animation that will be used for animating the renderable's mesh.
+        /// </summary>
+        internal NativeAnimation NativeAnimation
+        {
+            set
+            {
+                if (_native != null)
+                {
+                    _native.Animation = value;
+
+                    // Need to update transform because animated renderables handle local transforms through bones, so it
+                    // shouldn't be included in the renderable's transform.
+                    _native.UpdateTransform(SceneObject, true);
+                }
+            }
+        }
+
         /// <summary>
         /// Mesh to render. 
         /// </summary>
@@ -132,12 +150,12 @@ namespace BansheeEngine
 
             Animation animation = SceneObject.GetComponent<Animation>();
             if (animation != null)
-                _native.Animation = animation.Native;
+                NativeAnimation = animation.Native;
         }
 
         private void OnUpdate()
         {
-            _native.UpdateTransform(SceneObject);
+            _native.UpdateTransform(SceneObject, false);
         }
 
         private void OnDestroy()

+ 2 - 3
Source/SBansheeEngine/Include/BsScriptRenderable.h

@@ -27,7 +27,7 @@ namespace BansheeEngine
 		~ScriptRenderable();
 
 		/** Updates the internal transform of the renderable handled according to the scene object it is attached to. */
-		void updateTransform(const HSceneObject& parent);
+		void updateTransform(const HSceneObject& parent, bool force);
 
 		/**	Destroys the internal renderable object. */
 		void destroy();
@@ -36,14 +36,13 @@ namespace BansheeEngine
 		void _onManagedInstanceDeleted() override;
 
 		SPtr<Renderable> mRenderable;
-		UINT32 mLastUpdateHash;
 
 		/************************************************************************/
 		/* 								CLR HOOKS						   		*/
 		/************************************************************************/
 		static void internal_Create(MonoObject* instance, ScriptSceneObject* parentSO);
 		static void internal_SetAnimation(ScriptRenderable* thisPtr, ScriptAnimation* animation);
-		static void internal_UpdateTransform(ScriptRenderable* thisPtr, ScriptSceneObject* parentSO);
+		static void internal_UpdateTransform(ScriptRenderable* thisPtr, ScriptSceneObject* parentSO, bool force);
 		static void internal_SetMesh(ScriptRenderable* thisPtr, ScriptMesh* mesh);
 		static void internal_GetBounds(ScriptRenderable* thisPtr, ScriptSceneObject* parentSO, AABox* box, Sphere* sphere);
 		static UINT64 internal_GetLayers(ScriptRenderable* thisPtr);

+ 6 - 15
Source/SBansheeEngine/Source/BsScriptRenderable.cpp

@@ -18,7 +18,7 @@
 namespace BansheeEngine
 {
 	ScriptRenderable::ScriptRenderable(MonoObject* managedInstance, const HSceneObject& parentSO)
-		:ScriptObject(managedInstance), mRenderable(nullptr), mLastUpdateHash(0)
+		:ScriptObject(managedInstance), mRenderable(nullptr)
 	{
 		mRenderable = Renderable::create();
 		gSceneManager()._registerRenderable(mRenderable, parentSO);
@@ -41,21 +41,12 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_OnDestroy", &ScriptRenderable::internal_OnDestroy);
 	}
 
-	void ScriptRenderable::updateTransform(const HSceneObject& parent)
+	void ScriptRenderable::updateTransform(const HSceneObject& parent, bool force)
 	{
-		UINT32 curHash = parent->getTransformHash();
-		if (curHash != mLastUpdateHash)
-		{
-			Matrix4 transformNoScale = Matrix4::TRS(parent->getWorldPosition(), parent->getWorldRotation(), Vector3::ONE);
-			mRenderable->setTransform(parent->getWorldTfrm(), transformNoScale);
-
-			mLastUpdateHash = curHash;
-		}
+		mRenderable->_updateTransform(parent, force);
 
 		if (parent->getActive() != mRenderable->getIsActive())
-		{
 			mRenderable->setIsActive(parent->getActive());
-		}
 	}
 
 	void ScriptRenderable::internal_Create(MonoObject* instance, ScriptSceneObject* parentSO)
@@ -76,11 +67,11 @@ namespace BansheeEngine
 		thisPtr->getInternal()->setAnimation(anim);
 	}
 
-	void ScriptRenderable::internal_UpdateTransform(ScriptRenderable* thisPtr, ScriptSceneObject* parent)
+	void ScriptRenderable::internal_UpdateTransform(ScriptRenderable* thisPtr, ScriptSceneObject* parent, bool force)
 	{
 		HSceneObject parentSO = parent->getNativeSceneObject();
 
-		thisPtr->updateTransform(parentSO);
+		thisPtr->updateTransform(parentSO, force);
 	}
 
 	void ScriptRenderable::internal_SetMesh(ScriptRenderable* thisPtr, ScriptMesh* mesh)
@@ -95,7 +86,7 @@ namespace BansheeEngine
 	void ScriptRenderable::internal_GetBounds(ScriptRenderable* thisPtr, ScriptSceneObject* parent, AABox* box, Sphere* sphere)
 	{
 		HSceneObject parentSO = parent->getNativeSceneObject();
-		thisPtr->updateTransform(parentSO);
+		thisPtr->updateTransform(parentSO, false);
 
 		Bounds bounds = thisPtr->getInternal()->getBounds();