Changeset 400
- Timestamp:
- 10/05/11 11:21:02 (8 months ago)
- Location:
- cafu/trunk
- Files:
-
- 2 added
- 14 modified
-
CaWE/ModelEditor/ChildFrame.cpp (modified) (2 diffs)
-
CaWE/ModelEditor/Commands/Add.cpp (modified) (2 diffs)
-
CaWE/ModelEditor/Commands/Delete.cpp (modified) (6 diffs)
-
CaWE/ModelEditor/Commands/Delete.hpp (modified) (1 diff)
-
CaWE/ModelEditor/Commands/TransformJoint.cpp (modified) (2 diffs)
-
CaWE/ModelEditor/ModelDocument.cpp (modified) (4 diffs)
-
CaWE/ModelEditor/ModelDocument.hpp (modified) (4 diffs)
-
CaWE/ModelEditor/ScenePropGrid.cpp (modified) (3 diffs)
-
CaWE/ModelEditor/SceneView3D.cpp (modified) (8 diffs)
-
Libs/Models/AnimPose.cpp (added)
-
Libs/Models/AnimPose.hpp (added)
-
Libs/Models/Loader_ase.cpp (modified) (3 diffs)
-
Libs/Models/Loader_lwo.cpp (modified) (5 diffs)
-
Libs/Models/Model_cmdl.cpp (modified) (6 diffs)
-
Libs/Models/Model_cmdl.hpp (modified) (6 diffs)
-
Libs/SConscript (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
cafu/trunk/CaWE/ModelEditor/ChildFrame.cpp
r397 r400 841 841 m_ModelDoc->UpdateAllObservers_SelectionChanged(ANIM, OldSel, m_ModelDoc->GetSelection(ANIM)); 842 842 843 m_ModelDoc->GetAnimState(). FrameNr=0.0f;843 m_ModelDoc->GetAnimState().Pose.SetFrameNr(0.0f); 844 844 m_ModelDoc->UpdateAllObservers_AnimStateChanged(); 845 845 break; … … 852 852 m_ModelDoc->UpdateAllObservers_SelectionChanged(ANIM, OldSel, m_ModelDoc->GetSelection(ANIM)); 853 853 854 m_ModelDoc->GetAnimState(). FrameNr=0.0f;854 m_ModelDoc->GetAnimState().Pose.SetFrameNr(0.0f); 855 855 m_ModelDoc->UpdateAllObservers_AnimStateChanged(); 856 856 break; -
cafu/trunk/CaWE/ModelEditor/Commands/Add.cpp
r394 r400 103 103 104 104 // Make sure that the draw cache is refreshed. 105 m_ModelDoc->Get Model()->m_Draw_CachedDataAtSequNr=-1234;105 m_ModelDoc->GetAnimState().Pose.SetNeedsRecache(); 106 106 107 107 m_ModelDoc->UpdateAllObservers_Created(m_Type, Indices); … … 159 159 160 160 // Make sure that the draw cache is refreshed. 161 m_ModelDoc->Get Model()->m_Draw_CachedDataAtSequNr=-1234;161 m_ModelDoc->GetAnimState().Pose.SetNeedsRecache(); 162 162 163 163 m_ModelDoc->UpdateAllObservers_Deleted(m_Type, Indices); -
cafu/trunk/CaWE/ModelEditor/Commands/Delete.cpp
r396 r400 88 88 MeshInfoT& MI=m_MeshInfos[m_MeshInfos.Size()-1]; 89 89 90 MI.Mesh =m_ModelDoc->GetModel()->GetMeshes()[i]; 91 MI.DrawMesh=m_ModelDoc->GetModel()->m_Draw_Meshes[i]; 90 MI.Mesh=m_ModelDoc->GetModel()->GetMeshes()[i]; 92 91 93 92 for (unsigned long SkinNr=0; SkinNr<m_ModelDoc->GetModel()->GetSkins().Size(); SkinNr++) … … 158 157 if (m_Type==MESH) 159 158 { 159 if (m_Indices.Size() >= m_ModelDoc->GetModel()->GetMeshes().Size()) 160 { 161 m_Message="Cannot delete all meshes -- at least one mesh must be left."; 162 return false; 163 } 164 160 165 for (unsigned long GFixNr=0; GFixNr<m_ModelDoc->GetModel()->GetGuiFixtures().Size(); GFixNr++) 161 166 for (unsigned int PointNr=0; PointNr<3; PointNr++) … … 183 188 case MESH: 184 189 { 185 m_ModelDoc->GetModel()->m_Meshes .RemoveAtAndKeepOrder(i); 186 m_ModelDoc->GetModel()->m_Draw_Meshes.RemoveAtAndKeepOrder(i); 190 m_ModelDoc->GetModel()->m_Meshes.RemoveAtAndKeepOrder(i); 187 191 188 192 for (unsigned long SkinNr=0; SkinNr<m_ModelDoc->GetModel()->GetSkins().Size(); SkinNr++) … … 197 201 198 202 // Make sure that the draw cache is refreshed. 199 m_ModelDoc->Get Model()->m_Draw_CachedDataAtSequNr=-1234;203 m_ModelDoc->GetAnimState().Pose.SetNeedsRecache(); 200 204 201 205 m_ModelDoc->UpdateAllObservers_Deleted(m_Type, m_Indices); … … 226 230 const MeshInfoT& MI=m_MeshInfos[INr]; 227 231 228 m_ModelDoc->GetModel()->m_Meshes .InsertAt(i, MI.Mesh); 229 m_ModelDoc->GetModel()->m_Draw_Meshes.InsertAt(i, MI.DrawMesh); 232 m_ModelDoc->GetModel()->m_Meshes.InsertAt(i, MI.Mesh); 230 233 231 234 for (unsigned long SkinNr=0; SkinNr<m_ModelDoc->GetModel()->GetSkins().Size(); SkinNr++) … … 240 243 241 244 // Make sure that the draw cache is refreshed. 242 m_ModelDoc->Get Model()->m_Draw_CachedDataAtSequNr=-1234;245 m_ModelDoc->GetAnimState().Pose.SetNeedsRecache(); 243 246 244 247 m_ModelDoc->UpdateAllObservers_Created(m_Type, m_Indices); -
cafu/trunk/CaWE/ModelEditor/Commands/Delete.hpp
r396 r400 54 54 { 55 55 CafuModelT::MeshT Mesh; ///< The deleted mesh. 56 MatSys::MeshT DrawMesh; ///< The draw mesh related to \c Mesh.57 56 ArrayT<MaterialT*> SkinsMaterials; ///< The material in each skin for this mesh. 58 57 ArrayT<MatSys::RenderMaterialT*> SkinsRenderMaterials; ///< The render material in each skin for this mesh. -
cafu/trunk/CaWE/ModelEditor/Commands/TransformJoint.cpp
r358 r400 52 52 // Make sure that the BB is updated and the draw cache is refreshed. 53 53 m_ModelDoc->GetModel()->RecomputeBindPoseBB(); 54 m_ModelDoc->Get Model()->m_Draw_CachedDataAtSequNr=-1234;54 m_ModelDoc->GetAnimState().Pose.SetNeedsRecache(); 55 55 56 56 m_ModelDoc->UpdateAllObservers_JointChanged(m_JointNr); … … 71 71 // Make sure that the BB is updated and the draw cache is refreshed. 72 72 m_ModelDoc->GetModel()->RecomputeBindPoseBB(); 73 m_ModelDoc->Get Model()->m_Draw_CachedDataAtSequNr=-1234;73 m_ModelDoc->GetAnimState().Pose.SetNeedsRecache(); 74 74 75 75 m_ModelDoc->UpdateAllObservers_JointChanged(m_JointNr); -
cafu/trunk/CaWE/ModelEditor/ModelDocument.cpp
r394 r400 40 40 41 41 ModelEditor::ModelDocumentT::SubmodelT::SubmodelT(const wxString& fn, CafuModelT* sm, const ArrayT<unsigned int>& jm) 42 : m_Filename(fn), m_Submodel(sm), m_JointsMap(jm) 42 : m_Filename(fn), 43 m_Submodel(sm), 44 m_Pose(*sm, -1, 0.0f), 45 m_JointsMap(jm) 43 46 { 44 47 } … … 64 67 : m_Model(LoadModel(FileName)), 65 68 m_SequenceBB(m_Model->GetBB(-1, 0.0f)), 69 m_AnimState(*m_Model), 66 70 m_Submodels(), 67 71 m_Gui(new cf::GuiSys::GuiImplT("Win1=gui:new('WindowT'); gui:SetRootWindow(Win1); gui:activate(true); " … … 132 136 if (Type==ANIM) 133 137 { 138 m_AnimState.Pose.SetSequNr(m_Selection[ANIM].Size()==0 ? -1 : m_Selection[ANIM][0]); 139 134 140 if (m_Selection[ANIM].Size()==0) 135 141 { … … 224 230 void ModelEditor::ModelDocumentT::AdvanceTime(float Time) 225 231 { 226 if ( m_Selection[ANIM].Size()>0 &&Time*m_AnimState.Speed!=0.0f)227 { 228 m_AnimState. FrameNr=m_Model->AdvanceFrameNr(m_Selection[ANIM][0], m_AnimState.FrameNr,Time*m_AnimState.Speed, m_AnimState.Loop);232 if (Time*m_AnimState.Speed!=0.0f) 233 { 234 m_AnimState.Pose.Advance(Time*m_AnimState.Speed, m_AnimState.Loop); 229 235 } 230 236 } -
cafu/trunk/CaWE/ModelEditor/ModelDocument.hpp
r394 r400 27 27 #include "Math3D/BoundingBox.hpp" 28 28 #include "Math3D/Vector3.hpp" 29 #include "Models/AnimPose.hpp" 29 30 #include "Templates/Array.hpp" 30 31 #include "wx/wx.h" … … 63 64 public: 64 65 65 AnimStateT( )66 : FrameNr(0.0f), Speed(1.0f), Loop(true) { }66 AnimStateT(const CafuModelT& Model) 67 : Pose(Model), Speed(1.0f), Loop(true) { } 67 68 68 float FrameNr; ///< The currentframe number.69 float Speed; ///< The speed (relative to clock time) with which the animation is advanced, usually 0 for stop or 1 for playback.70 bool Loop; ///< When playing the sequence, loop automatically when its end has been reached?69 AnimPoseT Pose; ///< The current pose of the model, as defined by sequence and frame number. 70 float Speed; ///< The speed (relative to clock time) with which the animation is advanced, usually 0 for stop or 1 for playback. 71 bool Loop; ///< When playing the sequence, loop automatically when its end has been reached? 71 72 }; 72 73 … … 80 81 const wxString& GetFilename() const { return m_Filename; } 81 82 const CafuModelT* GetSubmodel() const { return m_Submodel; } 83 AnimPoseT& GetPose() { return m_Pose; } 82 84 const ArrayT<unsigned int>& GetJointsMap() const { return m_JointsMap; } 83 85 … … 87 89 wxString m_Filename; ///< The filename of the submodel. 88 90 CafuModelT* m_Submodel; ///< The submodel that is shown with the main model. 91 AnimPoseT m_Pose; ///< The pose of the submodel. 89 92 ArrayT<unsigned int> m_JointsMap; ///< Describes how the joints of the m_Submodel map to the joints of the m_Model super model. 90 93 -
cafu/trunk/CaWE/ModelEditor/ScenePropGrid.cpp
r383 r400 135 135 136 136 wxPGProperty* AnimControlCat=Append(new wxPropertyCategory("Animation Control")); 137 m_AnimFrameNrProp=AppendIn(AnimControlCat, new wxFloatProperty("Frame No.", wxPG_LABEL, Anim. FrameNr));137 m_AnimFrameNrProp=AppendIn(AnimControlCat, new wxFloatProperty("Frame No.", wxPG_LABEL, Anim.Pose.GetFrameNr())); 138 138 m_AnimSpeedProp =AppendIn(AnimControlCat, new wxFloatProperty("Speed", wxPG_LABEL, Anim.Speed)); 139 139 m_AnimLoopProp =AppendIn(AnimControlCat, new wxBoolProperty("Loop", wxPG_LABEL, Anim.Loop)); … … 218 218 else if (PropName=="Model.Show Mesh") m_Model_ShowMesh =Prop->GetValue().GetBool(); 219 219 else if (PropName=="Model.Show Skeleton") m_Model_ShowSkeleton=Prop->GetValue().GetBool(); 220 else if (PropName=="Frame No.") { AnimState. FrameNr=PropValueF; m_IsRecursiveSelfNotify=true; m_Parent->GetModelDoc()->UpdateAllObservers_AnimStateChanged(); m_IsRecursiveSelfNotify=false; }221 else if (PropName=="Speed") { AnimState.Speed =PropValueF; m_IsRecursiveSelfNotify=true; m_Parent->GetModelDoc()->UpdateAllObservers_AnimStateChanged(); m_IsRecursiveSelfNotify=false; }222 else if (PropName=="Loop") { AnimState.Loop =Prop->GetValue().GetBool(); m_IsRecursiveSelfNotify=true; m_Parent->GetModelDoc()->UpdateAllObservers_AnimStateChanged(); m_IsRecursiveSelfNotify=false; }220 else if (PropName=="Frame No.") { AnimState.Pose.SetFrameNr(PropValueF); m_IsRecursiveSelfNotify=true; m_Parent->GetModelDoc()->UpdateAllObservers_AnimStateChanged(); m_IsRecursiveSelfNotify=false; } 221 else if (PropName=="Speed") { AnimState.Speed=PropValueF; m_IsRecursiveSelfNotify=true; m_Parent->GetModelDoc()->UpdateAllObservers_AnimStateChanged(); m_IsRecursiveSelfNotify=false; } 222 else if (PropName=="Loop") { AnimState.Loop =Prop->GetValue().GetBool(); m_IsRecursiveSelfNotify=true; m_Parent->GetModelDoc()->UpdateAllObservers_AnimStateChanged(); m_IsRecursiveSelfNotify=false; } 223 223 else if (PropName=="Ambient Light Color") 224 224 { … … 275 275 const ModelDocumentT::AnimStateT& AnimState=m_Parent->GetModelDoc()->GetAnimState(); 276 276 277 if (m_AnimFrameNrProp->GetValue().GetDouble()!=AnimState. FrameNr)278 m_AnimFrameNrProp->SetValue(AnimState. FrameNr);277 if (m_AnimFrameNrProp->GetValue().GetDouble()!=AnimState.Pose.GetFrameNr()) 278 m_AnimFrameNrProp->SetValue(AnimState.Pose.GetFrameNr()); 279 279 280 280 if (m_AnimSpeedProp->GetValue().GetDouble()!=AnimState.Speed) -
cafu/trunk/CaWE/ModelEditor/SceneView3D.cpp
r383 r400 101 101 102 102 // Trace the ray against the model, which is a per-triangle accurate test. 103 const ModelDocumentT::AnimStateT& Anim =ModelDoc->GetAnimState();104 const ArrayT<unsigned int>& AnimSel=ModelDoc->GetSelection(ANIM);105 103 ModelT::TraceResultT Result; 106 104 107 if (ModelDoc->GetModel()->TraceRay(AnimSel.Size()==0 ? -1 : AnimSel[0], Anim.FrameNr, 108 ModelDoc->GetSelSkinNr(), RayOrigin, RayDir, Result) && Result.Fraction<BestFraction) 105 if (ModelDoc->GetAnimState().Pose.TraceRay(ModelDoc->GetSelSkinNr(), RayOrigin, RayDir, Result) && Result.Fraction<BestFraction) 109 106 { 110 107 BestFraction=Result.Fraction; … … 164 161 ModelDoc->UpdateAllObservers_SelectionChanged(ANIM, OldSel, ModelDoc->GetSelection(ANIM)); 165 162 166 ModelDoc->GetAnimState(). FrameNr=0.0f;163 ModelDoc->GetAnimState().Pose.SetFrameNr(0.0f); 167 164 ModelDoc->UpdateAllObservers_AnimStateChanged(); 168 165 break; … … 176 173 ModelDoc->UpdateAllObservers_SelectionChanged(ANIM, OldSel, ModelDoc->GetSelection(ANIM)); 177 174 178 ModelDoc->GetAnimState(). FrameNr=0.0f;175 ModelDoc->GetAnimState().Pose.SetFrameNr(0.0f); 179 176 ModelDoc->UpdateAllObservers_AnimStateChanged(); 180 177 break; … … 237 234 const Vector3fT HitPos=TraceCameraRay(ScreenToClient(CE.GetPosition()), ModelTR); 238 235 const CafuModelT* Model=m_Parent->GetModelDoc()->GetModel(); 236 const AnimPoseT& Pose=m_Parent->GetModelDoc()->GetAnimState().Pose; 239 237 unsigned int BestVertexNr=0; 240 238 bool HaveModelHit=false; … … 242 240 if (ModelTR.Fraction>0.0f && ModelTR.MeshNr<Model->GetMeshes().Size() && ModelTR.TriNr<Model->GetMeshes()[ModelTR.MeshNr].Triangles.Size()) 243 241 { 244 float BestDist=0.0f; 245 246 for (unsigned int i=0; i<3; i++) 247 { 248 const unsigned int VertexNr=Model->GetMeshes()[ModelTR.MeshNr].Triangles[ModelTR.TriNr].VertexIdx[i]; 249 const Vector3fT& DrawPos =Model->GetMeshes()[ModelTR.MeshNr].Vertices[VertexNr].Draw_Pos; 250 const float Dist =length(DrawPos-HitPos); 251 252 if (i==0 || Dist<BestDist) 253 { 254 BestDist =Dist; 255 BestVertexNr=VertexNr; 256 } 257 } 258 242 BestVertexNr=Pose.FindClosestVertex(ModelTR.MeshNr, ModelTR.TriNr, HitPos); 259 243 HaveModelHit=true; 260 244 } … … 383 367 384 368 // Render the model. 385 const CafuModelT* Model =ModelDoc->GetModel(); 386 const ModelDocumentT::AnimStateT& Anim =ModelDoc->GetAnimState(); 387 const ArrayT<unsigned int>& AnimSel=ModelDoc->GetSelection(ANIM); 388 const int SequNr =AnimSel.Size()==0 ? -1 : AnimSel[0]; 369 const CafuModelT* Model=ModelDoc->GetModel(); 370 const ModelDocumentT::AnimStateT& Anim =ModelDoc->GetAnimState(); 389 371 390 372 if (ScenePropGrid->m_Model_ShowMesh) 391 373 { 392 Model->Draw(SequNr, Anim.FrameNr, ModelDoc->GetSelSkinNr(), 0.0f /*LodDist*/, (CafuModelT::SuperT*)NULL);374 Anim.Pose.Draw(ModelDoc->GetSelSkinNr(), 0.0f /*LodDist*/); 393 375 394 376 for (unsigned long SmNr=0; SmNr<ModelDoc->GetSubmodels().Size(); SmNr++) 395 377 { 396 const ModelDocumentT::SubmodelT* SM=ModelDoc->GetSubmodels()[SmNr]; 397 const CafuModelT::SuperT Super( 398 Model->GetDrawJointMatrices(SequNr, Anim.FrameNr), 378 ModelDocumentT::SubmodelT* SM=ModelDoc->GetSubmodels()[SmNr]; 379 AnimPoseT& SmPose=SM->GetPose(); 380 381 const AnimPoseT::SuperT Super( 382 Anim.Pose.GetJointMatrices(), 399 383 SM->GetJointsMap()); 400 384 401 SM->GetSubmodel()->Draw(0, 0.0f, -1 /*SkinNr*/, 0.0f /*LodDist*/, &Super); 385 SmPose.SetSuper(&Super); 386 SmPose.Draw(-1 /*SkinNr*/, 0.0f /*LodDist*/); 387 SmPose.SetSuper(NULL); 402 388 } 403 389 } … … 407 393 if (ScenePropGrid->m_Model_ShowSkeleton && MatSys::Renderer->GetCurrentRenderAction()==MatSys::RendererI::AMBIENT) 408 394 { 409 RenderSkeleton(Model->GetJoints(), Model->GetDrawJointMatrices(SequNr, Anim.FrameNr), false);395 RenderSkeleton(Model->GetJoints(), Anim.Pose.GetJointMatrices(), false); 410 396 411 397 for (unsigned long SmNr=0; SmNr<ModelDoc->GetSubmodels().Size(); SmNr++) 412 398 { 413 const ModelDocumentT::SubmodelT* SM=ModelDoc->GetSubmodels()[SmNr]; 414 const CafuModelT::SuperT Super( 415 Model->GetDrawJointMatrices(SequNr, Anim.FrameNr), 399 ModelDocumentT::SubmodelT* SM=ModelDoc->GetSubmodels()[SmNr]; 400 AnimPoseT& SmPose=SM->GetPose(); 401 402 const AnimPoseT::SuperT Super( 403 Anim.Pose.GetJointMatrices(), 416 404 SM->GetJointsMap()); 417 405 418 RenderSkeleton(SM->GetSubmodel()->GetJoints(), SM->GetSubmodel()->GetDrawJointMatrices(0, 0.0f, &Super), true); 406 SmPose.SetSuper(&Super); 407 RenderSkeleton(SM->GetSubmodel()->GetJoints(), SmPose.GetJointMatrices(), true); 408 SmPose.SetSuper(NULL); 419 409 } 420 410 } … … 435 425 if (!Model->IsVertexNrOK(GF, PointNr)) continue; 436 426 437 Points[PointNr]= Model->GetMeshes()[GF.Points[PointNr].MeshNr].Vertices[GF.Points[PointNr].VertexNr].Draw_Pos;427 Points[PointNr]=Anim.Pose.GetVertexPos(GF.Points[PointNr].MeshNr, GF.Points[PointNr].VertexNr); 438 428 PointsOK|=(1 << PointNr); 439 429 } -
cafu/trunk/Libs/Models/Loader_ase.cpp
r334 r400 531 531 532 532 assert(CafuVertex.NumWeights==1); 533 assert(Mesh.Weights[CafuVertex.FirstWeightIdx].Pos==CafuVertex. Draw_Pos);534 535 if (CafuVertex. Draw_Pos!=AseVertexPos) continue;533 assert(Mesh.Weights[CafuVertex.FirstWeightIdx].Pos==CafuVertex.gts_Pos); 534 535 if (CafuVertex.gts_Pos!=AseVertexPos) continue; 536 536 if (CafuVertex.u!=GO.TexCoords[AseTri.IndTexCoords[i]].AsVectorOfFloat().x) continue; 537 537 if (CafuVertex.v!=GO.TexCoords[AseTri.IndTexCoords[i]].AsVectorOfFloat().y) continue; 538 538 539 if (CafuVertex. Draw_Normal!=AseTri.Normals[i].AsVectorOfFloat()) continue;540 if (CafuVertex. Draw_Tangent!=AseTri.Tangents[i].AsVectorOfFloat()) continue;541 if (CafuVertex. Draw_BiNormal!=AseTri.BiNormals[i].AsVectorOfFloat()) continue;539 if (CafuVertex.gts_Normal!=AseTri.Normals[i].AsVectorOfFloat()) continue; 540 if (CafuVertex.gts_Tangent!=AseTri.Tangents[i].AsVectorOfFloat()) continue; 541 if (CafuVertex.gts_BiNormal!=AseTri.BiNormals[i].AsVectorOfFloat()) continue; 542 542 543 543 // This vertex meets all criteria - take it. … … 569 569 CafuVertex.FirstWeightIdx=WeightNr; 570 570 CafuVertex.NumWeights =1; 571 CafuVertex. Draw_Pos=AseVertexPos;572 CafuVertex. Draw_Normal=AseTri.Normals[i].AsVectorOfFloat();573 CafuVertex. Draw_Tangent=AseTri.Tangents[i].AsVectorOfFloat();574 CafuVertex. Draw_BiNormal=AseTri.BiNormals[i].AsVectorOfFloat();571 CafuVertex.gts_Pos =AseVertexPos; 572 CafuVertex.gts_Normal =AseTri.Normals[i].AsVectorOfFloat(); 573 CafuVertex.gts_Tangent =AseTri.Tangents[i].AsVectorOfFloat(); 574 CafuVertex.gts_BiNormal =AseTri.BiNormals[i].AsVectorOfFloat(); 575 575 } 576 576 … … 580 580 } 581 581 582 CafuTri. Draw_Normal=AseTri.Normal.AsVectorOfFloat();582 CafuTri.gts_Normal=AseTri.Normal.AsVectorOfFloat(); 583 583 } 584 584 -
cafu/trunk/Libs/Models/Loader_lwo.cpp
r322 r400 369 369 MeshVertex.NumWeights =1; 370 370 371 MeshVertex. Draw_Pos =Mesh.Weights[PolyVert.index].Pos; // Normally the base class code computes this, but we also have to pre-provide a proper value here for ComputeTangents().372 MeshVertex. Draw_Normal =Vector3fT(PolyVert.norm);373 // MeshVertex. Draw_Tangent =...; // Set below to polygon average.374 // MeshVertex. Draw_BiNormal =...; // Set below to polygon average.371 MeshVertex.gts_Pos =Mesh.Weights[PolyVert.index].Pos; // Normally the base class code computes this, but we also have to pre-provide a proper value here for ComputeTangents(). 372 MeshVertex.gts_Normal =Vector3fT(PolyVert.norm); 373 // MeshVertex.gts_Tangent =...; // Set below to polygon average. 374 // MeshVertex.gts_BiNormal =...; // Set below to polygon average. 375 375 376 376 WeightVerts[PolyVert.index].PushBack(MeshVertexNr); … … 395 395 Triangle.VertexIdx[2]=PolygonMeshVertices[VertexNr+1]; 396 396 397 Triangle. Draw_Normal=Vector3fT(Poly.norm);397 Triangle.gts_Normal=Vector3fT(Poly.norm); 398 398 399 399 … … 415 415 // The vertex may be shared across multiple polygons, and we want to build the average over them. 416 416 // Therefore we only accumulate the tangents here, and normalize below. 417 Vertex. Draw_Tangent +=myNormalize(Poly_Tangent);418 Vertex. Draw_BiNormal+=myNormalize(Poly_BiTangent);417 Vertex.gts_Tangent +=myNormalize(Poly_Tangent); 418 Vertex.gts_BiNormal+=myNormalize(Poly_BiTangent); 419 419 } 420 420 } … … 426 426 CafuModelT::MeshT::VertexT& Vertex=Mesh.Vertices[VertexNr]; 427 427 428 Vertex. Draw_Tangent =myNormalize(Vertex.Draw_Tangent );429 Vertex. Draw_BiNormal=myNormalize(Vertex.Draw_BiNormal);428 Vertex.gts_Tangent =myNormalize(Vertex.gts_Tangent ); 429 Vertex.gts_BiNormal=myNormalize(Vertex.gts_BiNormal); 430 430 } 431 431 } … … 446 446 const CafuModelT::MeshT::VertexT& V_1 =Mesh.Vertices[Tri.VertexIdx[1]]; 447 447 const CafuModelT::MeshT::VertexT& V_2 =Mesh.Vertices[Tri.VertexIdx[2]]; 448 const Vector3fT Edge01=V_1. Draw_Pos-V_0.Draw_Pos;449 const Vector3fT Edge02=V_2. Draw_Pos-V_0.Draw_Pos;448 const Vector3fT Edge01=V_1.gts_Pos-V_0.gts_Pos; 449 const Vector3fT Edge02=V_2.gts_Pos-V_0.gts_Pos; 450 450 451 451 // Triangles are ordered CW for md5 models and CCW for ase models, so we write 452 452 // Normal=VectorCross(Edge02, Edge01) for md5 models and Normal=VectorCross(Edge01, Edge02) for ase models. 453 // Tri. Draw_Normal=myNormalize(Edge02.cross(Edge01));453 // Tri.gts_Normal=myNormalize(Edge02.cross(Edge01)); 454 454 455 455 // Understanding what's going on here is easy. The key statement is -
cafu/trunk/Libs/Models/Model_cmdl.cpp
r398 r400 21 21 22 22 #include "Model_cmdl.hpp" 23 #include "AnimPose.hpp" // Only for implementing the "old" ModelT interface methods. 23 24 #include "Loader.hpp" 24 25 #include "MaterialSystem/Material.hpp" 25 26 #include "MaterialSystem/Renderer.hpp" 26 27 #include "Math3D/BoundingBox.hpp" 27 #include "Math3D/Pluecker.hpp"28 28 #include "Math3D/Quaternion.hpp" 29 29 #include "String.hpp" … … 240 240 m_MaterialMan(), 241 241 m_UseGivenTangentSpace(Loader.UseGivenTS()), // Should we use the fixed, given tangent space, or recompute it ourselves here? 242 m_BindPoseBB(Vector3fT()), // Re-initialized in InitMeshes() calling RecomputeBindPoseBB(), but start with a valid box anyways (e.g. for testing models that have a skeleton, but no mesh). 243 m_Draw_CachedDataAtSequNr(-1234), // Just a random number that is unlikely to occur normally. 244 m_Draw_CachedDataAtFrameNr(-3.1415926f) // Just a random number that is unlikely to occur normally. 242 m_BindPoseBB(Vector3fT()) // Re-initialized in InitMeshes() calling RecomputeBindPoseBB(), but start with a valid box anyways (e.g. for testing models that have a skeleton, but no mesh). 245 243 { 246 244 // No matter the actual model file format (that is, even if the file format is not "cmdl"), … … 305 303 Skin.RenderMaterials[MatNr]=MatSys::Renderer->RegisterMaterial(Skin.Materials[MatNr]); 306 304 } 307 }308 309 // Allocate the cache space that is needed for drawing.310 m_JointMatrices.PushBackEmpty(m_Joints.Size());311 m_Draw_Meshes.PushBackEmpty(m_Meshes.Size());312 313 for (unsigned long MeshNr=0; MeshNr<m_Meshes.Size(); MeshNr++)314 {315 m_Draw_Meshes[MeshNr].Type =MatSys::MeshT::Triangles;316 // m_Draw_Meshes[MeshNr].Winding=MatSys::MeshT::CW; // CW is the default.317 m_Draw_Meshes[MeshNr].Vertices.PushBackEmpty(m_Meshes[MeshNr].Triangles.Size()*3);318 305 } 319 306 } … … 931 918 932 919 933 static Vector3fT myNormalize(const Vector3fT& A)934 {935 const float Length=length(A);936 937 return (Length>0.000001f) ? A.GetScaled(1.0f/Length) : Vector3fT();938 }939 940 941 void CafuModelT::UpdateCachedDrawData(int SequenceNr, float FrameNr, const SuperT* Super) const942 {943 // **************************************************************************************************************944 // Obtain a joints (bone) hierarchy for the desired frame FrameNr of the desired animation sequence SequenceNr.945 // The result will be a transformation matrix for each joint (bone).946 // **************************************************************************************************************947 948 if (SequenceNr==-1)949 {950 // Don't animate, just use the bind pose defined in the model file.951 for (unsigned long JointNr=0; JointNr<m_Joints.Size(); JointNr++)952 {953 if (Super && Super->HasMatrix(JointNr))954 {955 m_JointMatrices[JointNr]=Super->GetMatrix(JointNr);956 continue;957 }958 959 const JointT& J=m_Joints[JointNr];960 const MatrixT RelMatrix(J.Pos, cf::math::QuaternionfT::FromXYZ(J.Qtr), J.Scale);961 962 m_JointMatrices[JointNr]=(J.Parent==-1) ? RelMatrix : m_JointMatrices[J.Parent]*RelMatrix;963 }964 }965 else966 {967 // SequenceNr is a valid index into m_Anims, so use that.968 const AnimT& Anim=m_Anims[SequenceNr];969 const int Frame_0=int(FrameNr); // If FrameNr == 17.83, then Frame_0 == 17970 const float Frame_f=FrameNr-Frame_0; // Frame_f == 0.83971 const int Frame_1=(Frame_0+1>=int(Anim.Frames.Size())) ? 0 : Frame_0+1; // Frame_1 == 18972 973 for (unsigned long JointNr=0; JointNr<m_Joints.Size(); JointNr++)974 {975 if (Super && Super->HasMatrix(JointNr))976 {977 m_JointMatrices[JointNr]=Super->GetMatrix(JointNr);978 continue;979 }980 981 const AnimT::AnimJointT& AJ=Anim.AnimJoints[JointNr];982 Vector3fT Data_0[3]={ AJ.DefaultPos, AJ.DefaultQtr, AJ.DefaultScale };983 Vector3fT Data_1[3]={ AJ.DefaultPos, AJ.DefaultQtr, AJ.DefaultScale };984 985 // Determine the position, quaternion and scale for Frame_0 and Frame_1.986 unsigned int FlagCount=0;987 988 for (int i=0; i<9; i++)989 {990 if ((AJ.Flags >> i) & 1)991 {992 Data_0[i/3][i % 3]=Anim.Frames[Frame_0].AnimData[AJ.FirstDataIdx+FlagCount];993 Data_1[i/3][i % 3]=Anim.Frames[Frame_1].AnimData[AJ.FirstDataIdx+FlagCount];994 995 FlagCount++;996 }997 }998 999 // Interpolate the position and quaternion according to the fraction Frame_f.1000 const Vector3fT Pos =Data_0[0]*(1.0f-Frame_f) + Data_1[0]*Frame_f;1001 const cf::math::QuaternionfT Quat =slerp(cf::math::QuaternionfT::FromXYZ(Data_0[1]), cf::math::QuaternionfT::FromXYZ(Data_1[1]), Frame_f);1002 const Vector3fT Scale=Data_0[2]*(1.0f-Frame_f) + Data_1[2]*Frame_f;1003 1004 // Compute the matrix that is relative to the parent bone, and finally obtain the absolute matrix for that bone!1005 const MatrixT RelMatrix(Pos, Quat, Scale);1006 const JointT& J=m_Joints[JointNr];1007 1008 m_JointMatrices[JointNr]=(J.Parent==-1) ? RelMatrix : m_JointMatrices[J.Parent]*RelMatrix;1009 }1010 }1011 1012 1013 // *******************************************************************************************************************1014 // The JointMatrices represent now the pose of the model at the desired frame number of the desired sequence number.1015 // For all meshes do now compute the vertices according to their weights.1016 // *******************************************************************************************************************1017 1018 for (unsigned long MeshNr=0; MeshNr<m_Meshes.Size(); MeshNr++)1019 {1020 MeshT& Mesh=m_Meshes[MeshNr];1021 1022 for (unsigned long VertexNr=0; VertexNr<Mesh.Vertices.Size(); VertexNr++)1023 {1024 MeshT::VertexT& Vertex=Mesh.Vertices[VertexNr];1025 1026 if (Vertex.GeoDups.Size()>0 && Vertex.GeoDups[0]<VertexNr)1027 {1028 // This vertex has a geometrically identical duplicate that has already been computed.1029 // Therefore, don't bother to recompute the same position again, just copy it from the duplicate.1030 Vertex.Draw_Pos=Mesh.Vertices[Vertex.GeoDups[0]].Draw_Pos;1031 continue;1032 }1033 1034 if (Vertex.NumWeights==1)1035 {1036 const MeshT::WeightT& Weight=Mesh.Weights[Vertex.FirstWeightIdx];1037 1038 Vertex.Draw_Pos=m_JointMatrices[Weight.JointIdx].Mul_xyz1(Weight.Pos);1039 }1040 else1041 {1042 Vertex.Draw_Pos=Vector3fT(0.0f, 0.0f, 0.0f);1043 1044 for (unsigned int WeightNr=0; WeightNr<Vertex.NumWeights; WeightNr++)1045 {1046 const MeshT::WeightT& Weight=Mesh.Weights[Vertex.FirstWeightIdx+WeightNr];1047 1048 Vertex.Draw_Pos+=m_JointMatrices[Weight.JointIdx].Mul_xyz1(Weight.Pos) * Weight.Weight;1049 }1050 }1051 }1052 }1053 1054 1055 // *******************************************************************************************1056 // Compute the tangent-space basis vectors for all triangles and all vertices.1057 // This is done by first computing the per-triangle axes and then having them enter1058 // the relevant per-vertex averages as required (taking mirror corrections into account).1059 // The per-triangle normal vectors are also kept for stencil shadow silhoutte determination.1060 // *******************************************************************************************1061 1062 if (m_UseGivenTangentSpace)1063 {1064 assert(m_Anims.Size()==0); // It doesn't make sense to have statically given tangent-space axes with *animated* geometry...1065 goto DoneComputingTS;1066 }1067 1068 // For all vertices, zero the tangent-space vectors for the subsequent average accumulation.1069 for (unsigned long MeshNr=0; MeshNr<m_Meshes.Size(); MeshNr++)1070 {1071 MeshT& Mesh=m_Meshes[MeshNr];1072 1073 for (unsigned long VertexNr=0; VertexNr<Mesh.Vertices.Size(); VertexNr++)1074 {1075 MeshT::VertexT& Vertex=Mesh.Vertices[VertexNr];1076 1077 Vertex.Draw_Normal =Vector3fT(0, 0, 0);1078 Vertex.Draw_Tangent =Vector3fT(0, 0, 0);1079 Vertex.Draw_BiNormal=Vector3fT(0, 0, 0);1080 }1081 }1082 1083 // Compute the per-triangle tangent-space axes and distribute them over the relevant vertices appropriately.1084 for (unsigned long MeshNr=0; MeshNr<m_Meshes.Size(); MeshNr++)1085 {1086 MeshT& Mesh=m_Meshes[MeshNr];1087 1088 for (unsigned long TriangleNr=0; TriangleNr<Mesh.Triangles.Size(); TriangleNr++)1089 {1090 MeshT::TriangleT& Tri =Mesh.Triangles[TriangleNr];1091 const MeshT::VertexT& V_0 =Mesh.Vertices[Tri.VertexIdx[0]];1092 const MeshT::VertexT& V_1 =Mesh.Vertices[Tri.VertexIdx[1]];1093 const MeshT::VertexT& V_2 =Mesh.Vertices[Tri.VertexIdx[2]];1094 const Vector3fT Edge01=V_1.Draw_Pos-V_0.Draw_Pos;1095 const Vector3fT Edge02=V_2.Draw_Pos-V_0.Draw_Pos;1096 1097 // Triangles are ordered CW for md5 models and CCW for ase models, so we write1098 // Normal=VectorCross(Edge02, Edge01) for md5 models and Normal=VectorCross(Edge01, Edge02) for ase models.1099 Tri.Draw_Normal=myNormalize(Edge02.cross(Edge01));1100 1101 // Understanding what's going on here is easy. The key statement is1102 // "The tangent vector is parallel to the direction of increasing S on a parametric surface."1103 // First, there is a short explanation in "The Cg Tutorial", chapter 8.1104 // Second, I have drawn a simple figure that leads to a simple 2x2 system of Gaussian equations, see my TechArchive.1105 const Vector3fT uv01=Vector3fT(V_1.u, V_1.v, 0.0f)-Vector3fT(V_0.u, V_0.v, 0.0f);1106 const Vector3fT uv02=Vector3fT(V_2.u, V_2.v, 0.0f)-Vector3fT(V_0.u, V_0.v, 0.0f);1107 const float f =uv01.x*uv02.y-uv01.y*uv02.x>0.0 ? 1.0f : -1.0f;1108 1109 const Vector3fT Tri_Draw_Tangent =myNormalize(Edge02.GetScaled(-uv01.y*f) + Edge01.GetScaled(uv02.y*f));1110 const Vector3fT Tri_Draw_BiNormal=myNormalize(Edge02.GetScaled( uv01.x*f) - Edge01.GetScaled(uv02.x*f));1111 1112 1113 // Distribute the per-triangle tangent-space over the affected vertices.1114 #if 11115 const float Pi=3.14159265358979323846f;1116 1117 const float c0=dot(myNormalize(Edge01), myNormalize(Edge02));1118 const float c1=dot(myNormalize(Edge01), myNormalize(V_1.Draw_Pos-V_2.Draw_Pos));1119 1120 const float w0=(c0>=1.0f) ? 0.0f : ( (c0<=-1.0f) ? Pi : acos(c0) );1121 const float w1=(c1>=1.0f) ? 0.0f : ( (c1<=-1.0f) ? Pi : acos(c1) );1122 1123 const float TriWeight[3]={ w0, w1, Pi-TriWeight[0]-TriWeight[1] };1124 #else1125 const float TriWeight[3]={ 1.0f, 1.0f, 1.0f };1126 #endif1127 1128 for (int i=0; i<3; i++)1129 {1130 MeshT::VertexT& Vertex=Mesh.Vertices[Tri.VertexIdx[i]];1131 1132 assert(Tri.Polarity==Vertex.Polarity);1133 1134 Vertex.Draw_Normal +=Tri.Draw_Normal*TriWeight[i];1135 Vertex.Draw_Tangent +=Tri_Draw_Tangent*TriWeight[i];1136 Vertex.Draw_BiNormal+=Tri_Draw_BiNormal*TriWeight[i];1137 1138 for (unsigned long DupNr=0; DupNr<Vertex.GeoDups.Size(); DupNr++)1139 {1140 MeshT::VertexT& DupVertex=Mesh.Vertices[Vertex.GeoDups[DupNr]];1141 1142 DupVertex.Draw_Normal +=Tri.Draw_Normal*TriWeight[i];1143 DupVertex.Draw_Tangent +=Tri_Draw_Tangent*(Tri.Polarity==DupVertex.Polarity ? TriWeight[i] : -TriWeight[i]);1144 DupVertex.Draw_BiNormal+=Tri_Draw_BiNormal*TriWeight[i];1145 }1146 }1147 }1148 }1149 1150 // Finally normalize the per-vertex tangent-space axes; this is quasi the "division" in the average computations.1151 for (unsigned long MeshNr=0; MeshNr<m_Meshes.Size(); MeshNr++)1152 {1153 MeshT& Mesh=m_Meshes[MeshNr];1154 1155 for (unsigned long VertexNr=0; VertexNr<Mesh.Vertices.Size(); VertexNr++)1156 {1157 MeshT::VertexT& Vertex=Mesh.Vertices[VertexNr];1158 1159 // Normalize the tangent-space axes.1160 Vertex.Draw_Normal =myNormalize(Vertex.Draw_Normal );1161 Vertex.Draw_Tangent =myNormalize(Vertex.Draw_Tangent );1162 Vertex.Draw_BiNormal=myNormalize(Vertex.Draw_BiNormal);1163 }1164 }1165 1166 DoneComputingTS:1167 1168 1169 // ***************************************************************************************************************1170 // Construct explicit MatSys::MeshT meshes now.1171 // Note that this is very inefficient - we REALLY should work with index arrays! (and/or vertex buffer objects!)1172 // ***************************************************************************************************************1173 1174 for (unsigned long MeshNr=0; MeshNr<m_Meshes.Size(); MeshNr++)1175 {1176 const MeshT& Mesh=m_Meshes[MeshNr];1177 1178 for (unsigned long TriNr=0; TriNr<Mesh.Triangles.Size(); TriNr++)1179 {1180 for (unsigned long i=0; i<3; i++)1181 {1182 unsigned long VertexIdx=Mesh.Triangles[TriNr].VertexIdx[i];1183 1184 m_Draw_Meshes[MeshNr].Vertices[TriNr*3+i].SetOrigin(Mesh.Vertices[VertexIdx].Draw_Pos.x, Mesh.Vertices[VertexIdx].Draw_Pos.y, Mesh.Vertices[VertexIdx].Draw_Pos.z);1185 m_Draw_Meshes[MeshNr].Vertices[TriNr*3+i].SetTextureCoord(Mesh.Vertices[VertexIdx].u, Mesh.Vertices[VertexIdx].v);1186 m_Draw_Meshes[MeshNr].Vertices[TriNr*3+i].SetNormal (Mesh.Vertices[VertexIdx].Draw_Normal.x, Mesh.Vertices[VertexIdx].Draw_Normal.y, Mesh.Vertices[VertexIdx].Draw_Normal.z );1187 m_Draw_Meshes[MeshNr].Vertices[TriNr*3+i].SetTangent (Mesh.Vertices[VertexIdx].Draw_Tangent.x, Mesh.Vertices[VertexIdx].Draw_Tangent.y, Mesh.Vertices[VertexIdx].Draw_Tangent.z );1188 m_Draw_Meshes[MeshNr].Vertices[TriNr*3+i].SetBiNormal(Mesh.Vertices[VertexIdx].Draw_BiNormal.x, Mesh.Vertices[VertexIdx].Draw_BiNormal.y, Mesh.Vertices[VertexIdx].Draw_BiNormal.z);1189 }1190 }1191 }1192 }1193 1194 1195 const ArrayT<MatrixT>& CafuModelT::GetDrawJointMatrices(int SequenceNr, float FrameNr, const SuperT* Super) const1196 {1197 // SequenceNr==-1 means "use the bind pose from the model file only (no anim)".1198 if (SequenceNr>=int(m_Anims.Size())) SequenceNr=-1;1199 if (SequenceNr!=-1 && (m_Anims[SequenceNr].FPS<0.0 || m_Anims[SequenceNr].Frames.Size()==0)) SequenceNr=-1;1200 if (SequenceNr==-1) FrameNr=0.0;1201 1202 // See Draw() for details.1203 if (m_Draw_CachedDataAtSequNr!=SequenceNr || m_Draw_CachedDataAtFrameNr!=FrameNr || Super!=NULL)1204 {1205 m_Draw_CachedDataAtSequNr =SequenceNr;1206 m_Draw_CachedDataAtFrameNr=FrameNr;1207 1208 UpdateCachedDrawData(SequenceNr, FrameNr, Super);1209 }1210 1211 return m_JointMatrices;1212 }1213 1214 1215 920 const MaterialT* CafuModelT::GetMaterial(unsigned long MeshNr, int SkinNr) const 1216 921 { … … 1247 952 1248 953 1249 void CafuModelT::Draw(int SequenceNr, float FrameNr, int SkinNr, float /*LodDist*/, const SuperT* Super) const1250 {1251 // SequenceNr==-1 means "use the bind pose from the model file only (no anim)".1252 if (SequenceNr>=int(m_Anims.Size())) SequenceNr=-1;1253 if (SequenceNr!=-1 && (m_Anims[SequenceNr].FPS<0.0 || m_Anims[SequenceNr].Frames.Size()==0)) SequenceNr=-1;1254 if (SequenceNr==-1) FrameNr=0.0;1255 1256 1257 // Do an early check whether the light and the sequence BBs intersect.1258 switch (MatSys::Renderer->GetCurrentRenderAction())1259 {1260 case MatSys::RendererI::AMBIENT:1261 break;1262 1263 case MatSys::RendererI::LIGHTING:1264 case MatSys::RendererI::STENCILSHADOW:1265 {1266 const float LightRadius=MatSys::Renderer->GetCurrentLightSourceRadius();1267 const Vector3T<float> LightBox(LightRadius, LightRadius, LightRadius);1268 const Vector3T<float> LightPosOLD(MatSys::Renderer->GetCurrentLightSourcePosition());1269 const BoundingBox3T<float> LightBB(LightPosOLD+LightBox, LightPosOLD-LightBox);1270 1271 if (!LightBB.Intersects(GetBB(SequenceNr, FrameNr))) return;1272 break;1273 }1274 }1275 1276 1277 // The caching mechanism is really simple and works as follows:1278 // All data that does not depend on a frame or sequence number is precomputed and prepared once in the constructor.1279 // All data that is specific to a certain frame and sequence number is computed in UpdateCachedDrawData()1280 // and stored in member variables (those whose name begins with m_Draw_ or Draw_).1281 // If we are called again with the same frame and sequence numbers for which we have cached data in the last call,1282 // the data is simply re-used for drawing, skipping the expensive recomputations entirely.1283 // If the numbers are different, the cache data is recomputed and the reference frame and sequence numbers are updated.1284 //1285 // 1. To understand why this works well, consider first a scene with only a single animated model:1286 // First, we assume that the model will be drawn in the ambient pass plus for each light source in the stencil shadow and lighting pass.1287 // That is, assuming there are L light sources, this method is called 1+2*L times per frame with the same frame and sequence numbers.1288 // It's obvious that the first call for the ambient pass will come with different sequence or frame numbers than the1289 // previous call, as our model is animated. In this call the cache is recomputed, and it is obvious that for the 2*L subsequent1290 // calls for the stencil and lighting passes the frame and sequence numbers will be identical so that we can rely on the cached data.1291 // Thus, the computational effort with the cache is only 1/(1+2*L) of the amount without the cache.1292 //1293 // Note that we can ***NOT*** reasonably do any better by a more complex cache management (as is done in the ModelMdlT class).1294 // For example one might think that we might win something if we delay the computations of the tangent space in the ambient1295 // pass until a lighting pass occurs that actually needs the tangent space.1296 // First of all, this makes the cache management terribly complicated, see the ModelMdlT class for a scaring example.1297 // Even better, we may reasonably assume that we will need *all* cache data in each frame eventually (letztendlich) anyway,1298 // so that it is reasonable to compute it fully whenever the frame or sequence number changes.1299 // The only case where the assumption does not hold (and we could have saved computing something) is when no lightsource at all1300 // lights our model, and when also the ambient pass does not need the information (e.g. normal vectors for environment reflection mapping).1301 // As this is hopefully a rare case, we're doing pretty good.1302 // Border cases like outdoor terrains where animated player models are drawn only in the ambient pass should be addressed by dlod models.1303 //1304 // 2. Now consider a scene with multiple animated models that are all rendered by this single instance.1305 // Unfortunately, in this case our caching mechanism fails entirely: everything is recomputed on every call.1306 // In this case, several instances of the model should be created (if speed is important and space is dispensable).1307 // The fact that the Cafu Material System automatically shares rendering resources makes having multiple instances viable.1308 //1309 // 3. Finally, consider a scene with arbitrarily many non-animated models.1310 // As in this case the frame and sequence numbers are always identical for each call, the caching mechanism has maximum efficiency.1311 // All computations occur only once and then never again. This is the optimum cache utilization case.1312 if (m_Draw_CachedDataAtSequNr!=SequenceNr || m_Draw_CachedDataAtFrameNr!=FrameNr || Super!=NULL)1313 {1314 m_Draw_CachedDataAtSequNr =SequenceNr;1315 m_Draw_CachedDataAtFrameNr=FrameNr;1316 1317 UpdateCachedDrawData(SequenceNr, FrameNr, Super);1318 }1319 1320 1321 switch (MatSys::Renderer->GetCurrentRenderAction())1322 {1323 case MatSys::RendererI::AMBIENT:1324 {1325 for (unsigned long MeshNr=0; MeshNr<m_Meshes.Size(); MeshNr++)1326 {1327 MatSys::Renderer->SetCurrentMaterial(GetRenderMaterial(MeshNr, SkinNr));1328 MatSys::Renderer->RenderMesh(m_Draw_Meshes[MeshNr]);1329 1330 #if 01331 // Render the tangent space axes for each vertex.1332 static MaterialT SolidColorMaterial;1333 SolidColorMaterial.UseMeshColors=true;1334 1335 static MatSys::MeshT TangentSpaceAxes(MatSys::MeshT::Lines);1336 TangentSpaceAxes.Vertices.Overwrite();1337 1338 for (unsigned long VertexNr=0; VertexNr<m_Draw_Meshes[MeshNr].Vertices.Size(); VertexNr++)1339 {1340 const float scale=1.0f;1341 const Vector3fT Orig =Vector3fT(m_Draw_Meshes[MeshNr].Vertices[VertexNr].Origin);1342 const Vector3fT S_ =Vector3fT(m_Draw_Meshes[MeshNr].Vertices[VertexNr].Tangent);1343 const Vector3fT T_ =Vector3fT(m_Draw_Meshes[MeshNr].Vertices[VertexNr].BiNormal);1344 const Vector3fT N_ =Vector3fT(m_Draw_Meshes[MeshNr].Vertices[VertexNr].Normal);1345 const float col_ =m_Meshes[MeshNr].Triangles[VertexNr / 3].Polarity ? 0.5f : 0.0f;1346 const unsigned long Ofs =TangentSpaceAxes.Vertices.Size();1347 1348 TangentSpaceAxes.Vertices.PushBackEmpty(6);1349 1350 TangentSpaceAxes.Vertices[Ofs+0].SetOrigin(Orig);1351 TangentSpaceAxes.Vertices[Ofs+0].SetColor(1, col_, col_);1352 TangentSpaceAxes.Vertices[Ofs+1].SetOrigin(Orig+S_*scale);1353 TangentSpaceAxes.Vertices[Ofs+1].SetColor(1, col_, col_);1354 1355 TangentSpaceAxes.Vertices[Ofs+2].SetOrigin(Orig);1356 TangentSpaceAxes.Vertices[Ofs+2].SetColor(col_, 1, col_);1357 TangentSpaceAxes.Vertices[Ofs+3].SetOrigin(Orig+T_*scale);1358 TangentSpaceAxes.Vertices[Ofs+3].SetColor(col_, 1, col_);1359 1360 TangentSpaceAxes.Vertices[Ofs+4].SetOrigin(Orig);1361 TangentSpaceAxes.Vertices[Ofs+4].SetColor(col_, col_, 1);1362 TangentSpaceAxes.Vertices[Ofs+5].SetOrigin(Orig+N_*scale);1363 TangentSpaceAxes.Vertices[Ofs+5].SetColor(col_, col_, 1);1364 }1365 1366 MatSys::RenderMaterialT* SolidColorRenderMat=MatSys::Renderer->RegisterMaterial(&SolidColorMaterial);1367 1368 MatSys::Renderer->SetCurrentMaterial(SolidColorRenderMat);1369 MatSys::Renderer->RenderMesh(TangentSpaceAxes);1370 1371 MatSys::Renderer->FreeMaterial(SolidColorRenderMat);1372 1373 // FIXME! Rendering the stencil shadows uses the same material as the ambient pass does!1374 // (The call to FreeMaterial() above implies that no material is being set, and thus without this line,1375 // no stencil shadows get rendered!)1376 MatSys::Renderer->SetCurrentMaterial(m_Meshes[MeshNr].RenderMaterial);1377 #endif1378 }1379 break;1380 }1381 1382 case MatSys::RendererI::LIGHTING:1383 {1384 for (unsigned long MeshNr=0; MeshNr<m_Meshes.Size(); MeshNr++)1385 {1386 MatSys::Renderer->SetCurrentMaterial(GetRenderMaterial(MeshNr, SkinNr));1387 MatSys::Renderer->RenderMesh(m_Draw_Meshes[MeshNr]);1388 }1389 break;1390 }1391 1392 case MatSys::RendererI::STENCILSHADOW:1393 {1394 const Vector3fT LightPos(MatSys::Renderer->GetCurrentLightSourcePosition());1395 1396 for (unsigned long MeshNr=0; MeshNr<m_Meshes.Size(); MeshNr++)1397 {1398 const MeshT& Mesh =m_Meshes[MeshNr];1399 const MaterialT* MeshMat=GetMaterial(MeshNr, SkinNr);1400 1401 if (MeshMat==NULL || MeshMat->NoShadows) continue;1402 1403 static ArrayT<bool> TriangleIsFrontFacing;1404 if (TriangleIsFrontFacing.Size()<Mesh.Triangles.Size())1405 TriangleIsFrontFacing.PushBackEmpty(Mesh.Triangles.Size()-TriangleIsFrontFacing.Size());1406 1407 for (unsigned long TriNr=0; TriNr<Mesh.Triangles.Size(); TriNr++)1408 {1409 const MeshT::TriangleT& Tri=Mesh.Triangles[TriNr];1410 const float Dot=(LightPos-Mesh.Vertices[Tri.VertexIdx[0]].Draw_Pos).dot(Tri.Draw_Normal);1411 1412 TriangleIsFrontFacing[TriNr]=Dot>0;1413 }1414 1415 1416 // Note that we have to cull the following polygons wrt. the *VIEWER* (not the light source)!1417 static MatSys::MeshT MeshSilhouette(MatSys::MeshT::Quads); // The default winding order is "CW".1418 MeshSilhouette.Vertices.Overwrite();1419 1420 for (unsigned long TriNr=0; TriNr<Mesh.Triangles.Size(); TriNr++)1421 {1422 if (!TriangleIsFrontFacing[TriNr]) continue;1423 1424 // This triangle is front-facing wrt. the light source.1425 const MeshT::TriangleT& Tri=Mesh.Triangles[TriNr];1426 1427 for (unsigned long EdgeNr=0; EdgeNr<3; EdgeNr++)1428 {1429 // If an edge has no (-1) or more than one (-2) neighbours, make it a silhouette edge.1430 const bool IsSilhouetteEdge=(Tri.NeighbIdx[EdgeNr]<0) ? true : !TriangleIsFrontFacing[Tri.NeighbIdx[EdgeNr]];1431 1432 if (IsSilhouetteEdge)1433 {1434 // The neighbour at edge 'EdgeNr' is back-facing (or non-existant), so we have found a possible silhouette edge.1435 const unsigned long v1=EdgeNr;1436 const unsigned long v2=(EdgeNr+1) % 3;1437 const Vector3fT LA=Mesh.Vertices[Tri.VertexIdx[v1]].Draw_Pos-LightPos;1438 const Vector3fT LB=Mesh.Vertices[Tri.VertexIdx[v2]].Draw_Pos-LightPos;1439 1440 MeshSilhouette.Vertices.PushBackEmpty(4);1441 1442 const unsigned long MeshSize=MeshSilhouette.Vertices.Size();1443 1444 MeshSilhouette.Vertices[MeshSize-4].SetOrigin(Mesh.Vertices[Tri.VertexIdx[v2]].Draw_Pos);1445 MeshSilhouette.Vertices[MeshSize-3].SetOrigin(Mesh.Vertices[Tri.VertexIdx[v1]].Draw_Pos);1446 MeshSilhouette.Vertices[MeshSize-2].SetOrigin(LA, 0.0);1447 MeshSilhouette.Vertices[MeshSize-1].SetOrigin(LB, 0.0);1448 }1449 }1450 }1451 1452 MatSys::Renderer->RenderMesh(MeshSilhouette);1453 1454 1455 static MatSys::MeshT MeshCaps(MatSys::MeshT::Triangles); // The default winding order is "CW".1456 MeshCaps.Vertices.Overwrite();1457 1458 for (unsigned long TriNr=0; TriNr<Mesh.Triangles.Size(); TriNr++)1459 {1460 if (!TriangleIsFrontFacing[TriNr]) continue;1461 1462 // This triangle is front-facing wrt. the light source.1463 const MeshT::TriangleT& Tri=Mesh.Triangles[TriNr];1464 1465 MeshCaps.Vertices.PushBackEmpty(6);1466 1467 const unsigned long MeshSize=MeshCaps.Vertices.Size();1468 1469 // Render the occluder (front-facing wrt. the light source).1470 const Vector3fT& A=Mesh.Vertices[Tri.VertexIdx[0]].Draw_Pos;1471 const Vector3fT& B=Mesh.Vertices[Tri.VertexIdx[1]].Draw_Pos;1472 const Vector3fT& C=Mesh.Vertices[Tri.VertexIdx[2]].Draw_Pos;1473 1474 MeshCaps.Vertices[MeshSize-6].SetOrigin(A);1475 MeshCaps.Vertices[MeshSize-5].SetOrigin(B);1476 MeshCaps.Vertices[MeshSize-4].SetOrigin(C);1477 1478 // Render the occluder (back-facing wrt. the light source).1479 const Vector3fT LA=A-LightPos;1480 const Vector3fT LB=B-LightPos;1481 const Vector3fT LC=C-LightPos;1482 1483 MeshCaps.Vertices[MeshSize-3].SetOrigin(LC, 0.0);1484 MeshCaps.Vertices[MeshSize-2].SetOrigin(LB, 0.0);1485 MeshCaps.Vertices[MeshSize-1].SetOrigin(LA, 0.0);1486 }1487 1488 MatSys::Renderer->RenderMesh(MeshCaps);1489 }1490 1491 break;1492 }1493 }1494 }1495 1496 1497 954 void CafuModelT::Draw(int SequenceNr, float FrameNr, float LodDist, const ModelT* /*SubModel*/) const 1498 955 { 1499 Draw(SequenceNr, FrameNr, -1 /*default skin*/, LodDist, (SuperT*)NULL); 956 AnimPoseT Pose(*this, SequenceNr, FrameNr); // TODO: This is reconstructed on each call -- no caching at all! 957 958 Pose.Draw(-1 /*default skin*/, LodDist); 1500 959 } 1501 960 … … 1574 1033 bool CafuModelT::TraceRay(int SequenceNr, float FrameNr, int SkinNr, const Vector3fT& RayOrigin, const Vector3fT& RayDir, TraceResultT& Result) const 1575 1034 { 1576 float Fraction=0.0f; 1577 1578 // If we miss the bounding-box, then we miss all the triangles as well. 1579 if (!GetBB(SequenceNr, FrameNr).TraceRay(RayOrigin, RayDir, Fraction)) return false; 1580 1581 // Call this method to update the draw structures according to SequenceNr and FrameNr. 1582 GetDrawJointMatrices(SequenceNr, FrameNr); 1583 1584 for (unsigned long MeshNr=0; MeshNr<m_Meshes.Size(); MeshNr++) 1585 { 1586 const MeshT& Mesh =m_Meshes[MeshNr]; 1587 const MaterialT* MeshMat=GetMaterial(MeshNr, SkinNr); 1588 1589 // If the ClipFlags don't match the ClipMask, this polygon doesn't interfere with the trace. 1590 if (!MeshMat) continue; 1591 // if ((MeshMat->ClipFlags & ClipMask)==0) continue; 1592 1593 for (unsigned long TriNr=0; TriNr<Mesh.Triangles.Size(); TriNr++) 1594 { 1595 // This code is a modification of the code in CollisionModelStaticT::PolygonT::TraceRay(), 1596 // see there for details and additional information. 1597 using namespace cf::math; 1598 const MeshT::TriangleT& Tri=Mesh.Triangles[TriNr]; 1599 1600 const Vector3fT& A=Mesh.Vertices[Tri.VertexIdx[0]].Draw_Pos; 1601 const Vector3fT& B=Mesh.Vertices[Tri.VertexIdx[1]].Draw_Pos; 1602 const Vector3fT& C=Mesh.Vertices[Tri.VertexIdx[2]].Draw_Pos; 1603 1604 const PlueckerfT R=PlueckerfT::CreateFromRay(RayOrigin, RayDir); 1605 1606 // We use Pluecker coordinates for the orientation tests. 1607 // Note that Christer Ericson has shown in his blog at http://realtimecollisiondetection.net/blog/?p=13 1608 // that scalar triple products (Spatprodukte) are equivalent and could be used as well. ;-) 1609 if (!MeshMat->TwoSided) 1610 { 1611 if (R*PlueckerfT::CreateFromLine(A, B) >= 0) continue; 1612 if (R*PlueckerfT::CreateFromLine(B, C) >= 0) continue; 1613 if (R*PlueckerfT::CreateFromLine(C, A) >= 0) continue; 1614 } 1615 else 1616 { 1617 int Count=0; 1618 1619 // Should not change Count if result == 0... 1620 Count+=(R*PlueckerfT::CreateFromLine(A, B) >= 0) ? -1 : 1; 1621 Count+=(R*PlueckerfT::CreateFromLine(B, C) >= 0) ? -1 : 1; 1622 Count+=(R*PlueckerfT::CreateFromLine(C, A) >= 0) ? -1 : 1; 1623 1624 if (Count!=-3 && Count!=3) continue; 1625 } 1626 1627 // The "aperture" test passed, now compute the fraction at which RayDir intersects the triangle plane. 1628 const float Nenner=dot(Tri.Draw_Normal, RayDir); 1629 1630 if (Nenner==0) continue; // If Nenner==0, then RayDir is parallel to the triangle plane (no intersection). 1631 assert(MeshMat->TwoSided || Nenner<0); // If the material is single sided, then Nenner<0, a consequence of the Pluecker tests above. 1632 1633 const float Dist=dot(Tri.Draw_Normal, RayOrigin-A); // The distance of RayOrigin to the triangle plane. 1634 const float F =-(Dist-0.03125f)/Nenner; 1635 1636 // The intersection is only valid in the positive direction of RayDir. 1637 if (F<0) continue; 1638 1639 // Hit the triangle! 1640 Result.Fraction=F; 1641 Result.Normal =(Nenner<0) ? Tri.Draw_Normal : -Tri.Draw_Normal; // Handle two-sided materials properly. 1642 Result.Material=MeshMat; 1643 Result.MeshNr =MeshNr; 1644 Result.TriNr =TriNr; 1645 return true; 1646 } 1647 } 1648 1649 return false; 1035 AnimPoseT Pose(*this, SequenceNr, FrameNr); // TODO: This is reconstructed on each call -- no caching at all! 1036 1037 return Pose.TraceRay(SkinNr, RayOrigin, RayDir, Result); 1650 1038 } 1651 1039 -
cafu/trunk/Libs/Models/Model_cmdl.hpp
r398 r400 83 83 bool Polarity; ///< True if this triangle has positive polarity (texture is not mirrored), or false if it has negative polarity (texture is mirrored, SxT points inward). 84 84 85 Vector3fT Draw_Normal;///< The draw normal for this triangle, required for the shadow-silhouette determination.85 Vector3fT gts_Normal; ///< The draw normal for this triangle, required for the shadow-silhouette determination. 86 86 }; 87 87 … … 97 97 ArrayT<unsigned int> GeoDups; ///< This array contains the indices of vertices that are geometrical duplicates of this vertex, see AreVerticesGeoDups() for more information. The indices are stored in increasing order, and do *not* include the index of "this" vertex. Note that from the presence of GeoDups in a cmdl/md5 file we can *not* conclude that a break in the smoothing was intended by the modeller. Cylindrically wrapping seams are one counter-example. 98 98 99 Vector3fT Draw_Pos;///< Position of this vertex.100 Vector3fT Draw_Normal;///< Vertex normal.101 Vector3fT Draw_Tangent;///< Vertex tangent.102 Vector3fT Draw_BiNormal;///< Vertex binormal.99 Vector3fT gts_Pos; ///< Position of this vertex. 100 Vector3fT gts_Normal; ///< Vertex normal. 101 Vector3fT gts_Tangent; ///< Vertex tangent. 102 Vector3fT gts_BiNormal; ///< Vertex binormal. 103 103 }; 104 104 … … 239 239 240 240 241 /// This struct describes information about a parent or "super" model whose skeleton pose should be used when rendering this model.242 /// For example, a player model can act as the super model for a weapon, so that the skeleton of the weapon is copied from the243 /// player model in order to align the weapon with the hands of the player.244 struct SuperT245 {246 /// The constructor.247 /// @param Matrices_ The draw matrices of the super model.248 /// @param Map_ Describes how our joints map to the joints of the super model.249 /// If <tt>Map_[i]</tt> is not a valid index into \c Matrices_, then our joint \c i has no match in the skeleton of the super model.250 SuperT(const ArrayT<MatrixT>& Matrices_, const ArrayT<unsigned int>& Map_) : Matrices(Matrices_), Map(Map_) { }251 252 /// Has our joint \c JointNr a correspondence in the super model?253 bool HasMatrix(unsigned long JointNr) const { return Map[JointNr] < Matrices.Size(); }254 255 /// For our joint \c JointNr, return the corresponding matrix from the super model.256 /// Only call this if HasMatrix(JointNr) returns \c true.257 const MatrixT& GetMatrix(unsigned long JointNr) const { return Matrices[Map[JointNr]]; }258 259 const ArrayT<MatrixT>& Matrices; ///< The draw matrices of the super model.260 const ArrayT<unsigned int>& Map; ///< Describes how our joints map to the joints of the super model. If <tt>Map[i]</tt> is not a valid index into \c Matrices, then our joint \c i has no match in the skeleton of the super model.261 };262 263 264 241 /// The constructor. Creates a new Cafu model from a file as directed by the given model loader. 265 242 /// @param Loader The model loader that actually imports the file and fills in the model data. … … 282 259 const ArrayT<ChannelT>& GetChannels() const { return m_Channels; } 283 260 284 /// This method returns the set of drawing matrices (one per joint) at the given sequence and frame number.285 const ArrayT<MatrixT>& GetDrawJointMatrices(int SequenceNr, float FrameNr, const SuperT* Super=NULL) const;286 287 /// The new method to draw the model.288 /// @param SequenceNr The number of the animation sequence to use, -1 for the bind pose.289 /// @param FrameNr The frame number in the animation sequence to render to model at.290 /// @param SkinNr The skin to render the model with, -1 for the default skin.291 /// @param LodDist The distance to the camera for reducing the level-of-detail (currently unused).292 /// @param Super Information about a parent or "super" model whose skeleton pose should be used when rendering this model.293 void Draw(int SequenceNr, float FrameNr, int SkinNr, float LodDist, const SuperT* Super=NULL) const;294 295 261 /// Returns the proper material for the given mesh in the given skin. 296 262 const MaterialT* GetMaterial(unsigned long MeshNr, int SkinNr) const; 263 264 /// Returns the proper render material for the given mesh in the given skin. 265 MatSys::RenderMaterialT* GetRenderMaterial(unsigned long MeshNr, int SkinNr) const; 297 266 298 267 /// Determines if <tt>GF.Points[PointNr].MeshNr</tt> is a valid index into this model. … … 329 298 friend class ModelEditor::CommandUpdateGuiFixtureT; 330 299 331 void RecomputeBindPoseBB(); ///< Recomputes the bounding box for the model in bind pose (stored in m_BindPoseBB). 332 void InitMeshes(); ///< An auxiliary method for the constructors. 333 void UpdateCachedDrawData(int SequenceNr, float FrameNr, const SuperT* Super) const; ///< A private auxiliary method. 334 MatSys::RenderMaterialT* GetRenderMaterial(unsigned long MeshNr, int SkinNr) const; ///< Returns the proper render material for the given mesh in the given skin. 335 300 void RecomputeBindPoseBB(); ///< Recomputes the bounding box for the model in bind pose (stored in m_BindPoseBB). 301 void InitMeshes(); ///< An auxiliary method for the constructors. 336 302 337 303 const std::string m_FileName; ///< File name of this model. TODO: Remove!?! 338 304 MaterialManagerImplT m_MaterialMan; ///< The material manager for the materials that are used with the meshes of this model. 339 305 ArrayT<JointT> m_Joints; ///< Array of joints of this model. 340 mutable ArrayT<MeshT>m_Meshes; ///< Array of (sub)meshes of this model.306 ArrayT<MeshT> m_Meshes; ///< Array of (sub)meshes of this model. 341 307 ArrayT<SkinT> m_Skins; ///< Array of additional/alternative skins for this model. 342 308 ArrayT<GuiFixtureT> m_GuiFixtures; ///< Array of GUI fixtures in the model. … … 347 313 const bool m_UseGivenTangentSpace; ///< Whether this model should use the fixed, given tangent space that was loaded from the model file, or it the tangent space is dynamically recomputed (useful for animated models). 348 314 // const bool m_CastShadows; ///< Should this model cast shadows? 349 BoundingBox3fT m_BindPoseBB; ///< The bounding-box for the base pose of the model. 350 351 352 // Members for caching the data that is required for drawing the model at a given animation sequence and frame. 353 mutable int m_Draw_CachedDataAtSequNr; ///< The animation sequence number at which we have computed the cache data. 354 mutable float m_Draw_CachedDataAtFrameNr; ///< The animation frame number at which we have computed the cache data. 355 356 mutable ArrayT<MatrixT> m_JointMatrices; ///< The transformation matrices that represent the pose of the skeleton at the given animation sequence and frame number. 357 mutable ArrayT<MatSys::MeshT> m_Draw_Meshes; ///< The draw meshes resulting from m_JointMatrices. 315 BoundingBox3fT m_BindPoseBB; ///< [REMOVE???] The bounding-box for the base pose of the model. 358 316 }; 359 317 -
cafu/trunk/Libs/SConscript
r367 r400 14 14 MapFile.cpp 15 15 Models/Loader.cpp Models/Loader_ase.cpp Models/Loader_cmdl.cpp Models/Loader_lwo.cpp Models/Loader_md5.cpp 16 Models/Loader_mdl.cpp 16 Models/Loader_mdl.cpp Models/AnimPose.cpp 17 17 Models/Model_cmdl.cpp Models/Model_dlod.cpp Models/Model_dummy.cpp Models/Model_mdl.cpp Models/Model_proxy.cpp 18 18 Network/Network.cpp ParticleEngine/ParticleEngineMS.cpp PlatformAux.cpp Terrain/Terrain.cpp
