android - Android 上使用 WebGL 的顶点着色器 Artifact

标签 android glsl webgl webgl2 android-chrome

我在 WebGL 中渲染几何图形,在 Android 版 Chrome(不需要的伪影,左)和 Chrome 版 Windows(右)上得到了不同的结果:

Android Windows

我试过:

  • 使用 WebGL2 和 WebGL 上下文
  • 在传递索引缓冲区时使用 gl.UNSIGNED_INTgl.UNSIGNED_SHORT
  • 将逗号后的所有属性值四舍五入到小数点后 4 位

部分代码如下:

我已经“简化”了我的顶点着色器以缩小问题范围:

#version 100
precision mediump float;

attribute vec3 aPosition;
attribute vec3 aColor;
attribute vec3 aNormal;
varying vec3 vColor;
varying vec3 vNormal;
varying vec3 vPosition;
varying mat4 vView;
uniform mat4 uWorld;
uniform mat4 uView;
uniform mat4 uProjection;
uniform mat3 uNormal;
uniform float uTime;

void main() {
    vColor = aColor;
    vNormal = uNormal * aNormal;
    vPosition = (uWorld * vec4(aPosition, 1.0)).xyz;
    gl_Position = uProjection * uView * uWorld * vec4(aPosition, 1.0);
}

我通过交错缓冲区传递属性(所有值在逗号后四舍五入到小数点后四位):

gl.bindBuffer(gl.ARRAY_BUFFER, this.interleaved.buffer)
const bytesPerElement = 4
gl.vertexAttribPointer(this.interleaved.attribLocation.position, 3, gl.FLOAT, gl.FALSE, bytesPerElement * 9, bytesPerElement * 0)
gl.vertexAttribPointer(this.interleaved.attribLocation.normal, 3, gl.FLOAT, gl.FALSE, bytesPerElement * 9, bytesPerElement * 3)
gl.vertexAttribPointer(this.interleaved.attribLocation.color, 3, gl.FLOAT, gl.FALSE, bytesPerElement * 9, bytesPerElement * 6)

我正在使用索引缓冲区绘制几何图形:

gl.drawElements(gl.TRIANGLES, this.indices.length, gl.UNSIGNED_INT, 0)

索引范围从 0..3599,因此 gl.UNSIGNED_INT 应该足够大。

我没有收到任何错误消息。在 Windows 上,一切都呈现良好,只是 Android 上的 Chrome 有瑕疵。

最佳答案

这些瑕疵是由于不同设备上的着色器精度不够造成的。使用 precision highp float; 解决了这个问题。

lowpmediumphighp在不同的硬件上对应不同的值,只对OpenGL ES平台有影响。桌面平台充分利用 OpenGL 或 Direct X(与 OpenGL ES 相对),因此,在桌面计算机上,这些限定符都对应于相同的值。移动 WebGL 通常利用 OpenGL ES,因此在移动设备上这些限定符对应于不同的值。

在此示例中,lowpmediump 在 Android 上导致故障,需要替换为 highp

通常,如果性能很重要,则使用尽可能低的精度是 recommended to reduce shader execution time . WebGLRenderingContext.getShaderPrecisionFormat() 返回着色器数据类型的精度,分别用于顶点和 fragment 着色器 (MDN)。要使用尽可能低的精度,可以根据 WebGLRenderingContext.getShaderPrecisionFormat() 为所使用的着色器添加所需精度限定符的前缀。

例如

const lowPrecisionFormat = gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.LOW_FLOAT)
const mediumPrecisionFormat = gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.MEDIUM_FLOAT)
const highPrecisionFormat = gl.getShaderPrecisionFormat(gl.VERTEX_SHADER, gl.HIGH_FLOAT)

if (lowPrecisionFormat.precision >= 23)
    shaderString = "precision lowp float;" + shaderString
else if (mediumPrecisionFormat.precision >= 23)
    shaderString = "precision mediump float;" + shaderString
else
    shaderString = "precision highp float;" + shaderString

我在 Android 硬件上测试了 gl.getShaderPrecisionFormat()lowpmediump 返回相同的结果(较低比在 Windows 上),而 highp 返回的精度与在我的 Windows 机器上一样高。

关于android - Android 上使用 WebGL 的顶点着色器 Artifact ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57619576/

相关文章:

opengl - GLSL从顶点着色器传递纹理坐标

unity-game-engine - 如何将 HTML5 播放器中的视频绘制并投影到 WebGL 中的 3D 平面上?

opengl - 在 OpenGL 中,有没有办法获取着色器程序使用的所有制服和属性的列表?

fragment 中的 Android Snackbar NullPointerException

android - 在日历中显示事件列表?

android - 清除android应用程序用户数据

opengl - 如何将 GLSL 限制为核心语言?

javascript - 将 JavaScript 变量发送到片段着色器

javascript - vec3.unproject()鼠标碰撞问题

Android登录注册中java.lang.String无法转换为JSONObject