You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用putImageData实现Canvas火焰透明背景的问题求助

解决Canvas火焰效果背景不透明问题

问题根源

  • 初始获取的imageData所有像素默认是(0,0,0,255)(黑色不透明),未初始化透明背景
  • putImageData直接覆盖画布像素,不受globalCompositeOperation或globalAlpha参数影响,所以调整这两个属性无效
  • 代码仅更新火焰区域的颜色值,无火焰区域的alpha通道仍保持255,显示为黑色

修改方案

1. 初始化透明背景

获取imageData后,遍历所有像素将alpha通道设为0:

var imageData = ctx.getImageData(0, 0, canvasWidth, canvasHeight);
var data = imageData.data;
// 初始化所有像素为完全透明
for (var i = 0; i < data.length; i += 4) {
  data[i + 3] = 0;
}

2. 动态控制像素透明度

在绘制火焰的循环中,仅对有火焰的像素设置不透明alpha,无火焰区域保持透明:

var skipRows = 2;

for (var y = skipRows; y < canvasHeight; ++y) {
  for (var x = 0; x < canvasWidth; ++x) {
    var index = y * canvasWidth * 4 + x * 4;
    var value = fire[(y - skipRows) * canvasWidth + x];

    if (value > 0) {
      data[index] = colors[value][0];
      data[++index] = colors[value][1];
      data[++index] = colors[value][2];
      data[++index] = 255;
    } else {
      // 无火焰时设置为透明
      data[index + 3] = 0;
    }
  }
}

完整修改后的JS代码

document.addEventListener("DOMContentLoaded", function() {
  var canvas = document.getElementById('fire');
  var ctx = canvas.getContext('2d');
  var canvasWidth = canvas.width;
  var canvasHeight = canvas.height;
  var intensity = null;
  var fps = 30;
  var threshold = 0.5;
  var imageData = ctx.getImageData(0, 0, canvasWidth, canvasHeight);
  var data = imageData.data;
  var numPixels = data.length / 4;

  // 初始化所有像素为透明
  for (var i = 0; i < data.length; i += 4) {
    data[i + 3] = 0;
  }

  var colors = [];

  for (var i = 0; i < 256; i++) {
    var color = [];
    color[0] = color[1] = color[2] = 0;
    colors[i] = color;
  }

  for (var i = 0; i < 32; ++i) {
    colors[i][2] = i << 1;
    colors[i + 32][0] = i << 3;
    colors[i + 32][2] = 64 - (i << 1);
    colors[i + 64][0] = 255;
    colors[i + 64][1] = i << 3;
    colors[i + 96][0] = 255;
    colors[i + 96][1] = 255;
    colors[i + 96][2] = i << 2;
    colors[i + 128][0] = 255;
    colors[i + 128][1] = 255;
    colors[i + 128][2] = 64 + (i << 2);
    colors[i + 160][0] = 255;
    colors[i + 160][1] = 255;
    colors[i + 160][2] = 128 + (i << 2);
    colors[i + 192][0] = 255;
    colors[i + 192][1] = 255;
    colors[i + 192][2] = 192 + i;
    colors[i + 224][0] = 255;
    colors[i + 224][1] = 255;
    colors[i + 224][2] = 224 + i;
  }

  var fire = [];

  for (var i = 0; i < canvasWidth * canvasHeight; i++) {
    fire[i] = 0;
  }

  var time = new Date().getTime();

  function randomizeThreshold() {
    threshold += Math.random() * 0.2 - 0.1;
    threshold = Math.min(Math.max(threshold, 0.5), 0.8);
  }

  function burnBurnBurn() {
    window.requestAnimationFrame(burnBurnBurn);
    var now = new Date().getTime();
    dt = now - time;

    if (dt < (1000 / fps))
      return;

    time = now;

    var bottomLine = canvasWidth * (canvasHeight - 1);

    for (var x = 0; x < canvasWidth; x++) {
      var value = 0;

      if (Math.random() > threshold)
        value = 255;

      fire[bottomLine + x] = value;
    }

    var value = 0;

    for (var y = 0; y < canvasHeight; ++y) {
      for (var x = 0; x < canvasWidth; ++x) {
        if (x == 0) {
          value = fire[bottomLine];
          value += fire[bottomLine];
          value += fire[bottomLine - canvasWidth];
          value /= 3;
        } else if (x == canvasWidth - 1) {
          value = fire[bottomLine + x];
          value += fire[bottomLine - canvasWidth + x];
          value += fire[bottomLine + x - 1];
          value /= 3;
        } else {
          value = fire[bottomLine + x];
          value += fire[bottomLine + x + 1];
          value += fire[bottomLine + x - 1];
          value += fire[bottomLine - canvasWidth + x];
          value /= 4;
        }

        if (value > 1)
          value -= 1;

        value = Math.floor(value);
        var index = bottomLine - canvasWidth + x;
        fire[index] = value;
      }

      bottomLine -= canvasWidth;
    }

    var skipRows = 2;

    for (var y = skipRows; y < canvasHeight; ++y) {
      for (var x = 0; x < canvasWidth; ++x) {
        var index = y * canvasWidth * 4 + x * 4;
        var value = fire[(y - skipRows) * canvasWidth + x];

        if (value > 0) {
          data[index] = colors[value][0];
          data[++index] = colors[value][1];
          data[++index] = colors[value][2];
          data[++index] = 255;
        } else {
          data[index + 3] = 0;
        }
      }
    }
    if (intensity == null) {
      if (Math.random() > 0.95) {
        randomizeThreshold();
      }
    }

    ctx.putImageData(imageData, 0, 0);
  };

  window.requestAnimationFrame(burnBurnBurn);
});

HTML代码(无需修改)

<canvas id="fire"></canvas>

内容的提问来源于stack exchange,提问作者Leather

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 05:39:52