Article directory
environment
Unity : 2019.4.30f1
Pipeline : Built-in RP
Problem - OpenGL ES 2.0 doesn't have SV_VertexID
In the implementation of the after effects, because the world coordinates of the screen space need to be used
In order to obtain the world coordinates of the screen space, we convert the screen depth to the corresponding world coordinates. For details, please refer to my previous article:
Unity Shader - Reconstruct the world coordinates of the fragment according to the depth of the fragment
Then I used to get the world coordinates more efficiently, so I used SV_VertexID
to get the ID corresponding to the vertices of the four corners in the after effect
If you are under OpenGL ES 2.0 at this time, shader lab compilation will report an error:
Shader error in 'Test/MyFogOfWar_2dNoise_parallax_plane_mask': SV_VertexID semantic is not supported on GLES 2.0 (on gles)
It is said that OpenGL ES does not support SV_VertexID
solve
UV 转 ID
Because our after-effect vertex coordinates are only four, they can be distinguished by their own uv coordinates
As shown in the figure below, this is the UV situation of this vertex and the ID number of our aftereffect
In the frag, the uv will be output, and you can see that the UV coordinates are consistent with the above image:
So we can write this in the vertex shader:
...
struct appdata {
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
//uint vid : SV_VertexID; // jave.lin : 在 dx 没问题,在 openGL ES 2.0 有报错,在 OpenGL ES 3.0 虽然没编译报错,但是值不对,所以我们为了兼容性考虑,不适用这个特性
};
...
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
uint vid;
if (v.uv.x < 0.5 && v.uv.y < 0.5)
vid = 0;
else if (v.uv.x < 0.5 && v.uv.y >= 0.5)
vid = 1;
else if (v.uv.x >= 0.5 && v.uv.y >= 0.5)
vid = 2;
else
vid = 3;
//o.ray = _Ray[v.vid]; // 如上述,有兼容性问题,我们使用计算 uv 坐标的方式来得到 vertex id
o.ray = _Ray[vid];
return o;
}
Custom post-processing pipeline
Another way is: make a quad yourself to draw the color buffer, you can refer to: Unity Shader - imitating RenderImage to make a full screen Quad
The method is to set the ID number to the .w
fourth .
GL.PushMatrix();
mat.SetPass(0);
GL.LoadOrtho();
GL.Begin(GL.TRIANGLE_STRIP);
// 注意顶点顺序,组合为:顺时针即可,Unity 逆时针为正面
// 注意顶点顺序,组合为:顺时针即可,Unity 逆时针为正面
GL.Vertex3(-1, -1, 0, /*ID*/0);
GL.Vertex3(1, -1, 0 /*ID*/3);
GL.Vertex3(-1, 1, 0 /*ID*/1);
GL.Vertex3(1, 1, 0 /*ID*/2);
GL.End();
GL.Flush();
Then you can get the ID value passed in by yourself in vs
struct a2v
{
float4 positionNDC : POSITION; // jave.lin : xyz: positionNCD xyz, w: vertex ID
...
};
struct v2f {
...
};
v2f vert (a2v v)
{
v2f o = (v2f)0;
...
uint MyVertexID = (uint)v.positionNDC.w; // jave.lin : 在顶点着色器就可以拿到我们自定义后效管线传入的顶点 ID 值了
...
return o;
}
...
References
-
OpenGLES 2.0: gl_VertexID equivalent? - 9 years ago question, only this answer, 14 upvotes: Unfortunately there is no gl_VertexID equivalent in GLES2. You must create and pass additional data yourself. - All I can say is, a bit miserable
-
I remember that <unity shader lab entry essentials> also has a way to calculate SV_VertexID, and it is more efficient, because it uses a bit operation (bit operation) method, but there are only 4 vertices, it doesn't matter whether it is better or not.