From e469e8d3a5a66b29a76fe7fb8e7888d9d7786d15 Mon Sep 17 00:00:00 2001 From: Syndamia Date: Fri, 28 Oct 2022 10:18:41 +0300 Subject: [WGL/H03] Implemented view points, vertical rows, fixed color, added comments --- .../Homework 03 - The wall/Homework.html | 61 +++++++++++++++------- 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/Year 2/Computer Graphics with WebGL/Homework 03 - The wall/Homework.html b/Year 2/Computer Graphics with WebGL/Homework 03 - The wall/Homework.html index 2d528c3..11393ef 100644 --- a/Year 2/Computer Graphics with WebGL/Homework 03 - The wall/Homework.html +++ b/Year 2/Computer Graphics with WebGL/Homework 03 - The wall/Homework.html @@ -45,7 +45,21 @@ var proj = perspMatrix(30,gl.canvas.width/gl.canvas.height,1,40000); gl.uniformMatrix4fv(uProjectionMatrix,false,proj); - var view = viewMatrix([1, 60, 1], [0,0,-7], [0,0,1]); + /*** + *** Изгледите се променят с тази променлива! + ***/ + const VIEW_INDEX = 1; // 0 - Отстрани, 1 - Отгоре, 2 - От близко + + var view; + switch (VIEW_INDEX) { + case 0: + view = viewMatrix([-25, 30, -25], [-3,5,-6], [1.1,0,1]); break; + case 1: default: + view = viewMatrix([0, 60, -3], [0,0,-7], [0,0,1]); break; + case 2: + view = viewMatrix([-13, 3.2, -23], [0,3.2,-9], [0,90,1]); break; + } + gl.uniformMatrix4fv(uViewMatrix,false,view); gl.viewport(0, 0, 600, 400); @@ -75,19 +89,20 @@ gl.enableVertexAttribArray(aXYZ); gl.vertexAttribPointer(aXYZ,3,gl.FLOAT,false,0,0); - gl.uniform3f(uColor,127,0,0); + gl.uniform3f(uColor,0.5,0,0); // Вместо единичен куб, да се нарисува стена под формата на сърце // от 20 реда застъпващи се тухли, използвайки трансформиран куб - var brickLength = 1.5; - var brickHeight = 0.5; - var rows = 1; - var radius = 6; - var gap = 0.4; - var bottomHeight = 19; + var rows = 20; + var brickLength = 0.75; + var brickHeight = 0.25; + var brickWidth = 0.5; + var radius = 6; // определя радиус на полукръговете и амплитуда на синусоида за втората половина (виж drawBodyLine) + var gap = 0.2; // дупка между тухлите и два пъти дупка между редовете + var bottomHeight = 19; // височина от полукръговете до най-долната част на сърцето - var brickScale = [1, brickHeight, brickLength]; + var brickScale = [brickWidth, brickHeight, brickLength]; function drawBrick() { useMatrix(); gl.drawArrays(gl.LINE_LOOP,0,4); @@ -96,39 +111,45 @@ } var degreeStep = (brickLength + gap) / radius; - function drawHalfCircle(xOffset) { - for (var i = 0; i < Math.PI + 0.1; i += degreeStep) { + function drawHalfCircle(y, offsetBricks, xOffset) { + for (var i = (offsetBricks) ? degreeStep / 2 : 0; i < Math.PI + 0.1; i += degreeStep) { identity(); - translate([Math.cos(i) * radius + xOffset, 0, Math.sin(i) * radius]); + translate([Math.cos(i) * radius + xOffset, y, Math.sin(i) * radius]); yRotate((Math.PI - i) * 180 / Math.PI); scale(brickScale); drawBrick(); } } const SLOPE_EPSILON = 0.01; - function drawBodyLine(xOffset, direction, rotationCoefficient) { + function drawBodyLine(y, offsetBricks, xOffset, direction, rotationCoefficient) { function calcX(z) { + // direction е -1 или 1, като така разглеждаме синус в [-PI/2, PI/2] или [PI/2, PI] с амплитуда radius return Math.sin(Math.PI / 2 * direction + Math.PI * z / bottomHeight) * radius - xOffset; } - var zStep = 0; - for (var z = -brickLength - gap; z >= -bottomHeight - 0.1; z -= zStep) { + var zStep = 0; // ненужно, но иначе е малко объркващо + for (var z = -brickLength - gap + ((offsetBricks) ? brickLength / 2 : 0); z > -bottomHeight - 0.1; z -= zStep) { var xDistance = calcX(z); identity(); - translate([xDistance, 0, z]); yRotate(Math.sin(Math.PI * z / bottomHeight) * rotationCoefficient); + translate([xDistance, y, z]); yRotate(Math.sin(Math.PI * z / bottomHeight) * rotationCoefficient); scale(brickScale); drawBrick(); + // За равномерно разпределение по кривата, разглеждаме един малък участък като права, намираме наклона m + // и така преместваме тухлата вертикално, че разстоянието между сегашната и следващата тухла да е gap + // Най-перфектния начин е с интегриране, но това дава доста добър резултат за доста лесни (в сравнение) сметки var m = Math.abs(SLOPE_EPSILON / (xDistance - calcX(z + SLOPE_EPSILON))); + // Намираме от системата d = sqrt((x-x0)^2 + (y-y0)^2) и m = (y-y0)/(x-x0), където (x0, y0) е сегашната точка + // (центъра на тухлата), а (x, y) са следващите zStep = (brickLength + gap) * m / Math.sqrt(m * m + 1); } } for (var row = 0; row < rows; row++) { - drawHalfCircle(radius); // Горна лява четвърт - drawHalfCircle(-radius); // Горна дясна четвърт - drawBodyLine( radius, -1, 45); // Долна дясна четвърт - drawBodyLine(-radius, 1, -45); // Долна лява четвърт + drawHalfCircle(row * (brickHeight + gap / 2), (row % 2 === 1), radius); // Горна лява четвърт + drawHalfCircle(row * (brickHeight + gap / 2), (row % 2 === 1), -radius); // Горна дясна четвърт + drawBodyLine( row * (brickHeight + gap / 2), (row % 2 === 1), radius, -1, 45); // Долна дясна четвърт + drawBodyLine( row * (brickHeight + gap / 2), (row % 2 === 1), -radius, 1, -45); // Долна лява четвърт } // Debugging -- cgit v1.3.1-26-gb76a