From cb72a4105a40159d8427812eb2c9717dd3e88fba Mon Sep 17 00:00:00 2001 From: "geoffrey.menetrey" <geoffrey.menetrey@etu.hesge.ch> Date: Thu, 17 Dec 2020 15:58:28 +0100 Subject: [PATCH] =?UTF-8?q?d=C3=A9tection=20du=20click=20sur=20le=20sablie?= =?UTF-8?q?r,=20fonctionne=20mal=20avec=20la=20lumi=C3=A8re=20ponctuelle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lab3.zip | Bin 0 -> 41317 bytes lab4/lib/cuon-matrix.js | 741 ++++++++++++++++++++++++++++++++++++++++ lab4/src/lab4.html | 5 + lab4/src/lab4.js | 511 ++++++++++++++++++++++++++- 4 files changed, 1247 insertions(+), 10 deletions(-) create mode 100644 lab3.zip create mode 100644 lab4/lib/cuon-matrix.js diff --git a/lab3.zip b/lab3.zip new file mode 100644 index 0000000000000000000000000000000000000000..04bcfd0df37de238a57ffdf2ccc2a415a10b826c GIT binary patch literal 41317 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 literal 0 HcmV?d00001 diff --git a/lab4/lib/cuon-matrix.js b/lab4/lib/cuon-matrix.js new file mode 100644 index 0000000..ded82a7 --- /dev/null +++ b/lab4/lib/cuon-matrix.js @@ -0,0 +1,741 @@ +// cuon-matrix.js (c) 2012 kanda and matsuda +/** + * This is a class treating 4x4 matrix. + * This class contains the function that is equivalent to OpenGL matrix stack. + * The matrix after conversion is calculated by multiplying a conversion matrix from the right. + * The matrix is replaced by the calculated result. + */ + +/** + * Constructor of Matrix4 + * If opt_src is specified, new matrix is initialized by opt_src. + * Otherwise, new matrix is initialized by identity matrix. + * @param opt_src source matrix(option) + */ +var Matrix4 = function(opt_src) { + var i, s, d; + if (opt_src && typeof opt_src === 'object' && opt_src.hasOwnProperty('elements')) { + s = opt_src.elements; + d = new Float32Array(16); + for (i = 0; i < 16; ++i) { + d[i] = s[i]; + } + this.elements = d; + } else { + this.elements = new Float32Array([1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1]); + } +}; + +/** + * Set the identity matrix. + * @return this + */ +Matrix4.prototype.setIdentity = function() { + var e = this.elements; + e[0] = 1; e[4] = 0; e[8] = 0; e[12] = 0; + e[1] = 0; e[5] = 1; e[9] = 0; e[13] = 0; + e[2] = 0; e[6] = 0; e[10] = 1; e[14] = 0; + e[3] = 0; e[7] = 0; e[11] = 0; e[15] = 1; + return this; +}; + +/** + * Copy matrix. + * @param src source matrix + * @return this + */ +Matrix4.prototype.set = function(src) { + var i, s, d; + + s = src.elements; + d = this.elements; + + if (s === d) { + return; + } + + for (i = 0; i < 16; ++i) { + d[i] = s[i]; + } + + return this; +}; + +/** + * Multiply the matrix from the right. + * @param other The multiply matrix + * @return this + */ +Matrix4.prototype.concat = function(other) { + var i, e, a, b, ai0, ai1, ai2, ai3; + + // Calculate e = a * b + e = this.elements; + a = this.elements; + b = other.elements; + + // If e equals b, copy b to temporary matrix. + if (e === b) { + b = new Float32Array(16); + for (i = 0; i < 16; ++i) { + b[i] = e[i]; + } + } + + for (i = 0; i < 4; i++) { + ai0=a[i]; ai1=a[i+4]; ai2=a[i+8]; ai3=a[i+12]; + e[i] = ai0 * b[0] + ai1 * b[1] + ai2 * b[2] + ai3 * b[3]; + e[i+4] = ai0 * b[4] + ai1 * b[5] + ai2 * b[6] + ai3 * b[7]; + e[i+8] = ai0 * b[8] + ai1 * b[9] + ai2 * b[10] + ai3 * b[11]; + e[i+12] = ai0 * b[12] + ai1 * b[13] + ai2 * b[14] + ai3 * b[15]; + } + + return this; +}; +Matrix4.prototype.multiply = Matrix4.prototype.concat; + +/** + * Multiply the three-dimensional vector. + * @param pos The multiply vector + * @return The result of multiplication(Float32Array) + */ +Matrix4.prototype.multiplyVector3 = function(pos) { + var e = this.elements; + var p = pos.elements; + var v = new Vector3(); + var result = v.elements; + + result[0] = p[0] * e[0] + p[1] * e[4] + p[2] * e[ 8] + e[12]; + result[1] = p[0] * e[1] + p[1] * e[5] + p[2] * e[ 9] + e[13]; + result[2] = p[0] * e[2] + p[1] * e[6] + p[2] * e[10] + e[14]; + + return v; +}; + +/** + * Multiply the four-dimensional vector. + * @param pos The multiply vector + * @return The result of multiplication(Float32Array) + */ +Matrix4.prototype.multiplyVector4 = function(pos) { + var e = this.elements; + var p = pos.elements; + var v = new Vector4(); + var result = v.elements; + + result[0] = p[0] * e[0] + p[1] * e[4] + p[2] * e[ 8] + p[3] * e[12]; + result[1] = p[0] * e[1] + p[1] * e[5] + p[2] * e[ 9] + p[3] * e[13]; + result[2] = p[0] * e[2] + p[1] * e[6] + p[2] * e[10] + p[3] * e[14]; + result[3] = p[0] * e[3] + p[1] * e[7] + p[2] * e[11] + p[3] * e[15]; + + return v; +}; + +/** + * Transpose the matrix. + * @return this + */ +Matrix4.prototype.transpose = function() { + var e, t; + + e = this.elements; + + t = e[ 1]; e[ 1] = e[ 4]; e[ 4] = t; + t = e[ 2]; e[ 2] = e[ 8]; e[ 8] = t; + t = e[ 3]; e[ 3] = e[12]; e[12] = t; + t = e[ 6]; e[ 6] = e[ 9]; e[ 9] = t; + t = e[ 7]; e[ 7] = e[13]; e[13] = t; + t = e[11]; e[11] = e[14]; e[14] = t; + + return this; +}; + +/** + * Calculate the inverse matrix of specified matrix, and set to this. + * @param other The source matrix + * @return this + */ +Matrix4.prototype.setInverseOf = function(other) { + var i, s, d, inv, det; + + s = other.elements; + d = this.elements; + inv = new Float32Array(16); + + inv[0] = s[5]*s[10]*s[15] - s[5] *s[11]*s[14] - s[9] *s[6]*s[15] + + s[9]*s[7] *s[14] + s[13]*s[6] *s[11] - s[13]*s[7]*s[10]; + inv[4] = - s[4]*s[10]*s[15] + s[4] *s[11]*s[14] + s[8] *s[6]*s[15] + - s[8]*s[7] *s[14] - s[12]*s[6] *s[11] + s[12]*s[7]*s[10]; + inv[8] = s[4]*s[9] *s[15] - s[4] *s[11]*s[13] - s[8] *s[5]*s[15] + + s[8]*s[7] *s[13] + s[12]*s[5] *s[11] - s[12]*s[7]*s[9]; + inv[12] = - s[4]*s[9] *s[14] + s[4] *s[10]*s[13] + s[8] *s[5]*s[14] + - s[8]*s[6] *s[13] - s[12]*s[5] *s[10] + s[12]*s[6]*s[9]; + + inv[1] = - s[1]*s[10]*s[15] + s[1] *s[11]*s[14] + s[9] *s[2]*s[15] + - s[9]*s[3] *s[14] - s[13]*s[2] *s[11] + s[13]*s[3]*s[10]; + inv[5] = s[0]*s[10]*s[15] - s[0] *s[11]*s[14] - s[8] *s[2]*s[15] + + s[8]*s[3] *s[14] + s[12]*s[2] *s[11] - s[12]*s[3]*s[10]; + inv[9] = - s[0]*s[9] *s[15] + s[0] *s[11]*s[13] + s[8] *s[1]*s[15] + - s[8]*s[3] *s[13] - s[12]*s[1] *s[11] + s[12]*s[3]*s[9]; + inv[13] = s[0]*s[9] *s[14] - s[0] *s[10]*s[13] - s[8] *s[1]*s[14] + + s[8]*s[2] *s[13] + s[12]*s[1] *s[10] - s[12]*s[2]*s[9]; + + inv[2] = s[1]*s[6]*s[15] - s[1] *s[7]*s[14] - s[5] *s[2]*s[15] + + s[5]*s[3]*s[14] + s[13]*s[2]*s[7] - s[13]*s[3]*s[6]; + inv[6] = - s[0]*s[6]*s[15] + s[0] *s[7]*s[14] + s[4] *s[2]*s[15] + - s[4]*s[3]*s[14] - s[12]*s[2]*s[7] + s[12]*s[3]*s[6]; + inv[10] = s[0]*s[5]*s[15] - s[0] *s[7]*s[13] - s[4] *s[1]*s[15] + + s[4]*s[3]*s[13] + s[12]*s[1]*s[7] - s[12]*s[3]*s[5]; + inv[14] = - s[0]*s[5]*s[14] + s[0] *s[6]*s[13] + s[4] *s[1]*s[14] + - s[4]*s[2]*s[13] - s[12]*s[1]*s[6] + s[12]*s[2]*s[5]; + + inv[3] = - s[1]*s[6]*s[11] + s[1]*s[7]*s[10] + s[5]*s[2]*s[11] + - s[5]*s[3]*s[10] - s[9]*s[2]*s[7] + s[9]*s[3]*s[6]; + inv[7] = s[0]*s[6]*s[11] - s[0]*s[7]*s[10] - s[4]*s[2]*s[11] + + s[4]*s[3]*s[10] + s[8]*s[2]*s[7] - s[8]*s[3]*s[6]; + inv[11] = - s[0]*s[5]*s[11] + s[0]*s[7]*s[9] + s[4]*s[1]*s[11] + - s[4]*s[3]*s[9] - s[8]*s[1]*s[7] + s[8]*s[3]*s[5]; + inv[15] = s[0]*s[5]*s[10] - s[0]*s[6]*s[9] - s[4]*s[1]*s[10] + + s[4]*s[2]*s[9] + s[8]*s[1]*s[6] - s[8]*s[2]*s[5]; + + det = s[0]*inv[0] + s[1]*inv[4] + s[2]*inv[8] + s[3]*inv[12]; + if (det === 0) { + return this; + } + + det = 1 / det; + for (i = 0; i < 16; i++) { + d[i] = inv[i] * det; + } + + return this; +}; + +/** + * Calculate the inverse matrix of this, and set to this. + * @return this + */ +Matrix4.prototype.invert = function() { + return this.setInverseOf(this); +}; + +/** + * Set the orthographic projection matrix. + * @param left The coordinate of the left of clipping plane. + * @param right The coordinate of the right of clipping plane. + * @param bottom The coordinate of the bottom of clipping plane. + * @param top The coordinate of the top top clipping plane. + * @param near The distances to the nearer depth clipping plane. This value is minus if the plane is to be behind the viewer. + * @param far The distances to the farther depth clipping plane. This value is minus if the plane is to be behind the viewer. + * @return this + */ +Matrix4.prototype.setOrtho = function(left, right, bottom, top, near, far) { + var e, rw, rh, rd; + + if (left === right || bottom === top || near === far) { + throw 'null frustum'; + } + + rw = 1 / (right - left); + rh = 1 / (top - bottom); + rd = 1 / (far - near); + + e = this.elements; + + e[0] = 2 * rw; + e[1] = 0; + e[2] = 0; + e[3] = 0; + + e[4] = 0; + e[5] = 2 * rh; + e[6] = 0; + e[7] = 0; + + e[8] = 0; + e[9] = 0; + e[10] = -2 * rd; + e[11] = 0; + + e[12] = -(right + left) * rw; + e[13] = -(top + bottom) * rh; + e[14] = -(far + near) * rd; + e[15] = 1; + + return this; +}; + +/** + * Multiply the orthographic projection matrix from the right. + * @param left The coordinate of the left of clipping plane. + * @param right The coordinate of the right of clipping plane. + * @param bottom The coordinate of the bottom of clipping plane. + * @param top The coordinate of the top top clipping plane. + * @param near The distances to the nearer depth clipping plane. This value is minus if the plane is to be behind the viewer. + * @param far The distances to the farther depth clipping plane. This value is minus if the plane is to be behind the viewer. + * @return this + */ +Matrix4.prototype.ortho = function(left, right, bottom, top, near, far) { + return this.concat(new Matrix4().setOrtho(left, right, bottom, top, near, far)); +}; + +/** + * Set the perspective projection matrix. + * @param left The coordinate of the left of clipping plane. + * @param right The coordinate of the right of clipping plane. + * @param bottom The coordinate of the bottom of clipping plane. + * @param top The coordinate of the top top clipping plane. + * @param near The distances to the nearer depth clipping plane. This value must be plus value. + * @param far The distances to the farther depth clipping plane. This value must be plus value. + * @return this + */ +Matrix4.prototype.setFrustum = function(left, right, bottom, top, near, far) { + var e, rw, rh, rd; + + if (left === right || top === bottom || near === far) { + throw 'null frustum'; + } + if (near <= 0) { + throw 'near <= 0'; + } + if (far <= 0) { + throw 'far <= 0'; + } + + rw = 1 / (right - left); + rh = 1 / (top - bottom); + rd = 1 / (far - near); + + e = this.elements; + + e[ 0] = 2 * near * rw; + e[ 1] = 0; + e[ 2] = 0; + e[ 3] = 0; + + e[ 4] = 0; + e[ 5] = 2 * near * rh; + e[ 6] = 0; + e[ 7] = 0; + + e[ 8] = (right + left) * rw; + e[ 9] = (top + bottom) * rh; + e[10] = -(far + near) * rd; + e[11] = -1; + + e[12] = 0; + e[13] = 0; + e[14] = -2 * near * far * rd; + e[15] = 0; + + return this; +}; + +/** + * Multiply the perspective projection matrix from the right. + * @param left The coordinate of the left of clipping plane. + * @param right The coordinate of the right of clipping plane. + * @param bottom The coordinate of the bottom of clipping plane. + * @param top The coordinate of the top top clipping plane. + * @param near The distances to the nearer depth clipping plane. This value must be plus value. + * @param far The distances to the farther depth clipping plane. This value must be plus value. + * @return this + */ +Matrix4.prototype.frustum = function(left, right, bottom, top, near, far) { + return this.concat(new Matrix4().setFrustum(left, right, bottom, top, near, far)); +}; + +/** + * Set the perspective projection matrix by fovy and aspect. + * @param fovy The angle between the upper and lower sides of the frustum. + * @param aspect The aspect ratio of the frustum. (width/height) + * @param near The distances to the nearer depth clipping plane. This value must be plus value. + * @param far The distances to the farther depth clipping plane. This value must be plus value. + * @return this + */ +Matrix4.prototype.setPerspective = function(fovy, aspect, near, far) { + var e, rd, s, ct; + + if (near === far || aspect === 0) { + throw 'null frustum'; + } + if (near <= 0) { + throw 'near <= 0'; + } + if (far <= 0) { + throw 'far <= 0'; + } + + fovy = Math.PI * fovy / 180 / 2; + s = Math.sin(fovy); + if (s === 0) { + throw 'null frustum'; + } + + rd = 1 / (far - near); + ct = Math.cos(fovy) / s; + + e = this.elements; + + e[0] = ct / aspect; + e[1] = 0; + e[2] = 0; + e[3] = 0; + + e[4] = 0; + e[5] = ct; + e[6] = 0; + e[7] = 0; + + e[8] = 0; + e[9] = 0; + e[10] = -(far + near) * rd; + e[11] = -1; + + e[12] = 0; + e[13] = 0; + e[14] = -2 * near * far * rd; + e[15] = 0; + + return this; +}; + +/** + * Multiply the perspective projection matrix from the right. + * @param fovy The angle between the upper and lower sides of the frustum. + * @param aspect The aspect ratio of the frustum. (width/height) + * @param near The distances to the nearer depth clipping plane. This value must be plus value. + * @param far The distances to the farther depth clipping plane. This value must be plus value. + * @return this + */ +Matrix4.prototype.perspective = function(fovy, aspect, near, far) { + return this.concat(new Matrix4().setPerspective(fovy, aspect, near, far)); +}; + +/** + * Set the matrix for scaling. + * @param x The scale factor along the X axis + * @param y The scale factor along the Y axis + * @param z The scale factor along the Z axis + * @return this + */ +Matrix4.prototype.setScale = function(x, y, z) { + var e = this.elements; + e[0] = x; e[4] = 0; e[8] = 0; e[12] = 0; + e[1] = 0; e[5] = y; e[9] = 0; e[13] = 0; + e[2] = 0; e[6] = 0; e[10] = z; e[14] = 0; + e[3] = 0; e[7] = 0; e[11] = 0; e[15] = 1; + return this; +}; + +/** + * Multiply the matrix for scaling from the right. + * @param x The scale factor along the X axis + * @param y The scale factor along the Y axis + * @param z The scale factor along the Z axis + * @return this + */ +Matrix4.prototype.scale = function(x, y, z) { + var e = this.elements; + e[0] *= x; e[4] *= y; e[8] *= z; + e[1] *= x; e[5] *= y; e[9] *= z; + e[2] *= x; e[6] *= y; e[10] *= z; + e[3] *= x; e[7] *= y; e[11] *= z; + return this; +}; + +/** + * Set the matrix for translation. + * @param x The X value of a translation. + * @param y The Y value of a translation. + * @param z The Z value of a translation. + * @return this + */ +Matrix4.prototype.setTranslate = function(x, y, z) { + var e = this.elements; + e[0] = 1; e[4] = 0; e[8] = 0; e[12] = x; + e[1] = 0; e[5] = 1; e[9] = 0; e[13] = y; + e[2] = 0; e[6] = 0; e[10] = 1; e[14] = z; + e[3] = 0; e[7] = 0; e[11] = 0; e[15] = 1; + return this; +}; + +/** + * Multiply the matrix for translation from the right. + * @param x The X value of a translation. + * @param y The Y value of a translation. + * @param z The Z value of a translation. + * @return this + */ +Matrix4.prototype.translate = function(x, y, z) { + var e = this.elements; + e[12] += e[0] * x + e[4] * y + e[8] * z; + e[13] += e[1] * x + e[5] * y + e[9] * z; + e[14] += e[2] * x + e[6] * y + e[10] * z; + e[15] += e[3] * x + e[7] * y + e[11] * z; + return this; +}; + +/** + * Set the matrix for rotation. + * The vector of rotation axis may not be normalized. + * @param angle The angle of rotation (degrees) + * @param x The X coordinate of vector of rotation axis. + * @param y The Y coordinate of vector of rotation axis. + * @param z The Z coordinate of vector of rotation axis. + * @return this + */ +Matrix4.prototype.setRotate = function(angle, x, y, z) { + var e, s, c, len, rlen, nc, xy, yz, zx, xs, ys, zs; + + angle = Math.PI * angle / 180; + e = this.elements; + + s = Math.sin(angle); + c = Math.cos(angle); + + if (0 !== x && 0 === y && 0 === z) { + // Rotation around X axis + if (x < 0) { + s = -s; + } + e[0] = 1; e[4] = 0; e[ 8] = 0; e[12] = 0; + e[1] = 0; e[5] = c; e[ 9] =-s; e[13] = 0; + e[2] = 0; e[6] = s; e[10] = c; e[14] = 0; + e[3] = 0; e[7] = 0; e[11] = 0; e[15] = 1; + } else if (0 === x && 0 !== y && 0 === z) { + // Rotation around Y axis + if (y < 0) { + s = -s; + } + e[0] = c; e[4] = 0; e[ 8] = s; e[12] = 0; + e[1] = 0; e[5] = 1; e[ 9] = 0; e[13] = 0; + e[2] =-s; e[6] = 0; e[10] = c; e[14] = 0; + e[3] = 0; e[7] = 0; e[11] = 0; e[15] = 1; + } else if (0 === x && 0 === y && 0 !== z) { + // Rotation around Z axis + if (z < 0) { + s = -s; + } + e[0] = c; e[4] =-s; e[ 8] = 0; e[12] = 0; + e[1] = s; e[5] = c; e[ 9] = 0; e[13] = 0; + e[2] = 0; e[6] = 0; e[10] = 1; e[14] = 0; + e[3] = 0; e[7] = 0; e[11] = 0; e[15] = 1; + } else { + // Rotation around another axis + len = Math.sqrt(x*x + y*y + z*z); + if (len !== 1) { + rlen = 1 / len; + x *= rlen; + y *= rlen; + z *= rlen; + } + nc = 1 - c; + xy = x * y; + yz = y * z; + zx = z * x; + xs = x * s; + ys = y * s; + zs = z * s; + + e[ 0] = x*x*nc + c; + e[ 1] = xy *nc + zs; + e[ 2] = zx *nc - ys; + e[ 3] = 0; + + e[ 4] = xy *nc - zs; + e[ 5] = y*y*nc + c; + e[ 6] = yz *nc + xs; + e[ 7] = 0; + + e[ 8] = zx *nc + ys; + e[ 9] = yz *nc - xs; + e[10] = z*z*nc + c; + e[11] = 0; + + e[12] = 0; + e[13] = 0; + e[14] = 0; + e[15] = 1; + } + + return this; +}; + +/** + * Multiply the matrix for rotation from the right. + * The vector of rotation axis may not be normalized. + * @param angle The angle of rotation (degrees) + * @param x The X coordinate of vector of rotation axis. + * @param y The Y coordinate of vector of rotation axis. + * @param z The Z coordinate of vector of rotation axis. + * @return this + */ +Matrix4.prototype.rotate = function(angle, x, y, z) { + return this.concat(new Matrix4().setRotate(angle, x, y, z)); +}; + +/** + * Set the viewing matrix. + * @param eyeX, eyeY, eyeZ The position of the eye point. + * @param centerX, centerY, centerZ The position of the reference point. + * @param upX, upY, upZ The direction of the up vector. + * @return this + */ +Matrix4.prototype.setLookAt = function(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ) { + var e, fx, fy, fz, rlf, sx, sy, sz, rls, ux, uy, uz; + + fx = centerX - eyeX; + fy = centerY - eyeY; + fz = centerZ - eyeZ; + + // Normalize f. + rlf = 1 / Math.sqrt(fx*fx + fy*fy + fz*fz); + fx *= rlf; + fy *= rlf; + fz *= rlf; + + // Calculate cross product of f and up. + sx = fy * upZ - fz * upY; + sy = fz * upX - fx * upZ; + sz = fx * upY - fy * upX; + + // Normalize s. + rls = 1 / Math.sqrt(sx*sx + sy*sy + sz*sz); + sx *= rls; + sy *= rls; + sz *= rls; + + // Calculate cross product of s and f. + ux = sy * fz - sz * fy; + uy = sz * fx - sx * fz; + uz = sx * fy - sy * fx; + + // Set to this. + e = this.elements; + e[0] = sx; + e[1] = ux; + e[2] = -fx; + e[3] = 0; + + e[4] = sy; + e[5] = uy; + e[6] = -fy; + e[7] = 0; + + e[8] = sz; + e[9] = uz; + e[10] = -fz; + e[11] = 0; + + e[12] = 0; + e[13] = 0; + e[14] = 0; + e[15] = 1; + + // Translate. + return this.translate(-eyeX, -eyeY, -eyeZ); +}; + +/** + * Multiply the viewing matrix from the right. + * @param eyeX, eyeY, eyeZ The position of the eye point. + * @param centerX, centerY, centerZ The position of the reference point. + * @param upX, upY, upZ The direction of the up vector. + * @return this + */ +Matrix4.prototype.lookAt = function(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ) { + return this.concat(new Matrix4().setLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ)); +}; + +/** + * Multiply the matrix for project vertex to plane from the right. + * @param plane The array[A, B, C, D] of the equation of plane "Ax + By + Cz + D = 0". + * @param light The array which stored coordinates of the light. if light[3]=0, treated as parallel light. + * @return this + */ +Matrix4.prototype.dropShadow = function(plane, light) { + var mat = new Matrix4(); + var e = mat.elements; + + var dot = plane[0] * light[0] + plane[1] * light[1] + plane[2] * light[2] + plane[3] * light[3]; + + e[ 0] = dot - light[0] * plane[0]; + e[ 1] = - light[1] * plane[0]; + e[ 2] = - light[2] * plane[0]; + e[ 3] = - light[3] * plane[0]; + + e[ 4] = - light[0] * plane[1]; + e[ 5] = dot - light[1] * plane[1]; + e[ 6] = - light[2] * plane[1]; + e[ 7] = - light[3] * plane[1]; + + e[ 8] = - light[0] * plane[2]; + e[ 9] = - light[1] * plane[2]; + e[10] = dot - light[2] * plane[2]; + e[11] = - light[3] * plane[2]; + + e[12] = - light[0] * plane[3]; + e[13] = - light[1] * plane[3]; + e[14] = - light[2] * plane[3]; + e[15] = dot - light[3] * plane[3]; + + return this.concat(mat); +} + +/** + * Multiply the matrix for project vertex to plane from the right.(Projected by parallel light.) + * @param normX, normY, normZ The normal vector of the plane.(Not necessary to be normalized.) + * @param planeX, planeY, planeZ The coordinate of arbitrary points on a plane. + * @param lightX, lightY, lightZ The vector of the direction of light.(Not necessary to be normalized.) + * @return this + */ +Matrix4.prototype.dropShadowDirectionally = function(normX, normY, normZ, planeX, planeY, planeZ, lightX, lightY, lightZ) { + var a = planeX * normX + planeY * normY + planeZ * normZ; + return this.dropShadow([normX, normY, normZ, -a], [lightX, lightY, lightZ, 0]); +}; + +/** + * Constructor of Vector3 + * If opt_src is specified, new vector is initialized by opt_src. + * @param opt_src source vector(option) + */ +var Vector3 = function(opt_src) { + var v = new Float32Array(3); + if (opt_src && typeof opt_src === 'object') { + v[0] = opt_src[0]; v[1] = opt_src[1]; v[2] = opt_src[2]; + } + this.elements = v; +} + +/** + * Normalize. + * @return this + */ +Vector3.prototype.normalize = function() { + var v = this.elements; + var c = v[0], d = v[1], e = v[2], g = Math.sqrt(c*c+d*d+e*e); + if(g){ + if(g == 1) + return this; + } else { + v[0] = 0; v[1] = 0; v[2] = 0; + return this; + } + g = 1/g; + v[0] = c*g; v[1] = d*g; v[2] = e*g; + return this; +}; + +/** + * Constructor of Vector4 + * If opt_src is specified, new vector is initialized by opt_src. + * @param opt_src source vector(option) + */ +var Vector4 = function(opt_src) { + var v = new Float32Array(4); + if (opt_src && typeof opt_src === 'object') { + v[0] = opt_src[0]; v[1] = opt_src[1]; v[2] = opt_src[2]; v[3] = opt_src[3]; + } + this.elements = v; +} \ No newline at end of file diff --git a/lab4/src/lab4.html b/lab4/src/lab4.html index 2bb37bc..6bf6d90 100644 --- a/lab4/src/lab4.html +++ b/lab4/src/lab4.html @@ -8,9 +8,14 @@ <canvas width="400" height="600" id="my-canvas"> Please use a browser that supports "canvas" </canvas> +<div id="which_light">lumière directionnelle</div> +<div id="lightx">light x : </div> +<div id="lighty">light y : </div> +<div id="lightz">light z : </div> <script src="../lib/webgl-utils.js"></script> <script src="../lib/webgl-debug.js"></script> <script src="../lib/cuon-utils.js"></script> +<script src="../lib/cuon-matrix.js"></script> <script src="lab4.js"></script> </body> </html> \ No newline at end of file diff --git a/lab4/src/lab4.js b/lab4/src/lab4.js index 105a227..2e15fdd 100644 --- a/lab4/src/lab4.js +++ b/lab4/src/lab4.js @@ -1,18 +1,509 @@ +var eyeX = 0.0; +var eyeY = 3.0; +var eyeZ = 15.0; + +var xLightDir = 0.0; +var yLightDir = 0.0; +var zLightDir = 7.0; + +var canvas; +var gl; +// Model matrix +var u_MvpMatrix; +var u_NormalMatrix; + +// light color +var u_LightColor; + +// diffuse light direction +var u_LightDirection; + +// ambient light components +var u_ModelMatrix; +var u_LightPosition; +var u_AmbientLight; + +// click variable +var u_Clicked; + +which_light = true; + +document.onkeydown = checkKey; +function checkKey(e) { + switch (e.key) { + + // camera + case 'w': + eyeY += 1 + break; + case 's': + eyeY -= 1 + break; + case 'a': + eyeX -= 1 + break; + case 'd': + eyeX += 1 + break; + case 'e': + eyeZ += 1 + break; + case 'q': + eyeZ -= 1 + break; + + // light + case 'ArrowUp': + zLightDir -= 0.1 + break; + case 'ArrowDown': + zLightDir += 0.1; + break; + case 'ArrowLeft': + xLightDir -= 0.1; + break; + case 'ArrowRight': + xLightDir += 0.1 + break; + case 'o': // up + yLightDir += 0.1 + break; + case 'p': // down + yLightDir -= 0.1 + break; + + // choose light + case 'c': + which_light = !which_light + initElements(); + } +}; + // Vertex shader program -const VSHADER_SOURCE = - '\n' + - // TODO: Implement your vertex shader code here - '\n'; +var VSHADER_SOURCE_DIRECTIONAL = + 'attribute vec4 a_Position;\n' + + 'attribute vec4 a_Color;\n' + + 'attribute vec4 a_Normal;\n' + // Normal + + 'uniform mat4 u_MvpMatrix;\n' + + 'uniform mat4 u_NormalMatrix;\n' + + + 'uniform vec3 u_LightColor;\n' + // Light color + 'uniform vec3 u_LightDirection;\n' + // Light direction (in the world coordinate, normalized) + + 'varying vec4 v_Color;\n' + + + 'uniform bool u_Clicked;\n' + + + 'void main() {\n' + + ' gl_Position = u_MvpMatrix * a_Position;\n' + + ' vec4 normal = u_NormalMatrix * a_Normal;\n' + + ' float nDotL = max(dot(u_LightDirection, normalize(normal.xyz)), 0.0);\n' + + ' vec3 diffuse = u_LightColor * a_Color.rgb * nDotL;\n' + + + ' if (u_Clicked) {\n' + // Draw in red if mouse is pressed + ' v_Color = vec4(1.0, 0.0, 0.0, 1.0);\n' + + ' } else {\n' + + ' v_Color = vec4(diffuse, a_Color.a);\n' + + ' }\n' + + '}\n'; // Fragment shader program -const FSHADER_SOURCE = - '\n' + - // TODO: Implement your fragment shader code here - '\n'; +var FSHADER_SOURCE_DIRECTIONAL = + + 'precision mediump float;\n' + + + 'varying vec4 v_Color;\n' + + + 'void main() {\n' + + ' gl_FragColor = v_Color;\n' + + '}\n'; + +var VSHADER_SOURCE_PONCTUAL = + 'attribute vec4 a_Position;\n' + + 'attribute vec4 a_Color;\n' + + 'attribute vec4 a_Normal;\n' + + + 'uniform mat4 u_MvpMatrix;\n' + + 'uniform mat4 u_ModelMatrix;\n' + + 'uniform mat4 u_NormalMatrix;\n' + + + 'uniform vec3 u_AmbientLight;\n' + + + 'varying vec3 normal;\n' + + 'varying vec4 vertexPosition;\n' + + 'varying vec3 ambient;\n' + + + 'varying vec4 v_Color;\n' + + + 'uniform bool u_Clicked;\n' + + + 'void main() {\n' + + ' gl_Position = u_MvpMatrix * a_Position;\n' + + ' normal = normalize(vec3(u_NormalMatrix * a_Normal));\n' + + ' vertexPosition = u_ModelMatrix * a_Position;\n' + + + ' ambient = u_AmbientLight * a_Color.xyz;\n' + + + ' if (u_Clicked) {\n' + // Draw in red if mouse is pressed + ' v_Color = vec4(1.0, 0.0, 0.0, 1.0);\n' + + ' } else {\n' + + ' v_Color = a_Color;\n' + + ' }\n' + + '}\n'; + +var FSHADER_SOURCE_PONCTUAL = + 'precision mediump float;\n' + + + 'uniform vec3 u_LightColor;\n' + + 'uniform vec3 u_LightPosition;\n' + + + 'varying vec4 v_Color;\n' + + 'varying vec3 normal;\n' + + 'varying vec4 vertexPosition;\n' + + 'varying vec3 ambient;\n' + + + 'void main() {\n' + + + ' vec3 lightDirection = normalize(u_LightPosition - vec3(vertexPosition));\n' + + ' float nDotL = max(dot(normal, lightDirection), 0.0);\n' + + ' vec3 diffuse = u_LightColor * v_Color.rgb * nDotL;\n' + + + ' gl_FragColor = vec4(diffuse + ambient, v_Color.a);\n' + + '}\n'; + +function initElements(){ + // Initialize shaders + vh_source = VSHADER_SOURCE_DIRECTIONAL; + fh_source = FSHADER_SOURCE_DIRECTIONAL; + if (!which_light){ + vh_source = VSHADER_SOURCE_PONCTUAL; + fh_source = FSHADER_SOURCE_PONCTUAL; + } + if (!initShaders(gl, vh_source, fh_source)) { + console.log('Failed to intialize shaders.'); + return; + } + + // clear canva + gl.clearColor(0, 0, 0, 1); + gl.enable(gl.DEPTH_TEST); + gl.depthFunc(gl.LEQUAL); + + // Get the storage location of u_MvpMatrix + u_MvpMatrix = gl.getUniformLocation(gl.program, 'u_MvpMatrix'); + if (!u_MvpMatrix) { + console.log('Failed to get the storage locations of u_MvpMatrix'); + return -1; + } + + u_LightColor = gl.getUniformLocation(gl.program, 'u_LightColor'); + if (!u_LightColor) { + console.log('Failed to get the storage locations of u_LightColor'); + return -1; + } + + u_NormalMatrix = gl.getUniformLocation(gl.program, 'u_NormalMatrix'); + if (!u_NormalMatrix) { + console.log('Failed to get the storage locations of u_NormalMatrix'); + return -1; + } + + u_Clicked = gl.getUniformLocation(gl.program, 'u_Clicked'); + if (!u_Clicked) { + console.log('Failed to get the storage locations of u_Clicked'); + return -1; + } + + if (which_light){ // directionnal light + u_LightDirection = gl.getUniformLocation(gl.program, 'u_LightDirection'); + if (!u_LightDirection) { + console.log('Failed to get the storage locations of u_LightDirection'); + return -1; + } + }else { // ponctual light + u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix'); + if (!u_ModelMatrix) { + console.log('Failed to get the storage locations of u_ModelMatrix'); + return -1; + } + + u_LightPosition = gl.getUniformLocation(gl.program, 'u_LightPosition'); + if (!u_LightPosition) { + console.log('Failed to get the storage locations of u_LightPosition'); + return -1; + } + + u_AmbientLight = gl.getUniformLocation(gl.program, 'u_AmbientLight'); + if (!u_AmbientLight) { + console.log('Failed to get the storage locations of u_AmbientLight'); + return -1; + } + } + + gl.uniform1i(u_Clicked, 0); // Pass false to u_Clicked +} function main() { + // Retrieve <canvas> element - const canvas = document.getElementById('my-canvas'); + canvas = document.getElementById('my-canvas'); + + // Get the rendering context for WebGL + gl = getWebGLContext(canvas); + if (!gl) { + console.log('Failed to get the rendering context for WebGL'); + return; + } + + initElements(); + + canvas.onmousedown = function(ev) { // Mouse is pressed + var x = ev.clientX, y = ev.clientY; + var rect = ev.target.getBoundingClientRect(); + if (rect.left <= x && x < rect.right && rect.top <= y && y < rect.bottom) { + + var vpMatrix = new Matrix4(); // View projection matrix + // Calculate the view projection matrix + vpMatrix.setPerspective(30, canvas.width/canvas.height, 1, 100); + vpMatrix.lookAt(eyeX, eyeY, eyeZ, 0, 0, 0, 0, 1, 0); + var modelMatrix = new Matrix4(); // Model matrix + + // If pressed position is inside <canvas>, check if it is above object + var x_in_canvas = x - rect.left, y_in_canvas = rect.bottom - y; + var picked = check(gl, x_in_canvas, y_in_canvas, u_Clicked, vpMatrix, u_MvpMatrix, u_ModelMatrix, u_NormalMatrix, modelMatrix); + if (picked) alert('The Hourglass was selected'); + } + } + + setInterval(onTimerTick, 10); +} + +function onTimerTick() { + + var light = "lumière directionnelle" + if (!which_light){ + light = "lumière ponctuelle" + } + document.getElementById('which_light').innerHTML = light; + document.getElementById('lightx').innerHTML = "light x : " + xLightDir; + document.getElementById('lighty').innerHTML = "light y : " + yLightDir; + document.getElementById('lightz').innerHTML = "light z : " + zLightDir; + + vpMatrix = new Matrix4(); // View projection matrix + // Calculate the view projection matrix + vpMatrix.setPerspective(30, canvas.width/canvas.height, 1, 100); + vpMatrix.lookAt(eyeX, eyeY, eyeZ, 0, 0, 0, 0, 1, 0); + + gl.uniform3f(u_LightColor, 1.0, 1.0, 1.0); + if (which_light){ // diffuse light + var lightDirection = new Vector3([xLightDir, yLightDir, zLightDir]); + lightDirection.normalize(); // Normalize + gl.uniform3fv(u_LightDirection, lightDirection.elements); + }else { // ambient light + // Set the light direction (in the world coordinate) + gl.uniform3f(u_LightPosition, xLightDir, yLightDir, zLightDir); + // Set the ambient light + gl.uniform3f(u_AmbientLight, 0.3, 0.3, 0.3); + } + + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + + var modelMatrix = new Matrix4(); // Model matrix + + /*modelMatrix.rotate(xAngle, 1, 0, 0); + modelMatrix.rotate(yAngle, 0, 1, 0);*/ + + drawHourglass(gl, vpMatrix, u_MvpMatrix, u_ModelMatrix, u_NormalMatrix, modelMatrix) + //drawSquares(gl, canvas, u_MvpMatrix) + drawBase(gl, vpMatrix, u_MvpMatrix, u_ModelMatrix, u_NormalMatrix, modelMatrix) +} + +function drawHourglass(gl, vpMatrix, u_MvpMatrix, u_ModelMatrix, u_NormalMatrix, modelMatrix){ + // Write the positions of trapezes vertices to a vertex shader + var n = initVertexBufferHourglass(gl); + if (n < 0) { + console.log('Failed to set the positions of the vertices'); + return; + } + + var mvpMatrix = new Matrix4(); // Model view projection matrix + var normalMatrix = new Matrix4(); // Transformation matrix for normals + + // first half of hourglass + modelMatrix.translate(0, 0.0, 0); + if (!which_light){ gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements); } + mvpMatrix.set(vpMatrix).multiply(modelMatrix); + gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMatrix.elements); + + normalMatrix.setInverseOf(modelMatrix); + normalMatrix.transpose(); + gl.uniformMatrix4fv(u_NormalMatrix, false, normalMatrix.elements); + + gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0); + + // second half of hourglass + modelMatrix.translate(0, 1.0, 0); + modelMatrix.rotate(180, 0, 0, 1); + if (!which_light){ gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements); } + mvpMatrix.set(vpMatrix).multiply(modelMatrix); + gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMatrix.elements); + + normalMatrix.rotate(180, 0, 0, 1); + normalMatrix.transpose(); + gl.uniformMatrix4fv(u_NormalMatrix, false, normalMatrix.elements); + + gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0); +} + +function drawBase(gl, vpMatrix, u_MvpMatrix, u_ModelMatrix, u_NormalMatrix, modelMatrix){ + // Write the positions of square vertices to a vertex shader + var n = initVertexBufferBase(gl); + if (n < 0) { + console.log('Failed to set the positions of the vertices'); + return; + } + + var mvpMatrix = new Matrix4(); // Model view projection matrix + var normalMatrix = new Matrix4(); // Transformation matrix for normals + + modelMatrix.translate(0, 2.01, 0); + if (!which_light){ gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements); } + mvpMatrix.set(vpMatrix).multiply(modelMatrix); + gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMatrix.elements); + + normalMatrix.setInverseOf(modelMatrix); + normalMatrix.transpose(); + gl.uniformMatrix4fv(u_NormalMatrix, false, normalMatrix.elements); + + gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0); +} + +function initVertexBufferHourglass(gl){ + + const vertices = new Float32Array([ + -0.25, 0.5, 0.25, 0.25, 0.5, 0.25, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, // front + 0.25, 0.5, 0.25, 0.25, 0.5, -0.25, 0.5, -0.5, 0.5, 0.5, -0.5, -0.5, // right + 0.25, 0.5, -0.25, -0.25, 0.5, -0.25, 0.5, -0.5, -0.5, -0.5, -0.5, -0.5, // back + -0.25, 0.5, -0.25, -0.25, 0.5, 0.25, -0.5, -0.5, -0.5, -0.5, -0.5, 0.5, // left + -0.25, 0.5, 0.25, 0.25, 0.5, 0.25, -0.25, 0.5, -0.25, 0.25, 0.5, -0.25, // up + -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, -0.5, -0.5, -0.5, 0.5, -0.5, -0.5 // down + ]); + + const colors = new Float32Array([ + 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, + 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, + 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, + 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, + 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, + 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0 + ]); + + const indices = new Uint8Array([ + 0, 1, 2, 1, 2, 3, + 4, 5, 6, 5, 6, 7, + 8, 9,10, 9,10,11, + 12,13,14, 13,14,15, + 16,17,18, 17,18,19, + 20,21,22, 21,22,23 + ]); + + const normals = new Float32Array([ + 0.0, 0.25, 0.25, 0.0, 0.25, 0.25, 0.0, 0.25, 0.25, 0.0, 0.25, 0.25, + 0.25, 0.25, 0.0, 0.25, 0.25, 0.0, 0.25, 0.25, 0.0, 0.25, 0.25, 0.0, + 0.0, 0.25, -0.25, 0.0, 0.25, -0.25, 0.0, 0.25, -0.25, 0.0, 0.25, -0.25, + -0.25,0.25, 0.0, -0.25, 0.25, 0.0, -0.25, 0.25, 0.0, -0.25, 0.25, 0.0, + 0.0, 0.25, 0.0, 0.0, 0.25, 0.0, 0.0, 0.25, 0.0, 0.0, 0.25, 0.0, + 0.0, -0.25, 0.0, 0.0, -0.25, 0.0, 0.0, -0.25, 0.0, 0.0, -0.25, 0.0 + ]); + + initVertexBuffer(gl, vertices, colors, indices, normals) + return indices.length; // The number of vertices +} + +function initVertexBufferBase(gl){ + + const vertices = new Float32Array([ + -2.0, -0.50, 2.0, 2.0, -0.50, 2.0, 2.0, -0.50, -2.0, -2.0, -0.50, -2.0 // square + ]); + + const colors = new Float32Array([ + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 + ]); + + const indices = new Uint8Array([ + 0, 1, 2, 0, 2, 3 + ]); + + const normals = new Float32Array([ + -2.0, -0.50, 2.0, 2.0, -0.50, 2.0, 2.0, -0.50, -2.0, -2.0, -0.50, -2.0 + ]); + + initVertexBuffer(gl, vertices, colors, indices, normals) + return indices.length; // The number of vertices +} + +// init vertex buffer with given vertices +function initVertexBuffer(gl, vertices, colors, indices, normals) { + + const n = indices.length; // The number of vertices + + // Create a buffer object for indexes + var indexBuffer = gl.createBuffer(); + if (!indexBuffer) { + console.log('Failed to create the buffer object'); + return -1; + } + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW); + + // set array buffer for vertices + setArrayBuffer(gl, vertices, 'a_Position') + + // set array buffer for color + setArrayBuffer(gl, colors, 'a_Color') + + // set array buffer for normal + setArrayBuffer(gl, normals, 'a_Normal') + + return n; +} + +// set an array in the buffer of given attribute +function setArrayBuffer(gl, array, attribute){ + + // Create a buffer object for vertices / colors + var vertexBuffer = gl.createBuffer(); + if (!vertexBuffer) { + console.log('Failed to create the buffer object'); + return -1; + } + gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, array, gl.STATIC_DRAW); + + // Set attributes and uniforms + var attribute = gl.getAttribLocation(gl.program, attribute); + if (attribute < 0) { + console.log('Failed to get the storage location of a_Position'); + return -1; + } + gl.vertexAttribPointer(attribute, 3, gl.FLOAT, false, 0, 0); + gl.enableVertexAttribArray(attribute); +} + +function check(gl, x, y, u_Clicked, vpMatrix, u_MvpMatrix, u_ModelMatrix, u_NormalMatrix, modelMatrix) { + var picked = false; + gl.uniform1i(u_Clicked, 1); // Pass true to u_Clicked + drawHourglass(gl, vpMatrix, u_MvpMatrix, u_ModelMatrix, u_NormalMatrix, modelMatrix); // Draw cube with red + // Read pixel at the clicked position + var pixels = new Uint8Array(4); // Array for storing the pixel value + gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixels); + + if (pixels[0] == 255) // The mouse in on cube if R(pixels[0]) is 255 + picked = true; - // TODO: Complete with your code here + gl.uniform1i(u_Clicked, 0); // Pass false to u_Clicked(rewrite the cube) + drawHourglass(gl, vpMatrix, u_MvpMatrix, u_ModelMatrix, u_NormalMatrix, modelMatrix); // Draw the cube + + return picked; } \ No newline at end of file -- GitLab