概述
- vertex shader --> [geometry shader] --> fragment shader。[]: 可选阶段。
- 输入图元 —> 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
}
}
}