Использование одной и той же равномерной переменной между двумя шейдерами в WebGL - PullRequest
2 голосов
/ 04 мая 2020

Я использую WebGL, чтобы попытаться визуализировать сцену как с цветом, так и с текстурами, причем цвета визуализируются с помощью вершинного шейдера, а текстуры - с помощью фрагментного шейдера. Оба шейдера используют одни и те же одинаковые переменные, однако WebGL не позволяет мне передавать их между обоими, только одной или другой. Я получаю сообщение об ошибке «Единая переменная не связана между подключенными шейдерами». Я просматривал аналогичные сообщения других пользователей по этой проблеме, однако мне не удалось найти ту, которая соответствовала бы моей ситуации. Мой код выглядит следующим образом:

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;
}
`;

Переменные, которые я пытаюсь использовать между обоими шейдерами: light_position, light_ambient и light_diffuse. Как бы я go об этом?

Заранее спасибо.

1 Ответ

2 голосов
/ 04 мая 2020

Ошибка связи вызвана различной точностью в вершинном шейдере и фрагментном шейдере. См. 4.5 Прецизионные и прецизионные классификаторы

Из OpenGL ES Shading Language 1.00 Спецификация - 4.5.3 Стандартные прецизионные квалификаторы

Язык вершин имеет следующие предварительно объявленные глобальные операторы точности по умолчанию:

precision highp float;

Фрагментный шейдер не имеет точности по умолчанию для float, поэтому вы указали точность по умолчанию mediump:

precision mediump float;

Таким образом, точность форм с плавающей запятой различна в фрагментном шейдере и вершинном шейдере.

Либо установите явную mediump точность для float с в вершинном шейдере:

const vertex_shader = `
precision mediump float;
...

или измените точность в фрагментном шейдере с medium на high.

В качестве альтернативы вы можете установить квалификатор явной точности для равномерных переменных, которые используются в вершинном шейдере и фрагментном шейдере. Например:

uniform mediump vec4 light_position;
...