Как бы я повернул эти трехмерные объекты как группу вокруг синего куба? - PullRequest
0 голосов
/ 28 февраля 2020

Я пытаюсь создать маленькую 3D-систему, используя учебник, который я нашел в Интернете. Учебное пособие никогда не объясняет, как вращать все объекты как группу, и у каждого объекта есть свое собственное вращение вокруг его центра.

Я пытался добавить систему группировки самостоятельно, но никогда не мог понять это. В настоящее время он просто добавляет позицию синего куба к позиции создаваемого им объекта.

const _ZOOM = 5;

var Vertex = function(x, y, z) {
    this.x = parseFloat(x);
    this.y = parseFloat(y);
    this.z = parseFloat(z);
};

var Vertex2D = function(x, y) {
    this.x = parseFloat(x);
    this.y = parseFloat(y);
};

var Cube = function(center, side,colorData,groupParent) {
    // Generate the vertices
    var d = side / 2;

    this.center = center;
    this.stroke = colorData.strokeStyle;
    this.fill = colorData.fillStyle;

    this.center = center;
    if (groupParent){
        this.center.x -= groupParent.center.x;
        this.center.y -= groupParent.center.y;
        this.center.z -= groupParent.center.z;
    }

    this.vertices = [
        new Vertex(center.x - d, center.y - d, center.z + d),
        new Vertex(center.x - d, center.y - d, center.z - d),
        new Vertex(center.x + d, center.y - d, center.z - d),
        new Vertex(center.x + d, center.y - d, center.z + d),

        new Vertex(center.x + d, center.y + d, center.z + d),
        new Vertex(center.x + d, center.y + d, center.z - d),
        new Vertex(center.x - d, center.y + d, center.z - d),
        new Vertex(center.x - d, center.y + d, center.z + d)
    ];

    if (groupParent){
        for (let item in this.vertices){
            let index = this.vertices[item];
            index.x += groupParent.center.x;
            index.y += groupParent.center.y;
            index.z += groupParent.center.z;
        }
    }

    // Generate the faces
    this.faces = [
        [this.vertices[0], this.vertices[1], this.vertices[2], this.vertices[3]],
        [this.vertices[3], this.vertices[2], this.vertices[5], this.vertices[4]],
        [this.vertices[4], this.vertices[5], this.vertices[6], this.vertices[7]],
        [this.vertices[7], this.vertices[6], this.vertices[1], this.vertices[0]],
        [this.vertices[7], this.vertices[0], this.vertices[3], this.vertices[4]],
        [this.vertices[1], this.vertices[6], this.vertices[5], this.vertices[2]]
    ];
};

var Rectangle = function(center,side1,side2,colorData,groupParent) {
    // Generate the vertices
    var d = side1 / 2;
    var d2 = side2 / 2;

    this.center = center;
    if (groupParent){
        this.center.x -= groupParent.center.x;
        this.center.y -= groupParent.center.y;
        this.center.z -= groupParent.center.z;
    }

    this.stroke = colorData.strokeStyle;
    this.fill = colorData.fillStyle;

    this.vertices = [
        new Vertex(center.x - d, center.y - d2, center.z + d),
        new Vertex(center.x - d, center.y - d2, center.z - d),
        new Vertex(center.x + d, center.y - d2, center.z - d),
        new Vertex(center.x + d, center.y - d2, center.z + d),
        new Vertex(center.x + d, center.y + d2, center.z + d),
        new Vertex(center.x + d, center.y + d2, center.z - d),
        new Vertex(center.x - d, center.y + d2, center.z - d),
        new Vertex(center.x - d, center.y + d2, center.z + d)
    ];

    if (groupParent){
        for (let item in this.vertices){
            let index = this.vertices[item];
            index.x += groupParent.center.x;
            index.y += groupParent.center.y;
            index.z += groupParent.center.z;
        }
    }

    // Generate the faces
    this.faces = [
        [this.vertices[0], this.vertices[1], this.vertices[2], this.vertices[3]],
        [this.vertices[3], this.vertices[2], this.vertices[5], this.vertices[4]],
        [this.vertices[4], this.vertices[5], this.vertices[6], this.vertices[7]],
        [this.vertices[7], this.vertices[6], this.vertices[1], this.vertices[0]],
        [this.vertices[7], this.vertices[0], this.vertices[3], this.vertices[4]],
        [this.vertices[1], this.vertices[6], this.vertices[5], this.vertices[2]]
    ];
};

var Pyramid = function(center,width,height,colorData,groupParent) {
    // Generate the vertices
    var w = width / 2;
    var h = height / 2;

    this.center = center;
    this.stroke = colorData.strokeStyle;
    this.fill = colorData.fillStyle;

    this.center = center;
    if (groupParent){
        this.center.x -= groupParent.center.x;
        this.center.y -= groupParent.center.y;
        this.center.z -= groupParent.center.z;
    }

    this.vertices = [
        new Vertex(center.x - w, center.y + w, center.z + w),
        new Vertex(center.x - w, center.y + w, center.z - w),
        new Vertex(center.x + w, center.y + w, center.z - w),
        new Vertex(center.x + w, center.y + w, center.z + w),
        new Vertex(center.x, center.y - h, center.z),
    ];

    if (groupParent){
        for (let item in this.vertices){
            let index = this.vertices[item];
            index.x += groupParent.center.x;
            index.y += groupParent.center.y;
            index.z += groupParent.center.z;
        }
    }

    // Generate the faces
    this.faces = [
        [this.vertices[1], this.vertices[0], this.vertices[4]],
        [this.vertices[1], this.vertices[2], this.vertices[4]],
        [this.vertices[2], this.vertices[3], this.vertices[4]],
        [this.vertices[3], this.vertices[0], this.vertices[4]],
        [this.vertices[1], this.vertices[2],this.vertices[3],this.vertices[0]],
    ];
};

var Prism = function(center,width,height,colorData,groupParent) {
    // Generate the vertices
    var w = width / 2;
    var h = height / 2;

    this.center = center;
    this.stroke = colorData.strokeStyle;
    this.fill = colorData.fillStyle;

    this.center = center;
    if (groupParent){
        this.center.x -= groupParent.center.x;
        this.center.y -= groupParent.center.y;
        this.center.z -= groupParent.center.z;
    }

    this.vertices = [
        new Vertex(center.x + w, center.y, center.z - w),
        new Vertex(center.x - w, center.y, center.z),
        new Vertex(center.x + w, center.y, center.z + w),
        new Vertex(center.x + w, center.y - h, center.z - w),
        new Vertex(center.x - w, center.y - h, center.z),
        new Vertex(center.x + w, center.y - h, center.z + w),
    ];

    if (groupParent){
        for (let item in this.vertices){
            let index = this.vertices[item];
            index.x += groupParent.center.x;
            index.y += groupParent.center.y;
            index.z += groupParent.center.z;
        }
    }

    // Generate the faces
    this.faces = [
        [this.vertices[1], this.vertices[0], this.vertices[2]],
        [this.vertices[3], this.vertices[4], this.vertices[5]],

        [this.vertices[1], this.vertices[4], this.vertices[3],this.vertices[0]],
        [this.vertices[4], this.vertices[5], this.vertices[2],this.vertices[1]],
        [this.vertices[5], this.vertices[3], this.vertices[0],this.vertices[2]],
    ];
};

function project(M) {
    // Distance between the camera and the plane
    var d = 200;
    var r = d / M.y;

    return new Vertex2D(r * M.x, r * M.z);
}

function render(objects, ctx, dx, dy) {
    // Clear the previous frame
    ctx.clearRect(0, 0, 2*dx, 2*dy);

    // For each object
    for (var i = 0, n_obj = objects.length; i < n_obj; ++i) {
        // For each face
        for (var j = 0, n_faces = objects[i].faces.length; j < n_faces; ++j) {
            // Current face
            var face = objects[i].faces[j];

            // Draw the first vertex

            ctx.fillStyle = objects[i].fill;
            ctx.strokeStyle = objects[i].stroke;

            var P = project(face[0]);
            ctx.beginPath();
            ctx.moveTo(P.x + dx, -P.y + dy);

            // Draw the other vertices
            for (var k = 1, n_vertices = face.length; k < n_vertices; ++k) {
                P = project(face[k]);
                ctx.lineTo(P.x + dx, -P.y + dy);
            }

            // Close the path and draw the face
            ctx.closePath();
            ctx.stroke();
            ctx.fill();
        }
    }
}

(function() {
    // Fix the canvas width and height
    var canvas = document.getElementById('cnv');
    canvas.width = canvas.offsetWidth;
    canvas.height = canvas.offsetHeight;
    var dx = canvas.width / 2;
    var dy = canvas.height / 2;

    // Objects style
    var ctx = canvas.getContext('2d');

    // Create the cube
    var cube_center = new Vertex(0,10*dy/_ZOOM, 0);
    var cube = new Cube(cube_center, dy,{
        strokeStyle:"rgba(0,0,0,1)",
        fillStyle:"rgba(0,150,255,0.3)",
    });

    var cube_center2 = new Vertex(0,20*dy/_ZOOM,0);
    var cube2 = new Rectangle(cube_center2, dy,50,{
        strokeStyle:"rgba(0,0,0,1)",
        fillStyle:"rgba(255,150,0,0.3)",
    });

    var pyramid_center = new Vertex(dx + 150,20*dy/_ZOOM,0);
    var pyramid = new Pyramid(pyramid_center,200,400,{
        strokeStyle:"rgba(0,0,0,1)",
        fillStyle:"rgba(255,255,0,0.3)",
    },cube);

    var prism_center = new Vertex(0,20*dy/_ZOOM,0);
    var prism = new Prism(prism_center,200,400,{
        strokeStyle:"rgba(0,0,0,1)",
        fillStyle:"rgba(255,255,0,0.3)",
    });

    var objects = [cube,cube2,pyramid,prism];

    // First render
    render(objects, ctx, dx, dy);

    // Events
    var mousedown = false;
    var mx = 0;
    var my = 0;

    canvas.addEventListener('mousedown', initMove);
    document.addEventListener('mousemove', move);
    document.addEventListener('mouseup', stopMove);

    // Rotate a vertice
    function rotate(M, center, theta, phi) {
        // Rotation matrix coefficients
        var ct = Math.cos(theta);
        var st = Math.sin(theta);
        var cp = Math.cos(phi);
        var sp = Math.sin(phi);

        // Rotation
        var x = M.x - center.x;
        var y = M.y - center.y;
        var z = M.z - center.z;

        M.x = ct * x - st * cp * y + st * sp * z + center.x;
        M.y = st * x + ct * cp * y - ct * sp * z + center.y;
        M.z = sp * y + cp * z + center.z;
    }

    // Initialize the movement
    function initMove(evt) {
        clearTimeout(autorotate_timeout);
        mousedown = true;
        mx = evt.clientX;
        my = evt.clientY;
    }

    function rotObjs(objs,theta,phi){
        for (let item in objs){
            let index = objs[item];
            for (var i = 0; i < index.vertices.length; ++i){
                rotate(index.vertices[i],index.center, theta, phi);
            }
        }
    }

    function move(evt) {
        if (mousedown) {
            var theta = (evt.clientX - mx) * Math.PI / 360;
            var phi = (evt.clientY - my) * Math.PI / 360;
            rotObjs(objects,theta,phi);
            mx = evt.clientX;
            my = evt.clientY;
            render(objects, ctx, dx, dy);
        }
    }

    function stopMove() {
        mousedown = false;
        autorotate_timeout = setTimeout(autorotate, 2000);
    }

    function autorotate() {
        let theta = -Math.PI / 720;
        let phi = Math.PI / 720;
        rotObjs(objects,theta,phi);
        render(objects, ctx, dx, dy);
        autorotate_timeout = setTimeout(autorotate,30);
    }
    autorotate_timeout = setTimeout(autorotate, 2000);
})();```


...