天天看點

Directx11:基于GeometryShader的Billboard公告闆繪制

  •     公告闆是遊戲裡一很常見的技術,用來繪制樹木,草地,爆炸效果等。說白了就求一個矩形框,然後貼一張照片上去。(Ps下由于個人部落格是以講的比較随便,有時候講billboard,有時候公告闆,有時候一個矩形框,都指差不多一個東西)

        而Geometry Shader則是Directx10裡面推出的一個新的Shader能夠處理完整的幾何模型。想典型VertexShader隻知道并處理頂點,而Geometry Shader知道頂點,直線和三角形并處理它們。

        這裡用個Demo闡述下如何用GeomtryShader在GPU中繪制Billboard公告闆。

        1先講下求公告闆的算法。說白了就是求它的世界坐标系。

        假設這個公告闆上方的向量是v,面向我們眼睛向量w,公告闆右手方向u。公告闆中心位置為C,我們眼睛位置為E,則有:

    Directx11:基于GeometryShader的Billboard公告闆繪制
        用圖表達下場景:
    Directx11:基于GeometryShader的Billboard公告闆繪制
       則該公告闆的世界坐标系為
    Directx11:基于GeometryShader的Billboard公告闆繪制

        知道了其算法後,在GeomtryShader中我們主要根據傳進來的公告闆的中心點位置,求它的世界矩坐标系轉換陣。

    view source print ?

    01.

    [maxvertexcount(4)]

    02.

    03.

    void

    GS(point VS_OUT gIn[1],uint primID:SV_PrimitiveID,inout TriangleStream<GS_OUT> triStream)

    04.

    05.

    {

    06.

    07.

    float

    halfWidth=0.5f*gIn[0].sizeW.x;

    08.

    09.

    float

    halfHeight=0.5f*gIn[0].sizeW.y;

    10.

    11.

    float4 v[4];

    12.

    13.

    v[0]=float4(-halfWidth,-halfHeight,0.0f,1.0f);

    14.

    15.

    v[1]=float4(halfWidth,-halfHeight,0.0f,1.0f);

    16.

    17.

    v[2]=float4(-halfWidth,halfHeight,0.0f,1.0f);

    18.

    19.

    v[3]=float4(halfWidth,halfHeight,0.0f,1.0f);

    20.

    21.

    float2 texC[4];

    22.

    23.

    texC[0]=float2(0.0f,1.0f);

    24.

    25.

    texC[1]=float2(1.0f,1.0f);

    26.

    27.

    texC[2]=float2(0.0f,0.0f);

    28.

    29.

    texC[3]=float2(1.0f,0.0f);

    30.

    31.

    float3 up=float3(0.0f,1.0f,0.0f);

    32.

    33.

    float3 look=gEyePosW-gIn[0].posW;

    34.

    35.

    look.y=0.0f;

    36.

    37.

    look=normalize(look);

    38.

    39.

    float3 right=cross(up,look);

    40.

    41.

    matrix world;

    42.

    43.

    world[0]=float4(right,0.0f);

    44.

    45.

    world[1]=float4(up,0.0f);

    46.

    47.

    world[2]=float4(look,0.0f);

    48.

    49.

    world[3]=float4(gIn[0].posW,1.0f);

    50.

    51.

    GS_OUT gOut;

    52.

    53.

    //[unroll]

    54.

    55.

    for

    (

    int

    i=0;i<4;i++)

    56.

    57.

    {

    58.

    59.

    gOut.posW=mul(v[i],world);

    60.

    61.

    gOut.posH=mul(v[i],world);

    62.

    63.

    gOut.posH=mul(gOut.posH,View);

    64.

    65.

    gOut.posH=mul(gOut.posH,Projection);

    66.

    67.

    gOut.normalW=look;

    68.

    69.

    gOut.texC=texC[i];

    70.

    71.

    gOut.primID=primID;

    72.

    73.

    triStream.Append(gOut);

    74.

    75.

    }

    76.

    77.

    }

        2了解了公告闆的算法以及如何在GeometryShader中實作這個算法之後,因為上面得到的隻是一堆矩形框的位置,是以我們需要載入一組紋理圖檔,友善把這些紋理貼到這些矩形框上去。

        總的來說我們是把幾張紋理圖檔放到一個texture2Darray裡。Directx11用ID3D11Texture2D 表示這個2d紋理數組(沒看錯,不管是一張紋理,還是多張,Directx11都是ID3D11Texture2D 來表示)。

        建立步驟:

        1讀入圖檔,為每一張圖檔建立一個ID3D11Texture2D srcTex[i]。

        2建立用來存儲上面所有紋理的紋理數組ID3D11Texture2D texArray;

        3将每個紋理srcTex[i]拷貝到texArray相應的位置。

        4為texArray建立一個shader resource view.

        具體函數如下:

    view source print ?

    001.

    HRESULT

    Tree::BuildShaderResourceView()

    002.

    003.

    {

    004.

    005.

    HRESULT

    hr=S_OK;

    006.

    007.

    std::wstring filenames[4]={ L

    "tree0.dds"

    ,L

    "tree1.dds"

    ,L

    "tree2.dds"

    ,L

    "tree3.dds"

    };

    008.

    009.

    // 1讀入圖檔,為每一張圖檔建立一個ID3D11Texture2D srcTex[i]。

    010.

    011.

    ID3D11Texture2D* srcTex[4];

    012.

    013.

    for

    (

    UINT

    i=0;i<4;i++)

    014.

    015.

    {

    016.

    017.

    D3DX11_IMAGE_LOAD_INFO loadInfo;

    018.

    019.

    loadInfo.Width=D3DX11_DEFAULT;

    020.

    021.

    loadInfo.Height=D3DX11_DEFAULT;

    022.

    023.

    loadInfo.Depth=D3DX11_DEFAULT;

    024.

    025.

    loadInfo.CpuAccessFlags=D3D11_CPU_ACCESS_READ;

    026.

    027.

    loadInfo.BindFlags=0;

    028.

    029.

    loadInfo.Filter=D3DX11_FILTER_NONE;

    030.

    031.

    loadInfo.MipFilter=D3DX11_FILTER_NONE;

    032.

    033.

    loadInfo.FirstMipLevel=0;

    034.

    035.

    loadInfo.Format=DXGI_FORMAT_R8G8B8A8_UNORM;

    036.

    037.

    loadInfo.MipLevels=D3DX11_DEFAULT;

    038.

    039.

    loadInfo.MiscFlags=0;

    040.

    041.

    loadInfo.Usage=D3D11_USAGE_STAGING;

    042.

    043.

    loadInfo.pSrcInfo=0;

    044.

    045.

    IFR(D3DX11CreateTextureFromFile(m_pDevice,filenames[i].c_str(),&loadInfo,NULL,(ID3D11Resource**)&srcTex[i],NULL));

    046.

    047.

    }

    048.

    049.

    //2建立用來存儲上面所有紋理的紋理數組ID3D11Texture2D texArray;

    050.

    051.

    D3D11_TEXTURE2D_DESC texDesc;

    052.

    053.

    srcTex[0]->GetDesc(&texDesc);

    054.

    055.

    D3D11_TEXTURE2D_DESC texArrayDesc;

    056.

    057.

    texArrayDesc.Width=texDesc.Width;

    058.

    059.

    texArrayDesc.Height=texDesc.Height;

    060.

    061.

    texArrayDesc.MipLevels=texDesc.MipLevels;

    062.

    063.

    texArrayDesc.ArraySize=4;

    064.

    065.

    texArrayDesc.BindFlags=D3D11_BIND_SHADER_RESOURCE;

    066.

    067.

    texArrayDesc.Format=DXGI_FORMAT_R8G8B8A8_UNORM;

    068.

    069.

    texArrayDesc.CPUAccessFlags=0;

    070.

    071.

    texArrayDesc.SampleDesc.Count=1;

    072.

    073.

    texArrayDesc.SampleDesc.Quality=0;

    074.

    075.

    texArrayDesc.MiscFlags=0;

    076.

    077.

    texArrayDesc.Usage=D3D11_USAGE_DEFAULT;

    078.

    079.

    ID3D11Texture2D *texArray=NULL;

    080.

    081.

    IFR(m_pDevice->CreateTexture2D(&texArrayDesc,NULL,&texArray));

    082.

    083.

    //3将每個紋理srcTex[i]拷貝到texArray相應的位置。

    084.

    085.

    for

    (

    int

    i=0;i<4;i++)

    086.

    087.

    {

    088.

    089.

    for

    (

    int

    j=0;j<texDesc.MipLevels;j++)

    090.

    091.

    {

    092.

    093.

    D3D11_MAPPED_SUBRESOURCE subTex;

    094.

    095.

    m_pContext->Map(srcTex[i],j,D3D11_MAP_READ,0,&subTex);

    096.

    097.

    m_pContext->UpdateSubresource(texArray,D3D11CalcSubresource(j,i,texDesc.MipLevels),NULL,subTex.pData,subTex.RowPitch,0);

    098.

    099.

    m_pContext->Unmap(srcTex[i],j);

    100.

    101.

    }

    102.

    103.

    }

    104.

    105.

    //4為texArray建立一個shader resource view.

    106.

    107.

    D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc;

    108.

    109.

    ZeroMemory(&srvDesc,

    sizeof

    (srvDesc));

    110.

    111.

    srvDesc.Format=texArrayDesc.Format;

    112.

    113.

    srvDesc.Texture2DArray.MipLevels=texArrayDesc.MipLevels;

    114.

    115.

    srvDesc.Texture2DArray.MostDetailedMip=0;

    116.

    117.

    srvDesc.Texture2DArray.ArraySize=4;

    118.

    119.

    srvDesc.Texture2DArray.FirstArraySlice=0;

    120.

    121.

    srvDesc.ViewDimension=D3D11_SRV_DIMENSION_TEXTURE2DARRAY;

    122.

    123.

    IFR(m_pDevice->CreateShaderResourceView(texArray,&srvDesc,&m_pTreeMapRV));

    124.

    125.

    SAFE_RELEASE(texArray);

    126.

    127.

    for

    (

    int

    i=0;i<4;i++)

    128.

    129.

    SAFE_RELEASE(srcTex[i]);

    130.

    131.

    return

    hr;

    132.

    133.

    }

      最後我把Vertex,Geometry,還有特别負責繪制的Pixel Shader的具體代碼都貼出來。

    view source print ?

    001.

    VS_OUT VS(VS_IN vIn)

    002.

    003.

    {

    004.

    005.

    VS_OUT vOut;

    006.

    007.

    vOut.posW=vIn.posW;

    008.

    009.

    vOut.sizeW=vIn.sizeW;

    010.

    011.

    return

    vOut;

    012.

    013.

    }

    014.

    015.

    016.

    017.

    [maxvertexcount(4)]

    018.

    019.

    void

    GS(point VS_OUT gIn[1],uint primID:SV_PrimitiveID,inout TriangleStream<GS_OUT> triStream)

    020.

    021.

    {

    022.

    023.

    float

    halfWidth=0.5f*gIn[0].sizeW.x;

    024.

    025.

    float

    halfHeight=0.5f*gIn[0].sizeW.y;

    026.

    027.

    float4 v[4];

    028.

    029.

    v[0]=float4(-halfWidth,-halfHeight,0.0f,1.0f);

    030.

    031.

    v[1]=float4(halfWidth,-halfHeight,0.0f,1.0f);

    032.

    033.

    v[2]=float4(-halfWidth,halfHeight,0.0f,1.0f);

    034.

    035.

    v[3]=float4(halfWidth,halfHeight,0.0f,1.0f);

    036.

    037.

    float2 texC[4];

    038.

    039.

    texC[0]=float2(0.0f,1.0f);

    040.

    041.

    texC[1]=float2(1.0f,1.0f);

    042.

    043.

    texC[2]=float2(0.0f,0.0f);

    044.

    045.

    texC[3]=float2(1.0f,0.0f);

    046.

    047.

    float3 up=float3(0.0f,1.0f,0.0f);

    048.

    049.

    float3 look=gEyePosW-gIn[0].posW;

    050.

    051.

    look.y=0.0f;

    052.

    053.

    look=normalize(look);

    054.

    055.

    float3 right=cross(up,look);

    056.

    057.

    matrix world;

    058.

    059.

    world[0]=float4(right,0.0f);

    060.

    061.

    world[1]=float4(up,0.0f);

    062.

    063.

    world[2]=float4(look,0.0f);

    064.

    065.

    world[3]=float4(gIn[0].posW,1.0f);

    066.

    067.

    GS_OUT gOut;

    068.

    069.

    //[unroll]

    070.

    071.

    for

    (

    int

    i=0;i<4;i++)

    072.

    073.

    {

    074.

    075.

    gOut.posW=mul(v[i],world);

    076.

    077.

    gOut.posH=mul(v[i],world);

    078.

    079.

    gOut.posH=mul(gOut.posH,View);

    080.

    081.

    gOut.posH=mul(gOut.posH,Projection);

    082.

    083.

    gOut.normalW=look;

    084.

    085.

    gOut.texC=texC[i];

    086.

    087.

    gOut.primID=primID;

    088.

    089.

    triStream.Append(gOut);

    090.

    091.

    }

    092.

    093.

    }

    094.

    095.

    096.

    097.

    float4 PS(GS_OUT pIn):SV_Target

    098.

    099.

    {

    100.

    101.

    float3 uvw=float3(pIn.texC,pIn.primID%4);

    102.

    103.

    float4 diffuse=gDiffuseMap.Sample(gLinearSam,uvw);

    104.

    105.

    clip(diffuse.a-0.5f);

    106.

    107.

    return

    diffuse;

    108.

    109.

    //return float4(1.0f,0.0f,0.0f,0.5f);

    110.

    111.

    }

        最後實驗截圖,我們的樹都是公告闆生成的。
    Directx11:基于GeometryShader的Billboard公告闆繪制

延伸閱讀:

  • 1、Directx11基于GeometryShader的粒子系統
  • 2、Directx11與PhysX的結合
  • 3、Directx11_使用Effect架構包裝ComputeShader
  • 4、Directx11_使用Effect架構包裝ComputeShader

繼續閱讀