Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
374 views
in Technique[技术] by (71.8m points)

javascript - Efficient HTML5 Canvas Glow Effect without shape

I am creating a game using the HTML5 Canvas element, and as one of the visual effects I would like to create a glow (like a light) effect. Previously for glow effects I found solutions involving creating shadows of shapes, but these require a solid shape or object to cast the shadow. What I am looking for is a way to create something like an ambient light glow with a source location but no object at the position.

Something I have thought of was to define a centerpoint x and y and create hundreds of concentric circles, each 1px larger than the last and each with a very low opacity, so that together they create a solid center and a transparent edge. However, this is very computationally heavy and does not seem elegant at all, as the resulting glow looks awkward.

While this is all that I am asking of and I would be more than happy to stop here, bonus points if your solution is A) computationally light, B) modifiable to create a focused direction of light, or even better, C) if there was a way to create an "inverted" light system in which the entire screen is darkened by a mask and the shade is lifted where there is light.

I have done several searches, but none have turned up any particularly illuminating results.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

So I'm not quite sure what you want, but I hope the following snippet will help.

Instead of creating a lot of concentric circles, create one radialGradient.
Then you can combine this radial gradient with some blending, and even filters to modify the effect as you wish.

var img = new Image();
img.onload = init;
img.src = "https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/car.svg";
var ctx = c.getContext('2d');
var gradCtx = c.cloneNode().getContext('2d');
var w, h;
var ratio;

function init() {
  w = c.width = gradCtx.canvas.width = img.width;
  h = c.height = gradCtx.canvas.height = img.height;
  draw(w / 2, h / 2)
  updateGradient();
  c.onmousemove = throttle(handleMouseMove);
}

function updateGradient() {
  var grad = gradCtx.createRadialGradient(w / 2, h / 2, w / 8, w / 2, h / 2, 0);
  grad.addColorStop(0, 'transparent');
  grad.addColorStop(1, 'white');
  gradCtx.fillStyle = grad;
  gradCtx.filter = "blur(5px)";
  gradCtx.fillRect(0, 0, w, h);
}

function handleMouseMove(evt) {
  var rect = c.getBoundingClientRect();
  var x = evt.clientX - rect.left;
  var y = evt.clientY - rect.top;
  draw(x, y);
}

function draw(x, y) {
  ctx.clearRect(0, 0, w, h);
  ctx.globalCompositeOperation = 'source-over';
  ctx.drawImage(img, 0, 0);
  ctx.globalCompositeOperation = 'destination-in';
  ctx.drawImage(gradCtx.canvas, x - w / 2, y - h / 2);
  ctx.globalCompositeOperation = 'lighten';
  ctx.fillRect(0, 0, w, h);
}

function throttle(callback) {
  var active = false; // a simple flag
  var evt; // to keep track of the last event
  var handler = function() { // fired only when screen has refreshed
    active = false; // release our flag 
    callback(evt);
  }
  return function handleEvent(e) { // the actual event handler
    evt = e; // save our event at each call
    if (!active) { // only if we weren't already doing it
      active = true; // raise the flag
      requestAnimationFrame(handler); // wait for next screen refresh
    };
  }
}
<canvas id="c"></canvas>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...