2013-03-11 4 views
0

저는 게임 "Minecraft"스타일로 프로젝트에서 일합니다.XNA에서 유휴, 모델 인스턴스화없이 수백만 개의 큐브를 그리는 방법은 무엇입니까?

동일한 모델을 보유한 많은 수의 큐브를 생성하기 위해 "모델 인스턴스화"를 사용하기 시작했습니다. 지금까지 너무 좋아. 내 [300-1-300] (90000 큐빅 미터) [500-1-500] (250000 큐브)에서 그리기 위해 매트릭스의 크기를 늘리면 내 프로그램이 크게 느려집니다. . 60fps에서 20fps로 바뀝니다.

저는 왜 그런지 잘 모르겠습니다. 그러나이 기술을 올바르게 "하드웨어 인스턴스"라고 사용합니다. 또한 포럼에서이 기술을 통해 XNA가 700 만 입방을 얻을 수 있다는 사실을 알게되었습니다 !! 내 문제가 무엇인지 알 수 있습니까? 여기

// Draw the 3D map (world) of game 
public void drawWorld(GameTime gameTime) 
{ 
    /* Draw all the structures that make up the world with the instancing system */
    Array.Resize(ref instanceTransforms, smallListInstance.Count); 

    for (int i = 0; i < ListInstance.Count; i++) 
    { 
     instanceTransforms[i] = ListInstance[i].Transform; 
    } 

    DrawModelHardwareInstancing(myModel, myTexture2D,instancedModelBones,instanceTransforms, arcadia.camera.View, arcadia.camera.Projection); 


} 
// ### end function drawWorld 

이 방법 [하드웨어 인스 턴싱]와 모델을 끌어 내 기능 [DrawModelHardwareInstancing]입니다 :

감사합니다 많은 여기

인스턴스화 모델을 그리는 나의 기능입니다이 Microsoft의 샘플에 사용되었습니다.

// Function that will draw all the models instantiated in the list 
void DrawModelHardwareInstancing(Model model,Texture2D texture, Matrix[] modelBones, 
           Matrix[] instances, Matrix view, Matrix projection) 
{ 
    Game.GraphicsDevice.SamplerStates[0] = SamplerState.LinearWrap; 
    if (instances.Length == 0) 
     return; 

    // If we have more instances than room in our vertex buffer, grow it to the neccessary size. 
    if ((instanceVertexBuffer == null) || 
     (instances.Length > instanceVertexBuffer.VertexCount)) 
    { 
     if (instanceVertexBuffer != null) 
      instanceVertexBuffer.Dispose(); 

     instanceVertexBuffer = new DynamicVertexBuffer(Game.GraphicsDevice, instanceVertexDeclaration, 
                 instances.Length, BufferUsage.WriteOnly); 
    } 

    // Transfer the latest instance transform matrices into the instanceVertexBuffer. 
    instanceVertexBuffer.SetData(instances, 0, instances.Length, SetDataOptions.Discard); 

    foreach (ModelMesh mesh in model.Meshes) 
    { 
     foreach (ModelMeshPart meshPart in mesh.MeshParts) 
     { 
      // Tell the GPU to read from both the model vertex buffer plus our instanceVertexBuffer. 
      Game.GraphicsDevice.SetVertexBuffers(
       new VertexBufferBinding(meshPart.VertexBuffer, meshPart.VertexOffset, 0), 
       new VertexBufferBinding(instanceVertexBuffer, 0, 1) 
      ); 

      Game.GraphicsDevice.Indices = meshPart.IndexBuffer; 


      // Set up the instance rendering effect. 
      Effect effect = meshPart.Effect; 
      //effect.CurrentTechnique = effect.Techniques["HardwareInstancing"]; 
      effect.Parameters["World"].SetValue(modelBones[mesh.ParentBone.Index]); 
      effect.Parameters["View"].SetValue(view); 
      effect.Parameters["Projection"].SetValue(projection); 
      effect.Parameters["Texture"].SetValue(texture); 


      // Draw all the instance copies in a single call. 
      foreach (EffectPass pass in effect.CurrentTechnique.Passes) 
      { 
       pass.Apply(); 

       Game.GraphicsDevice.DrawInstancedPrimitives(PrimitiveType.TriangleList, 0, 0, 
                 meshPart.NumVertices, meshPart.StartIndex, 
                 meshPart.PrimitiveCount, instances.Length); 
      } 
     } 



    } 
} 
// ### end function DrawModelHardwareInstancing 
+1

각 프레임을 정점 버퍼와 인덱스 버퍼를 업데이트해야합니까? 백만 큐브를 렌더링하고 싶다면 버텍스 버퍼를별로 바꿀 필요가 없으므로 각 프레임을 업데이트해서는 안됩니다. 그게 문제가 될 수 없습니까? 많은 양의 객체를 반복하면서 각 프레임은 여전히 ​​많은 시간을 소비합니다. – Deukalion

+0

mhh 매우 흥미 롭습니다! 하지만 내 버텍스 버퍼를 업데이트하는 곳을 알려주시겠습니까? 너 그것에 대해서 이야기 해? Game.GraphicsDevice.SetVertexBuffers ( 새로운 VertexBufferBinding (meshPart.VertexBuffer, meshPart.VertexOffset, 0), 새로운 VertexBufferBinding (instanceVertexBuffer, 0, 1) ); Game.GraphicsDevice.Indices = meshPart.IndexBuffer; –

+0

큐브를 사용하여이 작업을 수행하지는 않았지만 작동해야합니다. 1000x1000 포인트의 그리드를 만들면 하나의 버텍스 버퍼와 인덱스 버퍼를 쉽게 만들고 하나의 포인트가 두 번 발생하지 않는지 확인한 다음 버텍스 버퍼와 인덱스 버퍼를 저장 한 다음 변경하지 않는 한 그것을 다시 만들 필요가 없습니다. 그러나 경우에 따라서는 여러 영역에 대해 여러 개의 버퍼를 만드는 변경 사항을 지원해야 할 수 있으므로 각 프레임 당 100 * 1000을 반복하지 않고 하나의 버텍스 버퍼를 100 개만 업데이트하면됩니다. 그냥 생각. – Deukalion

답변

0

대단히 감사합니다. 나는 마침내 조언 덕분에 내 문제를 해결했다 ;-)!

내 시야 '카메라'앞에있는 모델 만 그립니다. '편집', '새 위치 등 ..'이 필요한 경우에만 모델을 업데이트하십시오.

마지막 단계는 성능 향상을 위해 6면 중 3면을 그립니다.

코드 샘플이 앞에있는 경우에만 모델을 그릴

공공 BoundingFrustum 프러스 텀 {얻을; 개인 집합; }

//Initialize 
Matrix viewProjection = View * Projection; 
Frustum = new BoundingFrustum(viewProjection); 

//Update 
Matrix viewProjection = View * Projection; 
Frustum.Matrix = viewProjection; 

//Check instance and make the instanceTransformation for draw 
foreach (var object in ListInstance.Where(m => Frustum.Contains(m.BoundingBox) != ContaintmentType.Disjoint) 
{ 
    instanceTransforms[index].Add(smallListInstance[i].Transform); 

} 
// And now draw ... 
+1

또한 Extension을 사용하여 더 나아질 수 있습니다. 예를 들어 foreach (ListInstance.Where (m => Frustum.Contains (m.BoundingBox)! = ContaintmentType.Disjoint)의 var 객체는 모든 객체 당신은 몇 가지를 건너 뛰는 대신에 필요합니다. 단지 Frustum의 관점에있는 물체를 통해 반복됩니다. – Deukalion

+0

그래, 좋은 대답입니다! 고마워요. –

관련 문제