ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 11. D3D 그리기 연산2
    Software/DirectX 2024. 5. 24. 09:50
    728x90

    Table of Contents

    1. 지형

    2. 파도와 동적 정점버퍼






    1. 지형
    • 삼각형 격자 메시 하나를 생성한 후, 정점들의 높이를 적절히 조정해서 지형을 만들 수 있다.
    • 격자 정점정보 생성, 격자 색인정보 생성, y값 추출해서 높이 조절하는 순서로 지형을 만든다.



     

    1-1 격자 정점 및 색인 생성
    MeshData GeometryGenerator::CreateGrid(float width, float depth, uint32 m, uint32 n)
    {
        MeshData meshData;
    
        uint32 vertexCount = m*n;
        uint32 faceCount   = (m-1)*(n-1)*2;
    
        float halfWidth = 0.5f*width;
        float halfDepth = 0.5f*depth;
    
        float dx = width / (n-1);
        float dz = depth / (m-1);
    
        float du = 1.0f / (n-1);
        float dv = 1.0f / (m-1);
    
        //정점
        meshData.Vertices.resize(vertexCount);
        for(uint32 i = 0; i < m; ++i)
        {
            float z = halfDepth - i*dz;
            for(uint32 j = 0; j < n; ++j)
            {
                float x = -halfWidth + j*dx;
    
                meshData.Vertices[i*n+j].Position = XMFLOAT3(x, 0.0f, z);
                meshData.Vertices[i*n+j].Normal   = XMFLOAT3(0.0f, 1.0f, 0.0f);
                meshData.Vertices[i*n+j].TangentU = XMFLOAT3(1.0f, 0.0f, 0.0f);
    
                // Stretch texture over grid.
                meshData.Vertices[i*n+j].TexC.x = j*du;
                meshData.Vertices[i*n+j].TexC.y = i*dv;
            }
        }
    
         // 색인
        meshData.Indices32.resize(faceCount*3); // 면마다 3개의 인덱스 필요
    
        // Iterate over each quad and compute indices.
        uint32 k = 0;
        for(uint32 i = 0; i < m-1; ++i)
        {
            for(uint32 j = 0; j < n-1; ++j)
            {
                meshData.Indices32[k]   = i*n+j;
                meshData.Indices32[k+1] = i*n+j+1;
                meshData.Indices32[k+2] = (i+1)*n+j;
    
                meshData.Indices32[k+3] = (i+1)*n+j;
                meshData.Indices32[k+4] = i*n+j+1;
                meshData.Indices32[k+5] = (i+1)*n+j+1;
    
                k += 6; // next quad
            }
        }
    
        return meshData;
    }
    
    



     

     

     

    1-2 높이 함수
    void LandAndWavesApp::BuildLandGeometry()
    {
        GeometryGenerator geoGen;
        GeometryGenerator::MeshData grid = geoGen.CreateGrid(160.0f, 160.0f, 50, 50);
    
        //
        // 필요한 정점 성분들을 추출해서 각 정점에 높이 함수를 적용한다.
        // 그 높이에 기초해서 정점의 색상도 적절히 바꾼다.
        // 
    
        std::vector<Vertex> vertices(grid.Vertices.size());
        for(size_t i = 0; i < grid.Vertices.size(); ++i)
        {
            auto& p = grid.Vertices[i].Position;
            vertices[i].Pos = p;
            vertices[i].Pos.y = GetHillsHeight(p.x, p.z);
    
            // 높이로 정점의 색상 결정
            if(vertices[i].Pos.y < -10.0f)
            {
                // 모래 색
                vertices[i].Color = XMFLOAT4(1.0f, 0.96f, 0.62f, 1.0f);
            }
            else if(vertices[i].Pos.y < 5.0f)
            {
                // 풀 색
                vertices[i].Color = XMFLOAT4(0.48f, 0.77f, 0.46f, 1.0f);
            }
            else if(vertices[i].Pos.y < 12.0f)
            {
                // 검풀색
                vertices[i].Color = XMFLOAT4(0.1f, 0.48f, 0.19f, 1.0f);
            }
            else if(vertices[i].Pos.y < 20.0f)
            {
                // 검갈색
                vertices[i].Color = XMFLOAT4(0.45f, 0.39f, 0.34f, 1.0f);
            }
            else
            {
                // 눈색
                vertices[i].Color = XMFLOAT4(1.0f, 1.0f, 1.0f, 1.0f);
            }
        }
    
        const UINT vbByteSize = (UINT)vertices.size() * sizeof(Vertex);
    
        std::vector<std::uint16_t> indices = grid.GetIndices16();
        const UINT ibByteSize = (UINT)indices.size() * sizeof(std::uint16_t);
    
        auto geo = std::make_unique<MeshGeometry>();
        geo->Name = "landGeo";
    
        ThrowIfFailed(D3DCreateBlob(vbByteSize, &geo->VertexBufferCPU));
        CopyMemory(geo->VertexBufferCPU->GetBufferPointer(), vertices.data(), vbByteSize);
    
        ThrowIfFailed(D3DCreateBlob(ibByteSize, &geo->IndexBufferCPU));
        CopyMemory(geo->IndexBufferCPU->GetBufferPointer(), indices.data(), ibByteSize);
    
        geo->VertexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
            mCommandList.Get(), vertices.data(), vbByteSize, geo->VertexBufferUploader);
    
        geo->IndexBufferGPU = d3dUtil::CreateDefaultBuffer(md3dDevice.Get(),
            mCommandList.Get(), indices.data(), ibByteSize, geo->IndexBufferUploader);
    
        geo->VertexByteStride = sizeof(Vertex);
        geo->VertexBufferByteSize = vbByteSize;
        geo->IndexFormat = DXGI_FORMAT_R16_UINT;
        geo->IndexBufferByteSize = ibByteSize;
    
        SubmeshGeometry submesh;
        submesh.IndexCount = (UINT)indices.size();
        submesh.StartIndexLocation = 0;
        submesh.BaseVertexLocation = 0;
    
        geo->DrawArgs["grid"] = submesh;
    
        mGeometries["landGeo"] = std::move(geo);
    }
    





     

     

     

    2. 파도와 동적 정점버퍼
    • 파도를 구현하기 위해서는 만들어진 격자의 높이값을 동적으로 변환시켜야한다.
    • 디폴트 힙은 앞서 정적인 기하구조에 적합하다는 것을 배웠다.
    • 동적으로 변하는 기하구조를 위해서는 업로드힙에 올려놓고 씨피유가 빠르게 접근할 수 있도록 설정해야 한다는 것을 우리는 이미 알고 있다.

    ex) 파도 생성 동적 정점버퍼

    void LandAndWavesApp::UpdateWaves(const GameTimer& gt)
    {
        // 4분의 1초마다 무작위로 파도를 생성함.
        static float t_base = 0.0f;
        if((mTimer.TotalTime() - t_base) >= 0.25f)
        {
            t_base += 0.25f;
    
            int i = MathHelper::Rand(4, mWaves->RowCount() - 5);
            int j = MathHelper::Rand(4, mWaves->ColumnCount() - 5);
    
            float r = MathHelper::RandF(0.2f, 0.5f);
    
            mWaves->Disturb(i, j, r);
        }
    
        // 파도를 시간으로 갱신함
        mWaves->Update(gt.DeltaTime());
    
        // 새 정점들로 파도 정점버퍼 갱신함
        auto currWavesVB = mCurrFrameResource->WavesVB.get();
        for(int i = 0; i < mWaves->VertexCount(); ++i)
        {
            Vertex v;
    
            v.Pos = mWaves->Position(i);
            v.Color = XMFLOAT4(DirectX::Colors::Blue);
    
            currWavesVB->CopyData(i, v);
        }
    
        // 파도 동적 정점버퍼를 렌더할 정점버퍼로 설정함.
        mWavesRitem->Geo->VertexBufferGPU = currWavesVB->Resource();
    }
    • 동적버퍼는 CPU에서 새 자료를 GPU로 전송하는 데 따른 추가부담이 분명히 발생한다.
    • 따라서 최대한 사용을 줄이는 것이 바람직하다.
    • D3D 최근 버전들에서는 다음과 같은 개선사항으로 동적 버퍼 사용을 줄일 수 있게 되었다
    • 간단한 애니메이션은 정점 셰이더에서 수행할 수 있다.
    • 계산 셰이더를 사용하면 동적 계산을 전적으로 GPU에서 실행하는 것이 가능하다
    • 기하 셰이더를 이용하면 정점 생성파괴를 CPU대신 GPU에서 수행할 수 있다
    • 테셀레이션을 이용하면 GPU에서 세밀한 기하구조를 추가할 수 있다.





     

     

    728x90

    'Software > DirectX' 카테고리의 다른 글

    13. 빛  (0) 2024.05.24
    12. 조명  (1) 2024.05.24
    10. D3D 그리기 연산  (0) 2024.05.24
    9. D3D 실제 구현  (0) 2024.05.24
    8. 테셀레이션 ( Tessellation )과 기하 쉐이더 ( Geometry shader )  (0) 2024.05.24