基本上,问题是我图像的透明部分没有与之前绘制的内容正确混合。我知道我可以做一个
if(alpha<=0){discard;}
在片段着色器中,唯一的问题是我计划拥有大量片段并且不希望移动设备上的每个片段都有 if 语句。
这是我与 alpha 和深度测试相关的代码:
var gl = canvas.getContext("webgl2",
{
antialias : false,
alpha : false,
premultipliedAlpha: false,
}
);
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.GREATER);
此外,这些是我正在绘制的带纹理的 gl.POINTS。如果我改变两个图像在缓冲区中绘制的顺序,问题就不存在了。它们将在程序运行期间动态旋转,因此这不是一个选项。
最佳答案
如果没有更多代码,则不清楚您的问题是什么,但它看起来像是深度测试问题。
假设我理解正确,您正在绘制 2 个矩形?如果您在蓝色区域之前绘制红色区域,那么根据您的深度测试设置方式,当绘制 X 区域时,蓝色区域将无法通过深度测试。
您通常通过对绘制的内容进行排序来解决此问题,确保先绘制更远的东西。
对于“瓷砖”网格,您通常可以通过在正确的方向上移动网格本身而不是“排序”来排序
另一方面,如果您所有的透明度都是 100% 绘制或不绘制,则丢弃有其优势,您可以从前到后绘制。原因是因为在这种情况下从前到后绘制,在通过深度测试绘制蓝色四边形时,红色四边形绘制(未丢弃)的像素将被拒绝。深度测试通常被优化为在为某个像素运行片段着色器之前发生。如果深度测试表明像素不会被绘制,那么就没有理由为该像素运行片段着色器,节省时间。不幸的是,一旦您有任何不是 100% 不透明或 100% 透明的透明度,您就需要排序并拉回到前面。 this article 中涵盖了其中一些问题
一些注意事项:
您在代码示例中提到了移动设备和 WebGL2。 iOS 上没有 WebGL2
您说您正在使用 POINTS 绘图。规范说只需要 1 个像素大小的 POINTS。 It looks like you're safe up to points of size 60但为了安全起见,通常最好用三角形绘制 there are other isses with points
您可能也对 sprites with depth 感兴趣
关于2d - 为什么透明像素在 WebGL 中不能正确混合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59205157/