• Unity 几何着色器


    Unity 几何着色器

    Unity 几何着色器

    如果学习不能带来价值,那将毫无意义

    简介

        在顶点和片段着色器之间有一个可选的着色器,叫做几何着色器(Geometry Shader)。几何着色器以一个或多个表示为一个单独基本图形(primitive)即图元的顶点作为输入,比如可以是一个点或者三角形。几何着色器在将这些顶点发送到下一个着色阶段之前,可以将这些顶点转变为它认为合适的内容。几何着色器有意思的地方在于它可以把(一个或多个)顶点转变为完全不同的基本图形(primitive),从而生成比原来多得多的顶点。

    输入

        几何着色器阶段可将整个图元作为输入,并能够在输出上生成顶点。
        必须首先指定单次调用几何着色器输出的顶点的最大数量(每个图元调用几何着色器)。这可以通过使用以下属性语法在着色器定义之前设置最大顶点数:
    [maxvertexcount(N)]
        其中N是几何着色器为单个调用输出的顶点的最大数量。几何着色器可以在每次调用时输出的顶点数量是可变的,但不能超过定义的最大值。出于性能考虑,最大顶点数应尽可能小; [NVIDIA08]指出,当GS输出在1到20个标量之间时,可以实现GS的性能峰值,如果GS输出在27-40个标量之间,则性能下降50%。每次调用的标量输出数是最大顶点输出数和输出顶点类型结构中的标量数的乘积。

    基本图形描述
    point 绘制GL_POINTS基本图形的时候(1)
    line 当绘制GL_LINES或GL_LINE_STRIP(2)时
    lineadj 输入图元具有邻接线段(4)
    triangle GL_TRIANGLES, GL_TRIANGLE_STRIP或GL_TRIANGLE_FAN(3)
    triangleadj 输入图元具有邻接三角形(6)

    输出

    几何着色器通过将顶点附加到输出流对象来一次输出一个顶点。 流的拓扑由固定声明确定,选择 TriangleStream、LineStream 和 PointStream 作为 GS 阶段的输出。

    声明

    1.  
    2. [maxvertexcount(3)] 
    3. void geometry_shader(point VS_OUTPUT IN[1], inout TriangleStream<GS_ 
    4. OUTPUT> triStream) { /*shader body*/

    示例

    不做处理

        几何着色器位于顶点着色器和片元着色器之间,下面示例中几何着色器没做多余的效果,仅仅相当于默认的数据传递。

    1. Shader "ShaderCookbook/几何着色器/SimplePoint" 
    2. Properties 
    3. _MainTex ("Texture", 2D) = "white" {} 
    4. SubShader 
    5. Tags { "RenderType"="Opaque" } 
    6. LOD 100 
    7.  
    8. Pass 
    9. CGPROGRAM 
    10. #pragma vertex vert 
    11. //-------声明几何着色器 
    12. #pragma geometry geom 
    13. #pragma fragment frag 
    14.  
    15. #include "UnityCG.cginc" 
    16.  
    17. struct appdata 
    18. float4 vertex : POSITION; 
    19. float2 uv : TEXCOORD0; 
    20. }; 
    21.  
    22. //-------顶点向几何阶段传递数据 
    23. struct v2g{ 
    24. float4 vertex:SV_POSITION; 
    25. float2 uv:TEXCOORD0; 
    26. }; 
    27.  
    28. //-------几何阶段向片元阶段传递数据 
    29. struct g2f 
    30. float2 uv : TEXCOORD0; 
    31. float4 vertex : SV_POSITION; 
    32. }; 
    33.  
    34. sampler2D _MainTex; 
    35. float4 _MainTex_ST; 
    36.  
    37. v2g vert (appdata v) 
    38. v2g o; 
    39. o.vertex = UnityObjectToClipPos(v.vertex); 
    40. o.uv = TRANSFORM_TEX(v.uv, _MainTex); 
    41. return o; 
    42.  
    43. //-------静态制定单个调用的最大顶点个数 
    44. [maxvertexcount(3)] 
    45. void geom(triangle v2g input[3],inout TriangleStream<g2f> outStream){ 
    46. for(int i=0;i<3;i++){ 
    47. g2f o=(g2f)0
    48. o.vertex=input[i].vertex; 
    49. o.uv=input[i].uv; 
    50.  
    51. //-----将一个顶点添加到输出流列表 
    52. outStream.Append(o); 
    53.  
    54. //-------restart strip可以模拟一个primitives list 
    55. outStream.RestartStrip(); 
    56.  
    57. fixed4 frag (g2f i) : SV_Target 
    58. // sample the texture 
    59. fixed4 col = tex2D(_MainTex, i.uv); 
    60. return col; 
    61. ENDCG 
    62.  

    示例一:单纯的点

     

    点

     

    1. Shader "ShaderCookbook/几何着色器/OnlyPoint" 
    2. Properties 
    3. _MainTex ("Texture", 2D) = "white" {} 
    4. SubShader 
    5. Tags { "RenderType"="Opaque" } 
    6. LOD 100 
    7.  
    8. Pass 
    9. CGPROGRAM 
    10. #pragma vertex vert 
    11. //-------声明几何着色器 
    12. #pragma geometry geom 
    13. #pragma fragment frag 
    14.  
    15. #include "UnityCG.cginc" 
    16.  
    17. struct appdata 
    18. float4 vertex : POSITION; 
    19. float2 uv : TEXCOORD0; 
    20. }; 
    21.  
    22. //-------顶点向几何阶段传递数据 
    23. struct v2g{ 
    24. float4 vertex:SV_POSITION; 
    25. float2 uv:TEXCOORD0; 
    26. }; 
    27.  
    28. //-------几何阶段向片元阶段传递数据 
    29. struct g2f 
    30. float2 uv : TEXCOORD0; 
    31. float4 vertex : SV_POSITION; 
    32. }; 
    33.  
    34. sampler2D _MainTex; 
    35. float4 _MainTex_ST; 
    36.  
    37. v2g vert (appdata v) 
    38. v2g o; 
    39. o.vertex = UnityObjectToClipPos(v.vertex); 
    40. o.uv = TRANSFORM_TEX(v.uv, _MainTex); 
    41. return o; 
    42.  
    43. //-------静态制定单个调用的最大顶点个数 
    44. [maxvertexcount(4)] 
    45. void geom(point v2g input[1],inout PointStream<g2f> outStream){ 
    46. g2f o=(g2f)0
    47. o.vertex=input[0].vertex; 
    48. o.uv=input[0].uv; 
    49.  
    50. outStream.Append(o); 
    51.  
    52. fixed4 frag (g2f i) : SV_Target 
    53. // sample the texture 
    54. fixed4 col = tex2D(_MainTex, i.uv); 
    55. return col; 
    56. ENDCG 
    57.  

    示例二:散裂

        这里需要注意的是我们通过以v[0]为原点构建两个向量,通过这两个向量我们可以自定义点。

     

    由s,t构成的仿射坐标系
    由s,t构成的仿射坐标系

     

     

    炸裂
    炸裂

     

    1. Shader "ShaderCookbook/GeometryShader/分解" { 
    2. Properties { 
    3. _MainTex("Texture", 2 D) = "white" {} 
    4. _Height("Length", float) = 0.5 
    5. _Offset("Offset", float) = 0.1 
    6.  
    7. _StripColor("StripColor", Color) = (1, 1, 1, 1
    8. _OutColor("OutColor", Color) = (1, 1, 1, 1
    9. _InColor("InColor", Color) = (1, 1, 1, 1
    10. SubShader { 
    11. Cull off 
    12. Pass { 
    13. Tags { 
    14. "RenderType" = "Opaque" 
    15.  
    16. CGPROGRAM# pragma vertex vert# pragma fragment frag#include "UnityCG.cginc" 
    17.  
    18. struct appdata { 
    19. float4 vertex: POSITION; 
    20. float2 uv: TEXCOORD0; 
    21. }; 
    22.  
    23. struct v2f { 
    24. float4 vertex: SV_POSITION; 
    25. float4 objPos: TEXCOORD1; 
    26. float2 uv: TEXCOORD0; 
    27. }; 
    28.  
    29. sampler2D _MainTex; 
    30. float4 _MainTex_ST; 
    31. float _Height; 
    32. float _Offset; 
    33. fixed4 _StripColor; 
    34.  
    35. v2f vert(appdata v) { 
    36. v2f o; 
    37. o.vertex = UnityObjectToClipPos(v.vertex); 
    38. o.objPos = v.vertex; 
    39. o.uv = v.uv; 
    40. return o; 
    41.  
    42. fixed4 frag(v2f i): SV_Target { 
    43. fixed4 col = tex2D(_MainTex, i.uv); 
    44.  
    45. clip(_Height + _Offset - i.objPos.y); 
    46.  
    47. if (i.objPos.y > _Height) 
    48. col = _StripColor; 
    49.  
    50. return col; 
    51. ENDCG 
    52.  
    53. pass { 
    54. Tags { 
    55. "RenderType" = "Opaque" 
    56.  
    57. CGPROGRAM# pragma vertex vert# pragma geometry geome# pragma fragment frag#include "UnityCG.cginc" 
    58.  
    59. fixed4 _OutColor; 
    60. fixed4 _InColor; 
    61. float _Height; 
    62. float _Offset; 
    63.  
    64. struct appdata { 
    65. float4 vertex: POSITION; 
    66. float2 uv: TEXCOORD0; 
    67. float3 normal: NORMAL; 
    68. }; 
    69.  
    70. struct v2g { 
    71. float4 objPos: TEXCOORD0; 
    72. float3 normal: NORMAL; 
    73. }; 
    74.  
    75. struct g2f { 
    76. float4 vertex: SV_POSITION; 
    77. fixed4 col: TEXCOORD0; 
    78. }; 
    79.  
    80. void ADD_VERT(float4 v, g2f o, inout PointStream < g2f > outstream) { 
    81. o.vertex = v; 
    82. outstream.Append(o); 
    83.  
    84. v2g vert(appdata v) { 
    85. v2g o; 
    86. o.objPos = v.vertex; 
    87. o.normal = v.normal; 
    88. return o; 
    89.  
    90. [maxvertexcount(6)] 
    91. void geome(triangle v2g input[3], inout PointStream < g2f > outStream) { 
    92. g2f o; 
    93.  
    94. //--------将一个三角面三个顶点的平均位置作为均值 
    95. float4 vertex = (input[0].objPos + input[1].objPos + input[2].objPos) / 3.0
    96. float3 normal = (input[0].normal + input[1].normal + input[2].normal) / 3.0
    97.  
    98. if (vertex.y < _Height + _Offset) 
    99. return
    100.  
    101. //-------以v[0]为原点构建两个向量,用来在后续过程中通过这两个向量来构建三角面中自定义的点 
    102. float4 s = input[1].objPos - input[0].objPos; 
    103. float4 t = input[2].objPos - input[0].objPos; 
    104.  
    105. o.col = _OutColor * 2
    106. for (int i = 0; i < 3; i++) { 
    107. input[i].objPos.xyz += input[i].normal * (vertex.y - _Height); 
    108. input[i].objPos = UnityObjectToClipPos(input[i].objPos); 
    109. ADD_VERT(input[i].objPos, o, outStream); 
    110.  
    111. o.col = _InColor * 2
    112.  
    113. //-------通过s,t两个向量构建自定义点 
    114. float4 v[3]; 
    115.  
    116. v[0] = 0.2 * s + 0.2 * t; 
    117. v[1] = 0.4 * s + 0.6 * t; 
    118. v[2] = 0.6 * s + 0.4 * t; 
    119.  
    120. for (int i = 0; i < 3; i++) { 
    121. v[i].xyz += normal * (vertex.y - _Height); 
    122. v[i] = UnityObjectToClipPos(v[i]); 
    123. ADD_VERT(v[i], o, outStream); 
    124.  
    125. fixed4 frag(g2f i): SV_Target { 
    126. fixed4 col = i.col; 
    127. return col; 
    128. ENDCG 
    129.  

    线

     

    线
    线

     

    示例:wire frame

    1. Shader "ShaderCookbook/几何着色器/TriangleLine" 
    2. Properties 
    3. _MainTex ("Texture", 2D) = "white" {} 
    4. SubShader 
    5. Tags { "RenderType"="Opaque" } 
    6. LOD 100 
    7.  
    8. Pass 
    9. CGPROGRAM 
    10. #pragma vertex vert 
    11. //-------声明几何着色器 
    12. #pragma geometry geom 
    13. #pragma fragment frag 
    14.  
    15. #include "UnityCG.cginc" 
    16.  
    17. struct appdata 
    18. float4 vertex : POSITION; 
    19. float2 uv : TEXCOORD0; 
    20. }; 
    21.  
    22. //-------顶点向几何阶段传递数据 
    23. struct v2g{ 
    24. float4 vertex:SV_POSITION; 
    25. float2 uv:TEXCOORD0; 
    26. }; 
    27.  
    28. //-------几何阶段向片元阶段传递数据 
    29. struct g2f 
    30. float2 uv : TEXCOORD0; 
    31. float4 vertex : SV_POSITION; 
    32. }; 
    33.  
    34. sampler2D _MainTex; 
    35. float4 _MainTex_ST; 
    36.  
    37. v2g vert (appdata v) 
    38. v2g o; 
    39. o.vertex = UnityObjectToClipPos(v.vertex); 
    40. o.uv = TRANSFORM_TEX(v.uv, _MainTex); 
    41. return o; 
    42.  
    43. //-------静态制定单个调用的最大顶点个数 
    44. [maxvertexcount(3)] 
    45. //使用三角面作为输入,线段作为输出我们得到完整的线框 
    46. void geom(triangle v2g input[3],inout LineStream<g2f> outStream){ 
    47. g2f o=(g2f)0
    48. o.vertex=input[0].vertex; 
    49. o.uv=input[0].uv; 
    50.  
    51. outStream.Append(o); 
    52.  
    53.  
    54. o.vertex=input[1].vertex; 
    55. o.uv=input[1].uv; 
    56.  
    57. outStream.Append(o); 
    58.  
    59. o.vertex=input[2].vertex; 
    60. o.uv=input[2].uv; 
    61. outStream.Append(o); 
    62.  
    63.  
    64. fixed4 frag (g2f i) : SV_Target 
    65. // sample the texture 
    66. fixed4 col = tex2D(_MainTex, i.uv); 
    67. return col; 
    68. ENDCG 
    69.  

     

    enter description here
    enter description here

     

    示例:尖刺

    1. Shader "ShaderCookbook/GeometryShader/尖刺" { 
    2. Properties { 
    3. _MainTex("Texture", 2D) = "white" {} 
    4. _Length("Length", float) = 0.5 
    5. SubShader { 
    6. Tags { 
    7. "RenderType" = "Opaque" 
    8. LOD 100 
    9.  
    10. Pass { 
    11. CGPROGRAM 
    12. #pragma vertex vert 
    13. #pragma geometry geom 
    14. #pragma fragment frag 
    15. // make fog work 
    16. #pragma multi_compile_fog 
    17. #include "UnityCG.cginc" 
    18.  
    19. struct appdata { 
    20. float4 vertex: POSITION; 
    21. float2 uv: TEXCOORD0; 
    22. }; 
    23.  
    24. struct v2g { 
    25. float4 pos: SV_POSITION; 
    26. float2 uv: TEXCOORD0; 
    27. }; 
    28.  
    29. struct g2f { 
    30. float2 uv: TEXCOORD0; 
    31. float4 vertex: SV_POSITION; 
    32. }; 
    33.  
    34. sampler2D _MainTex; 
    35. float4 _MainTex_ST; 
    36. float _Length; 
    37.  
    38.  
    39. void ADD_VERT(float3 v, g2f o, inout TriangleStream < g2f > tristream) { 
    40. o.vertex = UnityObjectToClipPos(v); 
    41. tristream.Append(o); 
    42.  
    43.  
    44. void ADD_TRI(float3 p0, float3 p1, float3 p2, g2f o, inout TriangleStream < g2f > tristream) { 
    45. ADD_VERT(p0, o, tristream); 
    46. ADD_VERT(p1, o, tristream); 
    47. ADD_VERT(p2, o, tristream); 
    48. tristream.RestartStrip(); 
    49.  
    50.  
    51. v2g vert(appdata v) { 
    52. v2g o = (v2g) 0
    53. o.pos = v.vertex; 
    54. o.uv = TRANSFORM_TEX(v.uv, _MainTex); 
    55. return o; 
    56.  
    57. [maxvertexcount(9)] 
    58. void geom(triangle v2g input[3], inout TriangleStream < g2f > outStream) { 
    59. g2f o; 
    60.  
    61. //-----------这里通过三角面的两个边叉乘来获得垂直于三角面的法线方向 
    62. float3 s = (input[1].pos - input[0].pos).xyz; 
    63. float3 t = (input[2].pos - input[0].pos).xyz; 
    64.  
    65. float3 normal = normalize(cross(s, t)); 
    66.  
    67. float3 centerPos = (input[0].pos.xyz + input[1].pos.xyz + input[2].pos.xyz) / 3.0
    68. float2 centerUv = (input[0].uv + input[1].uv + input[2].uv) / 3.0
    69.  
    70. o.uv = centerUv; 
    71.  
    72. centerPos += normal * _Length * abs(sin(_Time.y * 5)); 
    73.  
    74. ADD_TRI(input[0].pos, centerPos, input[2].pos, o, outStream); 
    75. ADD_TRI(input[2].pos, centerPos, input[1].pos, o, outStream); 
    76. ADD_TRI(input[1].pos, centerPos, input[0].pos, o, outStream); 
    77.  
    78.  
    79. fixed4 frag(g2f i): SV_Target { 
    80. fixed4 col = tex2D(_MainTex, i.uv); 
    81. return col; 
    82. ENDCG 

     

    参考一
    参考二
    参考三
    可视化shader编程工具

    这里推荐一款可视化shader编程工具,对美术同学非常友好,就像建模工具中的材质编辑器一样

  • 相关阅读:
    【回溯】数字排列问题
    Price List
    NanoApe Loves Sequence-待解决
    【回溯】n皇后问题
    安卓 学习之旅 入门
    mysql链接 显示 error: 'Access denied for user 'root'@'localhost' (using password: NO)'
    javaweb 实战_1
    java 插件安装
    leetcode 最长有效括号
    hdu 1074 Doing Homework
  • 原文地址:https://www.cnblogs.com/Firepad-magic/p/10698749.html
Copyright © 2020-2023  润新知