在画布上循环绘制时阴影太多

问题描述 投票:0回答:1

我一直在尝试通过首先创建一个圆角矩形并向其添加阴影来在画布中制作阴影效果,如果我在没有循环的情况下执行此操作一次,一切似乎都工作正常。然而,当我尝试在视频帧中循环执行此操作时,我在背景上应用了太多阴影:-

export const titleRender = async () => {

    const canvas = createCanvas(1920, 1080);
    const ctx = canvas.getContext('2d');

    const img = await loadImage('blueBackground.png')

    ctx.drawImage(img, 0, 0, 1920, 1920);

    return canvas;
    
};

const drawEffects = async () => {
  
  
    const effectsCanvas = createCanvas(1920, 1080) 
  
    const ctx = effectsCanvas.getContext('2d');
    
  
    ctx.beginPath();
    ctx.roundRect(77 , 234 , 1766 , 846,[20, 20, 0, 0]);
    ctx.closePath()
  
    // Apply drop shadow effect
    ctx.shadowColor = '#00ff44';
    ctx.shadowBlur = 68;
    ctx.shadowOffsetX = 5;
    ctx.shadowOffsetY = 20;
    
  
    // Set the background color and fill the rectangle
    ctx.fillStyle = '#ffaadd';
    ctx.fill();
  
    ctx.strokeStyle = 'rgba(26, 26, 26, 0.46)';
    ctx.lineWidth = 2;
    ctx.stroke();
    // Reset shadow settings
    ctx.shadowColor = 'transparent';
    ctx.shadowBlur = 0;
    ctx.shadowOffsetX = 0;
    ctx.shadowOffsetY = 0;
  
    ctx.clip()
  
    //ctx.drawImage(cropedFrame as any, downscaleX, downscaleY, scaledWidth, scaledHeight);
  
    return effectsCanvas;
  
    
  }

async function test() {
    const img = await loadImage('overlayimage.jpg')
    const backgroundCanvas= createCanvas(1920, 1080)

    console.log('hii')
    
    const titleComposition = await titleRender();
    const effectsCanvas = await drawEffects()

    const backgroundCTX = backgroundCanvas.getContext('2d');
    const effectsCTX = effectsCanvas.getContext('2d');

    backgroundCTX.drawImage(titleComposition, 0, 0, titleComposition.width, titleComposition.height)
    
    effectsCTX.drawImage(img, 77 , 234 , 1766 , 846 )
    backgroundCTX.drawImage(effectsCanvas, 0, 0, effectsCanvas.width, effectsCanvas.height)

    const out = fs.createWriteStream(`comp/ren${1}.png`);
    const stream = backgroundCanvas.createPNGStream();
    stream.pipe(out);

    out.on('finish', () => console.log('Wows'))
    return true;
}
test()

这是我得到的最终结果:- A smooth green shadow behind the rounded ractangle

但是,我尝试对循环中的视频帧执行类似的操作:-

async function test() {
    const img = await loadImage('green/overlay.jpg')
    const backgroundCanvas= createCanvas(1920, 1080)

    console.log('hii')
    
    const titleComposition = await titleRender();
    const effectsCanvas = await drawEffects()

    const backgroundCTX = backgroundCanvas.getContext('2d');
    const effectsCTX = effectsCanvas.getContext('2d');

    backgroundCTX.drawImage(titleComposition, 0, 0, titleComposition.width, titleComposition.height)
    
    
    for (let i = 0; i<=20; i++) {
        effectsCTX.drawImage(img, 77 , 234 , 1766 , 846 )
        backgroundCTX.drawImage(effectsCanvas, 0, 0, effectsCanvas.width, effectsCanvas.height)
    
        const out = fs.createWriteStream(`comp/ren${1}.png`);
        const stream = backgroundCanvas.createPNGStream();
        stream.pipe(out);
    
        out.on('finish', () => console.log('Wows'))
        
    }

    return true;
}
test()

当我测试代码时,我应用了太多阴影enter image description here

javascript canvas html5-canvas node-canvas
1个回答
0
投票

如果您不想在目标画布上累积发光,则需要每帧清除目标画布。

尝试使用下面的代码片段呈现的按钮,看看在每一帧上绘制蓝色“标题”或仅绘制一次之间的区别。我还在覆盖层中添加了一些动画,因此更容易看到轨迹如何累积。

function createCanvas(width, height) {
  const c = document.createElement("canvas");
  return Object.assign(c, { width, height });
}

const titleRender = async () => {
  const canvas = createCanvas(1920, 1080);
  const ctx = canvas.getContext("2d");
  ctx.fillStyle = "blue";
  ctx.fillRect(0, 0, 1920, 1080);
  return canvas;
};

const drawEffects = async () => {
  const effectsCanvas = createCanvas(1920, 1080);

  const ctx = effectsCanvas.getContext("2d");

  ctx.beginPath();
  ctx.roundRect(77, 234, 1766, 846, [20, 20, 0, 0]);
  ctx.closePath();

  // Apply drop shadow effect
  ctx.shadowColor = "#00ff44";
  ctx.shadowBlur = 68;
  ctx.shadowOffsetX = 5;
  ctx.shadowOffsetY = 20;

  // Set the background color and fill the rectangle
  ctx.fillStyle = "#ffaadd";
  ctx.fill();

  ctx.strokeStyle = "rgba(26, 26, 26, 0.46)";
  ctx.lineWidth = 2;
  ctx.stroke();
  // Reset shadow settings
  ctx.shadowColor = "transparent";
  ctx.shadowBlur = 0;
  ctx.shadowOffsetX = 0;
  ctx.shadowOffsetY = 0;

  ctx.clip();

  return effectsCanvas;
};

async function sleep(number) {
  return new Promise((resolve) => setTimeout(() => resolve(), number));
}

async function test(drawBgEveryFrame) {
  const backgroundCanvas = createCanvas(1920, 1080);

  const titleComposition = await titleRender();
  const effectsCanvas = await drawEffects();

  const backgroundCTX = backgroundCanvas.getContext("2d");
  const effectsCTX = effectsCanvas.getContext("2d");

  for (let i = 0; i <= 20; i++) {
    if (i === 0 || drawBgEveryFrame) {
      backgroundCTX.drawImage(
        titleComposition,
        0,
        0,
        titleComposition.width,
        titleComposition.height,
      );
    }
    backgroundCTX.drawImage(
      effectsCanvas,
      0,
      Math.cos((i / 20) * 6.283) * 50,
      effectsCanvas.width,
      effectsCanvas.height,
    );

    document.getElementById("img").src = backgroundCanvas.toDataURL();
    await sleep(100);
  }
}
<button onclick="test(false)">Go, without clearing the frames</button> <button onclick="test(true)">Go, but draw background every frame</button>
<img id="img" style="width:100%;border:1px solid black">

© www.soinside.com 2019 - 2024. All rights reserved.