【问题标题】:How do I clip / use globalCompositeOperation = "desination-out" to exclude 2 circles from my Canvas?如何剪辑/使用 globalCompositeOperation = "destination-out" 从我的画布中排除 2 个圆圈?
【发布时间】:2017-11-20 22:29:58
【问题描述】:

我正在尝试找出CanvasRenderingContext2D.globalCompositeOperation = "destination-out 以创建“战争迷雾”效果。

举个例子

https://jsfiddle.net/wobzpjLL/

var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");

// a green background box
ctx.fillStyle = "green";
ctx.fillRect(0,0,300,150); 

// a line
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(300, 150);
ctx.stroke();

// Fog of war
ctx.fillStyle = "black";
ctx.fillRect(0,0,300,150); 

// Here I want two circles that shows the background (green & line)

// text
ctx.fillStyle = "red";
ctx.font = "30px Arial";
ctx.fillText("Hello World",10,50); 

如何创建两个不包括黑色叠加层的圆圈,以便用户可以看到绿色背景和线条,在这两个圆圈内,其他地方都是黑色的(因此会产生战争迷雾效果)?

【问题讨论】:

    标签: javascript canvas globalcompositeoperation


    【解决方案1】:

    使用面具

    使用合成的战争迷雾

    实现遮罩的最简单方法是创建一个屏幕外画布并将遮罩渲染到该画布上。然后在制作动画时渲染世界,然后使用"destination-in" 应用蒙版。您可以使用画布 CSS 背景作为雾(如演示中所做的那样),或者您可以使用 "destination-over" 在顶部渲染雾,也在演示中使用文本显示。

    分层渲染

    出于个人和性能考虑(如果代码需要每次中断),我会避免使用globalCompositeOperation,并通过在演示中创建蒙版的反转来渲染整个世界。这只会增加一个额外的渲染调用,无需更改复合操作

    使用组合的示例

    var c = document.getElementById("myCanvas");
    var ctx = c.getContext("2d");
    
    function createCanvas(){
      var c = document.createElement("canvas");
      c.width = 300;
      c.height = 150;
      c.ctx = c.getContext("2d");
      return c;
    }
    
    // draw game world on offscreen canvas
    function drawBackground(ctx){
      ctx.fillStyle = "green";
      ctx.fillRect(0,0,300,150); 
    
      // a line
      ctx.beginPath();
      ctx.lineWidth = 3;
      ctx.strokeStyle = "#08A";
      ctx.lineTo(0, 0);
      ctx.lineTo(300, 150);
      ctx.stroke();
    }
    
    // create and render world
    var bGround = createCanvas();
    drawBackground(bGround.ctx)
    
    
    // create mask 
    var grad = ctx.createRadialGradient(0,0,60,0,0,0);
    grad.addColorStop(0,"rgba(0,0,0,0.0)");
    grad.addColorStop(0.2,"rgba(0,0,0,1)");
    grad.addColorStop(1,"rgba(0,0,0,1)");
    
    var mask = createCanvas();
    mask.ctx.setTransform(1,0,0,1,75,75);
    mask.ctx.fillStyle = grad;
    mask.ctx.beginPath();
    mask.ctx.arc(0,0,60,0,Math.PI*2);
    mask.ctx.fill();
    mask.ctx.setTransform(1,0,0,1,225,75);
    mask.ctx.beginPath();
    mask.ctx.arc(0,0,60,0,Math.PI*2);
    mask.ctx.fill();
    document.body.appendChild(mask);
    
    // draws the fog
    function drawFog(ctx,x){
      ctx.globalCompositeOperation = "destination-in";
      ctx.drawImage(mask, x, 0);
      ctx.globalCompositeOperation = "source-over";
    }
    
    ctx.fillStyle = "red";
    ctx.font = "30px Arial";
    function loop(time){
      ctx.drawImage(bGround,0,0);
      drawFog(ctx,Math.sin(time / 1000) *20);
      ctx.globalCompositeOperation = "destination-over";
      ctx.fillText("Hello World",10,50); 
      ctx.globalCompositeOperation = "source-over";
      requestAnimationFrame(loop);
    }
    requestAnimationFrame(loop);
    canvas {
      border:1px solid #d3d3d3;
      
    }
    <canvas id="myCanvas" width="300" height="150" style="background : black;" ></canvas>
    <div>Pre rendered offscreen mask shown below for display only.</div>

    【讨论】:

    • 这非常有用,谢谢!在您的评论中,您写道,由于性能不佳,您会避免globalCompositeOperation,而是创建一个反向掩码?你有这方面的例子吗,或者我可以在网上搜索一下?
    • 或者你的意思是,创建第二个画布。让它全黑,但是 2x 透明并在主画布上绘制该图像?嗯。
    • @corgrath 是的,您在第二条评论中所描述的内容。
    猜你喜欢
    • 2016-03-05
    • 1970-01-01
    • 1970-01-01
    • 2012-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-11
    • 1970-01-01
    相关资源
    最近更新 更多