2015-01-27 4 views
2

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

У меня был некоторый успех, чтобы сохранитьAlphaBuffer в true и иметь след в фреймбуфере, но я не могу заставить фреймбуфер смешаться с бэкбуфером. Все, что я получаю, это фреймбуфер с солидным фоном. Я начинаю чувствовать, что это невозможно, поскольку я пробовал практически каждую комбинацию blendFunc и blendFuncSeparate. Надеюсь, есть кто-то, кто может помочь мне реализовать этот эффект?

var sketch; 
 
function init() { 
 

 
    sketch = new Sketch(); 
 
    document.body.appendChild(sketch); 
 

 
    sketch.width = window.innerWidth; 
 
    sketch.height = window.innerHeight; 
 

 
    loop(); 
 
} 
 

 
function loop() { 
 
    requestAnimationFrame(loop); 
 
    sketch.draw(); 
 
} 
 

 

 
var Sketch = function() { 
 

 
    var _canvas = document.createElement("canvas"); 
 
    var _gl; 
 
    var _image; 
 
    var _program, _fboProgram; 
 
    var _loaded = false; 
 
    var _fbo, _fboTexture,_texture; 
 

 
    var pos = { 
 
     x: 0, y: 0 
 
    }; 
 

 
    var speed = { 
 
     x: 10, 
 
     y: 10 
 
    } 
 

 
    function init() { 
 

 
     //start preloading image 
 
     _image = new Image(); 
 
     _image.onload = function() { 
 
      setTimeout(function() { 
 
       render(); 
 
      }, 1); 
 
     } 
 
     _image.src = "img/texture.png"; 
 
    } 
 

 
    function render() { 
 
     _gl = _canvas.getContext("experimental-webgl", {preserveDrawingBuffer: true});//setupWebGL(canvas, {preserveDrawingBuffer: true});//getWebGLContext(_canvas); 
 

 
     initCanvas(); 
 
     initFbo(); 
 

 
     _loaded = true; 
 
    } 
 

 
    function initCanvas() { 
 
     _program = initShaders(_gl, "vertex-shader", "fragment-shader"); 
 
     _gl.useProgram(_program); 
 
     initVertexShaderLocations(_program); 
 

 
     _gl.clearColor(1, 1, 1, 0); // red 
 
     _gl.clear(_gl.COLOR_BUFFER_BIT); 
 

 
     _texture = initTexture(_gl, _image); 
 

 
     _gl.enable(_gl.BLEND); 
 
     _gl.disable(_gl.DEPTH_TEST); 
 

 
     _gl.colorMask(1, 1, 1, 1); 
 
    } 
 

 
    function initFbo() { 
 

 
     _fboProgram = initShaders(_gl, "vertex-shader", "fbo-fragment-shader");//"2d-fragment-shader"); 
 

 
     _gl.useProgram(_fboProgram); 
 
     initVertexShaderLocations(_fboProgram); 
 

 
     _texture = initTexture(_gl, _image); 
 

 
     // create an empty texture 
 
     _fboTexture = _gl.createTexture(); 
 
     _gl.bindTexture(_gl.TEXTURE_2D, _fboTexture); 
 

 
     _gl.texParameteri(_gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE); 
 
     _gl.texParameteri(_gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE); 
 
     _gl.texParameteri(_gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, _gl.NEAREST); 
 
     _gl.texParameteri(_gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, _gl.NEAREST); 
 
     _gl.texImage2D(_gl.TEXTURE_2D, 0, _gl.RGBA, _gl.canvas.width, _gl.canvas.height, 0, _gl.RGBA, _gl.UNSIGNED_BYTE, null); 
 

 
     // Create a framebuffer and attach the texture. 
 
     _fbo = _gl.createFramebuffer(); 
 

 
     _gl.bindFramebuffer(_gl.FRAMEBUFFER, _fbo); 
 
     _gl.framebufferTexture2D(_gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, _fboTexture, 0); 
 

 
     _gl.viewport(0, 0, _gl.canvas.width, _gl.canvas.height); 
 
     _gl.clearColor(1, 1, 1, 0.2); 
 

 
     _gl.clear(_gl.COLOR_BUFFER_BIT); 
 

 
    } 
 

 

 
    function drawCanvas() { 
 

 
     _gl.useProgram(_program); 
 
     _gl.clearColor(1, 1, 1, 1); // red 
 
     _gl.clear(_gl.COLOR_BUFFER_BIT); 
 

 
     renderTexture(_program); 
 
     renderFbo(_program); 
 

 
     _loaded = true; 
 
    } 
 

 
    function drawFbo() { 
 
     _gl.bindFramebuffer(_gl.FRAMEBUFFER, _fbo); 
 

 
     _gl.useProgram(_fboProgram); 
 
     _gl.blendFunc(_gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA); 
 

 
     var blur = [ 
 
      0, 1, 0, 
 
      1, 1, 1, 
 
      0, 1, 0 
 
     ]; 
 

 
     var kernelLocation = _gl.getUniformLocation(_fboProgram, "u_kernel[0]"); 
 
     _gl.uniform1fv(kernelLocation, blur); 
 

 
     var textureSizeLocation = _gl.getUniformLocation(_fboProgram, "u_textureSize"); 
 
     _gl.uniform2f(textureSizeLocation, _image.width, _image.height); 
 

 
     // Render to the texture (using clear because it's simple) 
 
     _gl.clearColor(1, 1, 1, 0); // green; 
 
     _gl.clear(_gl.COLOR_BUFFER_BIT); 
 

 
     renderTexture(_fboProgram); 
 

 
     _gl.bindFramebuffer(_gl.FRAMEBUFFER, null); 
 
    } 
 

 

 
    function renderFbo(program) { 
 

 
     _gl.uniform2f(program.resolutionLocation, _gl.canvas.width, _gl.canvas.height); 
 
     _gl.uniform1f(program.flipYLocation, 1); 
 

 
     _gl.bindBuffer(_gl.ARRAY_BUFFER, program.texCoordBuffer); 
 
     setRectangle(_gl, 0, 0, 1, 1); 
 
     _gl.enableVertexAttribArray(program.texCoordLocation); 
 
     _gl.vertexAttribPointer(program.texCoordLocation, 2, _gl.FLOAT, false, 0, 0); 
 

 
     _gl.bindBuffer(_gl.ARRAY_BUFFER, program.positionBuffer); 
 
     setRectangle(_gl, 0, 0, _gl.canvas.width, _gl.canvas.height); 
 
     _gl.vertexAttribPointer(program.positionLocation, 2, _gl.FLOAT, false, 0, 0); 
 

 
     _gl.bindTexture(_gl.TEXTURE_2D, _fboTexture); 
 
     _gl.drawArrays(_gl.TRIANGLES, 0, 6); 
 
    } 
 

 
    function renderTexture(program) { 
 

 
     _gl.uniform1f(program.flipYLocation, 1.0); 
 

 
     _gl.bindBuffer(_gl.ARRAY_BUFFER, program.texCoordBuffer); 
 
     setRectangle(_gl, 0, 0, 1, 1); 
 
     _gl.enableVertexAttribArray(program.texCoordLocation); 
 
     _gl.vertexAttribPointer(program.texCoordLocation, 2, _gl.FLOAT, false, 0, 0); 
 

 
     _gl.bindBuffer(_gl.ARRAY_BUFFER, program.positionBuffer); 
 
     setRectangle(_gl, pos.x, pos.y, _image.width, _image.height); 
 
     _gl.vertexAttribPointer(program.positionLocation, 2, _gl.FLOAT, false, 0, 0); 
 
     _gl.enableVertexAttribArray(program.positionLocation); 
 

 
     // Tell the shader the resolution of the framebuffer. 
 
     _gl.uniform2f(program.resolutionLocation, _gl.canvas.width, _gl.canvas.height); 
 

 
     _gl.bindTexture(_gl.TEXTURE_2D, _texture); 
 
     _gl.drawArrays(_gl.TRIANGLES, 0, 6); 
 
    } 
 

 
    function setRectangle(gl, x, y, width, height) { 
 
     var x1 = x; 
 
     var x2 = x + width; 
 
     var y1 = y; 
 
     var y2 = y + height; 
 
     gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 
 
      x1, y1, 
 
      x2, y1, 
 
      x1, y2, 
 
      x1, y2, 
 
      x2, y1, 
 
      x2, y2]), gl.STATIC_DRAW); 
 
    } 
 

 
    function initVertexShaderLocations(program){ 
 
     program.texCoordLocation = _gl.getAttribLocation(program, "a_texCoord"); 
 
     program.positionLocation = _gl.getAttribLocation(program, "a_position"); 
 
     program.resolutionLocation = _gl.getUniformLocation(program, "u_resolution"); 
 
     program.flipYLocation = _gl.getUniformLocation(program, "u_flipY"); 
 
     program.positionBuffer = _gl.createBuffer(); 
 
     program.texCoordBuffer = _gl.createBuffer(); 
 
    } 
 

 
    function initTexture(gl, image) { 
 

 
     var texture = gl.createTexture(); 
 
     gl.bindTexture(gl.TEXTURE_2D, texture); 
 

 
     // Set up texture so we can render any size image and so we are 
 
     // working with pixels. 
 
     gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 
 
     gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 
 
     gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); 
 
     gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); 
 

 
     gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); 
 

 
     return texture; 
 
    } 
 

 
    function initShaders(gl, vert, frag) { 
 
     // setup a GLSL program 
 
     var vertexShader = createShaderFromScriptElement(gl, vert); 
 
     var fragmentShader = createShaderFromScriptElement(gl, frag); 
 
     return createProgram(gl, [vertexShader, fragmentShader]); 
 
    } 
 

 
    _canvas.draw = function() { 
 

 
     if (!_loaded) 
 
      return; 
 

 
     if (pos.x + 256 > _gl.canvas.width || pos.x < 0) speed.x *= -1; 
 
     if (pos.y + 256 > _gl.canvas.height || pos.y < 0) speed.y *= -1; 
 

 
     pos.x += speed.x; 
 
     pos.y += speed.y; 
 

 
     drawFbo(); 
 
     drawCanvas(); 
 
    } 
 

 
    init(); 
 
    return _canvas; 
 

 
} 
 

 

 
init();
<body> 
 

 

 
<script id="vertex-shader" type="x-shader/x-vertex"> 
 
attribute vec2 a_position; 
 
attribute vec2 a_texCoord; 
 
varying vec2 v_texCoord; 
 
uniform vec2 u_resolution; 
 
uniform float u_flipY; 
 

 
void main() { 
 

 
    // convert the rectangle from pixels to 0.0 to 1.0 
 
    vec2 zeroToOne = a_position/u_resolution; 
 

 
    // convert from 0->1 to 0->2 
 
    vec2 zeroToTwo = zeroToOne * 2.0; 
 

 
    // convert from 0->2 to -1->+1 (clipspace) 
 
    vec2 clipSpace = zeroToTwo - 1.0; 
 

 
    gl_Position = vec4(clipSpace * vec2(1, u_flipY), 0, 1); 
 

 
    v_texCoord = a_texCoord; 
 
} 
 

 
</script> 
 

 

 
<script id="fragment-shader" type="x-shader/x-fragment"> 
 
precision mediump float; 
 

 
// our texture 
 
uniform sampler2D u_image; 
 

 
// the texCoords passed in from the vertex shader. 
 
varying vec2 v_texCoord; 
 

 
void main() { 
 
    // Look up a color from the texture. 
 
    vec4 color = texture2D(u_image, v_texCoord); 
 

 
    if(color.a < 0.9) 
 
    color.a = 0.1; 
 

 
    gl_FragColor = color; 
 
} 
 

 

 
</script> 
 
<script id="fbo-fragment-shader" type="x-shader/x-fragment"> 
 
    precision mediump float; 
 

 
    // our texture 
 
    uniform sampler2D u_image; 
 
    // the texCoords passed in from the vertex shader. 
 
    varying vec2 v_texCoord; 
 

 
    void main() { 
 

 
     vec4 color = texture2D(u_image, v_texCoord); 
 

 
     if(color.r > 0.5) 
 
      color.a = 0.01; 
 

 
     gl_FragColor = color; 
 
    } 
 

 
</script> 
 

 

 
</body>

+0

Добро пожаловать в stackoverflow! У вас много избыточных вызовов в коде, поэтому вы можете вернуться к нескольким шагам и проделать свой путь через каждый шаг и убедиться, что знаете, что делает каждый звонок, утверждая свои предположения о текущем состоянии с помощью методов " getParameter "-семейство (" getShaderParameter "," getProgramParameter ", ...) посмотреть их здесь https://www.khronos.org/registry/webgl/specs/latest/1.0/ – Winchestro

+0

Не могли бы вы включить ваши шейдеры или лучше , опубликовать его с помощью http://jsfiddle.net/ например? Arnt вы ищете это: http://youtu.be/rfQ8rKGTVlg?t=31m46s? –

+2

Хорошо, я снял увольнения и включил шейдеры, которые я использую. Я не смог получить пример jsfiddle, работающий из-за проблем с изображением, которое я использовал, но, надеюсь, ясно, что я пытаюсь сделать.Вы увидите, что fbo-шейдер удаляет все красное изображение, поскольку я пытаюсь только отслеживать другие цвета (текстура, которую я использую, только красная и зеленая, поэтому я бы хотел увидеть все зеленые цвета задняя часть после формы) – Kev

ответ

0

Так что я сделал это короткое демо:

http://jsfiddle.net/windkiller/c46Lvbzp/

// custom fn 

function createShaderFromScriptElement(gl, scriptId) { 
    var shaderSource = "", 
     shaderType; 
    var shaderScript = document.getElementById(scriptId); 
    if (!shaderScript) { 
     throw ("*** Error: unknown script element" + scriptId); 
    } 
    shaderSource = shaderScript.text; 

    if (shaderScript.type == "x-shader/x-vertex") { 
     shaderType = gl.VERTEX_SHADER; 
    } else if (shaderScript.type == "x-shader/x-fragment") { 
     shaderType = gl.FRAGMENT_SHADER; 
    } else if (shaderType != gl.VERTEX_SHADER && shaderType != gl.FRAGMENT_SHADER) { 
     throw ("*** Error: unknown shader type"); 
     return null; 
    } 

    var shader = gl.createShader(shaderType); 

    // Load the shader source 
    gl.shaderSource(shader, shaderSource); 

    // Compile the shader 
    gl.compileShader(shader); 

    // Check the compile status 
    var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS); 
    if (!compiled) { 
     // Something went wrong during compilation; get the error 
     var lastError = gl.getShaderInfoLog(shader); 
     errFn("*** Error compiling shader '" + shader + "':" + lastError); 
     gl.deleteShader(shader); 
     return null; 
    } 

    return shader; 
} 

function createProgram(gl, shaders) { 

    var shaderProgram = gl.createProgram(); 
    gl.attachShader(shaderProgram, shaders[0]); 
    gl.attachShader(shaderProgram, shaders[1]); 
    gl.linkProgram(shaderProgram); 

    if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { 
     alert("Could not initialise shaders"); 
    } 
    // HINT dont use program here 
    return shaderProgram; 
} 

я должен был сделать несколько вещей вручную, это резюме: * createShaderFromScript и createProgram функции отсутствовали, поэтому я сделал это. Я уверен, что у вас их есть, поэтому просто игнорируйте это. * У меня не было текстуры, поэтому я сделал изображение base64 с зелеными и красными цветами и использовал его как текстуру. Это довольно долго, поэтому я не добавил код здесь.

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

Но у меня возникло ощущение, что у вас есть ошибка, как вы работаете с буферами кадров! Поэтому я попытался обменять призывы на призыв:

drawCanvas(); 
    drawFbo(); 

И это что-то сделало! Так что я тоже: * увеличить скорость * шейдеры немного изменить (только переменные для расчета альфа) * сделано кнопка остановки/запуска

Теперь при запуске демо и использовать стоп, вы увидите две картины, одна greenred и второй смешанный зеленый, где более красный = менее видимый (зеленый цвет делает более крупный след, затем красный).

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

Смежные вопросы