Как закрасить грань трехмерного куба?
У меня есть код с 3d объектами которые перемещаются в пространстве, с помощью TweenMax, мне нужно сделать заливку поверхностей, но не получается. Я убрала часть граней и оставила только квадрат (чтобы посмотреть как работает заливка), для этого я просто ограничила цикл с 12 до 4. Заливка не работает. Я решила попробовать просто начертить квадрат (moveTo и lineTo) и применить на нем заливку в этом случае работает, а когда пытаешься применить графику на 3d объекте сгенерированном в цикле то заливка не работает. В чем может быть проблема?
<!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title>Tween</title> <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script> <script src='./TweenMax.min.js'></script> <style> body { margin: 0; overflow: hidden; } canvas { width:100vw; height:100vh; } </style> </head> <body> <canvas id="scene"></canvas> <script> console.clear(); // Get the canvas element from the DOM const canvas = document.querySelector('#scene'); canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; // Store the 2D context const ctx = canvas.getContext('2d'); if (window.devicePixelRatio > 1) { canvas.width = canvas.clientWidth * 2; canvas.height = canvas.clientHeight * 2; ctx.scale(2, 2); } /* ====================== */ /* ====== VARIABLES ===== */ /* ====================== */ let width = canvas.clientWidth; // Width of the canvas let height = canvas.clientHeight; // Height of the canvas const dots = []; // Every dots in an array /* ====================== */ /* ====== CONSTANTS ===== */ /* ====================== */ /* Some of those constants may change if the user resizes their screen but I still strongly believe they belong to the Constants part of the variables */ const DOTS_AMOUNT = 1000; // Amount of dots on the screen const DOT_RADIUS = 2; // Radius of the dots let PROJECTION_CENTER_X = width / 2; // X center of the canvas HTML let PROJECTION_CENTER_Y = height / 2; // Y center of the canvas HTML let FIELD_OF_VIEW = width * 0.8; const CUBE_LINES = [[0, 1], [1, 3], [3, 2], [2, 0], [2, 6], [3, 7], [0, 4], [1, 5], [6, 7], [6, 4], [7, 5], [4, 5]]; const CUBE_VERTICES = [[-1, -1, -1],[1, -1, -1],[-1, 1, -1],[1, 1, -1],[-1, -1, 1],[1, -1, 1],[-1, 1, 1],[1, 1, 1]]; var test1 = [[-1, -1, -1],[1, -1, -1],[-1, 1, -1],[1, 1, -1],[-1, -1, 1],[1, -1, 1],[-1, 1, 1],[1, 1, 1]]; var xPos = 140; var yPos = 50; //{x:20,y:10,x:20,y:10,x:33,y:11,x:22,y:44,x:22,y:55,x:100,y:200}; class Cube { constructor(x, y, z) { this.x = (Math.random() - 0.5) * width; this.y = (Math.random() - 0.5) * width; this.z = (Math.random() - 0.5) * width; this.radius = Math.floor(Math.random() * 12 + 10); //TweenMax.to(this, Math.random() * 20 + 15, { // x: (Math.random() - 0.5) * (width * 0.5), // y: (Math.random() - 0.5) * (width * 0.5), // z: (Math.random() - 0.5) * width, // repeat: -1, // yoyo: true, // ease: Power2.EaseOut, // delay: Math.random() * -35 //}); } // Do some math to project the 3D position into the 2D canvas project(x, y, z) { const sizeProjection = FIELD_OF_VIEW / (FIELD_OF_VIEW + z); const xProject = (x * sizeProjection) + PROJECTION_CENTER_X; const yProject = (y * sizeProjection) + PROJECTION_CENTER_Y; return { size: sizeProjection, x: xProject, y: yProject } } // Draw the dot on the canvas draw() { // Do not render a cube that is in front of the camera if (this.z < -FIELD_OF_VIEW + this.radius) { return; } //CUBE_LINES.length for (let i = 0; i < 4; i++) { const v1 = { x: this.x + (this.radius * CUBE_VERTICES[CUBE_LINES[i][0]][0]), y: this.y + (this.radius * CUBE_VERTICES[CUBE_LINES[i][0]][1]), z: this.z + (this.radius * CUBE_VERTICES[CUBE_LINES[i][0]][2]) }; const v2 = { x: this.x + (this.radius * CUBE_VERTICES[CUBE_LINES[i][1]][0]), y: this.y + (this.radius * CUBE_VERTICES[CUBE_LINES[i][1]][1]), z: this.z + (this.radius * CUBE_VERTICES[CUBE_LINES[i][1]][2]) }; const v1Project = this.project(v1.x, v1.y, v1.z); const v2Project = this.project(v2.x, v2.y, v2.z); // ctx.beginPath(); // ctx.lineWidth = 2; // ctx.moveTo(v1Project.x, v1Project.y); //ctx.lineTo(v2Project.x, v2Project.y); // ctx.fillStyle = "#cc6666"; //console.log(test1[i][1][0]); // ctx.stroke(); // ctx.fill(); // console.log(CUBE_LINES.length); // console.log(test1.x); // ctx.save(); // ctx.lineWidth = 2; // ctx.fillStyle = ctx.strokeStyle = "#cc6666"; // ctx.beginPath(); /// ctx.moveTo(v1Project.x, v1Project.y); // ctx.lineTo(v2Project.x, v2Project.y); //ctx.closePath(); // ctx.stroke(); // ctx.fill(); // ctx.restore(); ctx.beginPath(); ctx.fillStyle = ctx.strokeStyle = "#6666cc"; //utils.colorToRGB(this.color, this.alpha); //************************************* //Не работает заливка //************************************* ctx.moveTo(v1Project.x,v1Project.y); ctx.lineTo(v2Project.x,v2Project.y); //************************************* //Работает заливка //************************************* ctx.moveTo(xPos,50+yPos); ctx.lineTo(xPos+50,50+yPos); ctx.lineTo(xPos+50,100+yPos); ctx.lineTo(xPos,100+yPos); ctx.lineTo(xPos,50+yPos); ctx.fill(); ctx.stroke(); } // ctx.globalAlpha = Math.abs(this.z / (width * 0.5)); } } function createDots() { // Empty the array of dots dots.length = 0; // Create a new dot based on the amount needed for (let i = 0; i < 100; i++) { dots.push(new Cube()); } } /* ====================== */ /* ======== RENDER ====== */ /* ====================== */ function render() { // Clear the scene ctx.clearRect(0, 0, width, height); // Loop through the dots array and draw every dot for (var i = 0; i < dots.length; i++) { dots[i].draw(); } window.requestAnimationFrame(render); } // Function called after the user resized its screen function afterResize () { width = canvas.offsetWidth; height = canvas.offsetHeight; if (window.devicePixelRatio > 1) { canvas.width = canvas.clientWidth * 2; canvas.height = canvas.clientHeight * 2; ctx.scale(2, 2); } else { canvas.width = width; canvas.height = height; } PROJECTION_CENTER_X = width / 2; PROJECTION_CENTER_Y = height / 2; FIELD_OF_VIEW = width * 0.8; createDots(); // Reset all dots } // Variable used to store a timeout when user resized its screen let resizeTimeout; // Function called right after user resized its screen function onResize () { // Clear the timeout variable resizeTimeout = window.clearTimeout(resizeTimeout); // Store a new timeout to avoid calling afterResize for every resize event resizeTimeout = window.setTimeout(afterResize, 500); } window.addEventListener('resize', onResize); // Populate the dots array with random dots createDots(); // Render the scene window.requestAnimationFrame(render); </script> </body> </html> |
Olga27,
строка 144 if(!i) { let h = -(v1Project.x - v2Project.x); ctx.fillRect(v1Project.x,v1Project.y, h, h) } |
>> Заливка не работает.
Заливка работает но не так как ты ожидаешь. Заливка применяется между всеми вершинами которые образует последовательный вызов ctx.lineTo( .... ) Вызов ctx.moveTo ( .... ) разрывает группу вершин между которыми применяется заливка. Т.е. в твоем случае когда после каждого вызова ctx.lineTo вызывается ctx.moveTo заливка применяется только под нарисованной линией и ее совсем не видно. Отрисовка ну очень не оптимальна на каждом шаге анимации функция draw() вызывается в цикле внутри этой функции то же цикл в котором вызывается ctx.beginPath(); |
рони, работает заливка, теперь я изменила цикл и увеличила до 12, чтобы все плоскости куба отображались, также я вернула tweenmax для перемещения по холсту. Как теперь остальным граням присвоить другие цвета? т.е. задняя плоскость не видна, остается еще четыре top, left,right и bottom, которые постепенно отображаются в зависимости перемещения объекта.
<!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title>Tween</title> <script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script> <script src='https://cdnjs.cloudflare.com/ajax/libs/gsap/1.14.2/TweenMax.min.js'></script> <style> body { margin: 0; overflow: hidden; } canvas { width:100vw; height:100vh; } </style> </head> <body> <canvas id="scene"></canvas> <script> console.clear(); // Get the canvas element from the DOM const canvas = document.querySelector('#scene'); canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; // Store the 2D context const ctx = canvas.getContext('2d'); if (window.devicePixelRatio > 1) { canvas.width = canvas.clientWidth * 2; canvas.height = canvas.clientHeight * 2; ctx.scale(2, 2); } /* ====================== */ /* ====== VARIABLES ===== */ /* ====================== */ let width = canvas.clientWidth; // Width of the canvas let height = canvas.clientHeight; // Height of the canvas const dots = []; // Every dots in an array /* ====================== */ /* ====== CONSTANTS ===== */ /* ====================== */ /* Some of those constants may change if the user resizes their screen but I still strongly believe they belong to the Constants part of the variables */ const DOTS_AMOUNT = 1000; // Amount of dots on the screen const DOT_RADIUS = 2; // Radius of the dots let PROJECTION_CENTER_X = width / 2; // X center of the canvas HTML let PROJECTION_CENTER_Y = height / 2; // Y center of the canvas HTML let FIELD_OF_VIEW = width * 0.8; const CUBE_LINES = [[0, 1], [1, 3], [3, 2], [2, 0], [2, 6], [3, 7], [0, 4], [1, 5], [6, 7], [6, 4], [7, 5], [4, 5]]; const CUBE_VERTICES = [[-1, -1, -1],[1, -1, -1],[-1, 1, -1],[1, 1, -1],[-1, -1, 1],[1, -1, 1],[-1, 1, 1],[1, 1, 1]]; var test1 = [[-1, -1, -1],[1, -1, -1],[-1, 1, -1],[1, 1, -1],[-1, -1, 1],[1, -1, 1],[-1, 1, 1],[1, 1, 1]]; var xPos = 140; var yPos = 50; //{x:20,y:10,x:20,y:10,x:33,y:11,x:22,y:44,x:22,y:55,x:100,y:200}; class Cube { constructor(x, y, z) { this.x = (Math.random() - 0.5) * width; this.y = (Math.random() - 0.5) * width; this.z = (Math.random() - 0.5) * width; this.radius = Math.floor(Math.random() * 12 + 10); TweenMax.to(this, Math.random() * 20 + 15, { x: (Math.random() - 0.5) * (width * 0.5), y: (Math.random() - 0.5) * (width * 0.5), z: (Math.random() - 0.5) * width, repeat: -1, yoyo: true, ease: Power2.EaseOut, delay: Math.random() * -35 }); } // Do some math to project the 3D position into the 2D canvas project(x, y, z) { const sizeProjection = FIELD_OF_VIEW / (FIELD_OF_VIEW + z); const xProject = (x * sizeProjection) + PROJECTION_CENTER_X; const yProject = (y * sizeProjection) + PROJECTION_CENTER_Y; return { size: sizeProjection, x: xProject, y: yProject } } // Draw the dot on the canvas draw() { // Do not render a cube that is in front of the camera if (this.z < -FIELD_OF_VIEW + this.radius) { return; } //CUBE_LINES.length for (let i = 0; i < 12; i++) { const v1 = { x: this.x + (this.radius * CUBE_VERTICES[CUBE_LINES[i][0]][0]), y: this.y + (this.radius * CUBE_VERTICES[CUBE_LINES[i][0]][1]), z: this.z + (this.radius * CUBE_VERTICES[CUBE_LINES[i][0]][2]) }; const v2 = { x: this.x + (this.radius * CUBE_VERTICES[CUBE_LINES[i][1]][0]), y: this.y + (this.radius * CUBE_VERTICES[CUBE_LINES[i][1]][1]), z: this.z + (this.radius * CUBE_VERTICES[CUBE_LINES[i][1]][2]) }; const v1Project = this.project(v1.x, v1.y, v1.z); const v2Project = this.project(v2.x, v2.y, v2.z); // ctx.beginPath(); // ctx.lineWidth = 2; // ctx.moveTo(v1Project.x, v1Project.y); //ctx.lineTo(v2Project.x, v2Project.y); // ctx.fillStyle = "#cc6666"; //console.log(test1[i][1][0]); // ctx.stroke(); // ctx.fill(); // console.log(CUBE_LINES.length); // console.log(test1.x); // ctx.save(); // ctx.lineWidth = 2; // ctx.fillStyle = ctx.strokeStyle = "#cc6666"; // ctx.beginPath(); /// ctx.moveTo(v1Project.x, v1Project.y); // ctx.lineTo(v2Project.x, v2Project.y); //ctx.closePath(); // ctx.stroke(); // ctx.fill(); // ctx.restore(); ctx.beginPath(); ctx.fillStyle = ctx.strokeStyle = "#6666cc"; //utils.colorToRGB(this.color, this.alpha); //************************************* //Не работает заливка //************************************* ctx.moveTo(v1Project.x,v1Project.y); ctx.lineTo(v2Project.x,v2Project.y); if(!i) { let h = -(v1Project.x - v2Project.x); ctx.fillRect(v1Project.x,v1Project.y, h, h) } ctx.stroke(); } // ctx.globalAlpha = Math.abs(this.z / (width * 0.5)); } } function createDots() { // Empty the array of dots dots.length = 0; // Create a new dot based on the amount needed for (let i = 0; i < 100; i++) { dots.push(new Cube()); } } /* ====================== */ /* ======== RENDER ====== */ /* ====================== */ function render() { // Clear the scene ctx.clearRect(0, 0, width, height); // Loop through the dots array and draw every dot for (var i = 0; i < dots.length; i++) { dots[i].draw(); } window.requestAnimationFrame(render); } // Function called after the user resized its screen function afterResize () { width = canvas.offsetWidth; height = canvas.offsetHeight; if (window.devicePixelRatio > 1) { canvas.width = canvas.clientWidth * 2; canvas.height = canvas.clientHeight * 2; ctx.scale(2, 2); } else { canvas.width = width; canvas.height = height; } PROJECTION_CENTER_X = width / 2; PROJECTION_CENTER_Y = height / 2; FIELD_OF_VIEW = width * 0.8; createDots(); // Reset all dots } // Variable used to store a timeout when user resized its screen let resizeTimeout; // Function called right after user resized its screen function onResize () { // Clear the timeout variable resizeTimeout = window.clearTimeout(resizeTimeout); // Store a new timeout to avoid calling afterResize for every resize event resizeTimeout = window.setTimeout(afterResize, 500); } window.addEventListener('resize', onResize); // Populate the dots array with random dots createDots(); // Render the scene window.requestAnimationFrame(render); </script> </body> </html> |
Часовой пояс GMT +3, время: 04:41. |