10,billboard(几何着色器)

终于到了DX10中的精华部分了,那就是几何着色器。一定要把它搞完再睡觉。

 

几何着色器特点

1,位于顶点着色器和像素着色器之间

2,流程:给你几个箱子,可以把这些箱子拆了,变成几个圆筒,材料不够了可以加,材料多余了可以扔。

 

注意事项

在顶点离开几何着色器之前,顶点坐标必须变换到齐次裁剪空间。

 

[maxvertexcount(能输出的顶点的最大数量)]
void GS(
输入图元类型 VS_OUT 输入图元数组名【输入图元个数],
inout 输出几何流类型<GS_OUT> 输出流名称)

其中,输入输出图元类型任意,点线三角形均可。

在pass中,也会加上GS

technique10 TreeBillboardTech
{
    pass P0
    {
        SetVertexShader(CompileShader(vs_4_0, VS()));
        SetGeometryShader(CompileShader(gs_4_0, GS()));
        SetPixelShader(CompileShader(ps_4_0, PS()));
    }
}

 

在这个例子里,是广告牌,简而言之,由一个点转成四边形,加上纹理。矩形的法线要时刻指向摄像机,

 

所以,在顶点结构体上要有中心点和矩形宽度


struct TreeVertex
{
    D3DXVECTOR3 centerW;
    D3DXVECTOR2 sizeW;
};

    D3D10_INPUT_ELEMENT_DESC vertexDesc[] =
    {
        { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D10_INPUT_PER_VERTEX_DATA, 0 },
        { "SIZE", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D10_INPUT_PER_VERTEX_DATA, 0 },
    };

由此来创建输入布局

    D3D10_PASS_DESC passDesc;
    mTech->GetPassByIndex(0)->GetDesc(&passDesc);
    md3dDevice->CreateInputLayout(vertexDesc, 2, passDesc.pIAInputSignature, passDesc.IAInputSignatureSize, &mVertexLayout);

 

对于这个纹理数组,相对比较麻烦
1. 分别创建每个纹理对象。
2. 创建纹理数组对象。
3. 将每个纹理对象依次复制到纹理数组元素中去。
4. 为纹理数组对象创建一个着色器资源视图。

大致如下:

D3DX10CreateTextureFromFile(md3dDevice, fileNames[i].c_str(), &loadInfo, 0, (ID3D10Resource**)&srcTex[i], 0);

    //单个纹理描述
    D3D10_TEXTURE2D_DESC texElementDesc;
    srcTex[0]->GetDesc(&texElementDesc);

//根据单个纹理描述和纹理数组个数等创建整个纹理数组描述
    D3D10_TEXTURE2D_DESC texArrayDesc;

//根据纹理数组描述创建纹理数组
    ID3D10Texture2D* texArray = 0;
    md3dDevice->CreateTexture2D(&texArrayDesc, 0, &texArray);

        //计算纹理子资源索引
            md3dDevice->UpdateSubresource(texArray, D3D10CalcSubresource(j, i, texElementDesc.MipLevels), 0, mappedTex2D.pData, mappedTex2D.RowPitch, 0);

//创建一个着色器资源视图。

    md3dDevice->CreateShaderResourceView(texArray, &viewDesc, &mTreeMapArrayRV);

 

从上边可以看到,有个纹理子资源索引,在GS中可以当个可选项。即无符号整数参数。标识为

uint primID : SV_PrimitiveID

从算法上可以看到,

需要三个参数

1,摄像机位置

2,投影矩阵

3,着色器资源视图

 

    mTech = mFX->GetTechniqueByName("TreeBillboardTech");
    mfxViewProjVar = mFX->GetVariableByName("gViewProj")->AsMatrix();
    mfxEyePosVar = mFX->GetVariableByName("gEyePosW");
    mfxTreeMapArrayVar = mFX->GetVariableByName("gDiffuseMapArray")->AsShaderResource();

每帧设置参数

    mfxEyePosVar->SetRawValue((void*)& eyePosW, 0, sizeof(D3DXVECTOR3));
    mfxViewProjVar->SetMatrix((float*)& viewProj);
    mfxTreeMapArrayVar->SetResource(mTreeMapArrayRV);

看看shader中,主要就是几何着色器了,其实算法已经明了,可以直接拷贝所有代码过来了

//=============================================================================
// tree.fx by Frank Luna (C) 2008 All Rights Reserved.
//
// Uses the geometry shader to expand points into y-axis aligned billboards.
//=============================================================================

#include "lighthelper.fx"

cbuffer cbPerFrame
{
    float3 gEyePosW;
    float4x4 gViewProj;
};

Texture2DArray gDiffuseMapArray;

SamplerState gTriLinearSam
{
    Filter = MIN_MAG_MIP_LINEAR;
    AddressU = Wrap;
    AddressV = Wrap;
};

struct VS_IN
{
    float3     centerW        :    POSITION;
    float2    sizeW        :    SIZE;
};

struct VS_OUT
{
    float3     centerW        :    POSITION;
    float2    sizeW        :    SIZE;
};

struct GS_OUT
{
    float4    posH        :    SV_POSITION;
    float3    posW        :    POSITION;
    float3    normalW        :    NORMAL;
    float2    texC        :    TEXCOORD;
    uint    primID        :    SV_PrimitiveID;
};
 
VS_OUT VS( VS_IN vIn)
        {
            VS_OUT    vOut;
            //转到世界坐标
            vOut.centerW = vIn.centerW;
            vOut.sizeW = vIn.sizeW;
            
            return vOut;
        }

[maxvertexcount(4)]
void GS(    point VS_OUT    gIn[1],
    uint primID : SV_PrimitiveID,
    inout TriangleStream<GS_OUT> triStream )
{
    float halfWidth = 0.5f * gIn[0].sizeW.x;
    float halfHeight = 0.5f * gIn[0].sizeW.y;
    
    float4 v[4];
    v[0] = float4(-halfWidth, -halfHeight, 0.0f, 1.0f );
    v[1] = float4(+halfWidth, -halfHeight, 0.0f, 1.0f );
    v[2] = float4(-halfWidth, +halfHeight, 0.0f, 1.0f );
    v[3] = float4(+halfWidth,+halfHeight, 0.0f, 1.0f );

    float2 texC[4];
    texC[0] = float2(0.0f, 1.0f );
    texC[1] = float2(1.0f, 1.0f );
    texC[2] = float2(0.0f, 0.0f );
    texC[3] = float2(1.0f, 0.0f );

    float3 up = float3(0.0f, 1.0f, 0.0f );
    float3 look = gEyePosW - gIn[0].centerW;
    look.y = 0.0f;
    look = normalize(look);
    float3 right = cross(up, look);
    
    float4x4 W;
    W[0] = float4( right,  0.0f);
    W[1] = float4( up, 0.0f );
    W[2] = float4( look, 0.0f );
    W[3] = float4( gIn[0].centerW, 1.0f);

    float4x4 WVP = mul(W, gViewProj );
    
    GS_OUT    gOut;
    [unroll]
    for(int i = 0; i < 4; i ++ )
    {
        gOut.posH = mul(v[i], WVP);
        gOut.posW = mul(v[i], W );
        gOut.normalW = look;
        gOut.texC = texC[i];
        gOut.primID = primID;

        triStream.Append(gOut);
    }

}
float4 PS( GS_OUT pIn) : SV_Target
        {
            float3 uvw = float3(pIn.texC, pIn.primID % 4);
            float4 diffuse = gDiffuseMapArray.Sample(gTriLinearSam,uvw);
            clip(diffuse.a - 0.25f);
            return diffuse;
        }
technique10 TreeBillboardTech
{
    pass P0
    {
        SetVertexShader( CompileShader(   vs_4_0, VS() ) );
        SetGeometryShader( CompileShader( gs_4_0, GS() ) );
        SetPixelShader( CompileShader(    ps_4_0, PS() ) );
    }
}

 

 

 

 

最后一项,上图

 

 

OK,睡觉了

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值