Unity Shader - No SV_VertexID in OpenGL ES 2.0 Post Processing and Solutions


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_VertexIDto 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
insert image description here

In the frag, the uv will be output, and you can see that the UV coordinates are consistent with the above image:
insert image description here

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 .wfourth .

        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.

Guess you like

Origin blog.csdn.net/linjf520/article/details/122364052