为什么我需要在webgl着色器中定义精度值?

Fla*_*vio 15 shader glsl webgl fragment-shader three.js

我试图让本教程工作,但我遇到了两个问题,其中一个是以下问题.

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

Jes*_*ssy 16

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

precision highp float;
Run Code Online (Sandbox Code Playgroud)

对于所有的片段着色器,这将消除为所有浮点矢量变量定义精度的需要,但通常情况下,

precision mediump float;
Run Code Online (Sandbox Code Playgroud)

为了表现,将是更可取的.我不建议低音; 今天优秀的移动硬件甚至不再支持它,并且相当于typedeffing lowp to mediump.

  • 我不确定你的观点是什么。如果您的意思是当用户要求 highp 时,为什么 GPU 不只是撒谎并使用 mediump?因为那将是非常不负责任的。你不知道他们只是将它用于图形。他们可能正在做医疗或财务计算。 (3认同)
  • 你不应该使用`highp`,除非你知道你需要它。大多数手机不支持`highp`,所以你的着色器不会在手机上运行。很少有着色器需要 `highp`,所以使用 `mediump`。至于为什么在着色器中看不到它,是因为three.js 将它添加到您编写的着色器中。安装 [WebGL Inspector](http://benvanik.github.io/WebGL-Inspector/),运行一个 Three.js 应用,点击“capture”和“ui”,然后点击“programs”并查看实际的着色器是由three.js 提供给WebGL 的。您会看到它们指定了精度。 (2认同)

Ant*_*ton 7

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);
}
Run Code Online (Sandbox Code Playgroud)

片段着色器

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
}
Run Code Online (Sandbox Code Playgroud)

更新材料

// create the sphere's material
var shaderMaterial = new THREE.ShaderMaterial({
    vertexShader:   document.getElementById('vertex-shader').innerHTML,
    fragmentShader: document.getElementById('fragment-shader').innerHTML
});
Run Code Online (Sandbox Code Playgroud)

是没有精确声明的代码的小提琴.