终于到了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,睡觉了