• 【Unity】Geometry Shader实现


    https://www.cnblogs.com/jaffhan/p/7565178.html 

     

    Unity官方文档关于Geometry Shader的内容较少。不过也是因为Unity的开发者大多数面向的是移动平台开发,所以Geometry Shader作为DirectX 10的特性并没有被开发者广泛使用。

      首先要知道,Geometry Shader和Vertex Shader以及Fragment Shader的区别。

      在DirectX 9的渲染管线中,可编程的Shader只有顶点着色器和片段着色器两类。但是在DirectX 10开始,渲染管线增加了一个【可选】的几何体着色器。这是与顶点着色器和片段着色器【理论可选】作为渲染管线必需的两个着色器的主要区别。

      几何着色器在渲染管线中的位置是在顶点着色器和片段着色器之间,准确的说是和顶点着色器相邻。所以在功能方面,几何体着色器的操作和顶点着色器有相似性。一些原来位于顶点着色器中的计算,理论上完全可以转移到几何体着色器中进行。但实际操作中,并不建议那么做。因为几何体着色器并行调用硬件困难,并行程度低,效率和顶点着色器有很大的差距,这是第二个区别。

      顶点着色器是逐顶点操作,可以进行坐标变换等计算。

      片段着色器是逐片段/像素操作,进行最终输出颜色的计算。

      几何着色器同理,是逐图元的操作。它的输入是图元,输出也是图元。

      图元是渲染对象在顶点着色器之后,光栅化之前的一种状态。简单的来说,就是包含点【点Point而不是顶点Vertex】或者线段或者三角形的集合。

      经过这些简单的了解,大概能猜到几何着色器可以用来做什么了。比如细分【DirectX 11新增了更优的可选的细分着色器实现】,比如Low Poly,比如线框。Billboard也可以,不过Billboard可以在脚本和顶点Shader中同样可以实现。

     通过简单的一个Billboard例子来讲解几何体着色器:

    给一个Quad使用后的运行结果是产生Y轴约束,面向摄像机的Quad。

    1 Shader "Custom/GS Billboard" 
      2 {
      3     Properties 
      4     {
      5         _SpriteTex ("Base (RGB)", 2D) = "white" {}
      6         _Size ("Size", Range(0, 3)) = 0.5
      7     }
      8 
      9     SubShader 
     10     {
     11         Pass
     12         {
     13             Tags { "RenderType"="Opaque" }
     14             LOD 200
     15         
     16             CGPROGRAM
     17                 #pragma target 5.0
     18                 #pragma vertex VS_Main
     19                 #pragma fragment FS_Main
     20                 #pragma geometry GS_Main
     21                 #include "UnityCG.cginc" 
     22 
     23                 // **************************************************************
     24                 // Data structures                                                *
     25                 // **************************************************************
     26                 struct GS_INPUT
     27                 {
     28                     float4    pos        : POSITION;
     29                     float3    normal    : NORMAL;
     30                     float2  tex0    : TEXCOORD0;
     31                 };
     32 
     33                 struct FS_INPUT
     34                 {
     35                     float4    pos        : POSITION;
     36                     float2  tex0    : TEXCOORD0;
     37                 };
     38 
     39 
     40                 // **************************************************************
     41                 // Vars                                                            *
     42                 // **************************************************************
     43 
     44                 float _Size;
     45                 float4x4 _VP;
     46                 Texture2D _SpriteTex;
     47                 SamplerState sampler_SpriteTex;
     48 
     49                 // **************************************************************
     50                 // Shader Programs                                                *
     51                 // **************************************************************
     52 
     53                 // Vertex Shader ------------------------------------------------
     54                 GS_INPUT VS_Main(appdata_base v)
     55                 {
     56                     GS_INPUT output = (GS_INPUT)0;
     57 
     58                     output.pos =  mul(_Object2World, v.vertex);
     59                     output.normal = v.normal;
     60                     output.tex0 = float2(0, 0);
     61 
     62                     return output;
     63                 }
     64 
     65 
     66 
     67                 // Geometry Shader -----------------------------------------------------
     68                 [maxvertexcount(4)]
     69                 void GS_Main(point GS_INPUT p[1], inout TriangleStream<FS_INPUT> triStream)
     70                 {
     71                     float3 up = float3(0, 1, 0);
     72                     float3 look = _WorldSpaceCameraPos - p[0].pos;
     73                     look.y = 0;
     74                     look = normalize(look);
     75                     float3 right = cross(up, look);
     76                     
     77                     float halfS = 0.5f * _Size;
     78                             
     79                     float4 v[4];
     80                     v[0] = float4(p[0].pos + halfS * right - halfS * up, 1.0f);
     81                     v[1] = float4(p[0].pos + halfS * right + halfS * up, 1.0f);
     82                     v[2] = float4(p[0].pos - halfS * right - halfS * up, 1.0f);
     83                     v[3] = float4(p[0].pos - halfS * right + halfS * up, 1.0f);
     84 
     85                     float4x4 vp = mul(UNITY_MATRIX_MVP, _World2Object);
     86                     FS_INPUT pIn;
     87                     pIn.pos = mul(vp, v[0]);
     88                     pIn.tex0 = float2(1.0f, 0.0f);
     89                     triStream.Append(pIn);
     90 
     91                     pIn.pos =  mul(vp, v[1]);
     92                     pIn.tex0 = float2(1.0f, 1.0f);
     93                     triStream.Append(pIn);
     94 
     95                     pIn.pos =  mul(vp, v[2]);
     96                     pIn.tex0 = float2(0.0f, 0.0f);
     97                     triStream.Append(pIn);
     98 
     99                     pIn.pos =  mul(vp, v[3]);
    100                     pIn.tex0 = float2(0.0f, 1.0f);
    101                     triStream.Append(pIn);
    102                 }
    103 
    104 
    105 
    106                 // Fragment Shader -----------------------------------------------
    107                 float4 FS_Main(FS_INPUT input) : COLOR
    108                 {
    109                     return _SpriteTex.Sample(sampler_SpriteTex, input.tex0);
    110                 }
    111 
    112             ENDCG
    113         }
    114     } 
    115 }
    
    GS Billboard
    

      

    设定着色器编译目标级别为5.0。不过根据Unity的文档,4.0的着色器编译目标级别就已经支持Geometry Shader了。

    #pragma target 5.0

    设定几何体着色器函数名称为GS_Main【可自定义】。

    #pragma geometry GS_Main

    设置顶点着色器向几何体着色器输出的最大顶点数量为4。

    [maxvertexcount(4)]

    几何体着色器输入的图元是点,数量为1。输出的图元是三角形流。

    void GS_Main(point GS_INPUT p[1], inout TriangleStream<FS_INPUT> triStream)

    Append()是几何着色器内置的向输出流附加顶点的函数,因为允许的最大输出顶点数量就是4,所以append四次,输出四个顶点。

    triStream.Append(pIn);

    其他没有什么新东西要讲,简单的描述一下这个Shader的流程。

    顶点着色器:

      将顶点变换到世界空间,同时传递顶点法线和填充纹理坐标。

    几何着色器:

      1.定义一个垂直向上的向量up。

      2.计算观察向量look。

      3.将look向量的Y轴设为0并规格化,使得look向量成为平行于XZ平面指向摄像机的单位向量。

      4.计算up向量和look向量的叉乘,得到一个垂直于二者的新向量right。

      5.计算Size的一半halfS。

      6.将输入的点,以该点为中心点,分别向right向量正负轴向,up向量正负轴向移动halfS的距离,四个顶点的四个顶点的坐标。

      7.将顶点依次转换到投影空间,分配UV并Append到输出流上,最后输出。

    片段着色器:

      根据UV对贴图进行采样,返回颜色。

  • 相关阅读:
    迪杰斯特拉算法
    基数排序
    快排算法
    插入排序与希尔排序算法
    java--jmm知识
    Java基础
    socket代理
    TestLink 学习第一周
    软件体系结构第三章之解释器风格
    如何衡量个人在各自团队的效率和绩效
  • 原文地址:https://www.cnblogs.com/nafio/p/13433516.html
Copyright © 2020-2023  润新知