Unity Shader - OpenGL ES 2.0没有 SV

Unity Shader - OpenGL ES 2.0没有 SV,第1张

Unity Shader - OpenGL ES 2.0没有 SV

文章目录
  • 环境
  • 问题 - OpenGL ES 2.0 没有 SV_VertexID
  • 解决
    • UV 转 ID
    • 自定义后效处理管线
  • References


环境

Unity : 2019.4.30f1
Pipeline : Built-in RP


问题 - OpenGL ES 2.0 没有 SV_VertexID

在实现后效中,因为需要使用到屏幕空间的世界坐标

而为了获得屏幕空间的世界坐标,我们将 屏幕深度,转为对应的世界坐标,具体可以参考我之前的一篇:
Unity Shader - 根据片段深度重建片段的世界坐标

然后我为了更高效的获取世界坐标,因此使用到了 SV_VertexID 来得到后效中四个角落的顶点对应的ID

如果这时你在 OpenGL ES 2.0 下的话,shader lab 编译会报错:
Shader error in 'Test/MyFogOfWar_2dNoise_parallax_plane_mask': SV_VertexID semantic is not supported on GLES 2.0 (on gles)

说是 OpenGL ES 不支持 SV_VertexID


解决
UV 转 ID

因为我们的后效顶点坐标就那么四个,是可以自己根据 uv 坐标来区别的

如下图,这是我们后效的这个顶点的 UV 情况,与 ID 编号的情况

将 在 frag 中,将 uv 输出,可以查看到与上图的 UV 坐标是一致的:

所以我们可以在 顶点着色器 中这么写:

...
			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;
            }

自定义后效处理管线

另一种方法就是:自己弄个 quad 来绘制 color buffer,可以参考:Unity Shader - 模仿RenderImage制作全屏Quad

方法是,在传入 quad 的顶点坐标信息时,给 .w 第四个分量设置上 ID 编号

        GL.PushMatrix();
        mat.SetPass(0);
        GL.LoadOrtho();

        GL.Begin(GL.TRIANGLE_STRIP);

        // 注意顶点顺序,组合为:顺时针即可,Unity 逆时针为正面
        // 注意顶点顺序,组合为:顺时针即可,Unity 逆时针为正面
        GL.Vertex3(-1, -1, 0, 0);
        GL.Vertex3(1, -1, 0 3);
        GL.Vertex3(-1, 1, 0 1);
        GL.Vertex3(1, 1, 0 2);
        GL.End();

        GL.Flush();

然后再 vs 中就可以获得 自己传入的 ID 值

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年前的问题,结果只有这个回答,14 赞的:Unfortunately there is no gl_VertexID equivalent in GLES2. You must create and pass additional data yourself. - 我只能说,有点惨

  • 我记得 也有运算 SV_VertexID 的方式,而且是更加高效的,因为使用到的是 bit operation (位运算) 的方式, 但是顶点就这么 4 个, 优不优化都无所谓了

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5698637.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存