首页 > 解决方案 > 自定义 3D 引擎中的不稳定投影

问题描述

今天我一直在尝试使用 JavaScript 组装一个 3D 线框渲染引擎;请注意,我的目标是最终创建一个 Rails 射击游戏,因此相机转换对我来说还不是很重要。但是,我似乎无法让透视投影正常工作:

这是我的渲染代码,请注意我对 glMatrix 的依赖:

export default (() =>
{
    const { mat4, vec3 } = glMatrix;
    function line(pixels, a_x = 0, a_y = 0, b_x = 0, b_y = 0, color = 0xFF0000)
    {
        // Bresenham's algorithm
    };
    function translate(point, pos)
    {
        vec3.add(point, point, pos);
    }
    function rotate(point, pos, rot)
    {
        vec3.rotateX(point, point, pos, rot[0]);
        vec3.rotateY(point, point, pos, rot[1]);
        vec3.rotateZ(point, point, pos, rot[2]);
    };
    function transform(point, pos, rot)
    {
        translate(point, pos);
        rotate(point, pos, rot);
    };
    return {
        Camera: class
        {
            constructor(pos, fudge)
            {
                /* Unused
                this.pos = pos;
                this.rot = [0, 0, 0]; */
                this.fudge = fudge;
            }
            fudged(p)
            {
                return this.fudge / (p[2] + this.fudge);
            }
        },
        Model: class
        {
            constructor(verts, edges, faces)
            {
                this.faces = faces;
                this.edges = edges;
                this.verts = verts;
                
                this.pos = [0, 0, 0];
                this.rot = [0, 0, 0];
                this.scale = [1, 1, 1];
            }
            render(camera, pixels)
            {
                for (const face of this.faces)
                {
                    for (const index of face.edges)
                    {
                        const edge = this.edges[index];
                        const a = [...this.verts[edge.verts[0]]];
                        const b = [...this.verts[edge.verts[1]]];
                        transform(a, this.pos, this.rot);
                        transform(b, this.pos, this.rot);
                        
                        const a_p = camera.fudged(a);
                        const b_p = camera.fudged(b);
                        line(pixels, a[0] * a_p, a[1] * a_p, b[0] * b_p, b[1] * b_p, edge.color);
                    }
                }
            }
        },
    };
})();

这是设置场景的代码:

import Wireframe from './wireframe.js';

export default function main()
{
    const canvas = document.querySelector `canvas`;
    canvas.width = canvas.clientWidth;
    canvas.height = canvas.clientHeight;
    const ctx = canvas.getContext('2d');
    const camera = new Wireframe.Camera([canvas.width / 2, canvas.height / 2, 200], canvas.width);
    const model = new Wireframe.Model(
        [ // Verts
            [-50, -50, 50], [50, -50, 50],
            [50, 50, 50], [-50, 50, 50],
            [50, 50, -50], [-50, 50, -50],
            [-50, -50, -50], [50, -50, -50]],
        [ // Edges
            { color: 0xFFC800, verts: [0, 1] },
            { color: 0x20C8FF, verts: [1, 2] },
            { color: 0x00C800, verts: [2, 3] },
            { color: 0xC82020, verts: [3, 0] },
            
            { color: 0xFFC800, verts: [3, 5] },
            { color: 0x20C8FF, verts: [5, 6] },
            { color: 0x00C800, verts: [6, 0] },
            { color: 0xC82020, verts: [0, 3] },
            
            { color: 0xFFC800, verts: [4, 5] },
            { color: 0x20C8FF, verts: [5, 6] },
            { color: 0x00C800, verts: [6, 7] },
            { color: 0xC82020, verts: [7, 4] }],
        [ // Faces
            { edges: [0, 1, 2, 3] },
            { edges: [4, 5, 6, 7] },
            { edges: [8, 9, 10, 11] }]);
    model.pos = [canvas.width / 2, canvas.height / 2, 0];
    const draw = (() =>
    {
        return mil =>
        {
            window.requestAnimationFrame(draw);
            ctx.fillStyle = 'black';
            ctx.fillRect(0, 0, canvas.width, canvas.height);
            const pixels = ctx.getImageData(0, 0, canvas.width, canvas.height);
            model.render(camera, pixels);
            model.rot[1] += 0.01;
            ctx.putImageData(pixels, 0, 0);
        };
    })();
    window.requestAnimationFrame(draw);
};

感谢您提供任何帮助,谢谢。

标签: javascript3dprojection

解决方案


推荐阅读