瀏覽代碼

Removed the nonintuitive "invisible LOD factor" attribute from AnimatedModel and replaced it with updateInvisible flag similar to ParticleEmitter. This flag must be used for ragdolls or other physically animated objects to ensure that they come into view properly during animation if they previously were outside view. Fixes #40.

Lasse Öörni 12 年之前
父節點
當前提交
82007cc4f4

+ 3 - 0
Bin/Data/LuaScripts/13_Ragdolls.lua

@@ -95,6 +95,9 @@ function CreateScene()
             modelObject.model = cache:GetResource("Model", "Models/Jack.mdl")
             modelObject.material = cache:GetResource("Material", "Materials/Jack.xml")
             modelObject.castShadows = true
+            -- Set the model to also update when invisible to avoid staying invisible when the model should come into
+            -- view, but does not as the bounding box is not updated
+            modelObject.updateInvisible = true;
 
             -- Create a rigid body and a collision shape. These will act as a trigger for transforming the
             -- model into a ragdoll when hit by a moving object

+ 0 - 1
Bin/Data/Objects/Ninja.xml

@@ -65,7 +65,6 @@
 			<attribute name="Shadow Distance" value="0" />
 			<attribute name="LOD Bias" value="1" />
 			<attribute name="Animation LOD Bias" value="1" />
-			<attribute name="Invisible Anim LOD" value="3" />
 			<attribute name="Max Lights" value="0" />
 			<attribute name="View Mask" value="-1" />
 			<attribute name="Light Mask" value="-1" />

+ 4 - 1
Bin/Data/Scripts/13_Ragdolls.as

@@ -93,7 +93,10 @@ void CreateScene()
             modelObject.model = cache.GetResource("Model", "Models/Jack.mdl");
             modelObject.material = cache.GetResource("Material", "Materials/Jack.xml");
             modelObject.castShadows = true;
-            
+            // Set the model to also update when invisible to avoid staying invisible when the model should come into
+            // view, but does not as the bounding box is not updated
+            modelObject.updateInvisible = true;
+
             // Create a rigid body and a collision shape. These will act as a trigger for transforming the
             // model into a ragdoll when hit by a moving object
             RigidBody@ body = modelNode.CreateComponent("RigidBody");

+ 1 - 1
Docs/AngelScriptAPI.h

@@ -3307,7 +3307,7 @@ uint numGeometries;
 /* (readonly) */
 Zone zone;
 float animationLodBias;
-float invisibleLodFactor;
+bool updateInvisible;
 /* (readonly) */
 Skeleton skeleton;
 /* (readonly) */

+ 3 - 3
Docs/LuaScriptAPI.dox

@@ -1079,7 +1079,7 @@ Methods:
 - void RemoveAnimationState(unsigned index)
 - void RemoveAllAnimationStates()
 - void SetAnimationLodBias(float bias)
-- void SetInvisibleLodFactor(float factor)
+- void SetUpdateInvisible(bool enable)
 - void SetMorphWeight(unsigned index, float weight)
 - void SetMorphWeight(const String name, float weight)
 - void SetMorphWeight(StringHash nameHash, float weight)
@@ -1091,7 +1091,7 @@ Methods:
 - AnimationState* GetAnimationState(const StringHash animationNameHash) const
 - AnimationState* GetAnimationState(unsigned index) const
 - float GetAnimationLodBias() const
-- float GetInvisibleLodFactor() const
+- bool GetUpdateInvisible() const
 - unsigned GetNumMorphs() const
 - float GetMorphWeight(unsigned index) const
 - float GetMorphWeight(const String name) const
@@ -1104,7 +1104,7 @@ Properties:
 - Skeleton& skeleton (readonly)
 - unsigned numAnimationStates (readonly)
 - float animationLodBias
-- float invisibleLodFactor
+- bool updateInvisible
 - unsigned numMorphs (readonly)
 - bool master (readonly)
 

+ 1 - 1
Docs/ScriptAPI.dox

@@ -2914,7 +2914,7 @@ Properties:
 - uint numGeometries (readonly)
 - Zone@ zone (readonly)
 - float animationLodBias
-- float invisibleLodFactor
+- bool updateInvisible
 - Skeleton@ skeleton (readonly)
 - uint numAnimationStates (readonly)
 - AnimationState@[] animationStates (readonly)

+ 12 - 20
Source/Engine/Graphics/AnimatedModel.cpp

@@ -63,7 +63,7 @@ AnimatedModel::AnimatedModel(Context* context) :
     animationLodBias_(1.0f),
     animationLodTimer_(-1.0f),
     animationLodDistance_(0.0f),
-    invisibleLodFactor_(0.0f),
+    updateInvisible_(false),
     animationDirty_(false),
     animationOrderDirty_(false),
     morphsDirty_(false),
@@ -89,11 +89,11 @@ void AnimatedModel::RegisterObject(Context* context)
     ATTRIBUTE(AnimatedModel, VAR_BOOL, "Is Occluder", occluder_, false, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_BOOL, "Can Be Occluded", IsOccludee, SetOccludee, bool, true, AM_DEFAULT);
     ATTRIBUTE(AnimatedModel, VAR_BOOL, "Cast Shadows", castShadows_, false, AM_DEFAULT);
+    ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_BOOL, "Update When Invisible", GetUpdateInvisible, SetUpdateInvisible, bool, false, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_FLOAT, "Draw Distance", GetDrawDistance, SetDrawDistance, float, 0.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_FLOAT, "Shadow Distance", GetShadowDistance, SetShadowDistance, float, 0.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_FLOAT, "LOD Bias", GetLodBias, SetLodBias, float, 1.0f, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_FLOAT, "Animation LOD Bias", GetAnimationLodBias, SetAnimationLodBias, float, 1.0f, AM_DEFAULT);
-    ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_FLOAT, "Invisible Anim LOD", GetInvisibleLodFactor, SetInvisibleLodFactor, float, 0.0f, AM_DEFAULT);
     COPY_BASE_ATTRIBUTES(AnimatedModel, Drawable);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_VARIANTVECTOR, "Bone Animation Enabled", GetBonesEnabledAttr, SetBonesEnabledAttr, VariantVector, Variant::emptyVariantVector, AM_FILE | AM_NOEDIT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_VARIANTVECTOR, "Animation States", GetAnimationStatesAttr, SetAnimationStatesAttr, VariantVector, Variant::emptyVariantVector, AM_FILE);
@@ -191,26 +191,25 @@ void AnimatedModel::ProcessRayQuery(const RayOctreeQuery& query, PODVector<RayQu
 
 void AnimatedModel::Update(const FrameInfo& frame)
 {
-    // Update animation here
-    if (!animationDirty_ && !animationOrderDirty_)
-        return;
-
     // If node was invisible last frame, need to decide animation LOD distance here
     // If headless, retain the current animation distance (should be 0)
     if (frame.camera_ && abs((int)frame.frameNumber_ - (int)viewFrameNumber_) > 1)
     {
-        if (invisibleLodFactor_ == 0.0f)
+        // First check for no update at all when invisible
+        if (!updateInvisible_)
             return;
         float distance = frame.camera_->GetDistance(node_->GetWorldPosition());
         // If distance is greater than draw distance, no need to update at all
         if (drawDistance_ > 0.0f && distance > drawDistance_)
             return;
-        // Multiply the distance by a constant so that invisible nodes don't update that often
         float scale = GetWorldBoundingBox().Size().DotProduct(DOT_SCALE);
-        animationLodDistance_ = frame.camera_->GetLodDistance(distance, scale, lodBias_) * invisibleLodFactor_;
+        animationLodDistance_ = frame.camera_->GetLodDistance(distance, scale, lodBias_);
     }
 
-    UpdateAnimation(frame);
+    if (animationDirty_ || animationOrderDirty_)
+        UpdateAnimation(frame);
+    else if (boneBoundingBoxDirty_)
+        UpdateBoneBoundingBox();
 }
 
 void AnimatedModel::UpdateBatches(const FrameInfo& frame)
@@ -252,9 +251,6 @@ void AnimatedModel::UpdateGeometry(const FrameInfo& frame)
     if (morphsDirty_)
         UpdateMorphs();
     
-    if (boneBoundingBoxDirty_)
-        UpdateBoneBoundingBox();
-    
     if (skinningDirty_)
         UpdateSkinning();
 }
@@ -477,17 +473,13 @@ void AnimatedModel::SetAnimationLodBias(float bias)
     MarkNetworkUpdate();
 }
 
-void AnimatedModel::SetInvisibleLodFactor(float factor)
+void AnimatedModel::SetUpdateInvisible(bool enable)
 {
-    if (factor < 0.0f)
-        factor = 0.0f;
-    else if (factor != 0.0f && factor < 1.0f)
-        factor = 1.0f;
-
-    invisibleLodFactor_ = factor;
+    updateInvisible_ = enable;
     MarkNetworkUpdate();
 }
 
+
 void AnimatedModel::SetMorphWeight(unsigned index, float weight)
 {
     if (index >= morphs_.Size())

+ 6 - 6
Source/Engine/Graphics/AnimatedModel.h

@@ -84,8 +84,8 @@ public:
     void RemoveAllAnimationStates();
     /// Set animation LOD bias.
     void SetAnimationLodBias(float bias);
-    /// Set animation LOD distance factor when not visible (default 0 = do not update at all when invisible.)
-    void SetInvisibleLodFactor(float factor);
+    /// Set whether to update animation and the bounding box when not visible. Recommended to enable for physically controlled models like ragdolls.
+    void SetUpdateInvisible(bool enable);
     /// Set vertex morph weight by index.
     void SetMorphWeight(unsigned index, float weight);
     /// Set vertex morph weight by name.
@@ -111,8 +111,8 @@ public:
     AnimationState* GetAnimationState(unsigned index) const;
     /// Return animation LOD bias.
     float GetAnimationLodBias() const { return animationLodBias_; }
-    /// Return animation LOD distance factor when not visible.
-    float GetInvisibleLodFactor() const { return invisibleLodFactor_; }
+    /// Return whether to update animation when not visible.
+    bool GetUpdateInvisible() const { return updateInvisible_; }
     /// Return all vertex morphs.
     const Vector<ModelMorph>& GetMorphs() const { return morphs_; }
     /// Return all morph vertex buffers.
@@ -219,8 +219,8 @@ private:
     float animationLodTimer_;
     /// Animation LOD distance, the minimum of all LOD view distances last frame.
     float animationLodDistance_;
-    /// Animation LOD distance factor when not visible.
-    float invisibleLodFactor_;
+    /// Update animation when invisible flag.
+    bool updateInvisible_;
     /// Animation dirty flag.
     bool animationDirty_;
     /// Animation order dirty flag.

+ 1 - 0
Source/Engine/Graphics/ParticleEmitter.cpp

@@ -524,6 +524,7 @@ void ParticleEmitter::SetEmitting(bool enable, bool resetPeriod)
 void ParticleEmitter::SetUpdateInvisible(bool enable)
 {
     updateInvisible_ = enable;
+    MarkNetworkUpdate();
 }
 
 void ParticleEmitter::SetTimeToLive(float time)

+ 3 - 3
Source/Engine/LuaScript/pkgs/Graphics/AnimatedModel.pkg

@@ -11,7 +11,7 @@ class AnimatedModel : public StaticModel
     void RemoveAnimationState(unsigned index);
     void RemoveAllAnimationStates();
     void SetAnimationLodBias(float bias);
-    void SetInvisibleLodFactor(float factor);
+    void SetUpdateInvisible(bool enable);
     void SetMorphWeight(unsigned index, float weight);
     void SetMorphWeight(const String name, float weight);
     void SetMorphWeight(StringHash nameHash, float weight);
@@ -24,7 +24,7 @@ class AnimatedModel : public StaticModel
     AnimationState* GetAnimationState(const StringHash animationNameHash) const;
     AnimationState* GetAnimationState(unsigned index) const;
     float GetAnimationLodBias() const;
-    float GetInvisibleLodFactor() const;
+    bool GetUpdateInvisible() const;
     unsigned GetNumMorphs() const;
     float GetMorphWeight(unsigned index) const;
     float GetMorphWeight(const String name) const;
@@ -35,7 +35,7 @@ class AnimatedModel : public StaticModel
     tolua_readonly tolua_property__get_set Skeleton& skeleton;
     tolua_readonly tolua_property__get_set unsigned numAnimationStates;
     tolua_property__get_set float animationLodBias;
-    tolua_property__get_set float invisibleLodFactor;
+    tolua_property__get_set bool updateInvisible;
     tolua_readonly tolua_property__get_set unsigned numMorphs;
     tolua_readonly tolua_property__is_set bool master;
 };

+ 2 - 2
Source/Engine/Script/GraphicsAPI.cpp

@@ -898,8 +898,8 @@ static void RegisterAnimatedModel(asIScriptEngine* engine)
     engine->RegisterObjectMethod("AnimatedModel", "void set_model(Model@+)", asFUNCTION(AnimatedModelSetModel), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("AnimatedModel", "void set_animationLodBias(float)", asMETHOD(AnimatedModel, SetAnimationLodBias), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "float get_animationLodBias() const", asMETHOD(AnimatedModel, GetAnimationLodBias), asCALL_THISCALL);
-    engine->RegisterObjectMethod("AnimatedModel", "void set_invisibleLodFactor(float)", asMETHOD(AnimatedModel, SetInvisibleLodFactor), asCALL_THISCALL);
-    engine->RegisterObjectMethod("AnimatedModel", "float get_invisibleLodFactor() const", asMETHOD(AnimatedModel, GetInvisibleLodFactor), asCALL_THISCALL);
+    engine->RegisterObjectMethod("AnimatedModel", "void set_updateInvisible(bool)", asMETHOD(AnimatedModel, SetUpdateInvisible), asCALL_THISCALL);
+    engine->RegisterObjectMethod("AnimatedModel", "bool get_updateInvisible() const", asMETHOD(AnimatedModel, GetUpdateInvisible), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "Skeleton@+ get_skeleton()", asMETHOD(AnimatedModel, GetSkeleton), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "uint get_numAnimationStates() const", asMETHOD(AnimatedModel, GetNumAnimationStates), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "AnimationState@+ get_animationStates(const String&in) const", asMETHODPR(AnimatedModel, GetAnimationState, (const String&) const, AnimationState*), asCALL_THISCALL);

+ 3 - 0
Source/Samples/13_Ragdolls/Ragdolls.cpp

@@ -144,6 +144,9 @@ void Ragdolls::CreateScene()
             modelObject->SetModel(cache->GetResource<Model>("Models/Jack.mdl"));
             modelObject->SetMaterial(cache->GetResource<Material>("Materials/Jack.xml"));
             modelObject->SetCastShadows(true);
+            // Set the model to also update when invisible to avoid staying invisible when the model should come into
+            // view, but does not as the bounding box is not updated
+            modelObject->SetUpdateInvisible(true);
             
             // Create a rigid body and a collision shape. These will act as a trigger for transforming the
             // model into a ragdoll when hit by a moving object