为啥我需要在 webgl 着色器中定义一个精度值?

Posted

技术标签:

【中文标题】为啥我需要在 webgl 着色器中定义一个精度值?【英文标题】:Why do I need to define a precision value in webgl shaders?为什么我需要在 webgl 着色器中定义一个精度值? 【发布时间】:2015-01-19 09:42:14 【问题描述】:

我试图让this tutorial 工作,但我遇到了两个问题,其中一个是以下问题。

当我按原样运行代码时,片段着色器中出现错误提示:THREE.WebGLShader: gl.getShaderInfoLog() ERROR: 0:2: '' : No precision specified for (float)。所以我所做的是为我定义的每个浮点数/向量指定一个精度,就像varying highp vec3 vNormal 一样。这消除了错误,但我不明白为什么?我找不到任何其他将精度值添加到变量声明的示例。谁能解释为什么会这样?它与我的浏览器(Chrome 38)有关吗?

【问题讨论】:

这篇文章是否带来了一些启示? ***.com/questions/5366416 在回答你的问题的标题时,答案基本上是“因为规范是这样说的”。 WebGL 基于 OpenGL ES 2.0 规范,该规范要求您指定精度。 【参考方案1】:

Jessy 的回答是正确的,大多数片段着色器在片段着色器代码的顶部设置了默认精度。

但是,您使用的是 Three.js 的 RawShaderMaterial,它没有预先添加任何内置的统一、属性和精度声明。所以你必须自己定义。

另一方面,您链接到的教程使用 Three.js 的 ShaderMaterial 作为其材料,因此 Three.js 将自动添加精度声明。

如果您从着色器代码中删除默认的制服/属性并改用ShaderMaterial,则它可以在没有精度代码的情况下工作。

顶点着色器

varying vec3 vNormal;

void main() 
    vNormal = normal;
    gl_Position = projectionMatrix *
                modelViewMatrix *
                vec4(position,1.0);

片段着色器

varying vec3 vNormal;

void main() 
    vec3 light = vec3(0.5, 0.2, 1.0);

    // ensure it's normalized
    light = normalize(light);

    // calculate the dot product of
    // the light to the vertex normal
    float dProd = max(0.0, dot(vNormal, light));

    // feed into our frag colour
    gl_FragColor = vec4(dProd, // R
                        dProd, // G
                        dProd, // B
                        1.0);  // A

资料更新

// create the sphere's material
var shaderMaterial = new THREE.ShaderMaterial(
    vertexShader:   document.getElementById('vertex-shader').innerhtml,
    fragmentShader: document.getElementById('fragment-shader').innerHTML
);

Here 是没有精度声明的代码。

【讨论】:

哦,伙计,我花了几个小时试图找出问题所在,现在我觉得很傻。我不知道为什么我使用RawShaderMaterial() 这不是我的本意。非常感谢您的帮助! @Flavio 没问题我很高兴能帮上忙 :)【参考方案2】:

WebGL 片段着色器没有默认精度。 (高精度是顶点着色器的默认设置。)最简单的解决方案是添加

precision highp float;

到所有片段着色器,这将消除为所有浮点向量变量定义精度的需要,但通常,

precision mediump float;

将更可取,以提高性能。我不建议lowp;当今优秀的移动硬件甚至不再支持它,相当于将 lowp 类型定义为 mediump。

【讨论】:

酷非常感谢您的回答,这解释了很多。我仍然不明白为什么我在其他着色器程序中从未看到任何这些精度声明。他们甚至不在我试图上班的tutorial。 除非你知道你需要它,否则你不应该使用highp。大多数手机不支持highp,因此您的着色器无法在手机上运行。很少有着色器需要highp,所以使用mediump。至于为什么您在着色器中看不到它,那是因为three.js 将它添加到您编写的着色器中。安装WebGL Inspector,运行three.js 应用程序,单击“捕获”和“ui”,然后单击“程序”,查看由three.js 提供给WebGL 的实际着色器。你会看到他们指定了精度。 @gman 什么 POS 竟然完全禁用着色器而不是运行 highp 作为 mediump? 我不确定你的意思是什么。如果您的意思是当用户要求 highp 时,为什么 GPU 不只是撒谎并使用 mediump?因为那将是非常不负责任的。你不知道他们只是将它用于图形。他们可能正在进行医疗或财务计算。 如果精度确实符合标准,那么您的论点将成立,但 OpenGL ES 仅强制执行最低要求,该要求已在 2.0 和 3.0 之间更改。我现在正在寻找 WebGL 的要求是什么,但甚至找不到。我将假设我们只假设 2.0 的最低精度,但任何不从事图形工作的人都知道 WebGL 和 OpenGL ES 不适合他们的工作。幸运的是,现在有一种强制遵守 IEEE 的移动 GPU 语言。 bit.ly/1pe8zqB

以上是关于为啥我需要在 webgl 着色器中定义一个精度值?的主要内容,如果未能解决你的问题,请参考以下文章

shader编程-着色器中颜色基础(WebGL-Shader开发基础06)

shader编程-着色器中颜色基础(WebGL-Shader开发基础06)

为啥着色器必须在 webgl 程序的 html 文件中?

WebGL-四之二

为啥我的着色器中的 GLSL 纹理坐标不是线性的?

着色器中自己的双精度 cos() 实现的结果为 ON,但在 CPU 上运行良好。出了啥问题?