Применить альфа к текстуре в определенных координатах пространства клипа - PullRequest
1 голос
/ 03 апреля 2019

Это не совсем та проблема, которая у меня есть, а упрощенная версия. Скажем, у меня одно изображение на весь экран. Я хочу изменить альфу этого изображения так, чтобы в левой половине (по горизонтали) экрана альфа составляла 0,5, а в правой половине альфа составляла 1. Просто альфа 0,5 или 1, ничего больше между ними.

Вот мои (неудачные) коды до сих пор

Это мои javascript коды для настройки webgl

this.gl = canvas.getContext('webgl', {
    alpha: false,
});
this.gl.enable(this.gl.BLEND);
this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE_MINUS_SRC_ALPHA);
this.gl.clearColor(1, 0, 0, 0); // red to highlight alpha problem

это мой код вершинного шейдера

mediump float;
attribute vec2 coordinates;
attribute vec2 a_texcoord;

varying vec2 v_texcoord;
varying float alpha;

void main() {
    gl_Position = vec4(coordinates.x, coordinates.y, 1.0, 1.0);
    v_texcoord = a_texcoord;
    if (coordinates.x <= 0) {
        alpha = 0.5;
    } else {
        alpha = 1.0;
    }
}    

и мой фрагментный шейдер стандартно прост

precision mediump float;
varying vec2 v_texcoord;
varying float alpha;
uniform sampler2D u_texture;
void main() {
    vec4 color = texture2D(u_texture, v_texcoord).rgba;
    gl_FragColor = color;
}

и во время розыгрыша

window.canvas.gl.clear(window.canvas.gl.COLOR_BUFFER_BIT);
window.canvas.gl.useProgram(this.drawProgram);
window.canvas.gl.bindBuffer(window.canvas.gl.ARRAY_BUFFER, this.vertexBuffer);
window.canvas.gl.enableVertexAttribArray(this.positionLocation);
window.canvas.gl.vertexAttribPointer(this.positionLocation, 2, window.canvas.gl.FLOAT, false, 0, 0);
window.canvas.gl.bindBuffer(window.canvas.gl.ARRAY_BUFFER, null);
window.canvas.gl.bindBuffer(window.canvas.gl.ARRAY_BUFFER, this.texcoordBuffer);
window.canvas.gl.enableVertexAttribArray(this.texcoordLocation);
window.canvas.gl.vertexAttribPointer(this.texcoordLocation, 2, window.canvas.gl.FLOAT, false, 0, 0);
window.canvas.gl.bindBuffer(window.canvas.gl.ARRAY_BUFFER, null);

window.canvas.gl.bindTexture(window.canvas.gl.TEXTURE_2D, this.texture);
window.canvas.gl.uniform1i(this.textureLocation, 0);
window.canvas.gl.drawArrays(window.canvas.gl.TRIANGLES, 0, 6);

С этими кодами я не смог добиться того, чего хочу. Во-первых, прозрачность начинается не с середины экрана (пространство клипа x = 0), а с, казалось бы, случайного места. Кроме того, наблюдается постепенное снижение от альфа 1,0 до альфа 0,5, а не только 2 значения 0,5 и 1,0, на которые я надеюсь. И я понятия не имею, откуда этот постепенный переход.

Очевидно, я изучаю webgl, поэтому любой указатель будет очень полезен. Любой намек на то, как решить проблему, очень помог бы мне. Заранее спасибо!

1 Ответ

0 голосов
/ 03 апреля 2019

прозрачность не начинается с середины экрана [..]

, поскольку alpha вычисляется для каждой вершины и интерполируется для фрагментов.

Вы должны выполнять оценку по фрагменту, а не по вершине.

Передача coordinates.x или gl_Position.x/gl_Position.w из вершинного шейдера в фрагментный шейдер:

mediump float;
attribute vec2 coordinates;
attribute vec2 a_texcoord;

varying vec2  v_texcoord;
varying vec2  pos;

void main() {
    gl_Position = vec4(coordinates.xy, 1.0, 1.0);
    v_texcoord = a_texcoord;
    pos        = coordinates.xy;
}    

Вычислить альфа-значение в фрагментном шейдере:

precision mediump float;

varying vec2 v_texcoord;
varying vec2 pos;

uniform sampler2D u_texture;

void main() {
    vec4 color = texture2D(u_texture, v_texcoord).rgba;
    float alpha = pos.x < 0.5 ? 0.5 : 1.0; 
    gl_FragColor = vec4(color.rgb, color.a * alpha);  
}

Обратите внимание, что вершинный шейдер выполняется один раз для каждой координаты вершины.Координаты определяют углы примитивов.Фрагментный шейдер выполняется для каждого фрагмента.Выходные параметры вершинного шейдера интерполируются в зависимости от положения фрагмента на примитиве.Интерполированное значение является входным значением для фрагментного шейдера.
Если в вершинном шейдере вычислено alpha, то значение alpha для фрагментов слева равно 0,5, а справа - 1,0.Фрагменты между ними получают гладко интерполированное значение в диапазоне [0,5, 1,0].
То же самое происходит с позицией, когда она передается из вершинного шейдера в фрагментный шейдер.Но поскольку alpha вычисляется в шейдере фрагмента, значение alpha каждого фрагмента равно либо 0,5, либо 1,0, в зависимости от интерполированного значения pos.x

...