Я работаю над созданием эффекта цветовой трассы в 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>
Добро пожаловать в stackoverflow! У вас много избыточных вызовов в коде, поэтому вы можете вернуться к нескольким шагам и проделать свой путь через каждый шаг и убедиться, что знаете, что делает каждый звонок, утверждая свои предположения о текущем состоянии с помощью методов " getParameter "-семейство (" getShaderParameter "," getProgramParameter ", ...) посмотреть их здесь https://www.khronos.org/registry/webgl/specs/latest/1.0/ – Winchestro
Не могли бы вы включить ваши шейдеры или лучше , опубликовать его с помощью http://jsfiddle.net/ например? Arnt вы ищете это: http://youtu.be/rfQ8rKGTVlg?t=31m46s? –
Хорошо, я снял увольнения и включил шейдеры, которые я использую. Я не смог получить пример jsfiddle, работающий из-за проблем с изображением, которое я использовал, но, надеюсь, ясно, что я пытаюсь сделать.Вы увидите, что fbo-шейдер удаляет все красное изображение, поскольку я пытаюсь только отслеживать другие цвета (текстура, которую я использую, только красная и зеленая, поэтому я бы хотел увидеть все зеленые цвета задняя часть после формы) – Kev