Browse Source

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 years ago
parent
commit
82007cc4f4

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

@@ -95,6 +95,9 @@ function CreateScene()
             modelObject.model = cache:GetResource("Model", "Models/Jack.mdl")
             modelObject.model = cache:GetResource("Model", "Models/Jack.mdl")
             modelObject.material = cache:GetResource("Material", "Materials/Jack.xml")
             modelObject.material = cache:GetResource("Material", "Materials/Jack.xml")
             modelObject.castShadows = true
             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
             -- 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
             -- 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="Shadow Distance" value="0" />
 			<attribute name="LOD Bias" value="1" />
 			<attribute name="LOD Bias" value="1" />
 			<attribute name="Animation 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="Max Lights" value="0" />
 			<attribute name="View Mask" value="-1" />
 			<attribute name="View Mask" value="-1" />
 			<attribute name="Light 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.model = cache.GetResource("Model", "Models/Jack.mdl");
             modelObject.material = cache.GetResource("Material", "Materials/Jack.xml");
             modelObject.material = cache.GetResource("Material", "Materials/Jack.xml");
             modelObject.castShadows = true;
             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
             // 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
             // model into a ragdoll when hit by a moving object
             RigidBody@ body = modelNode.CreateComponent("RigidBody");
             RigidBody@ body = modelNode.CreateComponent("RigidBody");

+ 1 - 1
Docs/AngelScriptAPI.h

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

+ 3 - 3
Docs/LuaScriptAPI.dox

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

+ 1 - 1
Docs/ScriptAPI.dox

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

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

@@ -63,7 +63,7 @@ AnimatedModel::AnimatedModel(Context* context) :
     animationLodBias_(1.0f),
     animationLodBias_(1.0f),
     animationLodTimer_(-1.0f),
     animationLodTimer_(-1.0f),
     animationLodDistance_(0.0f),
     animationLodDistance_(0.0f),
-    invisibleLodFactor_(0.0f),
+    updateInvisible_(false),
     animationDirty_(false),
     animationDirty_(false),
     animationOrderDirty_(false),
     animationOrderDirty_(false),
     morphsDirty_(false),
     morphsDirty_(false),
@@ -89,11 +89,11 @@ void AnimatedModel::RegisterObject(Context* context)
     ATTRIBUTE(AnimatedModel, VAR_BOOL, "Is Occluder", occluder_, false, AM_DEFAULT);
     ATTRIBUTE(AnimatedModel, VAR_BOOL, "Is Occluder", occluder_, false, AM_DEFAULT);
     ACCESSOR_ATTRIBUTE(AnimatedModel, VAR_BOOL, "Can Be Occluded", IsOccludee, SetOccludee, bool, true, 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);
     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, "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, "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, "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, "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);
     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, "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);
     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)
 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 node was invisible last frame, need to decide animation LOD distance here
     // If headless, retain the current animation distance (should be 0)
     // If headless, retain the current animation distance (should be 0)
     if (frame.camera_ && abs((int)frame.frameNumber_ - (int)viewFrameNumber_) > 1)
     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;
             return;
         float distance = frame.camera_->GetDistance(node_->GetWorldPosition());
         float distance = frame.camera_->GetDistance(node_->GetWorldPosition());
         // If distance is greater than draw distance, no need to update at all
         // If distance is greater than draw distance, no need to update at all
         if (drawDistance_ > 0.0f && distance > drawDistance_)
         if (drawDistance_ > 0.0f && distance > drawDistance_)
             return;
             return;
-        // Multiply the distance by a constant so that invisible nodes don't update that often
         float scale = GetWorldBoundingBox().Size().DotProduct(DOT_SCALE);
         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)
 void AnimatedModel::UpdateBatches(const FrameInfo& frame)
@@ -252,9 +251,6 @@ void AnimatedModel::UpdateGeometry(const FrameInfo& frame)
     if (morphsDirty_)
     if (morphsDirty_)
         UpdateMorphs();
         UpdateMorphs();
     
     
-    if (boneBoundingBoxDirty_)
-        UpdateBoneBoundingBox();
-    
     if (skinningDirty_)
     if (skinningDirty_)
         UpdateSkinning();
         UpdateSkinning();
 }
 }
@@ -477,17 +473,13 @@ void AnimatedModel::SetAnimationLodBias(float bias)
     MarkNetworkUpdate();
     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();
     MarkNetworkUpdate();
 }
 }
 
 
+
 void AnimatedModel::SetMorphWeight(unsigned index, float weight)
 void AnimatedModel::SetMorphWeight(unsigned index, float weight)
 {
 {
     if (index >= morphs_.Size())
     if (index >= morphs_.Size())

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

@@ -84,8 +84,8 @@ public:
     void RemoveAllAnimationStates();
     void RemoveAllAnimationStates();
     /// Set animation LOD bias.
     /// Set animation LOD bias.
     void SetAnimationLodBias(float 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.
     /// Set vertex morph weight by index.
     void SetMorphWeight(unsigned index, float weight);
     void SetMorphWeight(unsigned index, float weight);
     /// Set vertex morph weight by name.
     /// Set vertex morph weight by name.
@@ -111,8 +111,8 @@ public:
     AnimationState* GetAnimationState(unsigned index) const;
     AnimationState* GetAnimationState(unsigned index) const;
     /// Return animation LOD bias.
     /// Return animation LOD bias.
     float GetAnimationLodBias() const { return animationLodBias_; }
     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.
     /// Return all vertex morphs.
     const Vector<ModelMorph>& GetMorphs() const { return morphs_; }
     const Vector<ModelMorph>& GetMorphs() const { return morphs_; }
     /// Return all morph vertex buffers.
     /// Return all morph vertex buffers.
@@ -219,8 +219,8 @@ private:
     float animationLodTimer_;
     float animationLodTimer_;
     /// Animation LOD distance, the minimum of all LOD view distances last frame.
     /// Animation LOD distance, the minimum of all LOD view distances last frame.
     float animationLodDistance_;
     float animationLodDistance_;
-    /// Animation LOD distance factor when not visible.
-    float invisibleLodFactor_;
+    /// Update animation when invisible flag.
+    bool updateInvisible_;
     /// Animation dirty flag.
     /// Animation dirty flag.
     bool animationDirty_;
     bool animationDirty_;
     /// Animation order dirty flag.
     /// 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)
 void ParticleEmitter::SetUpdateInvisible(bool enable)
 {
 {
     updateInvisible_ = enable;
     updateInvisible_ = enable;
+    MarkNetworkUpdate();
 }
 }
 
 
 void ParticleEmitter::SetTimeToLive(float time)
 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 RemoveAnimationState(unsigned index);
     void RemoveAllAnimationStates();
     void RemoveAllAnimationStates();
     void SetAnimationLodBias(float bias);
     void SetAnimationLodBias(float bias);
-    void SetInvisibleLodFactor(float factor);
+    void SetUpdateInvisible(bool enable);
     void SetMorphWeight(unsigned index, float weight);
     void SetMorphWeight(unsigned index, float weight);
     void SetMorphWeight(const String name, float weight);
     void SetMorphWeight(const String name, float weight);
     void SetMorphWeight(StringHash nameHash, float weight);
     void SetMorphWeight(StringHash nameHash, float weight);
@@ -24,7 +24,7 @@ class AnimatedModel : public StaticModel
     AnimationState* GetAnimationState(const StringHash animationNameHash) const;
     AnimationState* GetAnimationState(const StringHash animationNameHash) const;
     AnimationState* GetAnimationState(unsigned index) const;
     AnimationState* GetAnimationState(unsigned index) const;
     float GetAnimationLodBias() const;
     float GetAnimationLodBias() const;
-    float GetInvisibleLodFactor() const;
+    bool GetUpdateInvisible() const;
     unsigned GetNumMorphs() const;
     unsigned GetNumMorphs() const;
     float GetMorphWeight(unsigned index) const;
     float GetMorphWeight(unsigned index) const;
     float GetMorphWeight(const String name) 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 Skeleton& skeleton;
     tolua_readonly tolua_property__get_set unsigned numAnimationStates;
     tolua_readonly tolua_property__get_set unsigned numAnimationStates;
     tolua_property__get_set float animationLodBias;
     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__get_set unsigned numMorphs;
     tolua_readonly tolua_property__is_set bool master;
     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_model(Model@+)", asFUNCTION(AnimatedModelSetModel), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("AnimatedModel", "void set_animationLodBias(float)", asMETHOD(AnimatedModel, SetAnimationLodBias), asCALL_THISCALL);
     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", "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", "Skeleton@+ get_skeleton()", asMETHOD(AnimatedModel, GetSkeleton), asCALL_THISCALL);
     engine->RegisterObjectMethod("AnimatedModel", "uint get_numAnimationStates() const", asMETHOD(AnimatedModel, GetNumAnimationStates), 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);
     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->SetModel(cache->GetResource<Model>("Models/Jack.mdl"));
             modelObject->SetMaterial(cache->GetResource<Material>("Materials/Jack.xml"));
             modelObject->SetMaterial(cache->GetResource<Material>("Materials/Jack.xml"));
             modelObject->SetCastShadows(true);
             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
             // 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
             // model into a ragdoll when hit by a moving object