学习100个Unity Shader (18) --- 几何着色器(Geometry Shader)

发布于:2024-06-02 ⋅ 阅读:(142) ⋅ 点赞:(0)

概述

  1. vertex shader --> [geometry shader] --> fragment shader。[]: 可选阶段。
  2. 输入图元 —> geometry shader —> 其他图元

编写格式

[maxcertexcount(N)]
void ShaderName (PrimitiveType InputVertexType InputName[NumElements], 
inout StreamOutputObjectVertexType) OutputName){// 几何着色器具体实现}

几何着色器每次输出的顶点个数都可能不同,[maxvertexcount(N)]用来指定几何着色器单次调用所输出的顶点数量最大值,输出点=1,输出线=2,输出三角形=3。
PrimitiveType图元类型:

图元类型
point 输入图元拓扑类型为点列表
line 输入图元拓扑类型为线列表或线条带
triangle 输入的图元拓扑类型为三角形列表或三角形带
lineadj 输入的图元拓扑类型为线条列表/带及其邻接图元
triangleadj 输入的图元为三角形列表/带及其邻接图元

StreamOutputObjectVertexType 输出流类型

输出流类型
PointStream 一系列顶点所定义的点列表
LineStream 一系列顶点所定义的线条带
TriangleStream 一系列顶点所定义的三角形带

举例

//The data structure from the application to the vertex shader.
struct a2v  
{  
    float4 vertex : POSITION;  
    float2 uv : TEXCOORD0;  
};  

//The data structure from the vertex shader to the geometry shader.
struct v2g  
{  
    float4 vertex : POSITION;  
    float2 uv : TEXCOORD0;  
};

//The data structure from the geometry shader to the fragment shader.
struct g2f
{  
    float4 vertex : SV_POSITION;  
    float2 uv : TEXCOORD0;
}; 
[maxvertexcount(3)]  
void geom(triangle v2g input[3], inout TriangleStream<g2f> outStream)  
{  
      g2f o;
      for(int i = 0; i < 3; i++)  
      {  
            o.vertex = UnityObjectToClipPos(input[i].vertex);  
            o.uv = input[i].uv;  
            outStream.Append(o);  //Append函数用来将几何着色器的输出数据追加到一个现有的流中。   
      }  
      outStream.RestartStrip();  //输出流是三角,重置输出流
}

应用举例(用预制体球的每个顶点画一个立方体)

在这里插入图片描述

参考

Unity几何着色器详解
GITHUB-GeometryShaderCookbook

参考代码

Shader "Example/SimpleGeometryShader"
{
    Properties
    {
        _Color("Color", Color) = (1, 1, 1, 1)
        _Size("Size", Range(0, 0.05)) = 0.02

    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }

        Pass
        {
            Cull Off

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma geometry geom

            #include "UnityCG.cginc"

            struct a2v{
                float4 vertex : POSITION;
            };

            struct v2g{
              float4 vertex : POSITION;
            };
                      
            struct g2f{
                float4 pos : SV_POSITION;
            };

            float _Size;
            float4 _Color;

            v2g vert (a2v i)
            {
                v2g o;
                o.vertex = i.vertex;
                return o;
            }

            [maxvertexcount(36)] // 6 faces * 2 triangles * 3 vertices = 36
            void geom(point v2g input[1], inout TriangleStream<g2f> triStream)
            {
                float3 center = input[0].vertex.xyz;

                // Define the offsets for a cube
                float3 offsets[8] = {
                    float3(-_Size, -_Size, -_Size),
                    float3(_Size, -_Size, -_Size),
                    float3(_Size, _Size, -_Size),
                    float3(-_Size, _Size, -_Size),
                    float3(-_Size, -_Size, _Size),
                    float3(_Size, -_Size, _Size),
                    float3(_Size, _Size, _Size),
                    float3(-_Size, _Size, _Size)
                };

                // Define the vertices of each face of the cube
                int faces[6][4] = {
                    {0, 1, 2, 3}, // Front
                    {4, 5, 6, 7}, // Back
                    {0, 1, 5, 4}, // Bottom
                    {2, 3, 7, 6}, // Top
                    {0, 3, 7, 4}, // Left
                    {1, 2, 6, 5}  // Right
                };

                // Iterate through each face of the cube
                for (int i = 0; i < 6; ++i)
                {
                    g2f output;

                    // First triangle of the face
                    output.pos = UnityObjectToClipPos(float4(center + offsets[faces[i][0]], 1.0));
                    triStream.Append(output);

                    output.pos = UnityObjectToClipPos(float4(center + offsets[faces[i][1]], 1.0));
                    triStream.Append(output);

                    output.pos = UnityObjectToClipPos(float4(center + offsets[faces[i][2]], 1.0));
                    triStream.Append(output);

                    // Second triangle of the face
                    output.pos = UnityObjectToClipPos(float4(center + offsets[faces[i][0]], 1.0));
                    triStream.Append(output);

                    output.pos = UnityObjectToClipPos(float4(center + offsets[faces[i][2]], 1.0));
                    triStream.Append(output);

                    output.pos = UnityObjectToClipPos(float4(center + offsets[faces[i][3]], 1.0));
                    triStream.Append(output);

                }
            }

            fixed4 frag (g2f i) : SV_Target
            {
                return _Color;
            }
            ENDCG
        }
    }
}


网站公告

今日签到

点亮在社区的每一天
去签到