Unity中使用几何着色器制作类似于纪念碑谷的海(Unity几何着色器的一个例子)

7 篇文章 0 订阅
5 篇文章 0 订阅

前言

接触UNITY的shader这两年时间一直想写些关于纪念碑谷的东西,其实你完全可以用普通的顶点着色器加上片段着色器实现文中内容,今天稍稍借题发挥一下:

1.关于几何着色器?



      Input Assembler(IA)从顶点缓冲区上的输入流中接收顶点数据,并且把数据项转换为规范的格式。vertex shader通常用来把顶点从模型空间变换到平面空间,vertex shader读取一个顶点,输出一个顶点。Pixel Shader读取单一pixel属性,输出包含颜色和Z信息的的片断。而geometry shader是DirectX10提出的,把同一区域的所有顶点作为输入,产生新的顶点或者区域。此外数据流输出(steam output)把geometry shader输出的顶点信息复制为4个连续的输出缓冲子集。理论上来说,steam output的输出能力和Input Assembler的输入能力相匹配。
Shader就是一段可以改变像素、顶点和几何学特征的小程序。Vertex Shader是专门处理多边形顶点的。那么Geometry shader就是专门用来处理场景中的几何图形。在过去Vertex Shader每一次运行只能处理一个顶点的数据,并且每次只能输出一个顶点的结果。在整个游戏场景中,绘制的几何图形的任务量非常庞大,如果仅仅依靠 Vertex Shader单一来完成,效率会极其低下。

     现在DX10的设计师们在顶点与像素的处理过程中又加入了(Geometry shader)几何着色器。它可以根据顶点的信息来批量处理几何图形,对Vertex附近的数据进行函数处理,快速创造出新的多边形。通过stream out将这些结果传递给其他Shader或buffer。

      ----几何着色器来源介绍

2.Unity3D下几何着色器实现的例子介绍

    2.1 Properties的定义

    Properties

    {

           _FaceColor("Face Color",Color) = (1,1,1,1)//面向光源显示的颜色

           _BackColor("Back Color",Color) = (1,1,1,1)//背向光源显示的颜色

           _MaxTex("Main Texture",2D) = "white" {} //主贴图

           _NormalMap("Normal Map",2D) = "bump"{}//控制海面挪动的发现图

           _Hightness("Hightness",Float) = 4//调节海面的挪动高度

           _TimeRate("Time Rate",Float) = 0.2//控制海面的挪动频率

    }

    2.2 着色器的定义

          Tags{"RenderType" = "Opaque" "Queue" =  "Gepmetry"}

          LOD 200

          CGPROGRAM

          # pragma 5.0

          #include "UnityCG.cginc"

          #include "Lighting.cginc"

          #include "AutoLight.cginc"

          //定义顶点着色器

          #pragma vertex vert

         //定义片段着色器

         #pragma fragment frag

         //定义几何着色器

        #pragma geometry geom

 2.3 结构体的声明

      struct a2v

      {

              float4 vertex : POSITION;//模型顶点位置

              float3 normal : NORMAL;//模型法线

              float4 texcoord : TEXCOORD0;//输入的坐标纹理集

              float4 tangent : TANGENT;//模型切线

     }

     struct v2g

     {

             float4 pos :POSITION;//顶点位置

             float2 uv :TEXCOORD0;//坐标纹理集

             float3 lightDir : TEXCOORD1;//光照方向

     }

     struct g2f

     {

            float4 pos : POSITION;//位置信息

            float2 uv : TEXCOORD0;//坐标纹理集

            float3 diffColor:TEXCOORD1;//输出颜色

     }

     2.4 顶点着色器

     v2g vert(a2v v)

    {

           v2g output;

           float d2 = tex2Dlod(_NormalMap,float4(v.texcoord.xy+_Time.xx*_TimeRate,0,0)).r;//海水根据时间抖动高度

           output.pos = mul(UNITY_MATRIX_MVP,v.vertex) + float4(0,d2,0,0)*_Heightness;//平面顶点位置

           output.uv = TRANSFORM_TEX(v.texcoord,_MainTex);

          float3 binormal = cross(v.normal,v.tangent.xyz);//副法线

          float3x3 rotation = float3x3(v.tangent.xyz , binormal , v.normal );//自身矩阵

          output.lightDir = normalize(mul(UNITY_MATRIX_MVP,mul(rotation , ObjSpaceLightDir(v.vertex))));//光照方向

          return output;

    }

    2.5 几何着色器

      [maxvertexcount(3)]
      void geom (triangle v2g p[3] , inout TriangleStream<g2f> triStream)
      {
          //屏幕坐标的顶点位置
          float3 p0 = p[0].pos.xyz;
          float3 p1 = p[1].pos.xyz;
          float3 p2 = p[2].pos.xyz;
         //三角形三条边的矢量方向
          float3 v0 = p2  - p1;
          float3 v1 = p2  - p0;
          float3 v2 = p1 - p0;
          //计算三角形的法线
          float3  trianglenormal = normalize(cross(v1,v2));
          //计算三角形的光照方向
          float3  triangleLightDir = normalize( p[ 0 ]. lightDir + p[1].lightDir + p[2].lightDir);
          float  diff = max(dot(trianglenormal,triangleLightDir),0);
          g2f  pIn;
          pIn. diffColor = lerp(_FaceColor,_BackColor,diff);
      //输入第一个点
      pIn.pos = p[0].pos;
      pIn.uv = p[0].uv;
      triStream.Append(pIn);
      
      //输入第二个点
      pIn.pos = p[1].pos;
      pIn.uv = p[1].uv;
      triStream.Append(pIn);
      
       //输入第三个点
      pIn.pos = p[2].pos;
      pIn.uv = p[2].uv;
      triStream.Append(pIn);
      }

    2.6 片段着色器

     float4 frag(g2f  input):COLOR
     {
             float4 texColor = tex2D(_MainTex,input.uv);
             return float4(input.diffColor,1) * texColor ;
     }

    2.7 总览

    Shader  "Citrus/Sea"
    {    

    Properties

    {

           _FaceColor("Face Color",Color) = (1,1,1,1)//面向光源显示的颜色

           _BackColor("Back Color",Color) = (1,1,1,1)//背向光源显示的颜色

           _MainTex("Main Texture",2D) = "white" {} //主贴图

           _NormalMap("Normal Map",2D) = "bump"{}//控制海面挪动的发现图

           _Hightness("Hightness",Float) = 1//调节海面的挪动高度

           _TimeRate("Time Rate",Float) = 1//控制海面的挪动频率

     }

     SubShader

     {

          Pass

          {   

               Tags{"RenderType" = "Opaque" "Queue" =  "Gepmetry"}

               LOD 200

               CGPROGRAM

               # pragma 5.0

               #include "UnityCG.cginc"

               #include "Lighting.cginc"

              #include "AutoLight.cginc"

              //定义顶点着色器

              #pragma vertex vert

              //定义片段着色器

             #pragma fragment frag

             //定义几何着色器

             #pragma geometry geom

             

              struct a2v

              {

                      float4 vertex : POSITION;//模型顶点位置

                      float3 normal : NORMAL;//模型法线

                      float4 texcoord : TEXCOORD0;//输入的坐标纹理集

                      float4 tangent : TANGENT;//模型切线

              };

              struct v2g

             {

                     float4 pos :POSITION;//顶点位置

                     float2 uv :TEXCOORD0;//坐标纹理集

                     float3 lightDir : TEXCOORD1;//光照方向

             };

             struct g2f

             {

                     float4 pos : POSITION;//位置信息

                     float2 uv : TEXCOORD0;//坐标纹理集

                     float3 diffColor:TEXCOORD1;//输出颜色

             };

             float4  _MainTex_ST;

             sampler2D _MainTex;

             float4  _NormalMap_ST;

             sampler2D _NormalMap;

             float _TimeRate;

             float _Hightness;

             fixed4 _FaceColor;

             fixed4 _BackColor;

             

             

             v2g vert(a2v v)

             {

                 v2g output;

                 float d2 = tex2Dlod(_NormalMap,float4(v.texcoord.xy+_Time.xx*_TimeRate,0,0)).r;//海水根据时间抖动高度

                 output.pos = mul(UNITY_MATRIX_MVP,v.vertex) + float4(0,d2,0,0)*_Hightness;//平面顶点位置

                 output.uv = TRANSFORM_TEX(v.texcoord,_MainTex);

                 float3 binormal = cross(v.normal,v.tangent.xyz) * v.tangent.w;//副法线

                 float3x3 rotation = float3x3(v.tangent.xyz , binormal , v.normal );//自身矩阵

                 output.lightDir = normalize(mul(UNITY_MATRIX_MVP,mul(rotation , ObjSpaceLightDir(v.vertex))));//光照方向

                 return output;

            }

            

           [maxvertexcount(3)]
           void geom (triangle v2g p[3] , inout TriangleStream<g2f> triStream)
           {
                 //屏幕坐标的顶点位置
                 float3 p0 = p[0].pos.xyz;
                 float3 p1 = p[1].pos.xyz;
                 float3 p2 = p[2].pos.xyz;
                 //三角形三条边的矢量方向
                 float3 v0 = p2  - p1;
                 float3 v1 = p2  - p0;
                 float3 v2 = p1 - p0;
                 //计算三角形的法线
                 float3  trianglenormal = normalize(cross(v1,v2));
                 //计算三角形的光照方向
                 float3  triangleLightDir = normalize( p[ 0 ]. lightDir  + p[1].lightDir + p[2].lightDir);
                 float  diff = max(dot(trianglenormal,triangleLightDir),0);
                 g2f  pIn;
                 pIn. diffColor = lerp(_FaceColor,_BackColor,diff);
                 //输入第一个点
                 pIn.pos = p[0].pos;
                 pIn.uv = p[0].uv;
                 triStream.Append(pIn);
      
                 //输入第二个点
                 pIn.pos = p[1].pos;
                 pIn.uv = p[1].uv;
                 triStream. Append(pIn);
      
                 //输入第三个点
                pIn.pos = p[2].pos;
                pIn.uv = p[2].uv;
                triStream. Append(pIn);
            }
            
            float4 frag(g2f  input):COLOR
           {
                 float4 texColor = tex2D(_MainTex,input.uv);
                 return float4(input.diffColor,1) * texColor ;
           }
           ENDCG

          }

     }

    }




  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值