天天看點

DirectX11 地形水波紋理示例Demo地形水波紋理示例Demo

地形水波紋理示例Demo

1. 地形水波紋理示例Demo介紹

在本例中,我們要為地形和水體添加紋理。首先,我們要在地形上平鋪一幅草地紋理。 由于地形網格很大,如果我們直接拉伸紋理,那麼每個三角形隻能得到很少的幾個紋理元素。換句話說,這裡無法為表面提供足夠高的紋理分辨率;我們會受到倍增問題的影響。是以,我們要在地面網格上平鋪草地紋理,進而獲得較高的分辨率。其次,我們要通過一個時間函數對水體紋理進行平移,使水體顯得更真實一些。

2. 生成網格紋理坐标

圖8.16是一個建立在xz平面上的m×n網格以及一個在規範化紋理空間[0,1]2中的對應網格。可以看到,xz平面上的第ij個網格頂點的紋理坐标對應于紋理空間中的第ij個網格頂點的坐标。第ij個頂點對應的紋理空間坐标為:

uij = j ∙ ∆u

vij = i ∙ ∆v

其中,∆u = 1/(n-1) ,∆v = 1/(m-1) 。

DirectX11 地形水波紋理示例Demo地形水波紋理示例Demo

(空間中的網格頂點vij的紋理坐标等于uv空間中的第ij個網格頂點Tij的坐标。)

是以,我們可以使用如下代碼為地面網格生成紋理坐标:

void GeometryGenerator::CreateGrid(float width, float depth, UINT m, UINT n, MeshData& meshData)
{
    UINT vertexCount = m*n;
    UINT faceCount   = (m-)*(n-)*;

    //
    // 建立頂點
    //

    float halfWidth = *width;
    float halfDepth = *depth;

    float dx = width / (n-);
    float dz = depth / (m-);

    float du =  / (n-);
    float dv =  / (m-);

    meshData.Vertices.resize(vertexCount);
    for(UINT i = ; i < m; ++i)
    {
        float z = halfDepth - i*dz;
        for(UINT j = ; j < n; ++j)
        {
            float x = -halfWidth + j*dx;

            meshData.Vertices[i*n+j].Position = XMFLOAT3(x, , z);
            meshData.Vertices[i*n+j].Normal   = XMFLOAT3(, , );
            meshData.Vertices[i*n+j].TangentU = XMFLOAT3(, , );

            // 在網格上拉伸紋理
            meshData.Vertices[i*n+j].TexC.x = j*du;
            meshData.Vertices[i*n+j].TexC.y = i*dv;
        }
    }

    …
}
           

3. 紋理平鋪

前面提到,我們希望在地形網格上平鋪一幅草地紋理。但是,目前計算出來的紋理坐标是在機關區間[0,1]2中的,無法産生平鋪。是以,我們要指定重複尋址模式并通過一個紋理變換矩陣将紋理坐标擴大5倍。這樣,紋理坐标會被映射到[0,5]2區間内,使紋理在地形網格表面平鋪5×5次:

XMMATRIX grassTexScale = XMMatrixScaling(f, f, f);
XMStoreFloat4x4(&mGrassTexTransform, grassTexScale);
…
Effects::BasicFX->SetTexTransform(XMLoadFloat4x4(&mGrassTexTransform));
…
activeTech->GetPassByIndex(p)->Apply(, md3dImmediateContext);
md3dImmediateContext->DrawIndexed(mLandIndexCount, , );
           

4. 紋理動畫

我們要通過一個位于UpdateScene方法中的時間函數在紋理空間中平移紋理坐标,使水體紋理在網格上移動。我們為每幀提供一個很小的位移量,以得到一個平滑動畫。我們同時使用無縫紋理和重複尋址模式,以使紋理坐标在平移時不出現間斷。下面的代碼示範了如何為水體紋理計算位移量,并生成和設定水體的紋理矩陣:

// 平鋪水面紋理
XMMATRIX wavesScale = XMMatrixScaling(, , );

// 根據時間平移紋理
mWaterTexOffset.y += *dt;
mWaterTexOffset.x += *dt;  
XMMATRIX wavesOffset = XMMatrixTranslation(mWaterTexOffset.x, mWaterTexOffset.y, );

// 組合縮放和平移
XMStoreFloat4x4(&mWaterTexTransform, wavesScale*wavesOffset);
…
Effects::BasicFX->SetTexTransform(XMLoadFloat4x4(&mWaterTexTransform));
…
activeTech->GetPassByIndex(p)->Apply(, md3dImmediateContext);
           

5. 程式運作結果截圖

項目完整源代碼請到DirectX11 龍書官網下載下傳。

DirectX11 地形水波紋理示例Demo地形水波紋理示例Demo
DirectX11 地形水波紋理示例Demo地形水波紋理示例Demo

繼續閱讀