Compare commits
24 Commits
Author | SHA1 | Date |
---|---|---|
|
2525f321ee | |
|
e842eb3d66 | |
|
6f50150a6b | |
|
c4599824c6 | |
|
2d7fb37165 | |
|
57b6851c8d | |
|
0c3f1577ce | |
|
de72dafd2d | |
|
f56912b41e | |
|
5a0cbe6e35 | |
|
7f3e1da3b9 | |
|
0ec890f026 | |
|
5efb9c9b2a | |
|
0b8fa336ce | |
|
4c4087a8a9 | |
|
505aee8ecc | |
|
64bf69ec71 | |
|
65d7ee8e82 | |
|
27be22842b | |
|
4ad7e2e3d0 | |
|
e749bfee47 | |
|
48d3d91aaa | |
|
bf6404cd85 | |
|
6ebddae435 |
|
@ -4,24 +4,69 @@
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>CG1 MDI</title>
|
<title>CG1 MDI</title>
|
||||||
|
<script src="matrix-math.js"></script>
|
||||||
<script src="shader.js"></script>
|
<script src="shader.js"></script>
|
||||||
|
<script src="wavefront.js"></script>
|
||||||
<script src="script.js"></script>
|
<script src="script.js"></script>
|
||||||
<style>
|
<style>
|
||||||
body {
|
:root {
|
||||||
display: flex;
|
font-size: 20px;
|
||||||
justify-content: center;
|
--padding: 10px;
|
||||||
align-items: center;
|
}
|
||||||
min-height: 100vh;
|
|
||||||
|
html, body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
padding: 1vw;
|
||||||
|
box-sizing: border-box;
|
||||||
background-color: #1e1e2e;
|
background-color: #1e1e2e;
|
||||||
|
color: #cdd6f4;
|
||||||
|
font-family: monospace;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
#display {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 20px;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
border: solid 2px #11111b;
|
||||||
}
|
}
|
||||||
#cv {
|
#cv {
|
||||||
border: solid 2px black;
|
position: relative;
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: block;
|
||||||
|
background-color: #181825;
|
||||||
|
}
|
||||||
|
#stats {
|
||||||
|
position: absolute;
|
||||||
|
top: var(--padding);
|
||||||
|
padding: var(--padding);
|
||||||
|
display: block;
|
||||||
|
border: solid 2px #11111b;
|
||||||
|
background-color: #313244;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#stats {
|
||||||
|
right: var(--padding);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<canvas id="cv" width="800" height="600"></canvas>
|
<div id="display">
|
||||||
|
<canvas id="cv"></canvas>
|
||||||
|
<div id="stats">
|
||||||
|
FPS: <span id="fps"></span> - <span id="ms"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -0,0 +1,530 @@
|
||||||
|
"use strict";
|
||||||
|
/**
|
||||||
|
* overwrites a 4x4 matrix with the identity matrix
|
||||||
|
*/
|
||||||
|
function mat4Identity(mat) {
|
||||||
|
for (let i = 0; i < 16; i++) {
|
||||||
|
mat[i] = (i % 5 == 0) ? 1 : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* copies a mat4 from src to dst
|
||||||
|
*/
|
||||||
|
function mat4Copy(src, dst) {
|
||||||
|
for (let i = 0; i < 16; i++) {
|
||||||
|
dst[i] = src[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets all the values in a mat4 to zero
|
||||||
|
*/
|
||||||
|
function mat4Empty(mat) {
|
||||||
|
for (let i = 0; i < 16; i++) {
|
||||||
|
mat[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* mutliplies A with B and stores the result in result
|
||||||
|
*/
|
||||||
|
function mat4Multiply(result, A, B) {
|
||||||
|
// if result is one of the arguments, modify copy instead of result directly
|
||||||
|
if (result == A || result == B) {
|
||||||
|
let tempResult = [];
|
||||||
|
mat4Multiply(tempResult, A, B);
|
||||||
|
mat4Copy(tempResult, result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// loops over cells of the result matrix
|
||||||
|
for (let i = 0; i < 16; i++) {
|
||||||
|
let col = (i / 4) | 0;
|
||||||
|
let row = i % 4;
|
||||||
|
|
||||||
|
// initialise current cell with 0
|
||||||
|
result[i] = 0;
|
||||||
|
|
||||||
|
// loop over the row of A and column of B
|
||||||
|
// continuously adding the multiplication of the two values to the result cell
|
||||||
|
for (let j = 0; j < 4; j++) {
|
||||||
|
result[i] += A[row + j * 4] * B[j + col * 4];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* prints a mat4 to the screen
|
||||||
|
*/
|
||||||
|
function mat4Print(m) {
|
||||||
|
let str = "";
|
||||||
|
for (let i = 0; i < 4; i++) {
|
||||||
|
for (let j = 0; j < 4; j++) {
|
||||||
|
str += m[j * 4 + i] + " ";
|
||||||
|
}
|
||||||
|
str += "\n";
|
||||||
|
}
|
||||||
|
console.log(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* translates by the vector v
|
||||||
|
*/
|
||||||
|
function mat4Translate(out, inm, v) {
|
||||||
|
let t = [];
|
||||||
|
mat4Identity(t);
|
||||||
|
|
||||||
|
t[12] = v[0];
|
||||||
|
t[13] = v[1];
|
||||||
|
t[14] = v[2];
|
||||||
|
|
||||||
|
mat4Multiply(out, t, inm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* scales by the vector v
|
||||||
|
*/
|
||||||
|
function mat4Scale(out, inm, v) {
|
||||||
|
let t = [];
|
||||||
|
mat4Identity(t);
|
||||||
|
|
||||||
|
t[0] = v[0];
|
||||||
|
t[5] = v[1];
|
||||||
|
t[10] = v[2];
|
||||||
|
|
||||||
|
mat4Multiply(out, t, inm);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rotates around the X axis by the angle a (in radians)
|
||||||
|
*/
|
||||||
|
function mat4RotateX(out, inm, a) {
|
||||||
|
let t = [];
|
||||||
|
mat4Identity(t);
|
||||||
|
|
||||||
|
t[5] = Math.cos(a);
|
||||||
|
t[6] = Math.sin(a);
|
||||||
|
t[9] = -Math.sin(a);
|
||||||
|
t[10] = Math.cos(a);
|
||||||
|
|
||||||
|
mat4Multiply(out, t, inm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rotates around the Y axis by the angle a (in radians)
|
||||||
|
*/
|
||||||
|
function mat4RotateY(out, inm, a) {
|
||||||
|
let t = [];
|
||||||
|
mat4Identity(t);
|
||||||
|
|
||||||
|
t[0] = Math.cos(a);
|
||||||
|
t[2] = -Math.sin(a);
|
||||||
|
t[8] = Math.sin(a);
|
||||||
|
t[10] = Math.cos(a);
|
||||||
|
|
||||||
|
mat4Multiply(out, t, inm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* rotates around the Z axis by the angle a (in radians)
|
||||||
|
*/
|
||||||
|
function mat4RotateZ(out, inm, a) {
|
||||||
|
let t = [];
|
||||||
|
mat4Identity(t);
|
||||||
|
|
||||||
|
t[0] = Math.cos(a);
|
||||||
|
t[1] = Math.sin(a);
|
||||||
|
t[4] = -Math.sin(a);
|
||||||
|
t[5] = Math.cos(a);
|
||||||
|
|
||||||
|
mat4Multiply(out, t, inm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* builds a look-at matrix, overwriting out
|
||||||
|
* eye is the position of the camera
|
||||||
|
* look is the position of the target to be looked at
|
||||||
|
* up is the up vector
|
||||||
|
*/
|
||||||
|
function mat4BuildLookAt(out, eye, look, up) {
|
||||||
|
let n = [];
|
||||||
|
let u = [];
|
||||||
|
let v = [];
|
||||||
|
let t = [];
|
||||||
|
|
||||||
|
vec3Subtract(n, eye, look);
|
||||||
|
|
||||||
|
vec3CrossProduct(u, up, n);
|
||||||
|
|
||||||
|
vec3CrossProduct(v, n, u);
|
||||||
|
|
||||||
|
vec3Normalise(n, n);
|
||||||
|
vec3Normalise(u, u);
|
||||||
|
vec3Normalise(v, v);
|
||||||
|
|
||||||
|
t[0] = - vec3DotProduct(u, eye);
|
||||||
|
t[1] = - vec3DotProduct(v, eye);
|
||||||
|
t[2] = - vec3DotProduct(n, eye);
|
||||||
|
|
||||||
|
out[0] = u[0]; out[4] = u[1]; out[8] = u[2]; out[12] = t[0];
|
||||||
|
out[1] = v[0]; out[5] = v[1]; out[9] = v[2]; out[13] = t[1];
|
||||||
|
out[2] = n[0]; out[6] = n[1]; out[10] = n[2]; out[14] = t[2];
|
||||||
|
out[3] = 0; out[7] = 0; out[11] = 0; out[15] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* builds a projection matrix, overwriting out
|
||||||
|
* r, l, t, b are the right, left, top and bottom of the frustum
|
||||||
|
* n and f are the distance of the near and far planes from the camera
|
||||||
|
*/
|
||||||
|
function mat4BuildProjection(out, r, l, t, b, n, f) {
|
||||||
|
mat4Identity(out);
|
||||||
|
|
||||||
|
out[0] = 2.0 / (r - l);
|
||||||
|
out[5] = 2.0 / (t - b);
|
||||||
|
|
||||||
|
out[8] = 1.0 / n * (r + l) / (r - l);
|
||||||
|
out[9] = 1.0 / n * (t + b) / (t - b);
|
||||||
|
out[10] = -1.0 / n * (f + n) / (f - n);
|
||||||
|
out[11] = -1.0 / n;
|
||||||
|
|
||||||
|
out[14] = - 2.0 * f / (f - n);
|
||||||
|
out[15] = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* builds a perspective projection matrix, overwriting out
|
||||||
|
* fovy is the field of view in the y direction
|
||||||
|
* aspect is the aspect ratio
|
||||||
|
* n and f are the distance of the near and far planes from the camera
|
||||||
|
*/
|
||||||
|
function mat4BuildPerspective(out, fovy, aspect, n, f) {
|
||||||
|
let t = n * Math.tan(0.5 * fovy);
|
||||||
|
let b = -t;
|
||||||
|
|
||||||
|
let r = aspect * t;
|
||||||
|
let l = -r;
|
||||||
|
|
||||||
|
mat4BuildProjection(out, r, l, t, b, n, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* linearly interpolates between a and b, storing the result in out
|
||||||
|
*/
|
||||||
|
function mat4Interpolate(out, a, b, f) {
|
||||||
|
for (let i = 0; i < 16; i++) {
|
||||||
|
out[i] = (1 - f) * a[i] + f * b[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mat4From3(out, inm) {
|
||||||
|
mat4Identity(out);
|
||||||
|
out[0] = inm[0];
|
||||||
|
out[1] = inm[1];
|
||||||
|
out[2] = inm[2];
|
||||||
|
|
||||||
|
out[4] = inm[3];
|
||||||
|
out[5] = inm[4];
|
||||||
|
out[6] = inm[5];
|
||||||
|
|
||||||
|
out[8] = inm[6];
|
||||||
|
out[9] = inm[7];
|
||||||
|
out[10] = inm[8];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://stackoverflow.com/questions/1148309/inverting-a-4x4-matrix
|
||||||
|
*/
|
||||||
|
function mat4Inverse(out, m) {
|
||||||
|
let inv = [];
|
||||||
|
let det;
|
||||||
|
let i;
|
||||||
|
|
||||||
|
inv[0] = m[5] * m[10] * m[15] -
|
||||||
|
m[5] * m[11] * m[14] -
|
||||||
|
m[9] * m[6] * m[15] +
|
||||||
|
m[9] * m[7] * m[14] +
|
||||||
|
m[13] * m[6] * m[11] -
|
||||||
|
m[13] * m[7] * m[10];
|
||||||
|
|
||||||
|
inv[4] = -m[4] * m[10] * m[15] +
|
||||||
|
m[4] * m[11] * m[14] +
|
||||||
|
m[8] * m[6] * m[15] -
|
||||||
|
m[8] * m[7] * m[14] -
|
||||||
|
m[12] * m[6] * m[11] +
|
||||||
|
m[12] * m[7] * m[10];
|
||||||
|
|
||||||
|
inv[8] = m[4] * m[9] * m[15] -
|
||||||
|
m[4] * m[11] * m[13] -
|
||||||
|
m[8] * m[5] * m[15] +
|
||||||
|
m[8] * m[7] * m[13] +
|
||||||
|
m[12] * m[5] * m[11] -
|
||||||
|
m[12] * m[7] * m[9];
|
||||||
|
|
||||||
|
inv[12] = -m[4] * m[9] * m[14] +
|
||||||
|
m[4] * m[10] * m[13] +
|
||||||
|
m[8] * m[5] * m[14] -
|
||||||
|
m[8] * m[6] * m[13] -
|
||||||
|
m[12] * m[5] * m[10] +
|
||||||
|
m[12] * m[6] * m[9];
|
||||||
|
|
||||||
|
inv[1] = -m[1] * m[10] * m[15] +
|
||||||
|
m[1] * m[11] * m[14] +
|
||||||
|
m[9] * m[2] * m[15] -
|
||||||
|
m[9] * m[3] * m[14] -
|
||||||
|
m[13] * m[2] * m[11] +
|
||||||
|
m[13] * m[3] * m[10];
|
||||||
|
|
||||||
|
inv[5] = m[0] * m[10] * m[15] -
|
||||||
|
m[0] * m[11] * m[14] -
|
||||||
|
m[8] * m[2] * m[15] +
|
||||||
|
m[8] * m[3] * m[14] +
|
||||||
|
m[12] * m[2] * m[11] -
|
||||||
|
m[12] * m[3] * m[10];
|
||||||
|
|
||||||
|
inv[9] = -m[0] * m[9] * m[15] +
|
||||||
|
m[0] * m[11] * m[13] +
|
||||||
|
m[8] * m[1] * m[15] -
|
||||||
|
m[8] * m[3] * m[13] -
|
||||||
|
m[12] * m[1] * m[11] +
|
||||||
|
m[12] * m[3] * m[9];
|
||||||
|
|
||||||
|
inv[13] = m[0] * m[9] * m[14] -
|
||||||
|
m[0] * m[10] * m[13] -
|
||||||
|
m[8] * m[1] * m[14] +
|
||||||
|
m[8] * m[2] * m[13] +
|
||||||
|
m[12] * m[1] * m[10] -
|
||||||
|
m[12] * m[2] * m[9];
|
||||||
|
|
||||||
|
inv[2] = m[1] * m[6] * m[15] -
|
||||||
|
m[1] * m[7] * m[14] -
|
||||||
|
m[5] * m[2] * m[15] +
|
||||||
|
m[5] * m[3] * m[14] +
|
||||||
|
m[13] * m[2] * m[7] -
|
||||||
|
m[13] * m[3] * m[6];
|
||||||
|
|
||||||
|
inv[6] = -m[0] * m[6] * m[15] +
|
||||||
|
m[0] * m[7] * m[14] +
|
||||||
|
m[4] * m[2] * m[15] -
|
||||||
|
m[4] * m[3] * m[14] -
|
||||||
|
m[12] * m[2] * m[7] +
|
||||||
|
m[12] * m[3] * m[6];
|
||||||
|
|
||||||
|
inv[10] = m[0] * m[5] * m[15] -
|
||||||
|
m[0] * m[7] * m[13] -
|
||||||
|
m[4] * m[1] * m[15] +
|
||||||
|
m[4] * m[3] * m[13] +
|
||||||
|
m[12] * m[1] * m[7] -
|
||||||
|
m[12] * m[3] * m[5];
|
||||||
|
|
||||||
|
inv[14] = -m[0] * m[5] * m[14] +
|
||||||
|
m[0] * m[6] * m[13] +
|
||||||
|
m[4] * m[1] * m[14] -
|
||||||
|
m[4] * m[2] * m[13] -
|
||||||
|
m[12] * m[1] * m[6] +
|
||||||
|
m[12] * m[2] * m[5];
|
||||||
|
|
||||||
|
inv[3] = -m[1] * m[6] * m[11] +
|
||||||
|
m[1] * m[7] * m[10] +
|
||||||
|
m[5] * m[2] * m[11] -
|
||||||
|
m[5] * m[3] * m[10] -
|
||||||
|
m[9] * m[2] * m[7] +
|
||||||
|
m[9] * m[3] * m[6];
|
||||||
|
|
||||||
|
inv[7] = m[0] * m[6] * m[11] -
|
||||||
|
m[0] * m[7] * m[10] -
|
||||||
|
m[4] * m[2] * m[11] +
|
||||||
|
m[4] * m[3] * m[10] +
|
||||||
|
m[8] * m[2] * m[7] -
|
||||||
|
m[8] * m[3] * m[6];
|
||||||
|
|
||||||
|
inv[11] = -m[0] * m[5] * m[11] +
|
||||||
|
m[0] * m[7] * m[9] +
|
||||||
|
m[4] * m[1] * m[11] -
|
||||||
|
m[4] * m[3] * m[9] -
|
||||||
|
m[8] * m[1] * m[7] +
|
||||||
|
m[8] * m[3] * m[5];
|
||||||
|
|
||||||
|
inv[15] = m[0] * m[5] * m[10] -
|
||||||
|
m[0] * m[6] * m[9] -
|
||||||
|
m[4] * m[1] * m[10] +
|
||||||
|
m[4] * m[2] * m[9] +
|
||||||
|
m[8] * m[1] * m[6] -
|
||||||
|
m[8] * m[2] * m[5];
|
||||||
|
|
||||||
|
det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12];
|
||||||
|
|
||||||
|
if (det == 0) {
|
||||||
|
mat4Copy(m, out); // singular matrix, can't invert
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
det = 1.0 / det;
|
||||||
|
|
||||||
|
for (i = 0; i < 16; i++)
|
||||||
|
out[i] = inv[i] * det;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mat4vec4Multiply(out, inMat, inVec) {
|
||||||
|
let result = [0, 0, 0, 0];
|
||||||
|
for (let i = 0; i < 4; i++) {
|
||||||
|
for (let j = 0; j < 4; j++) {
|
||||||
|
result[i] += inMat[i + j * 4] * inVec[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out[0] = result[0];
|
||||||
|
out[1] = result[1];
|
||||||
|
out[2] = result[2];
|
||||||
|
out[3] = result[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* subtracts b from a, storing the result in out
|
||||||
|
*/
|
||||||
|
function vec3Subtract(out, a, b) {
|
||||||
|
out[0] = a[0] - b[0];
|
||||||
|
out[1] = a[1] - b[1];
|
||||||
|
out[2] = a[2] - b[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* calculates the cross product of a and b, storing the result in out
|
||||||
|
*/
|
||||||
|
function vec3CrossProduct(out, a, b) {
|
||||||
|
let result = [];
|
||||||
|
result[0] = a[1] * b[2] - a[2] * b[1];
|
||||||
|
result[1] = a[2] * b[0] - a[0] * b[2];
|
||||||
|
result[2] = a[0] * b[1] - a[1] * b[0];
|
||||||
|
|
||||||
|
out[0] = result[0];
|
||||||
|
out[1] = result[1];
|
||||||
|
out[2] = result[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* normalizes in storing the result in out
|
||||||
|
*/
|
||||||
|
function vec3Normalise(out, inv) {
|
||||||
|
let length = vec3Length(inv);
|
||||||
|
out[0] = inv[0] / length;
|
||||||
|
out[1] = inv[1] / length;
|
||||||
|
out[2] = inv[2] / length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the length of the vector in
|
||||||
|
*/
|
||||||
|
function vec3Length(inv) {
|
||||||
|
return Math.sqrt(inv[0] * inv[0] + inv[1] * inv[1] + inv[2] * inv[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns the dot product of the vectors a and b
|
||||||
|
*/
|
||||||
|
function vec3DotProduct(a, b) {
|
||||||
|
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sets the values of out to x, y and z
|
||||||
|
*/
|
||||||
|
function vec3Set(out, x, y, z) {
|
||||||
|
out[0] = x;
|
||||||
|
out[1] = y;
|
||||||
|
out[2] = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function mat3Copy(src, dst) {
|
||||||
|
for (let i = 0; i < 9; i++) {
|
||||||
|
dst[i] = src[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mat3From4(out, inm) {
|
||||||
|
out[0] = inm[0];
|
||||||
|
out[1] = inm[1];
|
||||||
|
out[2] = inm[2];
|
||||||
|
|
||||||
|
out[3] = inm[4];
|
||||||
|
out[4] = inm[5];
|
||||||
|
out[5] = inm[6];
|
||||||
|
|
||||||
|
out[6] = inm[8];
|
||||||
|
out[7] = inm[9];
|
||||||
|
out[8] = inm[10];
|
||||||
|
}
|
||||||
|
|
||||||
|
function mat3Transpose(out, inm) {
|
||||||
|
let result = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
for (let j = 0; j < 3; j++) {
|
||||||
|
result[i * 3 + j] = inm[j * 3 + i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mat3Copy(result, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mat3Minor(out, inm) {
|
||||||
|
let result = [];
|
||||||
|
|
||||||
|
// TODO: check if this is correct
|
||||||
|
result[0] = inm[4] * inm[8] - inm[5] * inm[7];
|
||||||
|
result[1] = inm[3] * inm[8] - inm[5] * inm[6];
|
||||||
|
result[2] = inm[3] * inm[7] - inm[4] * inm[6];
|
||||||
|
|
||||||
|
result[3] = inm[1] * inm[8] - inm[2] * inm[7];
|
||||||
|
result[4] = inm[0] * inm[8] - inm[2] * inm[6];
|
||||||
|
result[5] = inm[0] * inm[7] - inm[1] * inm[6];
|
||||||
|
|
||||||
|
result[6] = inm[1] * inm[5] - inm[2] * inm[4];
|
||||||
|
result[7] = inm[0] * inm[5] - inm[2] * inm[3];
|
||||||
|
result[8] = inm[0] * inm[4] - inm[1] * inm[3];
|
||||||
|
|
||||||
|
mat3Copy(result, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mat3Cofactor(out, inm) {
|
||||||
|
mat3Minor(out, inm);
|
||||||
|
|
||||||
|
out[1] *= -1;
|
||||||
|
out[3] *= -1;
|
||||||
|
out[5] *= -1;
|
||||||
|
out[7] *= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mat3Adjoint(out, inm) {
|
||||||
|
mat3Cofactor(out, inm);
|
||||||
|
mat3Transpose(out, inm);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mat3MultiplyScalar(out, inm, x) {
|
||||||
|
for (let i = 0; i < 9; i++) {
|
||||||
|
out[i] = inm[i] * x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mat3Determinant(m) {
|
||||||
|
return + m[0] * m[4] * m[8] + m[3] * m[7] * m[2] + m[6] * m[1] * m[5] - m[2] * m[4] * m[6] - m[5] * m[7] * m[0] - m[8] * m[1] * m[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
function mat3Inverse(out, inm) {
|
||||||
|
let result = [];
|
||||||
|
mat3Adjoint(result, inm);
|
||||||
|
mat3MultiplyScalar(result, result, 1 / mat3Determinant(inm));
|
||||||
|
mat3Copy(result, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
function mat3MakeNormal(out, inm) {
|
||||||
|
let result = [];
|
||||||
|
mat3From4(result, inm);
|
||||||
|
mat3Inverse(result, result);
|
||||||
|
mat3Transpose(result, result);
|
||||||
|
mat3Copy(result, out);
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
# Blender 4.4.3
|
||||||
|
# www.blender.org
|
||||||
|
o Cube
|
||||||
|
v 1.000000 1.000000 -1.000000
|
||||||
|
v 1.000000 -1.000000 -1.000000
|
||||||
|
v 1.000000 1.000000 1.000000
|
||||||
|
v 1.000000 -1.000000 1.000000
|
||||||
|
v -1.000000 1.000000 -1.000000
|
||||||
|
v -1.000000 -1.000000 -1.000000
|
||||||
|
v -1.000000 1.000000 1.000000
|
||||||
|
v -1.000000 -1.000000 1.000000
|
||||||
|
vn -0.0000 1.0000 -0.0000
|
||||||
|
vn -0.0000 -0.0000 1.0000
|
||||||
|
vn -1.0000 -0.0000 -0.0000
|
||||||
|
vn -0.0000 -1.0000 -0.0000
|
||||||
|
vn 1.0000 -0.0000 -0.0000
|
||||||
|
vn -0.0000 -0.0000 -1.0000
|
||||||
|
vt 1.000000 0.000000
|
||||||
|
vt 0.000000 1.000000
|
||||||
|
vt 0.000000 0.000000
|
||||||
|
vt 1.000000 1.000000
|
||||||
|
s 0
|
||||||
|
f 5/1/1 3/2/1 1/3/1
|
||||||
|
f 3/1/2 8/2/2 4/3/2
|
||||||
|
f 7/1/3 6/2/3 8/3/3
|
||||||
|
f 2/1/4 8/2/4 6/3/4
|
||||||
|
f 1/1/5 4/2/5 2/3/5
|
||||||
|
f 5/1/6 2/2/6 6/3/6
|
||||||
|
f 5/1/1 7/4/1 3/2/1
|
||||||
|
f 3/1/2 7/4/2 8/2/2
|
||||||
|
f 7/1/3 5/4/3 6/2/3
|
||||||
|
f 2/1/4 4/4/4 8/2/4
|
||||||
|
f 1/1/5 3/4/5 4/2/5
|
||||||
|
f 5/1/6 1/4/6 2/2/6
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
250
src/script.js
250
src/script.js
|
@ -4,87 +4,235 @@ let cv, gl;
|
||||||
|
|
||||||
let program;
|
let program;
|
||||||
|
|
||||||
let vertexBuffer;
|
class Object {
|
||||||
|
vertexBuffer;
|
||||||
|
numVertices;
|
||||||
|
}
|
||||||
|
|
||||||
|
let o = new Object();
|
||||||
|
|
||||||
|
let lastFrame = Date.now();
|
||||||
|
|
||||||
|
let cameraPitch = 0.565;
|
||||||
|
let cameraYaw = 0.375;
|
||||||
|
let cameraDistance = 4;
|
||||||
|
let smoothCameraDistance = 4;
|
||||||
|
|
||||||
|
let mouseDragging = false;
|
||||||
|
|
||||||
|
let frameTimes = [];
|
||||||
|
|
||||||
|
function resizeCanvas() {
|
||||||
|
const dpr = window.devicePixelRatio;
|
||||||
|
cv.width = cv.parentElement.clientWidth * dpr;
|
||||||
|
cv.height = cv.parentElement.clientHeight * dpr;
|
||||||
|
gl.viewport(0, 0, cv.width, cv.height);
|
||||||
|
}
|
||||||
|
|
||||||
async function init() {
|
async function init() {
|
||||||
cv = document.getElementById("cv");
|
cv = document.getElementById("cv");
|
||||||
|
|
||||||
gl = cv.getContext("webgl");
|
gl = cv.getContext("webgl");
|
||||||
|
|
||||||
if (!gl) {
|
if (!gl) {
|
||||||
window.alert("WebGL not supported");
|
window.alert("WebGL not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const resizeObserver = new ResizeObserver(resizeCanvas);
|
||||||
|
resizeObserver.observe(cv.parentElement);
|
||||||
|
resizeCanvas();
|
||||||
|
|
||||||
|
|
||||||
|
// input handling
|
||||||
|
cv.addEventListener("mousedown", (e) => {
|
||||||
|
if (e.button == 0) {
|
||||||
|
mouseDragging = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
document.addEventListener("mouseup", (e) => {
|
||||||
|
if (e.button == 0) {
|
||||||
|
mouseDragging = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
document.addEventListener("mouseleave", (e) => {
|
||||||
|
mouseDragging = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener("mousemove", (e) => {
|
||||||
|
if (mouseDragging) {
|
||||||
|
cameraYaw += e.movementX / 100;
|
||||||
|
cameraPitch += e.movementY / 100;
|
||||||
|
|
||||||
|
if (cameraPitch < -Math.PI / 2) cameraPitch = -Math.PI / 2;
|
||||||
|
if (cameraPitch > Math.PI / 2) cameraPitch = Math.PI / 2;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
cv.addEventListener("wheel", (e) => {
|
||||||
|
cameraDistance += e.deltaY / 100;
|
||||||
|
if (cameraDistance < 1) cameraDistance = 1;
|
||||||
|
if (cameraDistance > 15) cameraDistance = 15;
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
// end input handling
|
||||||
|
|
||||||
console.log("compiling shaders...");
|
console.log("compiling shaders...");
|
||||||
|
program = await buildShaderProgram(gl, "shaders/vertex.glsl", "shaders/fragment.glsl");
|
||||||
console.log("compiling vertex shader...");
|
|
||||||
let vertexShader = await fetchAndCompileShader(gl, gl.VERTEX_SHADER, "shaders/vertex.glsl");
|
|
||||||
|
|
||||||
console.log("compiling fragment shader...");
|
|
||||||
let fragmentShader = await fetchAndCompileShader(gl, gl.FRAGMENT_SHADER, "shaders/fragment.glsl");
|
|
||||||
|
|
||||||
console.log("linking shader program...");
|
|
||||||
program = linkShaderProgram(gl, vertexShader, fragmentShader);
|
|
||||||
|
|
||||||
|
|
||||||
let triangleVertices = [
|
|
||||||
// X // Y // R // G // B
|
|
||||||
0.0, 0.5, 0.0, 1.0, 1.0,
|
|
||||||
-0.5, -0.5, 1.0, 0.0, 1.0,
|
|
||||||
0.5, -0.5, 1.0, 1.0, 0.0
|
|
||||||
];
|
|
||||||
|
|
||||||
console.log("creating vertex buffer");
|
console.log("creating vertex buffer");
|
||||||
|
|
||||||
vertexBuffer = gl.createBuffer();
|
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
|
|
||||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangleVertices), gl.STATIC_DRAW);
|
|
||||||
|
|
||||||
// get location of vertPosition attribute
|
let f = await readObjFile("obj/smooth_monkey.obj");
|
||||||
let positionAttribLocation = gl.getAttribLocation(program, "vertPosition");
|
o = new Object();
|
||||||
|
|
||||||
gl.vertexAttribPointer(
|
o.vertexBuffer = gl.createBuffer();
|
||||||
positionAttribLocation, // which attribute is read
|
o.numVertices = f.length / 8;
|
||||||
2, // number of values to read
|
gl.bindBuffer(gl.ARRAY_BUFFER, o.vertexBuffer);
|
||||||
gl.FLOAT, // type of values
|
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(f), gl.STATIC_DRAW);
|
||||||
gl.FALSE, // whether to normalize
|
|
||||||
5 * Float32Array.BYTES_PER_ELEMENT, // size of individual vertex / distance between values to read
|
|
||||||
0 // offset where to start reading
|
|
||||||
);
|
|
||||||
|
|
||||||
// enable attribute
|
|
||||||
gl.enableVertexAttribArray(positionAttribLocation);
|
|
||||||
|
|
||||||
let colorAttribLocation = gl.getAttribLocation(program, "vertColor");
|
|
||||||
gl.vertexAttribPointer(
|
|
||||||
colorAttribLocation,
|
|
||||||
3,
|
|
||||||
gl.FLOAT,
|
|
||||||
gl.FALSE,
|
|
||||||
5 * Float32Array.BYTES_PER_ELEMENT,
|
|
||||||
2 * Float32Array.BYTES_PER_ELEMENT
|
|
||||||
);
|
|
||||||
gl.enableVertexAttribArray(colorAttribLocation);
|
|
||||||
|
|
||||||
// unbind buffer
|
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
||||||
|
|
||||||
|
|
||||||
// set clear colour
|
// set clear colour
|
||||||
gl.clearColor(0.1, 0.1, 0.1, 1.0);
|
gl.clearColor(...hexToRgb("181825"), 1.0);
|
||||||
|
|
||||||
|
gl.enable(gl.DEPTH_TEST);
|
||||||
|
gl.enable(gl.BLEND);
|
||||||
|
gl.enable(gl.CULL_FACE);
|
||||||
|
gl.frontFace(gl.CCW);
|
||||||
|
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
// start drawing
|
// start drawing
|
||||||
requestAnimationFrame(draw);
|
requestAnimationFrame(draw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setAttribPointers() {
|
||||||
|
let positionAttribLocation = gl.getAttribLocation(program, "vertPosition");
|
||||||
|
let normalAttribLocation = gl.getAttribLocation(program, "vertNormal");
|
||||||
|
let textureAttribLocation = gl.getAttribLocation(program, "vertTexture");
|
||||||
|
|
||||||
|
gl.vertexAttribPointer(positionAttribLocation, 3, gl.FLOAT, gl.FALSE, 8 * Float32Array.BYTES_PER_ELEMENT, 0);
|
||||||
|
gl.vertexAttribPointer(textureAttribLocation, 2, gl.FLOAT, gl.FALSE, 8 * Float32Array.BYTES_PER_ELEMENT, 3 * Float32Array.BYTES_PER_ELEMENT);
|
||||||
|
gl.vertexAttribPointer(normalAttribLocation, 3, gl.FLOAT, gl.FALSE, 8 * Float32Array.BYTES_PER_ELEMENT, 5 * Float32Array.BYTES_PER_ELEMENT);
|
||||||
|
|
||||||
|
gl.enableVertexAttribArray(positionAttribLocation);
|
||||||
|
gl.enableVertexAttribArray(textureAttribLocation);
|
||||||
|
gl.enableVertexAttribArray(normalAttribLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
let frameCount = 0;
|
||||||
|
let lastStatUpdate = Date.now();
|
||||||
|
|
||||||
|
function updateStats(deltaTime) {
|
||||||
|
frameCount++;
|
||||||
|
|
||||||
|
let now = Date.now();
|
||||||
|
let timeSinceLastUpdate = (now - lastStatUpdate) / 1000;
|
||||||
|
|
||||||
|
if (timeSinceLastUpdate < 0.5) return;
|
||||||
|
|
||||||
|
lastStatUpdate = now;
|
||||||
|
|
||||||
|
let fpsDisplay = document.getElementById("fps");
|
||||||
|
fpsDisplay.innerText = Math.round(frameCount / timeSinceLastUpdate)
|
||||||
|
|
||||||
|
let msDisplay = document.getElementById("ms");
|
||||||
|
if (frameTimes.length > 0) {
|
||||||
|
msDisplay.innerText = (Math.round(frameTimes.reduce((prev, curr) => prev + curr) / frameTimes.length * 100) / 100) + "ms";
|
||||||
|
}
|
||||||
|
|
||||||
|
frameTimes = [];
|
||||||
|
frameCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let hue = 0;
|
||||||
|
|
||||||
async function draw() {
|
async function draw() {
|
||||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
let now = Date.now();
|
||||||
|
let deltaTime = (now - lastFrame) / 1000;
|
||||||
|
let frameStart = performance.now();
|
||||||
|
|
||||||
|
hue += deltaTime / 5;
|
||||||
|
if (hue > 1) hue = 0;
|
||||||
|
|
||||||
|
smoothCameraDistance += (cameraDistance - smoothCameraDistance) / 8;
|
||||||
|
|
||||||
|
updateStats(deltaTime);
|
||||||
|
|
||||||
|
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||||
|
|
||||||
|
let identity = [];
|
||||||
|
mat4Identity(identity);
|
||||||
|
|
||||||
|
// Real Matrices
|
||||||
|
let projectionMatrix = [];
|
||||||
|
mat4BuildPerspective(projectionMatrix, 90.0 / 180.0 * Math.PI, cv.width / cv.height, 0.1, 30);
|
||||||
|
|
||||||
|
let viewMatrix = [];
|
||||||
|
let cameraPosition = [Math.cos(cameraYaw) * smoothCameraDistance * Math.cos(cameraPitch), Math.sin(cameraPitch) * smoothCameraDistance, Math.sin(cameraYaw) * smoothCameraDistance * Math.cos(cameraPitch)];
|
||||||
|
let cameraLookAt = [0, 0, 0];
|
||||||
|
let cameraUp = [0, 1, 0];
|
||||||
|
mat4BuildLookAt(viewMatrix, cameraPosition, cameraLookAt, cameraUp);
|
||||||
|
|
||||||
|
let normalMatrix = [];
|
||||||
|
mat3MakeNormal(normalMatrix, viewMatrix);
|
||||||
|
|
||||||
gl.useProgram(program);
|
gl.useProgram(program);
|
||||||
|
gl.uniformMatrix4fv(gl.getUniformLocation(program, "projectionMatrix"), gl.FALSE, new Float32Array(projectionMatrix));
|
||||||
|
gl.uniformMatrix4fv(gl.getUniformLocation(program, "modelViewMatrix"), gl.FALSE, new Float32Array(viewMatrix));
|
||||||
|
gl.uniformMatrix3fv(gl.getUniformLocation(program, "normalMatrix"), gl.FALSE, new Float32Array(normalMatrix));
|
||||||
|
|
||||||
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
|
let lightPosition = [Math.cos(hue * Math.PI * 2) * 3, 2.0, Math.sin(hue * Math.PI * 2) * 3, 1.0];
|
||||||
|
mat4vec4Multiply(lightPosition, viewMatrix, lightPosition);
|
||||||
|
|
||||||
gl.drawArrays(gl.TRIANGLES, 0, 3);
|
gl.uniform3f(gl.getUniformLocation(program, "Light.position"), ...lightPosition.slice(0, 3));
|
||||||
|
gl.uniform3f(gl.getUniformLocation(program, "Light.color"), 1, 1, 1);
|
||||||
|
|
||||||
|
gl.uniform3f(gl.getUniformLocation(program, "Material.ambientColor"), 0.1, 0.1, 0.1);
|
||||||
|
gl.uniform3f(gl.getUniformLocation(program, "Material.emitColor"), 0.05, 0.05, 0.0);
|
||||||
|
gl.uniform3f(gl.getUniformLocation(program, "Material.diffColor"), 0.7, 0.8, 0.1);
|
||||||
|
gl.uniform3f(gl.getUniformLocation(program, "Material.specColor"), 1, 1, 0.8);
|
||||||
|
gl.uniform1f(gl.getUniformLocation(program, "Material.shininess"), 10);
|
||||||
|
|
||||||
|
gl.bindBuffer(gl.ARRAY_BUFFER, o.vertexBuffer);
|
||||||
|
setAttribPointers();
|
||||||
|
gl.drawArrays(gl.TRIANGLES, 0, o.numVertices);
|
||||||
|
|
||||||
|
frameTimes.push(performance.now() - frameStart);
|
||||||
|
lastFrame = now;
|
||||||
requestAnimationFrame(draw);
|
requestAnimationFrame(draw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hexToRgb(hex) {
|
||||||
|
let r = parseInt(hex.substring(0, 2), 16) / 255;
|
||||||
|
let g = parseInt(hex.substring(2, 4), 16) / 255;
|
||||||
|
let b = parseInt(hex.substring(4, 6), 16) / 255;
|
||||||
|
|
||||||
|
return [r, g, b];
|
||||||
|
}
|
||||||
|
|
||||||
|
function hslToRgb(h, s, l) {
|
||||||
|
let r, g, b;
|
||||||
|
|
||||||
|
if (s == 0) {
|
||||||
|
r = g = b = l;
|
||||||
|
} else {
|
||||||
|
let hue2rgb = function hue2rgb(p, q, t) {
|
||||||
|
if (t < 0) t += 1;
|
||||||
|
if (t > 1) t -= 1;
|
||||||
|
if (t < 1 / 6) return p + (q - p) * 6 * t;
|
||||||
|
if (t < 1 / 2) return q;
|
||||||
|
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
let q = l < 0.5 ? l * (1 + s) : l + s - l * s;
|
||||||
|
let p = 2 * l - q;
|
||||||
|
|
||||||
|
r = hue2rgb(p, q, h + 1 / 3);
|
||||||
|
g = hue2rgb(p, q, h);
|
||||||
|
b = hue2rgb(p, q, h - 1 / 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [r, g, b];
|
||||||
|
}
|
||||||
|
|
||||||
window.addEventListener("DOMContentLoaded", init);
|
window.addEventListener("DOMContentLoaded", init);
|
|
@ -46,3 +46,9 @@ function linkShaderProgram(gl, vertexShader, fragmentShader) {
|
||||||
|
|
||||||
return program;
|
return program;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function buildShaderProgram(gl, vertexPath, fragmentPath) {
|
||||||
|
let vertexShader = await fetchAndCompileShader(gl, gl.VERTEX_SHADER, vertexPath);
|
||||||
|
let fragmentShader = await fetchAndCompileShader(gl, gl.FRAGMENT_SHADER, fragmentPath);
|
||||||
|
return linkShaderProgram(gl, vertexShader, fragmentShader);
|
||||||
|
}
|
|
@ -1,6 +1,33 @@
|
||||||
precision mediump float;
|
precision mediump float;
|
||||||
varying vec3 fragColor;
|
|
||||||
|
uniform struct {
|
||||||
|
vec3 position;
|
||||||
|
vec3 color;
|
||||||
|
} Light;
|
||||||
|
|
||||||
|
uniform struct {
|
||||||
|
vec3 ambientColor;
|
||||||
|
vec3 emitColor;
|
||||||
|
vec3 diffColor;
|
||||||
|
vec3 specColor;
|
||||||
|
float shininess;
|
||||||
|
} Material;
|
||||||
|
|
||||||
|
varying vec3 vNormal;
|
||||||
|
varying vec2 vTexture;
|
||||||
|
varying vec3 vPosition;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
gl_FragColor = vec4(fragColor, 1.0);
|
vec3 pleaseDontDeleteMe = vec3(vTexture, 0.0);
|
||||||
|
|
||||||
|
vec3 eyeDir = normalize(-vPosition);
|
||||||
|
vec3 lightDir = normalize(Light.position - vPosition);
|
||||||
|
vec3 r = reflect(-lightDir, vNormal);
|
||||||
|
|
||||||
|
vec3 ambient = Material.ambientColor;
|
||||||
|
vec3 emit = Material.emitColor;
|
||||||
|
vec3 diff = max(dot(lightDir, vNormal), 0.0) * Material.diffColor * Light.color;
|
||||||
|
vec3 spec = pow(max(dot(r, eyeDir), 0.0), Material.shininess) * Material.specColor * Light.color;
|
||||||
|
|
||||||
|
gl_FragColor = vec4(ambient + emit + diff + spec, 1);
|
||||||
}
|
}
|
|
@ -1,10 +1,21 @@
|
||||||
precision mediump float;
|
precision mediump float;
|
||||||
|
|
||||||
attribute vec2 vertPosition;
|
attribute vec3 vertPosition;
|
||||||
attribute vec3 vertColor;
|
attribute vec3 vertNormal;
|
||||||
varying vec3 fragColor;
|
attribute vec2 vertTexture;
|
||||||
|
|
||||||
|
uniform mat4 modelViewMatrix;
|
||||||
|
uniform mat4 projectionMatrix;
|
||||||
|
uniform mat3 normalMatrix;
|
||||||
|
|
||||||
|
varying vec3 vNormal;
|
||||||
|
varying vec2 vTexture;
|
||||||
|
varying vec3 vPosition;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
fragColor = vertColor;
|
vNormal = normalize(normalMatrix * vertNormal);
|
||||||
gl_Position = vec4(vertPosition, 0.0, 1.0);
|
vTexture = vertTexture;
|
||||||
|
vPosition = (modelViewMatrix * vec4(vertPosition, 1.0)).xyz;
|
||||||
|
|
||||||
|
gl_Position = projectionMatrix * modelViewMatrix * vec4(vertPosition, 1.0);
|
||||||
}
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
async function readObjFile(path) {
|
||||||
|
const res = await fetch(path);
|
||||||
|
const text = await res.text();
|
||||||
|
|
||||||
|
let vertices = [];
|
||||||
|
let textures = [];
|
||||||
|
let normals = [];
|
||||||
|
|
||||||
|
let result = [];
|
||||||
|
|
||||||
|
const lines = text.replace("\r","").split("\n");
|
||||||
|
|
||||||
|
for (let line of lines) {
|
||||||
|
const parts = line.split(/\s+/);
|
||||||
|
|
||||||
|
switch (parts[0]) {
|
||||||
|
case "v":
|
||||||
|
vertices.push(parts.slice(1, 4).map(parseFloat));
|
||||||
|
break;
|
||||||
|
case "vt":
|
||||||
|
textures.push(parts.slice(1, 3).map(parseFloat));
|
||||||
|
break;
|
||||||
|
case "vn":
|
||||||
|
normals.push(parts.slice(1, 4).map(parseFloat));
|
||||||
|
break;
|
||||||
|
case "f":
|
||||||
|
for (const part of parts.slice(1, 4)) {
|
||||||
|
const [v, vt, vn] = part.split("/").map((i) => parseInt(i) - 1);
|
||||||
|
result.push(...vertices[v], ...textures[vt], ...normals[vn]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// support for quads:
|
||||||
|
if (parts.length > 4) {
|
||||||
|
for (let i of [1, 3, 4]) {
|
||||||
|
const part = parts[i];
|
||||||
|
const [v, vt, vn] = part.split("/").map((i) => parseInt(i) - 1);
|
||||||
|
result.push(...vertices[v], ...textures[vt], ...normals[vn]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
Loading…
Reference in New Issue