Как использовать текстуру и цвет также в WebGL? - PullRequest
1 голос
/ 18 декабря 2011

Я изучаю WebGL, и я хотел бы создать программу, в которой есть цветные и текстурированные объекты. Я попытался немного изменить фрагментный шейдер: если объект не имеет текстуры, он будет окрашен.

precision mediump float;

varying vec4 vColor;
varying vec2 vTextureCoord;

uniform sampler2D uSampler;

void main(void) {
    gl_FragColor = vColor;
    gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
}

Это не работает. Я получаю сообщение об ошибке: не удалось инициализировать шейдеры.

Ответы [ 2 ]

8 голосов
/ 21 декабря 2011

Это может иметь или не иметь смысла, но если у вас есть текстура или нет, требуются разные шейдеры.Чтобы обойти это, многие люди используют однопиксельную белую текстуру, когда им не нужны текстуры.Таким образом, им нужен только 1 шейдер для обоих случаев.Шейдер может выглядеть примерно так

uniform vec4 u_color;
uniform sampler2D u_texture;

varying vec2 v_texCoord;

void main(void) {
  gl_FragColor = texture2D(u_texture, v_texCoord) * u_color;
}

Теперь, в вашем коде вы можете рисовать текстурированно вот так

// at init time.
var whiteColor = new Float32Array([1, 1, 1, 1]);

// at draw time
gl.uniform4fv(u_colorLocation, whiteColor);  // use white color
gl.bindTexture(gl.TEXTURE_2D, someTexture);  // and some texture
... draw ...

А для рисования без текстуры вы делаете это

// at init time.
var whiteTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, whiteTexture);
var whitePixel = new Uint8Array([255, 255, 255, 255]);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, 
              gl.RGBA, gl.UNSIGNED_BYTE, whitePixel);


// at draw time
gl.uniform4fv(u_colorLocation, someColor);  // use the color I want
gl.bindTexture(gl.TEXTURE_2D, whiteTexture);  // use the white texture
... draw ...

Это также дает вам возможность окрашивать ваши текстуры, используя не белый цвет и текстуру вместе.

3 голосов
/ 19 декабря 2011

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

Между тем, я могу дать вам пару советов о шейдере, который вы опубликовали.С одной стороны, это не даст вам эффект, который вы описали.Что на самом деле произойдет, так это то, что он всегда будет показывать цвет текстуры или, если текстура не указана, отображать черный цвет.Цвет вершины никогда не будет показан.Это потому, что вы присваиваете последний цвет фрагмента дважды, при этом второе присваивание всегда переопределяет первое.

Возможно, вы захотите попробовать смешать два значения вместе путем добавления или умножения значений цвета и текстуры,Попробуйте что-то вроде этого:

gl_FragColor = vColor + texture2D(uSampler, vTextureCoord);

Единственная проблема в том, что если текстура пуста, вы все равно получите черный (все, что умножено на 0, все равно равно 0).Чтобы избежать этого, всегда используйте сплошную белую текстуру, если у вас нет фактической текстуры.

Если вы хотите точный эффект, который вы описали (вершинный цвет только при отсутствии текстуры), вам может понадобиться использовать условныйзаявление.Этого обычно лучше избегать, но я сомневаюсь, что ваше использование будет чем-то ужасно тяжелым.

Кроме того, в качестве подсказки стиля следующие строки эквивалентны:

vec2(vTextureCoord.s, vTextureCoord.t)
vTextureCoord.st

Вторая может быть быстрее,однако и должно быть предпочтительным.Помимо этого, однако, вы можете просто передать vTextureCoord напрямую (как я показал), потому что это уже a vec2.

...