瀏覽代碼

To save GPU memory with many morphed instances of an AnimatedModel, copy only the morphable attributes into the morph vertex buffer, and read other (static) attributes from the original vertex buffer.
Fixed OpenGL vertex attributes getting erroneously disabled when one vertex buffer assignment changes and another remains.

Lasse Öörni 13 年之前
父節點
當前提交
e2790f81b0
共有 3 個文件被更改,包括 89 次插入16 次删除
  1. 80 15
      Engine/Graphics/AnimatedModel.cpp
  2. 3 1
      Engine/Graphics/AnimatedModel.h
  3. 6 0
      Engine/Graphics/OpenGL/OGLGraphics.cpp

+ 80 - 15
Engine/Graphics/AnimatedModel.cpp

@@ -339,6 +339,7 @@ void AnimatedModel::SetModel(Model* model, bool createBones)
     morphVertexBuffers_.Clear();
     morphVertexBuffers_.Clear();
     morphs_.Clear();
     morphs_.Clear();
     const Vector<ModelMorph>& morphs = model->GetMorphs();
     const Vector<ModelMorph>& morphs = model->GetMorphs();
+    unsigned morphElementMask = 0;
     for (unsigned i = 0; i < morphs.Size(); ++i)
     for (unsigned i = 0; i < morphs.Size(); ++i)
     {
     {
         ModelMorph newMorph;
         ModelMorph newMorph;
@@ -346,13 +347,15 @@ void AnimatedModel::SetModel(Model* model, bool createBones)
         newMorph.nameHash_ = morphs[i].nameHash_;
         newMorph.nameHash_ = morphs[i].nameHash_;
         newMorph.weight_ = 0.0f;
         newMorph.weight_ = 0.0f;
         newMorph.buffers_ = morphs[i].buffers_;
         newMorph.buffers_ = morphs[i].buffers_;
+        for (Map<unsigned, VertexBufferMorph>::ConstIterator j = morphs[i].buffers_.Begin(); j != morphs[i].buffers_.End(); ++j)
+            morphElementMask |= j->second_.elementMask_;
         morphs_.Push(newMorph);
         morphs_.Push(newMorph);
     }
     }
     
     
     // If model has morphs, must clone all geometries & vertex buffers that refer to morphable vertex data
     // If model has morphs, must clone all geometries & vertex buffers that refer to morphable vertex data
     if (morphs.Size())
     if (morphs.Size())
     {
     {
-        CloneGeometries();
+        CloneGeometries(morphElementMask);
         MarkMorphsDirty();
         MarkMorphsDirty();
     }
     }
     
     
@@ -917,12 +920,11 @@ void AnimatedModel::MarkMorphsDirty()
     morphsDirty_ = true;
     morphsDirty_ = true;
 }
 }
 
 
-void AnimatedModel::CloneGeometries()
+void AnimatedModel::CloneGeometries(unsigned morphElementMask)
 {
 {
     // Clone vertex buffers as necessary
     // Clone vertex buffers as necessary
     const Vector<SharedPtr<VertexBuffer> >& originalVertexBuffers = model_->GetVertexBuffers();
     const Vector<SharedPtr<VertexBuffer> >& originalVertexBuffers = model_->GetVertexBuffers();
     Map<VertexBuffer*, SharedPtr<VertexBuffer> > clonedVertexBuffers;
     Map<VertexBuffer*, SharedPtr<VertexBuffer> > clonedVertexBuffers;
-    
     morphVertexBuffers_.Resize(originalVertexBuffers.Size());
     morphVertexBuffers_.Resize(originalVertexBuffers.Size());
     
     
     for (unsigned i = 0; i < originalVertexBuffers.Size(); ++i)
     for (unsigned i = 0; i < originalVertexBuffers.Size(); ++i)
@@ -931,9 +933,13 @@ void AnimatedModel::CloneGeometries()
         if (model_->GetMorphRangeCount(i))
         if (model_->GetMorphRangeCount(i))
         {
         {
             SharedPtr<VertexBuffer> clone(new VertexBuffer(context_));
             SharedPtr<VertexBuffer> clone(new VertexBuffer(context_));
-            clone->SetSize(original->GetVertexCount(), original->GetElementMask(), true);
-            clone->SetData(original->GetShadowData());
-            
+            clone->SetSize(original->GetVertexCount(), morphElementMask & original->GetElementMask(), true);
+            void* dest = clone->Lock(0, original->GetVertexCount());
+            if (dest)
+            {
+                CopyMorphVertices(dest, original->GetShadowData(), original->GetVertexCount(), clone, original);
+                clone->Unlock();
+            }
             clonedVertexBuffers[original] = clone;
             clonedVertexBuffers[original] = clone;
             morphVertexBuffers_[i] = clone;
             morphVertexBuffers_[i] = clone;
         }
         }
@@ -947,18 +953,39 @@ void AnimatedModel::CloneGeometries()
         for (unsigned j = 0; j < geometries_[i].Size(); ++j)
         for (unsigned j = 0; j < geometries_[i].Size(); ++j)
         {
         {
             SharedPtr<Geometry> original = geometries_[i][j];
             SharedPtr<Geometry> original = geometries_[i][j];
+            SharedPtr<Geometry> clone(new Geometry(context_));
             
             
+            // Add an additional vertex stream into the clone, which supplies only the morphable vertex data, while the static
+            // data comes from the original vertex buffer(s)
             const Vector<SharedPtr<VertexBuffer> >& originalBuffers = original->GetVertexBuffers();
             const Vector<SharedPtr<VertexBuffer> >& originalBuffers = original->GetVertexBuffers();
+            unsigned totalBuf = originalBuffers.Size();
+            for (unsigned k = 0; k < originalBuffers.Size(); ++k)
+            {
+                VertexBuffer* originalBuffer = originalBuffers[k];
+                if (clonedVertexBuffers.Contains(originalBuffer))
+                    ++totalBuf;
+            }
+            clone->SetNumVertexBuffers(totalBuf);
             
             
-            SharedPtr<Geometry> clone(new Geometry(context_));
-            clone->SetNumVertexBuffers(originalBuffers.Size());
+            unsigned l = 0;
             for (unsigned k = 0; k < originalBuffers.Size(); ++k)
             for (unsigned k = 0; k < originalBuffers.Size(); ++k)
             {
             {
                 VertexBuffer* originalBuffer = originalBuffers[k];
                 VertexBuffer* originalBuffer = originalBuffers[k];
+                unsigned originalMask = original->GetVertexElementMask(k);
+                
                 if (clonedVertexBuffers.Contains(originalBuffer))
                 if (clonedVertexBuffers.Contains(originalBuffer))
-                    clone->SetVertexBuffer(k, clonedVertexBuffers[originalBuffer], original->GetVertexElementMask(k));
+                {
+                    VertexBuffer* clonedBuffer = clonedVertexBuffers[originalBuffer];
+                    clone->SetVertexBuffer(l, originalBuffer, originalMask & ~clonedBuffer->GetElementMask());
+                    ++l;
+                    clone->SetVertexBuffer(l, clonedBuffer, originalMask & clonedBuffer->GetElementMask());
+                    ++l;
+                }
                 else
                 else
-                    clone->SetVertexBuffer(k, originalBuffers[k], original->GetVertexElementMask(k));
+                {
+                    clone->SetVertexBuffer(l, originalBuffer, originalMask);
+                    ++l;
+                }
             }
             }
             
             
             clone->SetIndexBuffer(original->GetIndexBuffer());
             clone->SetIndexBuffer(original->GetIndexBuffer());
@@ -970,6 +997,44 @@ void AnimatedModel::CloneGeometries()
     }
     }
 }
 }
 
 
+void AnimatedModel::CopyMorphVertices(void* destVertexData, void* srcVertexData, unsigned vertexCount, VertexBuffer* destBuffer, VertexBuffer* srcBuffer)
+{
+    unsigned mask = destBuffer->GetElementMask() & srcBuffer->GetElementMask();
+    unsigned normalOffset = srcBuffer->GetElementOffset(ELEMENT_NORMAL);
+    unsigned tangentOffset = srcBuffer->GetElementOffset(ELEMENT_TANGENT);
+    unsigned vertexSize = srcBuffer->GetVertexSize();
+    float* dest = (float*)destVertexData;
+    unsigned char* src = (unsigned char*)srcVertexData;
+    
+    while (vertexCount--)
+    {
+        if (mask & MASK_POSITION)
+        {
+            float* posSrc = (float*)src;
+            *dest++ = posSrc[0];
+            *dest++ = posSrc[1];
+            *dest++ = posSrc[2];
+        }
+        if (mask & MASK_NORMAL)
+        {
+            float* normalSrc = (float*)(src + normalOffset);
+            *dest++ = normalSrc[0];
+            *dest++ = normalSrc[1];
+            *dest++ = normalSrc[2];
+        }
+        if (mask & MASK_TANGENT)
+        {
+            float* tangentSrc = (float*)(src + tangentOffset);
+            *dest++ = tangentSrc[0];
+            *dest++ = tangentSrc[1];
+            *dest++ = tangentSrc[2];
+            *dest++ = tangentSrc[3];
+        }
+        
+        src += vertexSize;
+    }
+}
+
 void AnimatedModel::SetGeometryBoneMappings()
 void AnimatedModel::SetGeometryBoneMappings()
 {
 {
     geometrySkinMatrices_.Clear();
     geometrySkinMatrices_.Clear();
@@ -1095,7 +1160,6 @@ void AnimatedModel::UpdateMorphs()
                 VertexBuffer* originalBuffer = model_->GetVertexBuffers()[i];
                 VertexBuffer* originalBuffer = model_->GetVertexBuffers()[i];
                 unsigned morphStart = model_->GetMorphRangeStart(i);
                 unsigned morphStart = model_->GetMorphRangeStart(i);
                 unsigned morphCount = model_->GetMorphRangeCount(i);
                 unsigned morphCount = model_->GetMorphRangeCount(i);
-                unsigned vertexSize = buffer->GetVertexSize();
                 
                 
                 if (!buffer->IsDataLost())
                 if (!buffer->IsDataLost())
                 {
                 {
@@ -1103,7 +1167,8 @@ void AnimatedModel::UpdateMorphs()
                     if (dest)
                     if (dest)
                     {
                     {
                         // Reset morph range by copying data from the original vertex buffer
                         // Reset morph range by copying data from the original vertex buffer
-                        memcpy(dest, originalBuffer->GetShadowData() + morphStart * vertexSize, morphCount * vertexSize);
+                        CopyMorphVertices(dest, originalBuffer->GetShadowData() + morphStart * originalBuffer->GetVertexSize(),
+                            morphCount, buffer, originalBuffer);
                         
                         
                         for (unsigned j = 0; j < morphs_.Size(); ++j)
                         for (unsigned j = 0; j < morphs_.Size(); ++j)
                         {
                         {
@@ -1125,9 +1190,9 @@ void AnimatedModel::UpdateMorphs()
                     void* dest = buffer->Lock(0, vertexCount, true);
                     void* dest = buffer->Lock(0, vertexCount, true);
                     if (dest)
                     if (dest)
                     {
                     {
-                        memcpy(dest, originalBuffer->GetShadowData(), vertexCount * vertexSize);
+                        CopyMorphVertices(dest, originalBuffer->GetShadowData(), vertexCount, buffer, originalBuffer);
                         
                         
-                        dest = ((unsigned char*)dest) + morphStart * vertexSize;
+                        dest = ((unsigned char*)dest) + morphStart * buffer->GetVertexSize();
                         for (unsigned j = 0; j < morphs_.Size(); ++j)
                         for (unsigned j = 0; j < morphs_.Size(); ++j)
                         {
                         {
                             if (morphs_[j].weight_ > 0.0f)
                             if (morphs_[j].weight_ > 0.0f)
@@ -1152,7 +1217,7 @@ void AnimatedModel::UpdateMorphs()
 
 
 void AnimatedModel::ApplyMorph(VertexBuffer* buffer, void* destVertexData, unsigned morphRangeStart, const VertexBufferMorph& morph, float weight)
 void AnimatedModel::ApplyMorph(VertexBuffer* buffer, void* destVertexData, unsigned morphRangeStart, const VertexBufferMorph& morph, float weight)
 {
 {
-    unsigned elementMask = morph.elementMask_;
+    unsigned elementMask = morph.elementMask_ & buffer->GetElementMask();
     unsigned vertexCount = morph.vertexCount_;
     unsigned vertexCount = morph.vertexCount_;
     unsigned normalOffset = buffer->GetElementOffset(ELEMENT_NORMAL);
     unsigned normalOffset = buffer->GetElementOffset(ELEMENT_NORMAL);
     unsigned tangentOffset = buffer->GetElementOffset(ELEMENT_TANGENT);
     unsigned tangentOffset = buffer->GetElementOffset(ELEMENT_TANGENT);

+ 3 - 1
Engine/Graphics/AnimatedModel.h

@@ -163,7 +163,9 @@ private:
     /// %Set mapping of subgeometry bone indices.
     /// %Set mapping of subgeometry bone indices.
     void SetGeometryBoneMappings();
     void SetGeometryBoneMappings();
     /// Clone geometries as required.
     /// Clone geometries as required.
-    void CloneGeometries();
+    void CloneGeometries(unsigned morphElementMask);
+    /// Copy morph vertices.
+    void CopyMorphVertices(void* dest, void* src, unsigned vertexCount, VertexBuffer* clone, VertexBuffer* original);
     /// Recalculate animations. Called from UpdateNode().
     /// Recalculate animations. Called from UpdateNode().
     void UpdateAnimation(const FrameInfo& frame);
     void UpdateAnimation(const FrameInfo& frame);
     /// Recalculate skinning.
     /// Recalculate skinning.

+ 6 - 0
Engine/Graphics/OpenGL/OGLGraphics.cpp

@@ -609,7 +609,10 @@ bool Graphics::SetVertexBuffers(const Vector<VertexBuffer*>& buffers, const PODV
         
         
         // If buffer and element mask have stayed the same, skip to the next buffer
         // If buffer and element mask have stayed the same, skip to the next buffer
         if (buffer == vertexBuffers_[i] && elementMask == elementMasks_[i] && !changed)
         if (buffer == vertexBuffers_[i] && elementMask == elementMasks_[i] && !changed)
+        {
+            newAttributes |= elementMask;
             continue;
             continue;
+        }
         
         
         vertexBuffers_[i] = buffer;
         vertexBuffers_[i] = buffer;
         elementMasks_[i] = elementMask;
         elementMasks_[i] = elementMask;
@@ -697,7 +700,10 @@ bool Graphics::SetVertexBuffers(const Vector<SharedPtr<VertexBuffer> >& buffers,
         }
         }
         
         
         if (buffer == vertexBuffers_[i] && elementMask == elementMasks_[i] && !changed)
         if (buffer == vertexBuffers_[i] && elementMask == elementMasks_[i] && !changed)
+        {
+            newAttributes |= elementMask;
             continue;
             continue;
+        }
         
         
         vertexBuffers_[i] = buffer;
         vertexBuffers_[i] = buffer;
         elementMasks_[i] = elementMask;
         elementMasks_[i] = elementMask;