DirectX11 使用几何着色器实现公告板效果

来源:互联网 发布:950 600淘宝轮播图 编辑:程序博客网 时间:2024/05/31 00:39

之前说过,可编程的着色器阶段有三个,依次是顶点着色器、几何着色器、像素着色器。之前说的都是顶点着色器和像素着色器,今天第一次详细介绍几何着色器,几何着色器是一个可选的阶段。

一、使用几何着色器的好处
不像顶点着色器那样,输入一个顶点必须输出一个顶点。在几何着色器中,最大的好处是,你可以创建或销毁顶点,实现一些有趣的效果。例如在本例中,输入公告板的中心顶点,可以扩展出四个边框角顶点(两个三角形)。注意,由几何着色器输出的顶点必须是经过齐次空间投影变换。

几何着色器入口函数定义如下:

[maxvertexcount(N)]void ShaderName (PrimitiveType InputVertexType InputName [NumElements],inout StreamOutputObject<OutputVertexType> OutputName){    // Geometry shader body…}

[maxvertexcount(N)]中的N是自己指定的最大输出顶点数,尽量不要设置太大,否则会造成巨大性能的消耗(书中是1-20为宜)。

输入的图元类型PrimitiveType可以是如下几种:
1. point:点
2. line:线
3. triangle:三角
4. lineadj:邻接线
5. triangleadj:邻接三角

但是顶点类型还是顶点着色器输出的顶点类型。

输出类型总是有inout修饰符,并且是一个steam流类型,添加顶点到流中可以使用Append()方法。流类型可以是如下几种:
1. PointStream:点流
2. LineStream:线流
3. TriangleStream:三角流

二、公告板效果
公告板效果是用2D纹理来代替复杂的3D模型以节省资源,达到视觉欺骗的效果。

相信很多人以前都玩过一款十分经典的游戏《抢滩登陆2002》,当时的电脑显卡跟现在比差太远,但是可以模拟出大量的3D士兵人物,是怎么做到的呢?也是利用了公告板技术。

这里写图片描述

上面的人物都是2D纹理,没有想到吧?因为这款游戏的视角都是固定在中央,使用公告板技术几乎看不出来是2D纹理。所以如果运用恰当,公告板技术也可以发挥出很惊人的效果。即使到了如今显卡这么发达,也有很多网游和单机游戏使用公告板技术来实现草地这种3D模型复杂而且需要大量产生的物体。

下面就来看看如何用公告板技术实现树木的渲染。

首先需要一张2D树木的纹理:

这里写图片描述

(我故意在photoshop中打开,证明它完全只是一张2D图片)

我们重点关注在HLSL的几何着色器代码上。

我们要做的事情是,在几何着色器中将该纹理的中心顶点扩展到四个角顶点。

 // 输出顶点数是4个[maxvertexcount(4)]void GS(point VertexOut gin[1],         uint primID : SV_PrimitiveID,         inout TriangleStream<GeoOut> triStream){       // 根据树的朝向,得到上、前、右向量    float3 up = float3(0.0f, 1.0f, 0.0f);    float3 look = gEyePosW - gin[0].CenterW; //CenterW是中心顶点位置    look.y = 0.0f; // 让y分量为零,这棵树就可以垂直于xz平面    look = normalize(look);    float3 right = cross(up, look);    //    // 根据中心顶点,计算四个角的顶点坐标(三角带形式)    //    float halfWidth  = 0.5f*gin[0].SizeW.x;    float halfHeight = 0.5f*gin[0].SizeW.y;    float4 v[4];    v[0] = float4(gin[0].CenterW + halfWidth*right - halfHeight*up, 1.0f);    v[1] = float4(gin[0].CenterW + halfWidth*right + halfHeight*up, 1.0f);    v[2] = float4(gin[0].CenterW - halfWidth*right - halfHeight*up, 1.0f);    v[3] = float4(gin[0].CenterW - halfWidth*right + halfHeight*up, 1.0f);    //    // 将坐标投影变换到齐次空间    //    GeoOut gout;    [unroll]    for(int i = 0; i < 4; ++i)    {        gout.PosH     = mul(v[i], gViewProj); //这里不需要world投影,因为在应用程序阶段产生了世界坐标。保存了齐次空间坐标。        gout.PosW     = v[i].xyz; //保存世界坐标,像素着色器要进行计算        gout.NormalW  = look;        gout.Tex      = gTexC[i];        gout.PrimID   = primID;        triStream.Append(gout); //将顶点添加到输出流    }}

像素着色器主要做的事情也只是根据顶点位置的进行UV纹理采样。

这里写图片描述

这里写图片描述

粗略一看效果还是可以骗人的。

这里写图片描述

不过,视角一移动到上方就露馅了,所以建议还是远处的物体采用Billboard技术吧~哈哈

示例源代码:
https://github.com/ljcduo/Introduction-to-3D-Game-Programming-With-DirectX11/tree/master/Chapter%2011%20The%20Geometry%20Shader/TreeBillboard

原创粉丝点击