Why do I need to define a precision value in webgl

2020-08-10 05:51发布

问题:

I'm trying to get this tutorial to work but I ran into two issues, one of which is the following.

When I run the code as is I get an error in the fragment shader saying: THREE.WebGLShader: gl.getShaderInfoLog() ERROR: 0:2: '' : No precision specified for (float). So what I did was specifying a precision for every float/vector I define like so varying highp vec3 vNormal. This eliminates the error but I don't get why? I can't find any other example where precision values are added to variable declarations. Can anybody explain why this occurs? Does it have something to do with my Browser (Chrome 38)?

回答1:

Jessy's answer is correct that most fragment shaders set a default precision at the top of the fragment shader code.

However you are using Three.js's RawShaderMaterial which does not prepend any of the built-in uniforms, attributes, and precision declarations. So you have to define it yourself.

On the other hand the tutorial you linked to is using Three.js's ShaderMaterial for its material so Three.js will have the precision declaration prepended automatically.

If you remove the default uniforms/attributes from your shader code and use ShaderMaterial instead it will work without the precision code.

Vertex Shader

varying vec3 vNormal;

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

Fragment Shader

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
}

Update to the material

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

Here is a fiddle of your code without the precision declarations.



回答2:

There is no default precision in WebGL fragment shaders. (High precision is default for vertex shaders.) The easiest solution is to add

precision highp float;

to all of your fragment shaders, which will eliminate the need to define the precision for all floating point vector variables, but generally,

precision mediump float;

will be preferable, for performance. I do not advise lowp; the good mobile hardware of today doesn't even support it anymore, and does the equivalent of typedeffing lowp to mediump.