2
votes

I am using WebGL to try and render a scene with both color and textures, with the colors being rendered through the vertex shader and the textures being rendered through the fragment shader. Both shaders utilize some of the same uniform variables, however WebGL does not allow me to pass them between both, only one or the other. The error message I receive is "Uniform variable not linkable between attached shaders." I have gone through similar posts by other users regarding this issue however I was not able to find one that matched my situation. My code is as follows:

const vertex_shader = `

attribute vec4 vertex;
attribute vec2 textureCoordinates;
attribute vec4 normal;

uniform mat4 model_transform;
uniform mat4 vp_transform;
uniform mat4 normal_transform;

varying vec2 vTexCoords;
varying vec4 obj_loc;
varying vec4 transformed_normal;
varying vec4 vColor;
uniform vec4 light_position;
uniform vec4 light_ambient;
uniform vec4 light_diffuse;

uniform vec4 mat_ambient;
uniform vec4 mat_diffuse;
uniform vec4 mat_specular;
uniform float mat_shininess;

uniform vec4 light_specular;

uniform vec4 camera_position;

uniform int flags;

void main()
{
    obj_loc = model_transform * vertex; // vertex in model coordinates
    gl_Position = vp_transform * obj_loc; // vertex in device independent coordinates
    transformed_normal = normal_transform * normal;  // normal in model coordinates
    vTexCoords = textureCoordinates;

    vec4 l_vec = normalize(light_position - obj_loc);
    vec4 n_vec = normalize(normal_transform * normal);
    float lndot = dot(l_vec, n_vec);
    float diffuse_scale = max(0.0, lndot);
    vec4 diffuse_color = diffuse_scale * light_diffuse * mat_diffuse;
    if( (flags - 2*(flags/2)) == 0)
        diffuse_color = vec4(0.0, 0.0, 0.0, 1.0);
    
    vec4 h_vec = normalize(l_vec + normalize(camera_position - obj_loc));
    float spec_scale = pow(max(0.0, dot(h_vec, n_vec)), mat_shininess);
    vec4 specular_color;
    if(lndot < 0.0) {
        specular_color = vec4(0.0, 0.0, 0.0, 1.0);
    } else {
        specular_color = spec_scale * mat_specular * light_specular;
    }
    if( (flags - 4*(flags/4)) < 2 ) {
        specular_color = vec4(0.0, 0.0, 0.0, 1.0);
    }      
 
    vec4 ambient_color = mat_ambient * light_ambient; 
    if(flags < 4) {
        ambient_color = vec4(0.0, 0.0, 0.0, 1.0);
    }
}`;

const fragment_shader = `
precision mediump float;

uniform vec4 light_position;
uniform vec4 light_ambient;
uniform vec4 light_diffuse;

varying vec2 vTexCoords;
varying vec4 obj_loc;
varying vec4 transformed_normal;
uniform sampler2D sampler;

void
main()
{
    vec4 texture_sample = texture2D(sampler, vTexCoords);

    vec4 l_vec = normalize(light_position - obj_loc);
    vec4 n_vec = normalize(transformed_normal);
    float lndot = dot(l_vec, n_vec);
    float diffuse_scale = max(0.0, lndot);
    vec4 diffuse_color = diffuse_scale * light_diffuse * texture_sample;
    
    vec4 ambient_color = light_ambient * texture_sample;
    
    
    gl_FragColor = diffuse_color + ambient_color;
    gl_FragColor.a = 1.0;
}
`;

The variables I am trying to use between both shaders are light_position, light_ambient, and light_diffuse. How would I go about doing this?

1

1 Answers

3
votes

The link error is caused by the different precision in the vertex shader and fragment shader. See 4.5 Precision and Precision Qualifiers

From OpenGL ES Shading Language 1.00 Specification - 4.5.3 Default Precision Qualifiers

The vertex language has the following predeclared globally scoped default precision statements:

precision highp float;

The fragment shader has no default precision for float, hence you have specified the default precision mediump:

precision mediump float;

Thus the precision of the floating point uniforms are different in the fragment shader and vertex shader.

Either set an explicit mediump precision for floats in the vertex shader:

const vertex_shader = `
precision mediump float;
...

or change the precision in the fragment shader from medium to high.

Alternatively you can set an explicite precision qualifier to the uniform variables which are used in the vertex shader and fragment shader. For instance:

uniform mediump vec4 light_position;