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

为何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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 01:00:48