Как сохранить значение внутри шейдера фрагментов, чтобы использовать его позже?



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



В настоящее время я готовлю изображение, используя огромный алгоритм, и я хочу сохранить его в некотором vec4, и, как только меня снова попросят, я хочу просто получить этот vec4 и должен сказать



gl_FragColor = vec4(previously saved variable)



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



Есть предложения ?

498   2  

2 ответов:

Фрагмент шейдеров в WebGL напишите 1 из 2 вещей. Либо (1) холст, либо (2) вложения буфера кадров. Вложения фреймбуффера могут быть текстурами. Текстуры можно использовать в качестве входных данных для шейдера. Поэтому вы можете написать текстуру и использовать ее в следующем розыгрыше.

Вот пример

var vs = `
attribute vec4 position;
void main() {
  gl_Position = position;
}
`;
var fs = `
precision mediump float;
uniform sampler2D u_texture;
void main() {
  // just grab the middle pixel(s) from the texture
  // but swizzle the colors g->r, b->g, r->b
  gl_FragColor = texture2D(u_texture, vec2(.5)).gbra;
}`;

var canvas = document.querySelector("canvas");
var gl = canvas.getContext("webgl");
var program = twgl.createProgramFromSources(gl, [vs, fs]);

var positionLocation = gl.getAttribLocation(program, "position");
// we don't need to look up the texture's uniform location because
// we're only using 1 texture. Since the uniforms default to 0
// it will use texture 0.

// put in a clipspace quad
var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
  -1, -1,
   1, -1,
  -1,  1,
  -1,  1,
   1, -1,
   1,  1,
]), gl.STATIC_DRAW);
  

gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);

// make 2 1x1 pixel textures and put a red pixel the first one
var tex1 = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex1);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA,
              gl.UNSIGNED_BYTE, new Uint8Array([255, 0, 0, 255]));
var tex2 = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex2);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA,
              gl.UNSIGNED_BYTE, null);

// make a framebuffer for tex1
var fb1 = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb1);
// attach tex1
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, 
                        gl.TEXTURE_2D, tex1, 0);
// check this will actually work
if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) !==
    gl.FRAMEBUFFER_COMPLETE) {
  alert("this combination of attachments not supported");
}

// make a framebuffer for tex2
var fb2 = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);
// attach tex2
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, 
                        gl.TEXTURE_2D, tex2, 0);
// check this will actually work
if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) !==
    gl.FRAMEBUFFER_COMPLETE) {
  alert("this combination of attachments not supported");
}

function render() {
  gl.useProgram(program);
  // render tex1 to the tex2
  
  // input to fragment shader
  gl.bindTexture(gl.TEXTURE_2D, tex1);  
  
  // output from fragment shader
  gl.bindFramebuffer(gl.FRAMEBUFFER, fb2);  
  gl.viewport(0, 0, 1, 1);
  gl.drawArrays(gl.TRIANGLES, 0, 6);
  
  // render to canvas so we can see it
  gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
  // input to fragment shader, the texture we just rendered to
  gl.bindTexture(gl.TEXTURE_2D, tex2);
  gl.drawArrays(gl.TRIANGLES, 0, 6);
  
  // swap which texture we are rendering from and to
  var t = tex1;
  tex1 = tex2;
  tex2 = t;
  
  var f = fb1;
  fb1 = fb2;
  fb2 = f;
  
  requestAnimationFrame(render);
}
requestAnimationFrame(render);
<script src="https://twgljs.org/dist/twgl-full.min.js"></script>
<canvas></canvas>

Приведенный выше образец помещает красный цвет в текстуру. Затем он визуализирует эту текстуру, прокручивая цвет. Зеленый переходит в красный канал, синий переходит на зеленый канал, Красный переходит в синий канал.

Я делает 2 текстуры и придает им 2 фреймбуфферов.

Первая итерация

tex1 = red
tex2 = 0,0,0,0
render to fb2
tex2 is now blue (because red was copied to blue)
render tex2 to canvas (canvas is now green because blue is copied to green)
switch which textures we're rendering to

Вторая итерация

tex1 = blue (was tex2 last time) 
tex2 = red  (was tex1 last time)
render to fb2 (was fb1 last time)
tex2 = green (because blue is copied to green)
render tex2 to canvas (canvas is now red because green is copied to red)
switch which textures we're rendering to

Шейдер фрагментов выполняется для каждого фрагмента (пикселя).И как любой другой шейдер, он не может хранить значения по умолчанию, как можно было бы ожидать в обычном языке программирования. Есть несколько способов сделать то, что вы хотите: Вы можете использовать imageLoad/Store ,который позволяет считывать и записывать данные из шейдера в изображение.Image использует текстуры GL в качестве памяти.Что хорошо в нем, так это то, что вы можете хранить и загружать числовые данные без потери точности при использовании изображений, потому что фильтрация текстур отключен при доступе к текстурным данным через изображение.

Другой способ хранения и чтения данных в шейдерах - использование буферов.Однородные буферы, или начиная с GL4.3 буферы хранения шейдеров.. SSBO позволяет читать и писать огромное количество data.It это действительно зависит от вас, чтобы решить, какие из них использовать для хранения и извлечения ваших данных в шейдерах.Некоторые люди говорят, что доступ к текстурной памяти быстрее на некоторых аппаратных средствах.По моему опыту, используя SSBO vs image load store, я не нашел существенной разницы в производительности на графических процессорах Nvidia.

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

Кроме того ,я действительно не знаю, какую версию OpenGL вы используете, но для использования этих расширений вы должны использовать GL4.2 и GL4.3.

Comments

    Ничего не найдено.