Статья по теме:
Демо JavaScript:
СдвигX:
СдвигY:
СдвигZ:
ПоворотX:
ПоворотY:
ПоворотZ:
Наблюдатель:
<canvas width="500" height="500">Не поддерживается:С</canvas><br> СдвигX: <input id="moveX" type="range" min="-27" max="27" value="0" step="0.01" oninput="update()"><b id="infoX"></b><br> СдвигY: <input id="moveY" type="range" min="-27" max="27" value="0" step="0.01" oninput="update()"><b id="infoY"></b><br> СдвигZ: <input id="moveZ" type="range" min="-50" max="50" value="10" step="0.01" oninput="update()"><b id="infoZ"></b><br> ПоворотX: <input id="rotateX" type="range" min="-3.1415" max="3.1415" value="0" step = "0.0001" oninput="update()"><b id="infoRotateX"></b><br> ПоворотY: <input id="rotateY" type="range" min="-3.1415" max="3.1415" value="0" step = "0.0001" oninput="update()"><b id="infoRotateY"></b><br> ПоворотZ: <input id="rotateZ" type="range" min="-3.1415" max="3.1415" value="0" step = "0.0001" oninput="update()"><b id="infoRotateZ"></b><br> Наблюдатель: <input id="viever" type="range" min="-1000" max="1000" value="500" step = "1" oninput="update()"><b id="infoViever"></b><br>
var canvas = document.querySelector("canvas"); var ctx = canvas.getContext("2d"); class Vector2d{ constructor(x, y){ this.x = x; this.y = y; } move(mx, my){ let x = this.x + mx; let y = this.y + my; return new Vector2d(x, y); } scale(w){ let x = this.x * w; let y = this.y * w; return new Vector2d(x, y); } rotate(angle){ let x = this.x * Math.cos(angle) - this.y * Math.sin(angle); let y = this.x * Math.sin(angle) + this.y * Math.cos(angle); return new Vector2d(x, y); } } class Vector3d{ constructor(x, y, z){ this.x = x; this.y = y; this.z = z; } getProjection(dist){ //Получение проекции точек на плоскость let x = this.x*dist/this.z; let y = this.y*dist/this.z; return new Vector2d(x, y); } move(mx, my, mz){ let x = this.x + mx; let y = this.y + my; let z = this.z + mz; return new Vector3d(x, y, z); } scale(w){ let x = this.x * w; let y = this.y * w; let z = this.z * w; return new Vector3d(x, y, z); } rotate(angleX, angleY, angleZ){ let x, y, z; let temp = new Vector3d(this.x, this.y, this.z); //Вращение вокруг оси 0Y x = temp.x * Math.cos(angleY) + (temp.z)* Math.sin(angleY); y = temp.y; z = -temp.x * Math.sin(angleY) + (temp.z) * Math.cos(angleY); temp.x = x; temp.y = y; temp.z = z; //Вращение вокруг оси 0X x = temp.x; y = temp.y * Math.cos(angleX) + temp.z * Math.sin(angleX); z = -temp.y * Math.sin(angleX) + temp.z * Math.cos(angleX); temp.x = x; temp.y = y; temp.z = z; //Вращение вокруг оси 0Z x = temp.x * Math.cos(angleZ) + temp.y * Math.sin(angleZ); y = -temp.x * Math.sin(angleZ) + temp.y * Math.cos(angleZ); z = temp.z; temp.x = x; temp.y = y; temp.z = z; return temp; } static copy(vector){ return new Vector3d(vector.x, vector.y, vector.z); } } class Cub{ constructor(w, h, l, x, y, z){ this.world = [ //Мировые координаты точек new Vector3d(-w, -h, l), new Vector3d(-w, h, l), new Vector3d(w, -h, l), new Vector3d(w, h, l), new Vector3d(-w, -h, -l), new Vector3d(-w, h, -l), new Vector3d(w, -h, -l), new Vector3d(w, h, -l), ]; this.edges = [ //Связи точек для отрисовки ребер [0, 1], [0, 2], [3, 1], [3, 2], [4, 5], [4, 6], [7, 5], [7, 6], [0, 4], [1, 5], [2, 6], [3, 7], ]; this.display = []; //Массив для экранных координат проекций точек. this.projection = []; //Массив для координат проекций точек. this.scale = 1; //Углы поворота куба this.angleX = 0; this.angleY = 0; this.angleZ = 0; //Координаты куба this.x = x || 0; this.y = y || 0; this.z = z || 0; this.dist = 500; //Координаты проекции куба this.projX = 0; this.projY = 0; this.update(); } update(){ //Просчет новой проекции исходя из данных координат и углов поворота for(let i in this.world){ this.display[i] = this.world[i]; this.display[i] = this.display[i].rotate(this.angleX, this.angleY, this.angleZ); this.display[i] = this.display[i].scale(this.scale); this.display[i] = this.display[i].move(this.x, this.y, this.z); this.projection[i] = this.display[i].getProjection(this.dist); //Получаем проекцию this.projection[i] = this.projection[i].move(canvas.width/2, canvas.height/2); } } render(){ for(let i in this.edges){ if(this.display[this.edges[i][0]].z >= 0 && this.display[this.edges[i][1]].z >= 0){ ctx.strokeStyle = "yellow"; ctx.beginPath(); ctx.moveTo(this.projection[this.edges[i][0]].x, this.projection[this.edges[i][0]].y); ctx.lineTo(this.projection[this.edges[i][1]].x, this.projection[this.edges[i][1]].y); ctx.closePath(); ctx.stroke(); } } } } let cub = new Cub(1, 1, 1, 0, 0, 10); function update(){ let moveX = parseFloat(document.querySelector("#moveX").value) let moveY = parseFloat(document.querySelector("#moveY").value) let moveZ = parseFloat(document.querySelector("#moveZ").value) let angleX = parseFloat(document.querySelector("#rotateX").value) let angleY = parseFloat(document.querySelector("#rotateY").value) let angleZ = parseFloat(document.querySelector("#rotateZ").value) let viever = parseFloat(document.querySelector("#viever").value); document.querySelector("#infoX").innerHTML = moveX; document.querySelector("#infoY").innerHTML = moveY; document.querySelector("#infoZ").innerHTML = moveZ; document.querySelector("#infoRotateX").innerHTML = angleX; document.querySelector("#infoRotateY").innerHTML = angleY; document.querySelector("#infoRotateZ").innerHTML = angleZ; document.querySelector("#infoViever").innerHTML = viever; cub.angleX = angleX; cub.dist = viever; cub.angleY = angleY; cub.angleZ = angleZ; cub.x = moveX; cub.y = moveY; cub.z = moveZ; cub.update() //Просчитываем и применяем новую проекцию исходя из новых координат и углов ctx.fillRect(0, 0, canvas.width, canvas.height); cub.render(); //Отрисовываем куб } update();