为何JavaScript Canvas实现的3D隧道渲染效果异常?
修复Canvas 3D隧道效果的核心问题
你的代码存在两个关键问题导致效果异常:画布仅显示四分之一内容,且未呈现隧道形态,以下是修正方案:
修正后的完整代码
var texWidth = 256; var texHeight = 256; var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); // 先获取画布实际尺寸 var imageData = ctx.createImageData(canvas.width, canvas.height); var w = imageData.width; var h = imageData.height; // 延迟初始化数组,确保w/h已赋值 var texture = new Array(texHeight); var distanceTable = new Array(h); var angleTable = new Array(h); for (i = 0; i < texHeight; i++) { texture[i] = new Array(texWidth); } for (j = 0; j < h; j++) { distanceTable[j] = new Array(w); angleTable[j] = new Array(w); } // 修正纹理X轴循环边界 for (y = 0; y < texHeight; y++) { for (x = 0; x < texWidth; x++) { texture[y][x] = x ^ y; } } for (y2 = 0; y2 < h; y2++) { for (x2 = 0; x2 < w; x2++) { let angle; let distance; let ratio = 32.0; let dx = x2 - w / 2.0; let dy = y2 - h / 2.0; let dist = Math.sqrt(dx * dx + dy * dy); // 确保distance为非负数,避免模运算异常 distance = ~~(ratio * texHeight / dist); distance = (distance % texHeight + texHeight) % texHeight; // 调整角度计算,覆盖完整0-texWidth范围 angle = ~~(0.5 * texWidth * (Math.atan2(dy, dx) / Math.PI + 1)); distanceTable[y2][x2] = distance; angleTable[y2][x2] = angle; } } var animation = 0; function draw() { animation = animation + 0.01; // 动画方向匹配隧道逻辑:shiftX控制环绕旋转,shiftY控制纵深滚动 let shiftX = texWidth * 0.5 * animation; let shiftY = texHeight * 1.0 * animation; for (y3 = 0; y3 < h; y3++) { for (x3 = 0; x3 < w; x3++) { // 修正像素索引计算(每个像素占4个RGBA通道) let id = y3 * w * 4 + x3 * 4; // 颠倒纹理映射:角度对应X轴(环绕),距离对应Y轴(纵深) let texX = ~~(angleTable[y3][x3] + shiftX) % texWidth; let texY = ~~(distanceTable[y3][x3] + shiftY) % texHeight; let c = texture[texY][texX]; imageData.data[id] = 0; imageData.data[id+1] = 0; imageData.data[id+2] = c; imageData.data[id+3] = 255; } } ctx.putImageData(imageData, 0, 0); window.requestAnimationFrame(draw); } window.requestAnimationFrame(draw);
关键修正点说明
1. 解决画布仅显示四分之一的问题
- 像素索引计算错误:原代码
id = y3 * w + x3 * 4未考虑每个像素占4个通道,正确公式为y3 * w * 4 + x3 * 4,确保遍历所有像素的RGBA值。 - 数组初始化时机错误:原代码在获取
w和h前就创建了distanceTable和angleTable,导致数组长度异常,需移到imageData初始化后。
2. 实现正确的隧道形态
- 纹理映射逻辑颠倒:原代码用距离对应纹理X轴、角度对应Y轴,不符合隧道的环绕+纵深逻辑,需调整为角度对应纹理X轴(环绕方向)、距离对应纹理Y轴(纵深方向)。
- 角度计算范围修正:去掉
Math.abs()并调整公式,让角度覆盖0到texWidth的完整范围,避免仅显示半圈隧道。 - 距离模运算优化:通过
(distance % texHeight + texHeight) % texHeight确保距离值始终为非负数,避免纹理索引异常。 - 纹理循环边界修正:原代码纹理X轴循环用了
texHeight作为边界,改为texWidth确保纹理生成完整。
内容的提问来源于stack exchange,提问作者Matthew Miller
相关产品推荐
相关产品推荐

