UnityShader[4]几何着色器与可交互草地

本文介绍了如何使用Unity的Geometry Shader创建交互式草地效果。通过几何着色器,可以实现从单个三角形生成点阵、线段到复杂形状的变换。在生成大面积草地的过程中,通过随机数控制每个草的旋转、弯曲和摆动,从而营造出逼真的草地。同时,文章还详细讲解了如何处理草地的交互,如踩踏效果,使得草地在受到碰撞时能够有适当的反应。通过这种方法,不仅可以降低DrawCall,还能实现丰富的视觉效果和互动体验。
摘要由CSDN通过智能技术生成

GeometryShader执行顺序在顶点着色器之后,片元着色器以前。GeometryShader以一个/多个顶点组成的图元为输入,开发人员可以修改/添加顶点,修改为完全不同的网格,得到更多好看的效果。
缺点:并行困难,对移动端不友好,需要ShaderModel4.0以上
定义一个几何着色器,首先需要在声明模块添加几何着色器的声明;添加顶点着色器向几何着色器输出的结构体;修改ShaderModel版本为4.0以上

#pragma vertex vert
#pragma geometry geo
#pragma fragment frag

#include "UnityCG.cginc"
#pragma target 5.0

struct appdata
{
   
    float4 vertex : POSITION;
    float2 uv : TEXCOORD0;
};

struct v2g
{
   
    float4 vertex : POSITION;
    float2 uv : TEXCOORD0;
};

struct g2f
{
   
    float2 uv : TEXCOORD0;
    float4 vertex : SV_POSITION;
};

然后编写geometryShader主体:

[maxvertexcount(3)] // 最多调用3个顶点
// 输入:point / line / lineadj / triangle / triangleadj
// 输出:LineStream / PointStream / TriangleStream 
void geo(triangle v2g input[3], inout PointStream<g2f> outStream)
{
   
    g2f o;
    o.vertex = input[1].vertex;
    o.uv = input[1].uv;
    outStream.Append(o);
}
  • [maxvertexcount(value)] 代表告诉Shader该几何着色器最多单次调用多少个顶点
  • triangle v2g input[3] 参数代表以一个三角形图元为单位进行输入,包含3个顶点;
  • inout PointStream outStream 参数代表以一个点(PointStream)为单位进行输出;
  • outStream.Append(o) 代表将o点添加到outStream中;

可以看到几何着色器是以流为单位进行输入输出的,输入和输出关键字的区别会让流的解析发生改变,例如输出选择了PointStream,该类型的流会认为给定的数据中包含一个顶点,然后进行解析,将这个顶点输出;而选择了TriangStream则会认为给定的数据包含三个顶点,进行解析时会将三个顶点合成为一个三角形输出
上述代码:输入一个三角形,输出该三角形中的2号顶点(数组中顶点编号0,1,2代表三角形顶点编号1,2,3)。可以得到一个点阵Shader:
在这里插入图片描述

[maxvertexcount(3)]
void geo(triangle v2g input[3], inout LineStream<g2f> outStream)
{
   
    g2f o;
    for(int i=0; i<2; i++)
    {
   
        o.vertex = input[i].vertex;
        o.uv = input[i].uv;
        outStream.Append(o);
    }
}

上述代码:输入一个三角形,输出该三角形的0顶点、1顶点连接成的线段。(网格效果)

在这里插入图片描述

几何着色器还可以根据已有顶点生成新的顶点并构建图形,达到一些其他效果。此处尝试给每个三角形生成中心点:

[maxvertexcount(9)]
void geo(triangle v2g input[3], inout TriangleStream<g2f> outStream)
{
   
    g2f o;

    // 获取中心顶点
    float3 centerPos = (input[0].vertex + input[1].vertex + input[2].vertex) / 3;
    float2 centerUV = (input[0].uv + input[1].uv + input[2].uv) / 3;

    for(uint i=0; i<3; i++)
    {
   
        o.vertex = UnityObjectToClipPos(input[i].vertex);
        o.uv = input[i].uv;
        outStream.Append(o);

        uint j = (i + 1) % 3;
        o.vertex = UnityObjectToClipPos(input[j].vertex);
        o.uv = input[j].uv;
        outStream.Append(o);

        o.vertex = UnityObjectToClipPos(float4(centerPos, 1.0));
        o.uv = centerUV;
        outStream.Append(o);
                    
        // 重置剥
        outStream.RestartStrip();
    }
}

此时要适当提高控制的顶点数(9个,因为会输出3个三角面)。算法计算得出中心点在模型空间中的位置、uv等参数,将三个顶点(0号、1号、中心点)合成一个三角面添加进入outStream,直到将中心点分割得到的三个三角面均添加进入outStream,最后输出:
在这里插入图片描述

需要注意的是,如果先进行了顶点着色,即进入几何着色步骤时顶点已经转换到齐次裁剪空间下,会导致中心顶点计算错误,法线不匹配等问题。解决的方法就是将空间变换算法移动到中心顶点计算之后进行,如上述算法就是将UnityObjectToClipPos写到中心顶点计算完成之后(VertexShader只进行了数据转移操作)。
之后让中心点根据自身法线进行外扩,获取法线方向,然后对中心点坐标进行移动:

float3 edgeA = input[1].vertex - input[0].vertex;
float3 edgeB = input[2].vertex - input[0].vertex;
float3 normal = normalize(cross(edgeA, edgeB));
// 中心点向外挤出
centerPos += normal.xyz * _Length;

可以获得刺球效果:
在这里插入图片描述

生成大面积草地

几何着色器可用于生成网格,如果在其中增加一些随机数,就能让网格获得不同的旋转角度、弯曲程度、高度、摆动速度…足够生成一片随机的草地,而且因为没有使用预设的网格/实例,性能也变得可观。
参考:https://zhuanlan.zhihu.com/p/29632347
首先利用CPU生成大量随机位置,然后GPU在其上生成网格,渲染为草。
草的网格:
在这里插入图片描述

偶数顶点在左侧、奇数顶点在右侧,方便遍历和计算uv。
Shader需要根据给定顶点产生多个上述网格:

[maxvertexcount(30)]
void geo(point v2g input[1], inout TriangleStream<g2f> outStream)
{
   
    const uint vertexCount = 12; // 顶点数量
    g2f o[vertexCount]
UnityShader中的几何着色器(Geometry Shader)是一个可选的着色器阶段,它位于顶点着色器(Vertex Shader)之后,片元着色器(Fragment Shader)之前。几何着色器的主要作用是对输入的图元进行操作,比如产生新的图元,这可以用于实现例如粒子系统、毛发效果等复杂的渲染效果。 在几何着色器中,`triangleadj`是一种图元类型,表示带有相邻顶点的三角形带。这是DirectX 10及以上版本中引入的一种图元类型,与普通的三角形带(`trianglestrip`)不同,`triangleadj`允许每个三角形都访问其相邻的三角形的顶点,这样的相邻信息可以用于生成复杂的几何结构,比如几何体细分或者自定义的轮廓线效果。 在Unity中使用`triangleadj`图元类型,你需要在几何着色器的输入中声明相邻顶点的信息,然后在代码中通过访问这些相邻顶点来进行操作。下面是一个简单的示例代码: ```hlsl [maxvertexcount(6)] void geo(triangleadj VertexInput IN[6], inout TriangleStream<VertexOutput> triStream) { // 假设我们有一个顶点结构体叫做VertexInput,以及输出结构体叫做VertexOutput // 这里是处理每个顶点的代码 // 可以通过IN[0]到IN[5]访问相邻的顶点信息 // 例如,我们可以创建一个新的三角形带,或者对顶点进行其他处理 // ... // 最后将处理后的顶点输出到triStream // ... } ``` 需要注意的是,在Unity中使用几何着色器有一些限制,比如它不支持所有平台,并且在使用时可能需要配置特定的渲染管线。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值