Windows 8 Directx 開發學習筆記(六)添加水模型

HillExample已經完成山峯河谷的模型,可惜的是河谷是旱季的河谷,沒有水。這次的目標就在河谷裏注入水。

首先新建HillWaterExample項目,其配置與HillExample項目相同。然後複製HillExampleCubeRenderer.cppCubeRenderer.h文件到HillWaterExample目錄覆蓋同名文件,這樣可以省去重寫生成山峯模型的代碼。爲了使代碼結構更清晰,打算把生成模型的功能從CubeRenderer類裏抽出來,方便後面增加自定義模型,而CubeRenderer只負責進行渲染。由於CubeRenderer類不再生成Cube,就將它的名稱改爲Renderer。Crtl+Shift+H替換當前項目中所有的CubeRenderer爲Renderer,並重命名對應的.cpp和.h文件。同時把CubeRenderer.h裏兩個結構體的定義剪切到Direct3DBase.h裏,方便其他類使用。

接着右鍵點擊項目->添加->類。


新建HillModel類,編譯器會自動生成.h和.cpp文件。該類將負責定義山峯模型。在HillModel.h包含Direct3DBase.h,以使用頂點結構體。從Renderer類裏抽出頂點相關成員加入HillModel類,同時更改構造方法。

Microsoft::WRL::ComPtr<ID3D11Buffer> m_vertexBuffer;
Microsoft::WRL::ComPtr<ID3D11Buffer> m_indexBuffer;
uint32 m_indexCount;

HillModel類還需要兩個方法InitializeRender,分別負責初始化頂點緩衝區和渲染設置。這兩個方法的代碼都從Renderer類裏抽取。

void Initialize(ID3D11Device* d3dDevice);
void Render(ID3D11DeviceContext* d3dContext);

Initialize方法從Renderer類的CreateDeviceResources方法中抽取createCubeTask包括的代碼。Render方法從Renderer類的Render方法中抽取設置頂點緩衝區的代碼。這兩個方法的最終代碼見附1。完成HillModel類的創建後,開始更新Renderer類。

Renderer.h包含HillModel.h,並向Render類添加HillModel m_hill成員,專門負責山峯模型的頂點設置。

createCubeTask改爲createHillTask在其中添加HillModel的Initialize方法,代碼如下:

auto createHillTask = (createPSTask &&createVSTask).then([this] () {
       m_hill.Initialize(m_d3dDevice.Get());
    });

然後在Render方法末尾添加

m_hill.Render(m_d3dContext.Get());

完成以上工作後,程序功能並沒有變化,只是爲後面添加其他模型提供方便。下面創建WaterModel類。它的成員和方法中都可以直接複製HillModel類的代碼,只有Initialize方法與HillModel有差別,需要稍作改動。要實現藍色水平面,需將模型定義爲藍色,並統一各個頂點在一個水平面上,即各頂點的y座標相同。依此修改WaterModel類的Initialize方法,只需修改頂點生成部分,代碼如下:

const XMFLOAT3 BLUE(0.0f, 0.0f, 1.0f);
 
for(int row=0; row<zRange; ++row)
    {
       float zPos = row*dx;
 
       for(int col=0; col<xRange; ++col)
       {
           float xPos = col*dx;
           float yPos = 0.3f;
           Vertices[xRange*row +col].pos = XMFLOAT3(xPos, yPos, zPos);
           Vertices[xRange*row +col].color = BLUE;
       }
    }

水模型類就此完成,很簡單。接着讓Renderer.h包含WaterModel.h,向Renderer類添加成員WaterModel m_water

CreateDeviceResources方法中添加createWaterTask,當HillModel和WaterModel均初始化完成後設置載入完成。修改後的代碼如下:

auto createHillTask = (createPSTask&& createVSTask).then([this] () {
       m_hill.Initialize(m_d3dDevice.Get());
    });
 
    auto createWaterTask = (createPSTask&& createVSTask).then([this] () {
       m_water.Initialize(m_d3dDevice.Get());
    });
 
    (createHillTask &&createWaterTask).then([this] () {
       m_loadingComplete = true;
    });

最後還需要在Render方法中添加WaterModel的Render方法,如下:

m_hill.Render(m_d3dContext.Get());
m_water.Render(m_d3dContext.Get());

至此工作全部完成,運行後效果如圖2:


另外,在DirectX中有兩種渲染模式,實體模式和線框模式,爲了以後觀察方便,這裏再爲Renderer類增加私有成員Microsoft::WRL::ComPtr<ID3D11RasterizerState>m_rasterState和方法SetFillMode,用來設置渲染模式。

void Renderer::SetFillMode(D3D11_FILL_MODE mode)
{
    D3D11_RASTERIZER_DESC rasterDesc;
    rasterDesc.AntialiasedLineEnable= false;
    rasterDesc.CullMode = D3D11_CULL_BACK;
    rasterDesc.DepthBias = 0;
    rasterDesc.DepthBiasClamp =0.0f;
    rasterDesc.DepthClipEnable = true;
    rasterDesc.FillMode = mode; //實體模式D3D11_FILL_SOLID,線框模式D3D11_FILL_WIREFRAME
    rasterDesc.FrontCounterClockwise= false;
    rasterDesc.MultisampleEnable = false;
    rasterDesc.ScissorEnable = false;
    rasterDesc.SlopeScaledDepthBias= 0.0f;
 
    DX::ThrowIfFailed(
       m_d3dDevice->CreateRasterizerState(
           &rasterDesc,
           &m_rasterState
           )
    );
 
    m_d3dContext->RSSetState(m_rasterState.Get());
}

爲了設置渲染模式,需要在每個模型的Render方法前調用SetFillMode方法,代碼如下:

SetFillMode(D3D11_FILL_SOLID);
m_hill.Render(m_d3dContext.Get());
 
SetFillMode(D3D11_FILL_WIREFRAME);
m_water.Render(m_d3dContext.Get());

程序運行結果如圖3:

 

附1:

void HillModel::Initialize(ID3D11Device* d3dDevice)
{
    const int xRange = 128;
    const int zRange = 128;
    const float dx = 1.0f;
    const XMFLOAT3 WHITE(1.0f, 1.0f,1.0f);
    const XMFLOAT3 BEACH_SAND(1.0f,0.96f, 0.62f);
    const XMFLOAT3LIGHT_YELLOW_GREEN(0.48f, 0.77f, 0.46f);
    const XMFLOAT3DARK_YELLOW_GREEN(0.1f, 0.48f, 0.19f);
    const XMFLOAT3 DARKBROWN(0.45f,0.39f, 0.34f);
 
    VertexPositionColorVertices[xRange*zRange];
 
    for(int row=0;row<zRange; ++row)
    {
       float zPos = row*dx;
 
       for(int col=0;col<xRange; ++col)
       {
           float xPos = col*dx;
           float yPos = 0.3f *(zPos*sinf(0.1f*xPos) + xPos*cosf(0.1*zPos));
           Vertices[xRange*row+ col].pos = XMFLOAT3(xPos, yPos, zPos);
 
           if(yPos < -10.0f)
              Vertices[xRange*row+ col].color = BEACH_SAND;
           else if (yPos < 5.0f)
              Vertices[xRange*row+ col].color = LIGHT_YELLOW_GREEN;
           else if (yPos < 10.0f)
              Vertices[xRange*row+ col].color = DARK_YELLOW_GREEN;
           else if (yPos < 12.0f)
              Vertices[xRange*row+ col].color = DARKBROWN;
           else
              Vertices[xRange*row+ col].color = WHITE;
       }
    }
 
    D3D11_SUBRESOURCE_DATA vertexBufferData ={0};
    vertexBufferData.pSysMem= Vertices;
    vertexBufferData.SysMemPitch= 0;
    vertexBufferData.SysMemSlicePitch= 0;
    CD3D11_BUFFER_DESC vertexBufferDesc(sizeof(Vertices), D3D11_BIND_VERTEX_BUFFER);
    DX::ThrowIfFailed(
       d3dDevice->CreateBuffer(
       &vertexBufferDesc,
       &vertexBufferData,
       &m_vertexBuffer
       )
       );
 
    unsigned shortIndices[3*2*(xRange-1)*(zRange-1)];
 
    int tempIndice = 0;
    for(int row=0;row<(zRange-1); ++row)
    {
       for(int col=0; col<(xRange-1);++col)
       {
           Indices[tempIndice]= xRange*row + col;
           Indices[tempIndice+1]= xRange*row + col + 1;
           Indices[tempIndice+2]= xRange*(row+1) + col;
 
           Indices[tempIndice+3]= xRange*(row+1) + col;
           Indices[tempIndice+4]= xRange*row + col + 1;
           Indices[tempIndice+5]= xRange*(row+1) + col + 1;
 
           tempIndice+= 6;
       }
    }
 
    m_indexCount = ARRAYSIZE(Indices);
 
    D3D11_SUBRESOURCE_DATA indexBufferData ={0};
    indexBufferData.pSysMem= Indices;
    indexBufferData.SysMemPitch= 0;
    indexBufferData.SysMemSlicePitch= 0;
    CD3D11_BUFFER_DESC indexBufferDesc(sizeof(Indices), D3D11_BIND_INDEX_BUFFER);
    DX::ThrowIfFailed(
       d3dDevice->CreateBuffer(
       &indexBufferDesc,
       &indexBufferData,
       &m_indexBuffer
       )
       );
}
 
void HillModel::Render(ID3D11DeviceContext* d3dContext)
{
    UINT stride = sizeof(VertexPositionColor);
    UINT offset = 0;
    d3dContext->IASetVertexBuffers(
       0,
       1,
       m_vertexBuffer.GetAddressOf(),
       &stride,
       &offset
       );
 
    d3dContext->IASetIndexBuffer(
       m_indexBuffer.Get(),
       DXGI_FORMAT_R16_UINT,
       0
       );
 
    d3dContext->DrawIndexed(
       m_indexCount,
       0,
       0
       );
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章