2012-05-10 2 views
3

XNA에서 보셀 (미니 크래프트 스타일) 엔진을 사용하고 세계를 청크로 나누고 큐브를 수정할 때 모든 큐브를 스캔하고 얼굴이 표시되는지 확인하여 정점 버퍼를 다시 만듭니다. 이것은 일반적으로 좋은 속도로 작동하지만 큐브가 특정 방식으로 배열 될 때 (정점 버퍼가 훨씬 커질 때) 새로운 청크를 생성하기 위해 프레임을 넘길 수 있습니다. 가능한 최악의 구성 (가능한 가장 높은 정점이 표시됨)에서는 최대 100ms가 소요될 수 있습니다. 코드의 다음 부분은 100의 약 80-90ms를 나타내며, 청크가 업데이트 될 때 131,072 번 실행됩니다. 최악의 구성에서는 32,768 큐브가 생성되고 다른 모든 실행에서는 0 개의 정점이 생성됩니다.어쨌든이 기능을 빠르게하려면?

i5 2500k에서도 사용하기 때문에 이전 시스템에서는 매우 나쁠 수 있습니다.

나는 속도를 향상시키기 위해 어쨌든 생각할 수 없다. 그래서 나는 약간의 충고를 위해 그것을 게시 할 것이라고 생각했기 때문에 나는 프로그래밍에 아주 익숙하지 않은가? 감사.

public void GenerateCubeGeometryAtPosition(int x, int y, int z, byte id) 
{ 
    //We check if there's a cube in the six directions around the cube 
    //if there's no cube ot the cube is transparent we add the vertices to the vertex list 
    //if the cube is on the outside of the chunk we check the cube in the chunk next to it assuming it's loaded 

    //if we have to build part of the cube we make a new vertex 
    //first 3 bytes in the vertex are the position relative to the chunk 
    //4th byte is for normals, we check it in the shader to figure out the normal 
    //the next 2 bytes in the properties are for the texture positons on the texture atlas 
    //last 2 bytes are for other properties of the vertex like light/shade etc 

    //Check up and down 
    if (y > YSize - 2) 
    { 
     ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y + 1, z, 0f), GlobalWorld.Blocks[id].VertexPropertiesTop[0])); 
     ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y + 1, z, 0f), GlobalWorld.Blocks[id].VertexPropertiesTop[1])); 
     ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y + 1, 1 + z, 0f), GlobalWorld.Blocks[id].VertexPropertiesTop[2])); 
     ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y + 1, 1 + z, 0f), GlobalWorld.Blocks[id].VertexPropertiesTop[3])); 
    } 
    else if (Blocks[x, y + 1, z] == 0 || GlobalWorld.Blocks[Blocks[x, y + 1, z]].Transparent) 
    { 
     ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y + 1, z, 0f), GlobalWorld.Blocks[id].VertexPropertiesTop[0])); 
     ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y + 1, z, 0f), GlobalWorld.Blocks[id].VertexPropertiesTop[1])); 
     ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y + 1, 1 + z, 0f), GlobalWorld.Blocks[id].VertexPropertiesTop[2])); 
     ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y + 1, 1 + z, 0f), GlobalWorld.Blocks[id].VertexPropertiesTop[3])); 

    } 
    if (y != 0 && (Blocks[x, y - 1, z] == 0 || GlobalWorld.Blocks[Blocks[x, y - 1, z]].Transparent)) 
    { 
     ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y, z, 1f), GlobalWorld.Blocks[id].VertexPropertiesBottom[0])); 
     ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y, 1 + z, 1f), GlobalWorld.Blocks[id].VertexPropertiesBottom[1])); 
     ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y, z, 1f), GlobalWorld.Blocks[id].VertexPropertiesBottom[2])); 
     ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y, 1 + z, 1f), GlobalWorld.Blocks[id].VertexPropertiesBottom[3])); 
    } 

    //check Right and Left of the cube and the adjacent chunk at the edges 
    if (x == 0) 
    { 
     if (this.RightChunk != -1 && (GlobalWorld.LoadedChunks[this.RightChunk].Blocks[XSize - 1, y, z] == 0 || GlobalWorld.Blocks[GlobalWorld.LoadedChunks[this.RightChunk].Blocks[XSize - 1, y, z]].Transparent)) 
     { 
      ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y, z, 3f), GlobalWorld.Blocks[id].VertexPropertiesRight[0])); 
      ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y + 1, z, 3f), GlobalWorld.Blocks[id].VertexPropertiesRight[1])); 
      ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y, 1 + z, 3f), GlobalWorld.Blocks[id].VertexPropertiesRight[2])); 
      ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y + 1, 1 + z, 3f), GlobalWorld.Blocks[id].VertexPropertiesRight[3])); 
     } 
    } 
    else if (Blocks[x - 1, y, z] == 0 || GlobalWorld.Blocks[Blocks[x - 1, y, z]].Transparent) 
    { 
     //right 
     ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y, z, 3f), GlobalWorld.Blocks[id].VertexPropertiesRight[0])); 
     ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y + 1, z, 3f), GlobalWorld.Blocks[id].VertexPropertiesRight[1])); 
     ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y, 1 + z, 3f), GlobalWorld.Blocks[id].VertexPropertiesRight[2])); 
     ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y + 1, 1 + z, 3f), GlobalWorld.Blocks[id].VertexPropertiesRight[3])); 
    } 
    if (x > XSize - 2) 
    { 
     if (this.LeftChunk != -1 && (GlobalWorld.LoadedChunks[this.LeftChunk].Blocks[0, y, z] == 0 || GlobalWorld.Blocks[GlobalWorld.LoadedChunks[this.LeftChunk].Blocks[0, y, z]].Transparent)) 
     { 
      ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y, z, 2f), GlobalWorld.Blocks[id].VertexPropertiesLeft[0])); 
      ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y, 1 + z, 2f), GlobalWorld.Blocks[id].VertexPropertiesLeft[1])); 
      ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, 1 + y, z, 2f), GlobalWorld.Blocks[id].VertexPropertiesLeft[2])); 
      ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, 1 + y, 1 + z, 2f), GlobalWorld.Blocks[id].VertexPropertiesLeft[3])); 
     } 
    } 
    else if (Blocks[x + 1, y, z] == 0 || GlobalWorld.Blocks[Blocks[x + 1, y, z]].Transparent) 
    { 
     //left 
     ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y, z, 2f), GlobalWorld.Blocks[id].VertexPropertiesLeft[0])); 
     ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y, 1 + z, 2f), GlobalWorld.Blocks[id].VertexPropertiesLeft[1])); 
     ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, 1 + y, z, 2f), GlobalWorld.Blocks[id].VertexPropertiesLeft[2])); 
     ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, 1 + y, 1 + z, 2f), GlobalWorld.Blocks[id].VertexPropertiesLeft[3])); 
    } 

    //check Back and Front of the cube and the adjacent chunk at the edges 
    if (z == 0) 
    { 
     if (this.BackChunk != -1 && (GlobalWorld.LoadedChunks[this.BackChunk].Blocks[x, y, ZSize - 1] == 0 || GlobalWorld.Blocks[GlobalWorld.LoadedChunks[this.BackChunk].Blocks[x, y, ZSize - 1]].Transparent)) 
     { 
      ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y, z, 5f), GlobalWorld.Blocks[id].VertexPropertiesBack[0])); 
      ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y, z, 5f), GlobalWorld.Blocks[id].VertexPropertiesBack[1])); 
      ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y + 1, z, 5f), GlobalWorld.Blocks[id].VertexPropertiesBack[2])); 
      ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y + 1, z, 5f), GlobalWorld.Blocks[id].VertexPropertiesBack[3])); 
     } 
    } 
    else if (Blocks[x, y, z - 1] == 0 || GlobalWorld.Blocks[Blocks[x, y, z - 1]].Transparent) 
    { 
     ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y, z, 5f), GlobalWorld.Blocks[id].VertexPropertiesBack[0])); 
     ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y, z, 5f), GlobalWorld.Blocks[id].VertexPropertiesBack[1])); 
     ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y + 1, z, 5f), GlobalWorld.Blocks[id].VertexPropertiesBack[2])); 
     ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y + 1, z, 5f), GlobalWorld.Blocks[id].VertexPropertiesBack[3])); 
    } 
    if (z > ZSize - 2) 
    { 
     if (this.ForwardChunk != -1 && (GlobalWorld.LoadedChunks[this.ForwardChunk].Blocks[x, y, 0] == 0 || GlobalWorld.Blocks[GlobalWorld.LoadedChunks[this.ForwardChunk].Blocks[x, y, 0]].Transparent)) 
     { 
      ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y, 1 + z, 4f), GlobalWorld.Blocks[id].VertexPropertiesFront[0])); 
      ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y + 1, 1 + z, 4f), GlobalWorld.Blocks[id].VertexPropertiesFront[1])); 
      ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y, 1 + z, 4f), GlobalWorld.Blocks[id].VertexPropertiesFront[2])); 
      ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y + 1, 1 + z, 4f), GlobalWorld.Blocks[id].VertexPropertiesFront[3])); 
     } 
    } 
    else if (Blocks[x, y, z + 1] == 0 || GlobalWorld.Blocks[Blocks[x, y, z + 1]].Transparent) 
    { 
     ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y, 1 + z, 4f), GlobalWorld.Blocks[id].VertexPropertiesFront[0])); 
     ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(x, y + 1, 1 + z, 4f), GlobalWorld.Blocks[id].VertexPropertiesFront[1])); 
     ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y, 1 + z, 4f), GlobalWorld.Blocks[id].VertexPropertiesFront[2])); 
     ChunkVertices.Add(new VertexPositionNormalSmall(new Byte4(1 + x, y + 1, 1 + z, 4f), GlobalWorld.Blocks[id].VertexPropertiesFront[3])); 
    } 
} 
+1

먼저 GlobalWorld.Blocks [id]를 가져 와서 GlobalWorld.Blocks [id]가 호출 될 때마다 다른 값을 반환하지 않는 한 로컬 변수에 저장할 수 있습니다. 반복적으로 액세스하는 다른 클래스 속성에도 동일한 철학을 적용하십시오. 또한 이것은 매우 구체적이어서 SO에 적절하지 않습니다. http://gamedev.stackexchange.com을 사용해보십시오. –

+0

'Byte4'가 왜 떠 다니는가요? – Dani

+0

Vector4에서 변경하여 변경하는 것을 잊어 버렸기 때문에 저에게 상기시켜 주셔서 감사합니다. 왜 Globalworld.Vlocks에서 덩어리를 가져 오는 것이 천천히하는 원인이됩니까? 같은 속도가 아니겠습니까? –

답변

1

이 코드의 속도가 느려지는 이유는 분명하지 않습니다. 작은 코드 변경으로 인해 필요한 속도 향상을 얻지 못하는 경우 다른 구현을 시도합니다.

정확하게 이해하면 한 블록이 변경 될 때 64x64x32 (= 131072) 블록의 전체 청크에 대한 버텍스 버퍼를 재구성합니다. 청크의 블록이 한 번에 몇 개씩 만 변경된다고 가정하면 미리 정해진 위치에 모든 큐브의 모든면을 포함하는 하나의 영구적 인 정점 버퍼를 갖는 것이 훨씬 빠를 수 있습니다. 하나의 큐브면의 상태가 변경되면 처음부터 전체 정점 버퍼를 만드는 대신 정점 버퍼에서 네 개의 값만 변경하면됩니다.

예를 들어 GetCubeFaceStartIndex(5, 6, 7, CubeFaceType.Top)부터 시작하는 4 개의 연속 버텍스 버퍼 인덱스에서 (5, 6, 7)에 큐브 윗면의 4 개의 꼭지점을 지정할 수 있습니다.

enum CubeFaceType { Top, Bottom, Left, Right, Front, Back } 

int GetCubeFaceStartIndex(int x, int y, int z, CubeFaceType face) 
{ 
    return 4 * ((int)cubeFace + 6 * (x + CHUNK_WIDTH * (y + CHUNK_HEIGHT * z)); 
} 

(블록이 삭제 될 때), 같은 값으로 네 개의 정점을 설정합니다 하나 개의 얼굴을 제거하려면, 예를 들어, new VertexPositionNormalSmall(Vector4.Zero, DummyProperties). 꼭지점이 같은 위치를 공유하는 삼각형은 화면에 표시되지 않습니다.

면을 추가하거나 속성을 변경해야하는 경우, 입방체와면의 위치에 따라 결정된 색인에서만 이전에 한 작업을 수행합니다.

물론이 구현에는 더 큰 버텍스 버퍼가 필요합니다. 청크의 크기가 64x64x32 큐브 인 경우 정점 버퍼는 64 * 64 * 64 * 6 * 4 = 3145728 꼭지점이되어야하므로 실용적이지 않을 수 있습니다. 덩어리의 크기를 줄이는 것이 필요할 수 있습니다.

1
  1. '일반'구성에서 숨겨진 정점/표시된 버텍스 비율은 무엇입니까? 그래픽 카드는 숨겨진 정점을 표시하지 않으므로 그래픽 카드에서 가장자리를 제거하는 것보다 가장자리를 제거하는 데 더 많은 시간이 걸릴 수 있습니다.

  2. 똑같은 아이디어에서, 큐브 레벨에서만 처리하는 것이 흥미로울 수도 있습니다. 큐브가 다른 큐브 안에 완전히 있으면, 큐브 꼭지점을 모두 추가하지 않으면 정점을 추가하지 말고 검사. 여기 숨겨진/표시된 버텍스 비율에 따라 다릅니다.

  3. 큐브가 깊이 감추어 져 있다면 숨겨진 큐브로만 둘러싸인 것으로 나타납니다. 알고리즘에 의해 표시됩니다. 그러나 그것을 이용하려면 3D 페인트와 같은 복잡한 알고리즘 만 볼 수 있습니다. 음 ....

  4. 각 변경 사항을 알면 (단 하나의 블록 만 켜지거나 꺼짐) 매번 건물을 짓는 대신 정점 목록의 일부만 업데이트하여 작업 속도를 크게 높일 수 있습니다. 하나의 블록이 켜지면, 모두 다시 빌드하는 것이 필수는 아니라는 것을 알아 두십시오 : 새 큐브의 꼭지점을 추가하기 만하면 디스플레이가 괜찮습니다. 그러나 정점 목록에는 표시되지 않을 정점이 포함되어 있습니다. :-) 한 블록이 꺼지면 주변 큐브의 정점이 표시되지만 숨겨진 블록 주변의 제한된 영역에 표시됩니다 만. 그래서 vvnurmi가 제안한 것과 같이, (큐브 쪽) -> (꼭지점 시작 및 끝 인덱스) 사전을 갖는 것이 편리 할 것입니다. 그래서 주어진 입방체를 지울 수 있습니다.

관련 문제