我在 WebGL 中渲染几何图形,在 Android 版 Chrome(不需要的伪影,左)和 Chrome 版 Windows(右)上得到了不同的结果:
我试过:
- 使用 WebGL2 和 WebGL 上下文
- 在传递索引缓冲区时使用
gl.UNSIGNED_INT
和gl.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;
解决了这个问题。
lowp
、mediump
和highp
在不同的硬件上对应不同的值,只对OpenGL ES平台有影响。桌面平台充分利用 OpenGL 或 Direct X(与 OpenGL ES 相对),因此,在桌面计算机上,这些限定符都对应于相同的值。移动 WebGL 通常利用 OpenGL ES,因此在移动设备上这些限定符对应于不同的值。
在此示例中,lowp
和 mediump
在 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()
,lowp
和 mediump
返回相同的结果(较低比在 Windows 上),而 highp
返回的精度与在我的 Windows 机器上一样高。
关于android - Android 上使用 WebGL 的顶点着色器 Artifact ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57619576/