Создание эффективного раннего экземпляра шейдера верстекста WebGL2 - PullRequest
1 голос
/ 29 января 2020

Отбрасывание экземпляров в вершинном шейдере

Я использую экземплярный geom для отображения контента с использованием webGL2. Как часть процесса, каждый экземпляр имеет компонент цвета, который в некоторых случаях может иметь значение альфа-канала равное нулю.

Вместо того, чтобы передать его фрагментному шейдеру для отбрасывания, я проверяю альфа в шейдере vertext. Если ноль, то я вывожу каждый вершин как vec4(-2), чтобы поместить его вне клипа или, в худшем случае, иметь точку в 1 пиксель.

Я не могу найти информацию о том, как это обрабатывается каналом рендеринга.

Является ли это лучшей стратегией для удаления экземпляров из конвейера?

Альтернативой является удаление экземпляров из буфера, который в JS является интенсивной операцией ЦП при работе с 1000 экземплярами.

Шейдеры

const vertexSrc = `#version 300 es
    #define alphaCut 0.0
    in vec2 verts;
    in vec2 pos;       
    in vec2 scale;     
    in vec2 offset;    
    in float rotate;   
    in float zIdx;     // z index for zBuf clip only 
    in vec4 color;     // RGBA to color.a == 0.0 to remove not render
    in uint spriteIdx; 
    uniform vec4 sheetLayout[128];
    uniform vec2 sheetSize;     
    uniform mat2 view;              
    uniform vec2 origin;  
    out vec2 spr;
    out vec4 col;
    void main() {
        if (color.a <= alphaCut) { 
            gl_Position = vec4(-2); // put this instance outside clip
            return; 
        }
        col = color;
        vec4 sprite = sheetLayout[spriteIdx];
        spr = sprite.xy + verts * sprite.zw / sheetSize;
        vec2 loc = (verts - offset) * scale * sprite.zw;
        float xdx = cos(rotate);
        float xdy = sin(rotate);
        loc = view * (vec2(loc.x * xdx - loc.y * xdy, loc.x * xdy + loc.y * xdx) + pos - origin);
        gl_Position =  vec4(loc, zIdx, 1);
    }`;

const fragmentSrc = `#version 300 es
    precision mediump float;
    uniform sampler2D tex;
    #define alphaCut 0.0;
    in vec2 spr;
    in vec4 col;
    out vec4 pixel;
    void main() {
        pixel = texture(tex, spr) * col;
        if (pixel.a <= alphaCut) { discard; }
    }`; 

1 Ответ

0 голосов
/ 29 января 2020

Как указано в комментариях к вопросу и удаленном ответе, для перемещения вершины за пределы пространства клипа требуется gl_Position = vec4(vec3(-2), 1)

Установка gl_Position = vec4(-2) установит для вершины значение vec3(1) (вверху справа на ближний самолет). Это внутри области клипа и, следовательно, экземпляр geom окажется в фрагментном шейдере.

Но почему?

Перспективное деление

Когда вершина перемещается из вершинного шейдера как gl_position это как вектор 4D. Чтобы обрезать вершину, нам нужен трехмерный вектор, который находится за пределами пространства трехмерного обрезания.

Нормализация вершины из 4D в 3D называется перспективным делением и выполняется автоматически путем деления векторов x, y и z для компонентов w.

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

#define alphaCut 0.1
//...
void main() {
    if (color.a <= alphaCut) { 
        gl_Position = vec4(vec3(2), 1);
        return; 
    }
    //... rest of code
...