2011-06-02 57 views
6

好吧,我有80000的“盒子”网格用简单的纹理 我设置了一个观看距离与 只画那些你可以看到 其留下600到1000的DrawModel功能belowe 的problume是我只得到10帧每秒和我的视野距离是蹩脚的 此外,我已经做了所有我的代码的内存测试和“mesh.draw()”每秒关闭30帧。 没有别的东西需要那么多。 有什么帮助吗?C#XNA低帧率

 private void DrawModel(MeshHolder tmpMH) 
     {   
      Model tmpDrawModel = (Model)_Meshs[tmpMH.MeshFileName]; 
      Matrix[] transforms = new Matrix[tmpDrawModel.Bones.Count]; 
      tmpDrawModel.CopyAbsoluteBoneTransformsTo(transforms); 
      foreach (ModelMesh mesh in tmpDrawModel.Meshes) 
      { 
       foreach (BasicEffect effect in mesh.Effects) 
       { 

        effect.LightingEnabled = false; 

        effect.TextureEnabled = true; 
        effect.Texture = (Texture2D)_Textures[tmpMH.GetTexture(Count)]; 



        effect.View = _MainCam.View; 
        effect.Projection = _projection; 
        effect.World = 
         transforms[mesh.ParentBone.Index] * 
         Matrix.CreateFromYawPitchRoll(tmpMH.Rotation.Y, tmpMH.Rotation.X, tmpMH.Rotation.Z) * 
         Matrix.CreateScale(tmpMH.Scale) * 
         Matrix.CreateTranslation(tmpMH.Position); 
       } 

        mesh.Draw();    
      } 
     } 
+1

PC? XBox 360? Windows Phone? – 2011-06-03 04:10:27

+0

这与[此问题]非常相似(http://stackoverflow.com/questions/5268192/how-many-low-poly-models-can-xna-handle)。 – 2011-06-03 04:21:57

回答

3
effect.World = 
    transforms[mesh.ParentBone.Index] * 
    Matrix.CreateFromYawPitchRoll(
     tmpMH.Rotation.Y, tmpMH.Rotation.X, tmpMH.Rotation.Z) * 
    Matrix.CreateScale(tmpMH.Scale) * 
    Matrix.CreateTranslation(tmpMH.Position); 

我不是一个分析器,但我觉得这条线是一种痛苦。矩阵创建和乘法相当昂贵!我理解这个代码是必要的,这样,除非你可以预先计算这些矩阵,我想尝试:

Matrix pitch, scale, translation, temp1, temp2; 

Matrix.CreateFromYawPitchRoll(
    tmpMH.Rotation.Y, tmpMH.Rotation.X, tmpMH.Rotation.Z, out pitch); 
Matrix.CreateScale(ref tmpMH.Scale, out scale); 
Matrix.CreateTranslation(ref tmpMH.Position, out translation); 
Matrix.Multiply(ref transforms[mesh.ParentBone.Index], ref pitch, out temp1); 
Matrix.Multiply(ref temp1, ref scale, out temp2); 
Matrix.Multiply(ref temp2, ref translation, out effect.World); 

,因为没有必要每个矩阵复制堆栈传递参数上这可能会更快(更多比副本少20倍以上!)

+1

我*认真*怀疑未微单元优化的矩阵计算在这里主导着CPU的使用。 'effect.World'也不能是'out'参数。 – 2011-06-03 03:46:02

+0

@Andrew Russel:在我看来这会有所帮助。复制东西并不是CPU的使用情况,它只是减慢一切,因为CPU需要等待内存(http://en.wikipedia.org/wiki/Wait_state) – BlackBear 2011-06-03 10:56:56

+0

你不会打中主要内存与任一版本的代码。这里少量的堆栈数据很容易放入CPU缓存中。并且将CPU置于等待状态(例如缓存未命中状态)仍然会被视为CPU使用限制的“使用情况”。由于需要更少的指令 - 但只有一个*很小的数量 - 你的代码将“帮助”,并且当然不足以使OP低于CPU限制。 – 2011-06-04 05:33:17

7

什么是杀你的表现 - 如你所说 - 是ModelMesh.Draw。当你画出模型,它的工作原理是这样的:

for each frame 
    for each Model 
    for each ModelMesh // you call Draw(), which does: 
     for each ModelMeshPart 
     for each Effect 
      for each EffectPass 
      Draw some triangles // sends a batch of instructions to the GPU 

所以问题是:你发送一批到GPU的次数是多少?因为在饱和CPU之前,每帧只能发送几千个*批次 - 达到“批量限制”。 (每批最多使用CPU时间的图形驱动程序 - 它也使用了一些带宽和GPU时间,但CPU时间支配。)

您可能需要阅读this answerthis answerthis slide deck了解更多信息。

解决方案是修改您的场景(例如:组合一些网格部件,做一些剔除,添加实例支持)以减少发送到GPU的批次数量。


另外,尽量避免在DrawUpdate圈这样的事情:

Matrix[] transforms = new Matrix[tmpDrawModel.Bones.Count]; 

你真的应该尽最大努力避免这种情况发生每一帧内存分配 - 因为他们最终会导致昂贵的垃圾收集和潜在的帧率呃逆(特别是在Xbox上)。尝试将缓冲区存储在某处并重新使用它。

+0

谢谢,这真的很有帮助。 – codegreen 2011-06-03 22:29:18

+1

BatchBatchBatch.pdf链接现在似乎不起作用。这是一个工作:http://origin-developer.nvidia.com/docs/IO/8230/BatchBatchBatch.pdf?q=docs/IO/8230/BatchBatchBatch.pdf – Venesectrix 2011-06-16 19:02:43

+0

现在这一个也被打破了。我已经更新到一个更新的工程。 – 2013-12-10 08:38:29