Unity 幾何着色器

Unity 幾何着色器

Unity 幾何着色器

若是學習不能帶來價值,那將毫無心義html

簡介

    在頂點和片斷着色器之間有一個可選的着色器,叫作幾何着色器(Geometry Shader)。幾何着色器以一個或多個表示爲一個單獨基本圖形(primitive)即圖元的頂點做爲輸入,好比能夠是一個點或者三角形。幾何着色器在將這些頂點發送到下一個着色階段以前,能夠將這些頂點轉變爲它認爲合適的內容。幾何着色器有意思的地方在於它能夠把(一個或多個)頂點轉變爲徹底不一樣的基本圖形(primitive),從而生成比原來多得多的頂點。編程

輸入

    幾何着色器階段可將整個圖元做爲輸入,並可以在輸出上生成頂點。
    必須首先指定單次調用幾何着色器輸出的頂點的最大數量(每一個圖元調用幾何着色器)。這能夠經過使用如下屬性語法在着色器定義以前設置最大頂點數:
[maxvertexcount(N)]
    其中N是幾何着色器爲單個調用輸出的頂點的最大數量。幾何着色器能夠在每次調用時輸出的頂點數量是可變的,但不能超過定義的最大值。出於性能考慮,最大頂點數應儘量小; [NVIDIA08]指出,當GS輸出在1到20個標量之間時,能夠實現GS的性能峯值,若是GS輸出在27-40個標量之間,則性能降低50%。每次調用的標量輸出數是最大頂點輸出數和輸出頂點類型結構中的標量數的乘積。api

基本圖形 描述
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 階段的輸出。app

聲明

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

示例

不作處理

    幾何着色器位於頂點着色器和片元着色器之間,下面示例中幾何着色器沒作多餘的效果,僅僅至關於默認的數據傳遞。jsp

  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 

Other

項目工程:連接: https://pan.baidu.com/s/1eGk6GHIfWzIFcAX6pxTGRA 提取碼: fv75工具

解壓密碼:https://fgk.pw/i/eqm2Bj23236性能

 

參考一
參考二
參考三
可視化shader編程工具學習

這裏推薦一款可視化shader編程工具,對美術同窗很是友好,就像建模工具中的材質編輯器同樣ui

相關文章
相關標籤/搜索