片段着色器行为异常(测试网格)

Fragment shader behaves unexpectedly (Test grid)

我正在尝试编写一个简单的片段着色器来在多边形上显示网格(或者更确切地说是棋盘格图案)。我希望这个图案 "remain in place",即当多边形本身移动时,正方形保持在同一个位置,因此生成的图案在图案表面滑动。

我正在 Java 中使用 LWJGL 开发基于 ARM 的嵌入式系统,我可以在连接到我的 PC 的 ARM 设备上远程调试,也可以在 PC 本身本地调试。为此,我使用了 intelliJ。

在 PC 上,我的程序默认使用 OpenGL 3.2。在 ARM 上,上下文是 OpenGL ES 3.0。 ARM上的显卡是Vivante GC 2000.

问题是:本地,在我的 PC 上,着色器运行完美,就像我想要的那样。但是当我转到 ARM 时 - 图案在构成我的多边形的两个三角形之间抖动、扭曲和不同步。 有趣的是,即使着色器仅使用 ModelMatrix 和平面的顶点位置进行计算,图案也会根据相机位置发生变化和移动,这两者在帧之间保持完全相同(我检查过)。然而,相机位置会以某种方式显着影响结果,这是不应该发生的。

这是我的顶点着色器:

#version 300 es

layout (location=0) in vec3 position;

uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;
uniform mat4 modelMatrix;

out highp vec3 vertexPosition;

void main()
{   
    // generate position data for the fragment shader
    // does not take view matrix or projection matrix into account
    vec4 vp = modelMatrix * vec4(position, 1.0);
    vertexPosition = vec3(vp.x, vp.y, vp.z);

    // position data for the OpenGL vertex drawing
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}

片段着色器:

#version 300 es

precision highp float;

in highp vec3 vertexPosition;

out mediump vec4 fragColor;

void main()
{
    highp float c = float((int(round(vertexPosition.x/5.0))+int(round(vertexPosition.z/5.0))) % 2);

    fragColor = vec4(vec3(c/2.0 + 0.3), 1);
}

如您所见,我曾尝试修改浮点运算的精度,可惜无济于事。您还可以注意到,只有多边形的 modelMatrix 和 Vertex 位置会影响 fragColor,而且我可以保证我已关闭它们,并且它们不会在着色器调用之间发生变化,但相机移动最终会以某种方式影响生成的片段 colors/pattern。

还值得注意的是,场景中对象上的其他纹理似乎没有受到此问题的影响

这里有几个屏幕截图:

它在本地的外观(一切正常):

这是它在 ARM 设备上的样子。

注意纹理在三角形之间移动,它们之间有一条奇怪的线,似乎完全由一组完全不同的规则填充。问题不会出现在所有视角 - 只有一些。如果我将相机指向其他方向,有时我可以相当自由地移动它而不会看到伪影。

我注意到的另一件事是我的多边形越大,抖动和伪影就越多,这让我相信它与任一顶点位置(在顶点中)的 precision/calculation 有关着色器),或片段的位置相对于片段着色器部分中的那些顶点位置。

编辑:我已经使用 glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_HIGH_FLOAT, range, precision); 检查了 float 的精度;在本地 PC 和 MTU 上都是一样的。所以不应该是这样,除非你必须以某种方式专门启用一些我丢失的标志。

编辑:我注意到的另一件事是,在本地,在 PC 上,小测试草方块出现在其中一个方块的中心。在 ARM 上,正方形移动了一半,所以它直接站在交叉点上(如果我将相机排成一行,这样就不会发生伪影)。无法正确解释这一点,因为在我看来计算应该产生相同的结果。

无论如何,我实际上需要以某种方式解决这个问题,我将不胜感激。

所以最后证明是两个问题的混合:

1) 运算符 % 在 OGL 3.2 和 OGLES 3.0 中的工作方式不同。在前者中,它总是 returns 一个正整数,即使操作数是负数。 IE。 3 % 2 = -3 % 2 = 1 然而,在 OpenGL ES 中,它实际上保持了符号。

2) 这是一个精度问题。我在高正坐标下工作,所以我的 vertexPosition 坐标最终在 10k 正范围内。当我取总和时,它可以上升到 20k。似乎即使是 highP float 也不足以维持如此高的数字的足够精度,所以它最终会崩溃。这是奇数,因为 highP 精度范围显示为 -2^127~~2^127,这对我的计算来说应该足够了。但不知何故不是。我的解决方案是标准化坐标,将值减小到 <10。

如果有人可以进一步详细说明我可以做的事情 - 让我知道!

我的着色器问题仍然存在。多边形的 "texture" 在某些视角下变形。 我在这里发现了另一个与我遇到的问题几乎完全相同的问题,并且它有一些解决方法。我会link这里。

我将 post 我对这个问题的最终答案,这是一个经过大量努力、搜索和反复试验的问题。屏幕截图中实际上描述了两个不同的问题,因此我将同时介绍它们。

关于多边形交叉点上奇怪的纹理偏移。已确认这是 Vivante 驱动程序问题。对于片段着色器,位于平截头体之外太远的点的坐标计算错误(请注意,它们在顶点着色器中完全正常,因此平面不会出现撕裂 - 只有纹理受到影响)。

目前似乎没有驱动程序修复。

但是,您可以实施解决方法。分割网格。与其拥有一个由 2 个三角形组成的大四边形,不如用几个较小的四边形构建它。在我的例子中,我制作了一个 6x6 结构,总共有 36 个四边形和 64 个三角形。这样一来,任何点都不会超出截锥体的范围,而且精度似乎也不错。

是的,这远非理想,但总比让片段着色器产生视觉伪影要好。


关于颜色。您可能会注意到,在屏幕截图中,颜色最终变成了灰色和黑色,而它们应该是浅灰色和深灰色。

找到解决方案并不容易。是系统区域。

有些人甚至可能没有意识到,在某些斯拉夫语言环境中,分隔符是逗号,而不是点。所以基本上是:

fragColor = vec4(vec3(c/2.0 + 0.3), 1);

变成了

fragColor = vec4(vec3(c/2 , 0 + 0 , 3), 1);

如您所料,这是完全错误的。令我印象深刻的是,GLSL 似乎对此完全没问题,并且不会给出任何运行时错误。可能是因为 vec3 在创建过程中可以取 3 个坐标,或者什么的。 无论如何,这个bug让我代码中的所有浮点常量都完全错误,计算出来的结果也是错误的。

以防万一有人遇到那个问题。