Changeset 25306

Timestamp:
Apr 23, 2021, 4:26:59 PM (3 years ago)
Author:
wraitii
Message:

Cache the model-animation bounds more efficiently.

To render models, we need to know the maximum bounds it takes over the course of an animation. This depends only on the ModelDef and the AnimationDef (and thus the SkeletonDef).
Currently, we recompute this data for each model, which is inefficient.
Caching it in ModelDef is faster, particularly avoiding lag spikes at game start on some maps.
The animations are referred by a unique ID to avoid pointer-related issues. I would have preferred weak_ptr, but that cannot be stably hashed for now.

While at it, switch to unique_ptr/vectors.

Differential Revision: https://code.wildfiregames.com/D2967

Location:
ps/trunk/source/graphics
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • ps/trunk/source/graphics/Model.cpp

    r25210 r25306  
    131131void CModel::CalcStaticObjectBounds()
    132132{
    133     m_ObjectBounds.SetEmpty();
    134 
    135     size_t numverts=m_pModelDef->GetNumVertices();
    136     SModelVertex* verts=m_pModelDef->GetVertices();
    137 
    138     for (size_t i=0;i<numverts;i++) {
    139         m_ObjectBounds+=verts[i].m_Coords;
    140     }
     133    PROFILE2("CalcStaticObjectBounds");
     134    m_pModelDef->GetMaxBounds(nullptr, !(m_Flags & MODELFLAG_NOLOOPANIMATION), m_ObjectBounds);
    141135}
    142136
     
    145139void CModel::CalcAnimatedObjectBounds(CSkeletonAnimDef* anim, CBoundingBoxAligned& result)
    146140{
    147     result.SetEmpty();
    148 
    149     // Set the current animation on which to perform calculations (if it's necessary)
    150     if (anim != m_Anim->m_AnimDef)
    151     {
    152         CSkeletonAnim dummyanim;
    153         dummyanim.m_AnimDef=anim;
    154         if (!SetAnimation(&dummyanim)) return;
    155     }
    156 
    157     size_t numverts=m_pModelDef->GetNumVertices();
    158     SModelVertex* verts=m_pModelDef->GetVertices();
    159 
    160     // Remove any transformations, so that we calculate the bounding box
    161     // at the origin. The box is later re-transformed onto the object, without
    162     // having to recalculate the size of the box.
    163     CMatrix3D transform, oldtransform = GetTransform();
    164     CModelAbstract* oldparent = m_Parent;
    165 
    166     m_Parent = 0;
    167     transform.SetIdentity();
    168     CRenderableObject::SetTransform(transform);
    169 
    170     // Following seems to stomp over the current animation time - which, unsurprisingly,
    171     // introduces artefacts in the currently playing animation. Save it here and restore it
    172     // at the end.
    173     float AnimTime = m_AnimTime;
    174 
    175     // iterate through every frame of the animation
    176     for (size_t j=0;j<anim->GetNumFrames();j++) {
    177         m_PositionValid = false;
    178         ValidatePosition();
    179 
    180         // extend bounds by vertex positions at the frame
    181         for (size_t i=0;i<numverts;i++)
    182         {
    183             result += CModelDef::SkinPoint(verts[i], GetAnimatedBoneMatrices());
    184         }
    185         // advance to next frame
    186         m_AnimTime += anim->GetFrameTime();
    187     }
    188 
    189     m_PositionValid = false;
    190     m_Parent = oldparent;
    191     SetTransform(oldtransform);
    192     m_AnimTime = AnimTime;
     141    PROFILE2("CalcAnimatedObjectBounds");
     142    m_pModelDef->GetMaxBounds(anim, !(m_Flags & MODELFLAG_NOLOOPANIMATION), result);
    193143}
    194144
  • ps/trunk/source/graphics/ModelDef.cpp

    r24915 r25306  
    3131# include <xmmintrin.h>
    3232#endif
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
    3364
    3465CVector3D CModelDef::SkinPoint(const SModelVertex& vtx,
  • ps/trunk/source/graphics/ModelDef.h

    r24489 r25306  
    1 /* Copyright (C) 2020 Wildfire Games.
     1/* Copyright (C) 202 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
     
    2424
    2525#include "ps/CStr.h"
     26
    2627#include "maths/Matrix3D.h"
    2728#include "maths/Vector2D.h"
     
    3031#include "lib/file/vfs/vfs_path.h"
    3132#include "renderer/VertexArray.h"
     33
     34
    3235#include <map>
    33 #include <cstring>
     36#include <>
    3437
    3538class CBoneState;
     39
    3640
    3741/**
     
    188192    // null if no match (case insensitive search)
    189193    const SPropPoint* FindPropPoint(const char* name) const;
     194
     195
     196
     197
     198
    190199
    191200    /**
     
    267276    VfsPath m_Name; // filename
    268277
     278
     279
     280
    269281    // renderdata shared by models of the same modeldef,
    270282    // by render path
  • ps/trunk/source/graphics/SkeletonAnimDef.cpp

    r24267 r25306  
    1 /* Copyright (C) 2009 Wildfire Games.
     1/* Copyright (C) 20 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
     
    2626#include "maths/Matrix3D.h"
    2727#include "ps/CStr.h"
     28
    2829#include "ps/FileIo.h"
    2930
     31
     32
    3033
    3134///////////////////////////////////////////////////////////////////////////////////////////
    3235// CSkeletonAnimDef constructor
    33 CSkeletonAnimDef::CSkeletonAnimDef() : m_FrameTime(0), m_NumKeys(0), m_NumFrames(0), m_Keys(0)
     36CSkeletonAnimDef::CSkeletonAnimDef() : m_FrameTime(0), m_NumKeys(0), m_NumFrames(0)
    3437{
     38
     39
     40
     41
     42
     43
     44
     45
    3546}
    3647
     
    3950CSkeletonAnimDef::~CSkeletonAnimDef()
    4051{
    41     delete[] m_Keys;
    4252}
    4353
     
    90100///////////////////////////////////////////////////////////////////////////////////////////
    91101// Load: try to load the anim from given file; return a new anim if successful
    92 CSkeletonAnimDef* CSkeletonAnimDef::Load(const VfsPath& filename)
     102 CSkeletonAnimDef::Load(const VfsPath& filename)
    93103{
    94104    CFileUnpacker unpacker;
     
    101111
    102112    // unpack the data
    103     CSkeletonAnimDef* anim=new CSkeletonAnimDef;
     113    ;
    104114    try {
    105115        CStr name; // unused - just here to maintain compatibility with the animation files
     
    108118        anim->m_NumKeys = unpacker.UnpackSize();
    109119        anim->m_NumFrames = unpacker.UnpackSize();
    110         anim->m_Keys=new Key[anim->m_NumKeys*anim->m_NumFrames];
    111         unpacker.UnpackRaw(anim->m_Keys,anim->m_NumKeys*anim->m_NumFrames*sizeof(Key));
     120        anim->m_Keys;
     121        unpacker.UnpackRaw(anim->m_Keys));
    112122    } catch (PSERROR_File&) {
    113         delete anim;
     123        ;
    114124        throw;
    115125    }
     
    120130///////////////////////////////////////////////////////////////////////////////////////////
    121131// Save: try to save anim to file
    122 void CSkeletonAnimDef::Save(const VfsPath& pathname,const CSkeletonAnimDef* anim)
     132void CSkeletonAnimDef::Save(const VfsPath& pathname, anim)
    123133{
    124134    CFilePacker packer(FILE_VERSION, "PSSA");
     
    126136    // pack up all the data
    127137    packer.PackString("");
    128     packer.PackRaw(&anim->m_FrameTime,sizeof(anim->m_FrameTime));
    129     const size_t numKeys = anim->m_NumKeys;
     138    packer.PackRaw(&animm_FrameTime));
     139    const size_t numKeys = animm_NumKeys;
    130140    packer.PackSize(numKeys);
    131     const size_t numFrames = anim->m_NumFrames;
     141    const size_t numFrames = animm_NumFrames;
    132142    packer.PackSize(numFrames);
    133     packer.PackRaw(anim->m_Keys,numKeys*numFrames*sizeof(Key));
     143    packer.PackRaw(anim));
    134144
    135145    // now write it
  • ps/trunk/source/graphics/SkeletonAnimDef.h

    r18987 r25306  
    1 /* Copyright (C) 2009 Wildfire Games.
     1/* Copyright (C) 20 Wildfire Games.
    22 * This file is part of 0 A.D.
    33 *
     
    2626#include "maths/Quaternion.h"
    2727#include "lib/file/vfs/vfs_path.h"
     28
     29
     30
    2831
    2932////////////////////////////////////////////////////////////////////////////////////////
     
    7982
    8083    // anim I/O functions
    81     static CSkeletonAnimDef* Load(const VfsPath& filename);
    82     static void Save(const VfsPath& pathname, const CSkeletonAnimDef* anim);
     84    static Load(const VfsPath& filename);
     85    static void Save(const VfsPath& pathname, const CSkeletonAnimDef anim);
    8386
    8487public:
     
    9093    size_t m_NumFrames;
    9194    // animation data - m_NumKeys*m_NumFrames total keys
    92     Key* m_Keys;
     95    std::vector<Key> m_Keys;
     96    // Unique identifier - used by CModelDef to cache bounds per-animDef.
     97    // (hopefully we won't run into the u32 limit too soon).
     98    u32 m_UID;
     99    static u32 nextUID;
    93100};
    94101
  • ps/trunk/source/graphics/SkeletonAnimManager.cpp

    r25004 r25306  
    4141CSkeletonAnimManager::~CSkeletonAnimManager()
    4242{
    43     using Iter = std::unordered_map<VfsPath,CSkeletonAnimDef*>::iterator;
    44     for (Iter i = m_Animations.begin(); i != m_Animations.end(); ++i)
    45         delete i->second;
    4643}
    4744
     
    5451
    5552    // Find if it's already been loaded
    56     std::unordered_map<VfsPath, CSkeletonAnimDef*>::iterator iter = m_Animations.find(name);
     53    std::unordered_map<VfsPath, >::iterator iter = m_Animations.find(name);
    5754    if (iter != m_Animations.end())
    58         return iter->second;
     55        return iter->second;
    5956
    60     CSkeletonAnimDef* def = NULL;
     57    ;
    6158
    6259    // Find the file to load
     
    6461
    6562    if (psaFilename.empty())
    66     {
    6763        LOGERROR("Could not load animation '%s'", pathname.string8());
    68         def = NULL;
    69     }
    7064    else
    71     {
    7265        try
    7366        {
     
    7871            LOGERROR("Could not load animation '%s'", psaFilename.string8());
    7972        }
    80     }
    8173
    8274    if (def)
     
    8577        LOGERROR("CSkeletonAnimManager::GetAnimation(%s): Failed loading, marked file as bad", pathname.string8());
    8678
    87     // Add to map
    88     m_Animations[name] = def; // NULL if failed to load - we won't try loading it again
    89     return def;
     79    // Add to map, NULL if failed to load - we won't try loading it again
     80    return m_Animations.insert_or_assign(name, std::move(def)).first->second.get();
    9081}
  • ps/trunk/source/graphics/SkeletonAnimManager.h

    r25004 r25306  
    2525#include "lib/file/vfs/vfs_path.h"
    2626
     27
    2728#include <unordered_map>
    2829
     
    4849private:
    4950    // map of all known animations. Value is NULL if it failed to load.
    50     std::unordered_map<VfsPath, CSkeletonAnimDef*> m_Animations;
     51    std::unordered_map<VfsPath, > m_Animations;
    5152
    5253    CColladaManager& m_ColladaManager;
Note: See TracChangeset for help on using the changeset viewer.