canvas 上大约有 120 000 个粒子?
About 120 000 particles on canvas?
我有大约 120 000 个粒子(每个粒子 1px 大小),我需要找到最好的和最重要的:绘制到我的 canvas.
的最快方法
你会怎么做?
现在我基本上是将我的像素放入一个数组,然后我遍历这些粒子,进行一些 x 和 y 计算并使用 fillRect 将它们绘制出来。但是现在的帧率大约是 8-9 fps。
有什么想法吗?请举个例子。
谢谢
最新更新(我的代码)
function init(){
window.addEventListener("mousemove", onMouseMove);
let mouseX, mouseY, ratio = 2;
const canvas = document.getElementById("textCanvas");
const context = canvas.getContext("2d");
canvas.width = window.innerWidth * ratio;
canvas.height = window.innerHeight * ratio;
canvas.style.width = window.innerWidth + "px";
canvas.style.height = window.innerHeight + "px";
context.imageSmoothingEnabled = false;
context.fillStyle = `rgba(255,255,255,1)`;
context.setTransform(ratio, 0, 0, ratio, 0, 0);
const width = canvas.width;
const height = canvas.height;
context.font = "normal normal normal 232px EB Garamond";
context.fillText("howdy", 0, 160);
var pixels = context.getImageData(0, 0, width, height).data;
var data32 = new Uint32Array(pixels.buffer);
const particles = new Array();
for(var i = 0; i < data32.length; i++) {
if (data32[i] & 0xffff0000) {
particles.push({
x: (i % width),
y: ((i / width)|0),
ox: (i % width),
oy: ((i / width)|0),
xVelocity: 0,
yVelocity: 0,
a: pixels[i*4 + 3] / 255
});
}
}
/*const particles = Array.from({length: 120000}, () => [
Math.round(Math.random() * (width - 1)),
Math.round(Math.random() * (height - 1))
]);*/
function onMouseMove(e){
mouseX = parseInt((e.clientX-canvas.offsetLeft) * ratio);
mouseY = parseInt((e.clientY-canvas.offsetTop) * ratio);
}
function frame(timestamp) {
context.clearRect(0, 0, width, height);
const imageData = context.getImageData(0, 0, width, height);
const data = imageData.data;
for (let i = 0; i < particles.length; i++) {
const particle = particles[i];
const index = 4 * Math.round((particle.x + particle.y * width));
data[index + 0] = 0;
data[index + 1] = 0;
data[index + 2] = 0;
data[index + 3] = 255;
}
context.putImageData(imageData, 0, 0);
for (let i = 0; i < particles.length; i++) {
const p = particles[i];
var homeDX = p.ox - p.x;
var homeDY = p.oy - p.y;
var cursorForce = 0;
var cursorAngle = 0;
if(mouseX && mouseX > 0){
var cursorDX = p.ox - mouseX;
var cursorDY = p.oy - mouseY;
var cursorDistanceSquared = (cursorDX * cursorDX + cursorDY * cursorDY);
cursorForce = Math.min(10/cursorDistanceSquared,10);
cursorAngle = -Math.atan2(cursorDY, cursorDX);
}else{
cursorForce = 0;
cursorAngle = 0;
}
p.xVelocity += 0.2 * homeDX + cursorForce * Math.cos(cursorAngle);
p.yVelocity += 0.2 * homeDY + cursorForce * Math.sin(cursorAngle);
p.xVelocity *= 0.55;
p.yVelocity *= 0.55;
p.x += p.xVelocity;
p.y += p.yVelocity;
}
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
}
在 webgl
上下文中计算着色器内的这些粒子将提供最高性能的解决方案。见 e。 G。 https://www.shadertoy.com/view/MdtGDX 举个例子。
如果您希望继续使用 2d
上下文,您可以通过在屏幕外这样做来加速渲染粒子:
- 调用
context.getImageData()
获取图片数据数组
- 通过操作数据数组绘制像素
- 用
context.putImageData()
放回数据数组
一个简化的例子:
const output = document.getElementById("output");
const canvas = document.getElementById("canvas");
const context = canvas.getContext("2d");
const width = canvas.width;
const height = canvas.height;
const particles = Array.from({length: 120000}, () => [
Math.round(Math.random() * (width - 1)),
Math.round(Math.random() * (height - 1))
]);
let previous = 0;
function frame(timestamp) {
// Print frames per second:
const delta = timestamp - previous;
previous = timestamp;
output.textContent = `${(1000 / delta).toFixed(1)} fps`;
// Draw particles:
context.clearRect(0, 0, width, height);
const imageData = context.getImageData(0, 0, width, height);
const data = imageData.data;
for (let i = 0; i < particles.length; i++) {
const particle = particles[i];
const index = 4 * (particle[0] + particle[1] * width);
data[index + 0] = 0;
data[index + 1] = 0;
data[index + 2] = 0;
data[index + 3] = 255;
}
context.putImageData(imageData, 0, 0);
// Move particles randomly:
for (let i = 0; i < particles.length; i++) {
const particle = particles[i];
particle[0] = Math.max(0, Math.min(width - 1, Math.round(particle[0] + Math.random() * 2 - 1)));
particle[1] = Math.max(0, Math.min(height - 1, Math.round(particle[1] + Math.random() * 2 - 1)));
}
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
<canvas id="canvas" width="500" height="500"></canvas>
<output id="output"></output>
除了绘制单个像素,您可能还想考虑绘制和移动一些纹理,每个纹理上都有很多粒子。这可能会以更好的性能接近完整的粒子效果。
每秒移动 720 万个粒子
不使用 webGL 和着色器并且您希望每帧 120K 个粒子
60fps 你需要每秒 720 万点的吞吐量。你需要一台速度快的机器。
Web workers 多核 CPUs
快速解决方案。在多核机器上,网络工作者为每个硬件核心提供线性性能提升。例如,在 8 Core i7 上,您可以 运行 7 个工作人员通过 sharedArrayBuffers 共享数据(遗憾的是,由于 CPU 安全风险,它全部关闭了 ATM,请参阅 MDN sharedArrayBuffer)并且略低于 7 倍性能改进。请注意,好处仅来自实际的硬件核心,JS 线程往往 运行 平坦,运行 一个核心中的两个工作者导致整体吞吐量下降。
即使关闭了共享缓冲区,如果您可以控制 运行 使用的硬件,它仍然是一个可行的解决方案。
拍电影。
大声笑,但它不是一个选项,并且粒子数没有上限。虽然不像我想的那样具有交互性。如果您通过 FX 销售商品,您追求的是哇,而不是如何?
优化
说起来容易做起来难。您需要使用细齿梳检查代码。请记住,如果 运行 全速删除一行,则每秒删除 720 万行。
我又检查了一遍代码。我无法测试它,所以它可能会或可能不会工作。但它给你想法。您甚至可以考虑仅使用整数数学。 JS可以做定点数学。整数大小比 4K 显示器所需的多 32 位。
第二次优化。
// call this just once outside the animation loop.
const imageData = this.context.getImageData(0, 0, this.width * this.ratio, this.height * this.ratio);
// create a 32bit buffer
const data32 = new Uint32Array(imageData.data.buffer);
const pixel = 0xFF000000; // pixel to fill
const width = imageData.width;
// inside render loop
data32.fill(0); // clear the pixel buffer
// this line may be a problem I have no idea what it does. I would
// hope its only passing a reference and not creating a copy
var particles = this.particleTexts[0].getParticles();
var cDX,cDY,mx,my,p,cDistSqr,cForce,i;
mx = this.mouseX | 0; // may not need the floor bitwize or 0
my = this.mouseY | 0; // if mouse coords already integers
if(mX > 0){ // do mouse test outside the loop. Need loop duplication
// But at 60fps thats 7.2million less if statements
for (let i = 0; i < particles.length; i++) {
var p = particles[i];
p.xVelocity += 0.2 * (p.ox - p.x);
p.yVelocity += 0.2 * (p.oy - p.y);
p.xVelocity *= 0.55;
p.yVelocity *= 0.55;
data32[((p.x += p.xVelocity) | 0) + ((p.y += p.yVelocity) | 0) * width] = pixel;
}
}else{
for (let i = 0; i < particles.length; i++) {
var p = particles[i];
cDX = p.x - mx;
cDY = p.y - my;
cDist = Math.sqrt(cDistSqr = cDX*cDX + cDY*cDY + 1);
cForce = 1000 / (cDistSqr * cDist)
p.xVelocity += cForce * cDx + 0.2 * (p.ox - p.x);
p.yVelocity += cForce * cDY + 0.2 * (p.oy - p.y);
p.xVelocity *= 0.55;
p.yVelocity *= 0.55;
data32[((p.x += p.xVelocity) | 0) + ((p.y += p.yVelocity) | 0) * width] = pixel;
}
}
// put pixel onto the display.
this.context.putImageData(imageData, 0, 0);
以上是我能删减的差不多了。 (无法测试,所以可能适合也可能不适合您的需要)它可能每秒给您多几帧。
交织
另一个解决方案可能适合您,那就是欺骗眼睛。这会增加帧速率,但不会增加处理的点,并且要求点随机分布,否则伪影将非常明显。
每一帧你只处理一半的粒子。每次处理粒子时,您都会计算像素索引,设置该像素,然后将像素速度添加到像素索引和粒子位置。
效果是每一帧只有一半的粒子在力的作用下移动,另一半的粒子滑行一帧..
这可能会使帧率翻倍。如果您的粒子非常有条理并且出现成团闪烁类型的伪影,您可以通过在创建时对粒子阵列应用随机洗牌来随机化粒子的分布。同样,这需要良好的随机分布。
下一个片段只是一个例子。每个粒子需要将 pixelIndex
保存到像素 data32
数组中。请注意,第一帧必须是完整帧才能设置所有索引等。
const interleave = 2; // example only setup for 2 frames
// but can be extended to 3 or 4
// create frameCount outside loop
frameCount += 1;
// do half of all particals
for (let i = frameCount % frameCount ; i < particles.length; i += interleave ) {
var p = particles[i];
cDX = p.x - mx;
cDY = p.y - my;
cDist = Math.sqrt(cDistSqr = cDX*cDX + cDY*cDY + 1);
cForce = 1000 / (cDistSqr * cDist)
p.xVelocity += cForce * cDx + 0.2 * (p.ox - p.x);
p.yVelocity += cForce * cDY + 0.2 * (p.oy - p.y);
p.xVelocity *= 0.55;
p.yVelocity *= 0.55;
// add pixel index to particle's property
p.pixelIndex = ((p.x += p.xVelocity) | 0) + ((p.y += p.yVelocity) | 0) * width;
// write this frames pixel
data32[p.pixelIndex] = pixel;
// speculate the pixel index position in the next frame. This need to be as simple as possible.
p.pixelIndex += (p.xVelocity | 0) + (p.yVelocity | 0) * width;
p.x += p.xVelocity; // as the next frame this particle is coasting
p.y += p.yVelocity; // set its position now
}
// do every other particle. Just gets the pixel index and sets it
// this needs to remain as simple as possible.
for (let i = (frameCount + 1) % frameCount ; i < particles.length; i += interleave)
data32[particles[i].pixelIndex] = pixel;
}
颗粒少
接缝很明显,但通常被视为可行的解决方案。更少的颗粒并不意味着更少的视觉效果elements/pixels.
如果将粒子计数减少 8,并在设置时创建一个大的偏移索引缓冲区。这些缓冲区保存与像素行为非常匹配的动画像素运动。
这可能非常有效,给人一种每个像素实际上都是独立的错觉。但工作是在预处理和设置偏移动画中。
例如
// for each particle after updating position
// get index of pixel
p.pixelIndex = (p.x | 0 + p.y | 0) * width;
// add pixel
data32[p.pixelIndex] = pixel;
// now you get 8 more pixels for the price of one particle
var ind = p.offsetArrayIndex;
// offsetArray is an array of pixel offsets both negative and positive
data32[p.pixelIndex + offsetArray[ind++]] = pixel;
data32[p.pixelIndex + offsetArray[ind++]] = pixel;
data32[p.pixelIndex + offsetArray[ind++]] = pixel;
data32[p.pixelIndex + offsetArray[ind++]] = pixel;
data32[p.pixelIndex + offsetArray[ind++]] = pixel;
data32[p.pixelIndex + offsetArray[ind++]] = pixel;
data32[p.pixelIndex + offsetArray[ind++]] = pixel;
data32[p.pixelIndex + offsetArray[ind++]] = pixel;
// offset array arranged as sets of 8, each set of 8 is a frame in
// looping pre calculated offset animation
// offset array length is 65536 or any bit mask able size.
p.offsetArrayIndex = ind & 0xFFFF ; // ind now points at first pixel of next
// set of eight pixels
这个和其他各种类似的技巧可以为您提供您想要的每秒 720 万像素。
最后一个音符。
请记住,如今每台设备都有专用的 GPU。最好还是用吧,这种东西他们擅长的
我有大约 120 000 个粒子(每个粒子 1px 大小),我需要找到最好的和最重要的:绘制到我的 canvas.
的最快方法你会怎么做?
现在我基本上是将我的像素放入一个数组,然后我遍历这些粒子,进行一些 x 和 y 计算并使用 fillRect 将它们绘制出来。但是现在的帧率大约是 8-9 fps。
有什么想法吗?请举个例子。
谢谢
最新更新(我的代码)
function init(){
window.addEventListener("mousemove", onMouseMove);
let mouseX, mouseY, ratio = 2;
const canvas = document.getElementById("textCanvas");
const context = canvas.getContext("2d");
canvas.width = window.innerWidth * ratio;
canvas.height = window.innerHeight * ratio;
canvas.style.width = window.innerWidth + "px";
canvas.style.height = window.innerHeight + "px";
context.imageSmoothingEnabled = false;
context.fillStyle = `rgba(255,255,255,1)`;
context.setTransform(ratio, 0, 0, ratio, 0, 0);
const width = canvas.width;
const height = canvas.height;
context.font = "normal normal normal 232px EB Garamond";
context.fillText("howdy", 0, 160);
var pixels = context.getImageData(0, 0, width, height).data;
var data32 = new Uint32Array(pixels.buffer);
const particles = new Array();
for(var i = 0; i < data32.length; i++) {
if (data32[i] & 0xffff0000) {
particles.push({
x: (i % width),
y: ((i / width)|0),
ox: (i % width),
oy: ((i / width)|0),
xVelocity: 0,
yVelocity: 0,
a: pixels[i*4 + 3] / 255
});
}
}
/*const particles = Array.from({length: 120000}, () => [
Math.round(Math.random() * (width - 1)),
Math.round(Math.random() * (height - 1))
]);*/
function onMouseMove(e){
mouseX = parseInt((e.clientX-canvas.offsetLeft) * ratio);
mouseY = parseInt((e.clientY-canvas.offsetTop) * ratio);
}
function frame(timestamp) {
context.clearRect(0, 0, width, height);
const imageData = context.getImageData(0, 0, width, height);
const data = imageData.data;
for (let i = 0; i < particles.length; i++) {
const particle = particles[i];
const index = 4 * Math.round((particle.x + particle.y * width));
data[index + 0] = 0;
data[index + 1] = 0;
data[index + 2] = 0;
data[index + 3] = 255;
}
context.putImageData(imageData, 0, 0);
for (let i = 0; i < particles.length; i++) {
const p = particles[i];
var homeDX = p.ox - p.x;
var homeDY = p.oy - p.y;
var cursorForce = 0;
var cursorAngle = 0;
if(mouseX && mouseX > 0){
var cursorDX = p.ox - mouseX;
var cursorDY = p.oy - mouseY;
var cursorDistanceSquared = (cursorDX * cursorDX + cursorDY * cursorDY);
cursorForce = Math.min(10/cursorDistanceSquared,10);
cursorAngle = -Math.atan2(cursorDY, cursorDX);
}else{
cursorForce = 0;
cursorAngle = 0;
}
p.xVelocity += 0.2 * homeDX + cursorForce * Math.cos(cursorAngle);
p.yVelocity += 0.2 * homeDY + cursorForce * Math.sin(cursorAngle);
p.xVelocity *= 0.55;
p.yVelocity *= 0.55;
p.x += p.xVelocity;
p.y += p.yVelocity;
}
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
}
在 webgl
上下文中计算着色器内的这些粒子将提供最高性能的解决方案。见 e。 G。 https://www.shadertoy.com/view/MdtGDX 举个例子。
如果您希望继续使用 2d
上下文,您可以通过在屏幕外这样做来加速渲染粒子:
- 调用
context.getImageData()
获取图片数据数组 - 通过操作数据数组绘制像素
- 用
context.putImageData()
放回数据数组
一个简化的例子:
const output = document.getElementById("output");
const canvas = document.getElementById("canvas");
const context = canvas.getContext("2d");
const width = canvas.width;
const height = canvas.height;
const particles = Array.from({length: 120000}, () => [
Math.round(Math.random() * (width - 1)),
Math.round(Math.random() * (height - 1))
]);
let previous = 0;
function frame(timestamp) {
// Print frames per second:
const delta = timestamp - previous;
previous = timestamp;
output.textContent = `${(1000 / delta).toFixed(1)} fps`;
// Draw particles:
context.clearRect(0, 0, width, height);
const imageData = context.getImageData(0, 0, width, height);
const data = imageData.data;
for (let i = 0; i < particles.length; i++) {
const particle = particles[i];
const index = 4 * (particle[0] + particle[1] * width);
data[index + 0] = 0;
data[index + 1] = 0;
data[index + 2] = 0;
data[index + 3] = 255;
}
context.putImageData(imageData, 0, 0);
// Move particles randomly:
for (let i = 0; i < particles.length; i++) {
const particle = particles[i];
particle[0] = Math.max(0, Math.min(width - 1, Math.round(particle[0] + Math.random() * 2 - 1)));
particle[1] = Math.max(0, Math.min(height - 1, Math.round(particle[1] + Math.random() * 2 - 1)));
}
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
<canvas id="canvas" width="500" height="500"></canvas>
<output id="output"></output>
除了绘制单个像素,您可能还想考虑绘制和移动一些纹理,每个纹理上都有很多粒子。这可能会以更好的性能接近完整的粒子效果。
每秒移动 720 万个粒子
不使用 webGL 和着色器并且您希望每帧 120K 个粒子 60fps 你需要每秒 720 万点的吞吐量。你需要一台速度快的机器。
Web workers 多核 CPUs
快速解决方案。在多核机器上,网络工作者为每个硬件核心提供线性性能提升。例如,在 8 Core i7 上,您可以 运行 7 个工作人员通过 sharedArrayBuffers 共享数据(遗憾的是,由于 CPU 安全风险,它全部关闭了 ATM,请参阅 MDN sharedArrayBuffer)并且略低于 7 倍性能改进。请注意,好处仅来自实际的硬件核心,JS 线程往往 运行 平坦,运行 一个核心中的两个工作者导致整体吞吐量下降。
即使关闭了共享缓冲区,如果您可以控制 运行 使用的硬件,它仍然是一个可行的解决方案。
拍电影。
大声笑,但它不是一个选项,并且粒子数没有上限。虽然不像我想的那样具有交互性。如果您通过 FX 销售商品,您追求的是哇,而不是如何?
优化
说起来容易做起来难。您需要使用细齿梳检查代码。请记住,如果 运行 全速删除一行,则每秒删除 720 万行。
我又检查了一遍代码。我无法测试它,所以它可能会或可能不会工作。但它给你想法。您甚至可以考虑仅使用整数数学。 JS可以做定点数学。整数大小比 4K 显示器所需的多 32 位。
第二次优化。
// call this just once outside the animation loop.
const imageData = this.context.getImageData(0, 0, this.width * this.ratio, this.height * this.ratio);
// create a 32bit buffer
const data32 = new Uint32Array(imageData.data.buffer);
const pixel = 0xFF000000; // pixel to fill
const width = imageData.width;
// inside render loop
data32.fill(0); // clear the pixel buffer
// this line may be a problem I have no idea what it does. I would
// hope its only passing a reference and not creating a copy
var particles = this.particleTexts[0].getParticles();
var cDX,cDY,mx,my,p,cDistSqr,cForce,i;
mx = this.mouseX | 0; // may not need the floor bitwize or 0
my = this.mouseY | 0; // if mouse coords already integers
if(mX > 0){ // do mouse test outside the loop. Need loop duplication
// But at 60fps thats 7.2million less if statements
for (let i = 0; i < particles.length; i++) {
var p = particles[i];
p.xVelocity += 0.2 * (p.ox - p.x);
p.yVelocity += 0.2 * (p.oy - p.y);
p.xVelocity *= 0.55;
p.yVelocity *= 0.55;
data32[((p.x += p.xVelocity) | 0) + ((p.y += p.yVelocity) | 0) * width] = pixel;
}
}else{
for (let i = 0; i < particles.length; i++) {
var p = particles[i];
cDX = p.x - mx;
cDY = p.y - my;
cDist = Math.sqrt(cDistSqr = cDX*cDX + cDY*cDY + 1);
cForce = 1000 / (cDistSqr * cDist)
p.xVelocity += cForce * cDx + 0.2 * (p.ox - p.x);
p.yVelocity += cForce * cDY + 0.2 * (p.oy - p.y);
p.xVelocity *= 0.55;
p.yVelocity *= 0.55;
data32[((p.x += p.xVelocity) | 0) + ((p.y += p.yVelocity) | 0) * width] = pixel;
}
}
// put pixel onto the display.
this.context.putImageData(imageData, 0, 0);
以上是我能删减的差不多了。 (无法测试,所以可能适合也可能不适合您的需要)它可能每秒给您多几帧。
交织
另一个解决方案可能适合您,那就是欺骗眼睛。这会增加帧速率,但不会增加处理的点,并且要求点随机分布,否则伪影将非常明显。
每一帧你只处理一半的粒子。每次处理粒子时,您都会计算像素索引,设置该像素,然后将像素速度添加到像素索引和粒子位置。
效果是每一帧只有一半的粒子在力的作用下移动,另一半的粒子滑行一帧..
这可能会使帧率翻倍。如果您的粒子非常有条理并且出现成团闪烁类型的伪影,您可以通过在创建时对粒子阵列应用随机洗牌来随机化粒子的分布。同样,这需要良好的随机分布。
下一个片段只是一个例子。每个粒子需要将 pixelIndex
保存到像素 data32
数组中。请注意,第一帧必须是完整帧才能设置所有索引等。
const interleave = 2; // example only setup for 2 frames
// but can be extended to 3 or 4
// create frameCount outside loop
frameCount += 1;
// do half of all particals
for (let i = frameCount % frameCount ; i < particles.length; i += interleave ) {
var p = particles[i];
cDX = p.x - mx;
cDY = p.y - my;
cDist = Math.sqrt(cDistSqr = cDX*cDX + cDY*cDY + 1);
cForce = 1000 / (cDistSqr * cDist)
p.xVelocity += cForce * cDx + 0.2 * (p.ox - p.x);
p.yVelocity += cForce * cDY + 0.2 * (p.oy - p.y);
p.xVelocity *= 0.55;
p.yVelocity *= 0.55;
// add pixel index to particle's property
p.pixelIndex = ((p.x += p.xVelocity) | 0) + ((p.y += p.yVelocity) | 0) * width;
// write this frames pixel
data32[p.pixelIndex] = pixel;
// speculate the pixel index position in the next frame. This need to be as simple as possible.
p.pixelIndex += (p.xVelocity | 0) + (p.yVelocity | 0) * width;
p.x += p.xVelocity; // as the next frame this particle is coasting
p.y += p.yVelocity; // set its position now
}
// do every other particle. Just gets the pixel index and sets it
// this needs to remain as simple as possible.
for (let i = (frameCount + 1) % frameCount ; i < particles.length; i += interleave)
data32[particles[i].pixelIndex] = pixel;
}
颗粒少
接缝很明显,但通常被视为可行的解决方案。更少的颗粒并不意味着更少的视觉效果elements/pixels.
如果将粒子计数减少 8,并在设置时创建一个大的偏移索引缓冲区。这些缓冲区保存与像素行为非常匹配的动画像素运动。
这可能非常有效,给人一种每个像素实际上都是独立的错觉。但工作是在预处理和设置偏移动画中。
例如
// for each particle after updating position
// get index of pixel
p.pixelIndex = (p.x | 0 + p.y | 0) * width;
// add pixel
data32[p.pixelIndex] = pixel;
// now you get 8 more pixels for the price of one particle
var ind = p.offsetArrayIndex;
// offsetArray is an array of pixel offsets both negative and positive
data32[p.pixelIndex + offsetArray[ind++]] = pixel;
data32[p.pixelIndex + offsetArray[ind++]] = pixel;
data32[p.pixelIndex + offsetArray[ind++]] = pixel;
data32[p.pixelIndex + offsetArray[ind++]] = pixel;
data32[p.pixelIndex + offsetArray[ind++]] = pixel;
data32[p.pixelIndex + offsetArray[ind++]] = pixel;
data32[p.pixelIndex + offsetArray[ind++]] = pixel;
data32[p.pixelIndex + offsetArray[ind++]] = pixel;
// offset array arranged as sets of 8, each set of 8 is a frame in
// looping pre calculated offset animation
// offset array length is 65536 or any bit mask able size.
p.offsetArrayIndex = ind & 0xFFFF ; // ind now points at first pixel of next
// set of eight pixels
这个和其他各种类似的技巧可以为您提供您想要的每秒 720 万像素。
最后一个音符。
请记住,如今每台设备都有专用的 GPU。最好还是用吧,这种东西他们擅长的