WebGL: fade drawing buffer -
i've set preservedrawingbuffer
true
. doing results in drawn on buffer seen @ once, however, wondering if there way somehow fade buffer time goes on old elements drawn disappear on time, , newest drawn elements appear relatively high opacity until fade away.
is there better way achieve such effect?
i've tried render previous elements again lowering opacity until reaches 0 didn't seem efficient way of fading once drawn don't plan on changing it.
thanks!
it's common redraw stuff went on here
webgl: smoothly fade lines out of canvas
redrawing stuff means can keep things not fading out. example if you're making space shooting game , want explosions , missile trails fade out don't want spaceships , asteroids fade out need redrawing , manually fading stuff out drawn them while decreasing alpha
if want fade out can use post processing type effect.
you make 2 textures , attach them 2 framebuffers. blend/fade first framebuffer fadefb1
second 1 fadefb2
fadecolor using
gl_fragcolor = mix(texturecolor, fadecolor, mixamount);
you draw new stuff fadefb2
then draw fadefb2
canvas can see result.
the next frame same thing except swap buffer you're drawing , 1 you're fading to.
frame 0: mix(fadefb1,fadecolor)->fadefb2, draw->fadefb2, fadefb2->canvas frame 1: mix(fadefb2,fadecolor)->fadefb1, draw->fadefb1, fadefb1->canvas frame 2: mix(fadefb1,fadecolor)->fadefb2, draw->fadefb2, fadefb2->canvas ...
note don't clear when draw since need result left behind
as setting framebuffers there's tutorial here might useful
http://webglfundamentals.org/webgl/lessons/webgl-image-processing-continued.html
here's example using twgl since i'm lazy straight webgl
var vs = ` attribute vec4 position; uniform mat4 u_matrix; void main() { gl_position = u_matrix * position; } `; var fs = ` precision mediump float; uniform vec4 u_color; void main() { gl_fragcolor = u_color; } `; var vsquad = ` attribute vec4 position; attribute vec2 texcoord; varying vec2 v_texcoord; void main() { gl_position = position; v_texcoord = texcoord; } `; var fsfade = ` precision mediump float; varying vec2 v_texcoord; uniform sampler2d u_texture; uniform float u_mixamount; uniform vec4 u_fadecolor; void main() { vec4 color = texture2d(u_texture, v_texcoord); gl_fragcolor = mix(color, u_fadecolor, u_mixamount); } `; var fscopy = ` precision mediump float; varying vec2 v_texcoord; uniform sampler2d u_texture; void main() { gl_fragcolor = texture2d(u_texture, v_texcoord); } `; var $ = document.queryselector.bind(document); var mixamount = 0.05; var mixelem = $("#mix"); var mixvalueelem = $("#mixvalue"); mixelem.addeventlistener('input', function(e) { setmixamount(e.target.value / 100); }); function setmixamount(value) { mixamount = value; mixvalueelem.innerhtml = mixamount; } setmixamount(mixamount); var gl = $("canvas").getcontext("webgl"); var m4 = twgl.m4; var programinfo = twgl.createprograminfo(gl, [vs, fs]); var fadeprograminfo = twgl.createprograminfo(gl, [vsquad, fsfade]); var copyprograminfo = twgl.createprograminfo(gl, [vsquad, fscopy]); // creates -1 +1 quad var quadbufferinfo = twgl.primitives.createxyquadbufferinfo(gl); // creates rgba/unsigned_byte texture , depth buffer framebuffer var imgfbi = twgl.createframebufferinfo(gl); // creates 2 rgba texture + depth framebuffers var fadeattachments = [ { format: gl.rgba, min: gl.nearest, max: gl.nearest, wrap: gl.clamp_to_edge, }, { format: gl.depth_stencil }, ]; var fadefbi1 = twgl.createframebufferinfo(gl, fadeattachments); var fadefbi2 = twgl.createframebufferinfo(gl, fadeattachments); function drawthing(gl, x, y, rotation, scale, color) { var matrix = m4.ortho(0, gl.canvas.width, gl.canvas.height, 0, -1, 1); matrix = m4.translate(matrix, [x, y, 0]); matrix = m4.rotatez(matrix, rotation); matrix = m4.scale(matrix, [scale, scale, 1]); gl.useprogram(programinfo.program); twgl.setbuffersandattributes(gl, programinfo, quadbufferinfo); twgl.setuniforms(programinfo, { u_matrix: matrix, u_color: color, }); twgl.drawbufferinfo(gl, gl.triangles, quadbufferinfo); } function rand(min, max) { if (max === undefined) { max = min; min = 0; } return min + math.random() * (max - min); } function render(time) { if (twgl.resizecanvastodisplaysize(gl.canvas)) { twgl.resizeframebufferinfo(gl, fadefbi1, fadeattachments); twgl.resizeframebufferinfo(gl, fadefbi2, fadeattachments); } // fade copying fadefbi1 fabefbi2 using mixamount. // fadefbi2 contain mix(fadefb1, u_fadecolor, u_mixamount) twgl.bindframebufferinfo(gl, fadefbi2); gl.useprogram(fadeprograminfo.program); twgl.setbuffersandattributes(gl, fadeprograminfo, quadbufferinfo); twgl.setuniforms(fadeprograminfo, { u_texture: fadefbi1.attachments[0], u_mixamount: mixamount, u_fadecolor: [0, 0, 0, 0], }); twgl.drawbufferinfo(gl, gl.triangles, quadbufferinfo); // draw new stuff fadefb2. notice don't clear! twgl.bindframebufferinfo(gl, fadefbi2); var x = rand(gl.canvas.width); var y = rand(gl.canvas.height); var rotation = rand(math.pi); var scale = rand(10, 20); var color = [rand(1), rand(1), rand(1), 1]; drawthing(gl, x, y, rotation, scale, color); // copy fadefbi2 canvas can see result twgl.bindframebufferinfo(gl, null); gl.useprogram(copyprograminfo.program); twgl.setbuffersandattributes(gl, copyprograminfo, quadbufferinfo); twgl.setuniforms(copyprograminfo, { u_texture: fadefbi2.attachments[0], }); twgl.drawbufferinfo(gl, gl.triangles, quadbufferinfo); // swap variables render opposite textures next time var temp = fadefbi1; fadefbi1 = fadefbi2; fadefbi2 = temp; requestanimationframe(render); } requestanimationframe(render);
body { margin: 0; } canvas { display: block; width: 100vw; height: 100vh; } #ui { position: absolute; top: 0 }
<script src="https://twgljs.org/dist/twgl-full.min.js"></script> <canvas></canvas> <div id="ui"> <span>mix:</span><input id="mix" type="range" min="0" max="100" value="5" /><span id="mixvalue"></span> </div>
Comments
Post a Comment