Compare commits
7 Commits
Author | SHA1 | Date |
---|---|---|
|
1758567ca5 | |
|
9f7df2320b | |
|
4a330360db | |
|
5474bf85bb | |
|
58e8328042 | |
|
51077a21ae | |
|
5029ee59b4 |
|
@ -1,7 +1,11 @@
|
|||
services:
|
||||
cg1:
|
||||
image: nginx:alpine
|
||||
volumes:
|
||||
- ./src:/usr/share/nginx/html:ro
|
||||
ports:
|
||||
- "8080:80"
|
||||
services:
|
||||
cg1:
|
||||
image: nginx:alpine
|
||||
volumes:
|
||||
- ./src:/usr/share/nginx/html:ro
|
||||
networks:
|
||||
- public
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
public:
|
||||
external: true
|
||||
|
|
|
@ -6,12 +6,10 @@
|
|||
<title>CG1 MDI</title>
|
||||
<script src="matrix-math.js"></script>
|
||||
<script src="shader.js"></script>
|
||||
<script src="wavefront.js"></script>
|
||||
<script src="script.js"></script>
|
||||
<style>
|
||||
:root {
|
||||
font-size: 20px;
|
||||
--padding: 10px;
|
||||
}
|
||||
|
||||
html, body {
|
||||
|
@ -46,10 +44,10 @@
|
|||
display: block;
|
||||
background-color: #181825;
|
||||
}
|
||||
#stats {
|
||||
#stats, #controls {
|
||||
position: absolute;
|
||||
top: var(--padding);
|
||||
padding: var(--padding);
|
||||
top: 20px;
|
||||
padding: 20px;
|
||||
display: block;
|
||||
border: solid 2px #11111b;
|
||||
background-color: #313244;
|
||||
|
@ -57,7 +55,11 @@
|
|||
}
|
||||
|
||||
#stats {
|
||||
right: var(--padding);
|
||||
right: 20px;
|
||||
}
|
||||
|
||||
#controls {
|
||||
left: 20px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
@ -67,6 +69,28 @@
|
|||
<div id="stats">
|
||||
FPS: <span id="fps"></span> - <span id="ms"></span>
|
||||
</div>
|
||||
|
||||
<div id="controls">
|
||||
<div>
|
||||
Click & Drag to move camera
|
||||
</div>
|
||||
<div>
|
||||
Scroll to zoom
|
||||
</div>
|
||||
<div>
|
||||
LookAt Matrix: <input type="range" min=0 max=1 step=0.01 value=0 id="interpolateLookAt" autocomplete="off">
|
||||
</div>
|
||||
<div>
|
||||
Projection Matrix: <input type="range" min=0 max=1 step=0.01 value=0 id="interpolateProjection" autocomplete="off" disabled="yes">
|
||||
<div style="margin-left: 20px;">Invert Z-Axis: <input type="checkbox" id="invertZAxis" checked autocomplete="off"></div>
|
||||
</div>
|
||||
<div>
|
||||
Use virtual camera: <input type="checkbox" id="displayMatricesVirtually" checked autocomplete="off">
|
||||
</div>
|
||||
<div>
|
||||
Backface Culling: <input type="checkbox" id="backfaceCulling" autocomplete="off">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -369,18 +369,6 @@ function mat4Inverse(out, m) {
|
|||
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
|
||||
|
@ -519,12 +507,4 @@ function mat3Inverse(out, inm) {
|
|||
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);
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
# 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
|
33819
src/obj/monkey.obj
33819
src/obj/monkey.obj
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
16109
src/obj/teapot.obj
16109
src/obj/teapot.obj
File diff suppressed because it is too large
Load Diff
546
src/script.js
546
src/script.js
|
@ -3,16 +3,36 @@
|
|||
let cv, gl;
|
||||
|
||||
let program;
|
||||
let floorProgram;
|
||||
|
||||
class Object {
|
||||
vertexBuffer;
|
||||
numVertices;
|
||||
}
|
||||
let hVertices;
|
||||
let hVertexBuffer;
|
||||
|
||||
let o = new Object();
|
||||
let cubeVertices;
|
||||
let cubeVertexBuffer;
|
||||
|
||||
let lineCubeVertices;
|
||||
let lineCubeVertexBuffer;
|
||||
|
||||
let originVertices;
|
||||
let originVertexBuffer;
|
||||
|
||||
let floorVertices;
|
||||
let floorVertexBuffer;
|
||||
|
||||
let cameraVertices;
|
||||
let cameraVertexBuffer;
|
||||
|
||||
let lastFrame = Date.now();
|
||||
|
||||
let interpolateProjection = 0;
|
||||
let interpolateLookAt = 0;
|
||||
|
||||
let displayMatricesVirtually = true;
|
||||
let virtualRealInterpolation = 1;
|
||||
|
||||
let invertZAxis = true;
|
||||
|
||||
let cameraPitch = 0.565;
|
||||
let cameraYaw = 0.375;
|
||||
let cameraDistance = 4;
|
||||
|
@ -44,6 +64,43 @@ async function init() {
|
|||
|
||||
|
||||
// input handling
|
||||
document.getElementById("interpolateProjection").addEventListener("input", (e) => {
|
||||
interpolateProjection = e.target.value;
|
||||
if (interpolateProjection <= 0) {
|
||||
document.getElementById("interpolateLookAt").disabled = "";
|
||||
} else {
|
||||
document.getElementById("interpolateLookAt").disabled = "yes";
|
||||
}
|
||||
});
|
||||
document.getElementById("invertZAxis").addEventListener("input", (e) => {
|
||||
invertZAxis = e.target.checked;
|
||||
});
|
||||
document.getElementById("interpolateLookAt").addEventListener("input", (e) => {
|
||||
interpolateLookAt = e.target.value;
|
||||
if (interpolateLookAt >= 1) {
|
||||
document.getElementById("interpolateProjection").disabled = "";
|
||||
} else {
|
||||
document.getElementById("interpolateProjection").disabled = "yes";
|
||||
}
|
||||
});
|
||||
document.getElementById("displayMatricesVirtually").addEventListener("input", (e) => {
|
||||
displayMatricesVirtually = e.target.checked;
|
||||
if (!displayMatricesVirtually) {
|
||||
document.getElementById("invertZAxis").checked = true;
|
||||
document.getElementById("invertZAxis").disabled = true;
|
||||
} else {
|
||||
document.getElementById("invertZAxis").checked = invertZAxis;
|
||||
document.getElementById("invertZAxis").disabled = false;
|
||||
}
|
||||
});
|
||||
document.getElementById("backfaceCulling").addEventListener("input", (e) => {
|
||||
if (e.target.checked) {
|
||||
gl.enable(gl.CULL_FACE);
|
||||
} else {
|
||||
gl.disable(gl.CULL_FACE);
|
||||
}
|
||||
});
|
||||
|
||||
cv.addEventListener("mousedown", (e) => {
|
||||
if (e.button == 0) {
|
||||
mouseDragging = true;
|
||||
|
@ -59,7 +116,7 @@ async function init() {
|
|||
});
|
||||
|
||||
document.addEventListener("mousemove", (e) => {
|
||||
if (mouseDragging) {
|
||||
if (mouseDragging && displayMatricesVirtually) {
|
||||
cameraYaw += e.movementX / 100;
|
||||
cameraPitch += e.movementY / 100;
|
||||
|
||||
|
@ -73,49 +130,303 @@ async function init() {
|
|||
if (cameraDistance > 15) cameraDistance = 15;
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
|
||||
// end input handling
|
||||
|
||||
console.log("compiling shaders...");
|
||||
program = await buildShaderProgram(gl, "shaders/vertex.glsl", "shaders/fragment.glsl");
|
||||
floorProgram = await buildShaderProgram(gl, "shaders/floor-vertex.glsl", "shaders/floor-fragment.glsl");
|
||||
|
||||
console.log("creating vertex buffer");
|
||||
|
||||
hVertices = [
|
||||
// X // Y
|
||||
|
||||
let f = await readObjFile("obj/smooth_monkey.obj");
|
||||
o = new Object();
|
||||
// left vertical bar
|
||||
-0.35, 0.6, 0.0, 1.0, 0.3, 0.3,
|
||||
-0.35, -0.6, 0.0, 1.0, 0.3, 0.3,
|
||||
-0.2, 0.6, 0.0, 1.0, 0.3, 0.3,
|
||||
|
||||
o.vertexBuffer = gl.createBuffer();
|
||||
o.numVertices = f.length / 8;
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, o.vertexBuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(f), gl.STATIC_DRAW);
|
||||
-0.2, 0.6, 0.0, 1.0, 0.3, 0.3,
|
||||
-0.35, -0.6, 0.0, 1.0, 0.3, 0.3,
|
||||
-0.2, -0.6, 0.0, 1.0, 0.3, 0.3,
|
||||
|
||||
// right vertical bar
|
||||
0.35, -0.6, 0.0, 1.0, 0.3, 0.3,
|
||||
0.35, 0.6, 0.0, 1.0, 0.3, 0.3,
|
||||
0.2, 0.6, 0.0, 1.0, 0.3, 0.3,
|
||||
|
||||
0.35, -0.6, 0.0, 1.0, 0.3, 0.3,
|
||||
0.2, 0.6, 0.0, 1.0, 0.3, 0.3,
|
||||
0.2, -0.6, 0.0, 1.0, 0.3, 0.3,
|
||||
|
||||
// middle bar
|
||||
-0.2, 0.1, 0.0, 1.0, 0.3, 0.3,
|
||||
-0.2, -0.1, 0.0, 1.0, 0.3, 0.3,
|
||||
0.2, 0.1, 0.0, 1.0, 0.3, 0.3,
|
||||
|
||||
0.2, 0.1, 0.0, 1.0, 0.3, 0.3,
|
||||
-0.2, -0.1, 0.0, 1.0, 0.3, 0.3,
|
||||
0.2, -0.1, 0.0, 1.0, 0.3, 0.3,
|
||||
|
||||
// bottom bar
|
||||
-0.35, -0.7, 0.0, 1.0, 0.3, 0.3,
|
||||
-0.35, -0.9, 0.0, 1.0, 0.3, 0.3,
|
||||
0.35, -0.9, 0.0, 1.0, 0.3, 0.3,
|
||||
|
||||
-0.35, -0.7, 0.0, 1.0, 0.3, 0.3,
|
||||
0.35, -0.9, 0.0, 1.0, 0.3, 0.3,
|
||||
0.35, -0.7, 0.0, 1.0, 0.3, 0.3,
|
||||
];
|
||||
|
||||
cubeVertices = [
|
||||
// Back face (red)
|
||||
-1, -1, -1, 1, 0.5, 0.5,
|
||||
-1, 1, -1, 1, 0.5, 0.5,
|
||||
1, 1, -1, 1, 0.5, 0.5,
|
||||
-1, -1, -1, 1, 0.5, 0.5,
|
||||
1, 1, -1, 1, 0.5, 0.5,
|
||||
1, -1, -1, 1, 0.5, 0.5,
|
||||
|
||||
// Front face (green)
|
||||
-1, -1, 1, 0.5, 1, 0.5,
|
||||
1, -1, 1, 0.5, 1, 0.5,
|
||||
1, 1, 1, 0.5, 1, 0.5,
|
||||
-1, -1, 1, 0.5, 1, 0.5,
|
||||
1, 1, 1, 0.5, 1, 0.5,
|
||||
-1, 1, 1, 0.5, 1, 0.5,
|
||||
|
||||
// Left face (blue)
|
||||
-1, 1, -1, 0.5, 0.5, 1,
|
||||
-1, -1, -1, 0.5, 0.5, 1,
|
||||
-1, 1, 1, 0.5, 0.5, 1,
|
||||
-1, 1, 1, 0.5, 0.5, 1,
|
||||
-1, -1, -1, 0.5, 0.5, 1,
|
||||
-1, -1, 1, 0.5, 0.5, 1,
|
||||
|
||||
// Right face (yellow)
|
||||
1, -1, -1, 1, 1, 0.5,
|
||||
1, 1, -1, 1, 1, 0.5,
|
||||
1, 1, 1, 1, 1, 0.5,
|
||||
1, -1, -1, 1, 1, 0.5,
|
||||
1, 1, 1, 1, 1, 0.5,
|
||||
1, -1, 1, 1, 1, 0.5,
|
||||
|
||||
// Top face (magenta)
|
||||
-1, 1, -1, 1, 0.5, 1,
|
||||
-1, 1, 1, 1, 0.5, 1,
|
||||
1, 1, 1, 1, 0.5, 1,
|
||||
-1, 1, -1, 1, 0.5, 1,
|
||||
1, 1, 1, 1, 0.5, 1,
|
||||
1, 1, -1, 1, 0.5, 1,
|
||||
|
||||
// Bottom face (cyan)
|
||||
-1, -1, 1, 0.5, 1, 1,
|
||||
-1, -1, -1, 0.5, 1, 1,
|
||||
1, -1, 1, 0.5, 1, 1,
|
||||
1, -1, 1, 0.5, 1, 1,
|
||||
-1, -1, -1, 0.5, 1, 1,
|
||||
1, -1, -1, 0.5, 1, 1
|
||||
];
|
||||
|
||||
lineCubeVertices = [
|
||||
1, 1, 1, 1, 0, 0,
|
||||
1, 1, -1, 1, 0, 0,
|
||||
1, 1, 1, 1, 0, 0,
|
||||
1, -1, 1, 1, 0, 0,
|
||||
1, 1, 1, 1, 0, 0,
|
||||
-1, 1, 1, 1, 0, 0,
|
||||
1, 1, -1, 1, 0, 0,
|
||||
1, -1, -1, 1, 0, 0,
|
||||
1, 1, -1, 1, 0, 0,
|
||||
-1, 1, -1, 1, 0, 0,
|
||||
1, -1, 1, 1, 0, 0,
|
||||
1, -1, -1, 1, 0, 0,
|
||||
1, -1, 1, 1, 0, 0,
|
||||
-1, -1, 1, 1, 0, 0,
|
||||
-1, 1, 1, 1, 0, 0,
|
||||
-1, 1, -1, 1, 0, 0,
|
||||
-1, 1, 1, 1, 0, 0,
|
||||
-1, -1, 1, 1, 0, 0,
|
||||
1, -1, -1, 1, 0, 0,
|
||||
-1, -1, -1, 1, 0, 0,
|
||||
-1, -1, 1, 1, 0, 0,
|
||||
-1, -1, -1, 1, 0, 0,
|
||||
-1, 1, -1, 1, 0, 0,
|
||||
-1, -1, -1, 1, 0, 0,
|
||||
];
|
||||
|
||||
originVertices = [
|
||||
0, 0, 0, 1, 0, 0,
|
||||
1, 0, 0, 1, 0, 0,
|
||||
0, 0, 0, 0, 1, 0,
|
||||
0, 1, 0, 0, 1, 0,
|
||||
0, 0, 0, 0, 0, 1,
|
||||
0, 0, 1, 0, 0, 1,
|
||||
];
|
||||
|
||||
floorVertices = [
|
||||
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,
|
||||
];
|
||||
|
||||
cameraVertices = [
|
||||
// Cube Body (dark gray)
|
||||
// Front face
|
||||
-1, -1, 1, 0.196, 0.196, 0.196,
|
||||
1, -1, 1, 0.196, 0.196, 0.196,
|
||||
1, 1, 1, 0.196, 0.196, 0.196,
|
||||
-1, -1, 1, 0.196, 0.196, 0.196,
|
||||
1, 1, 1, 0.196, 0.196, 0.196,
|
||||
-1, 1, 1, 0.196, 0.196, 0.196,
|
||||
|
||||
// Back face
|
||||
-1, -1, -1, 0.196, 0.196, 0.196,
|
||||
1, 1, -1, 0.196, 0.196, 0.196,
|
||||
1, -1, -1, 0.196, 0.196, 0.196,
|
||||
-1, -1, -1, 0.196, 0.196, 0.196,
|
||||
-1, 1, -1, 0.196, 0.196, 0.196,
|
||||
1, 1, -1, 0.196, 0.196, 0.196,
|
||||
|
||||
// Left face
|
||||
-1, -1, -1, 0.196, 0.196, 0.196,
|
||||
-1, -1, 1, 0.196, 0.196, 0.196,
|
||||
-1, 1, 1, 0.196, 0.196, 0.196,
|
||||
-1, -1, -1, 0.196, 0.196, 0.196,
|
||||
-1, 1, 1, 0.196, 0.196, 0.196,
|
||||
-1, 1, -1, 0.196, 0.196, 0.196,
|
||||
|
||||
// Right face
|
||||
1, -1, -1, 0.196, 0.196, 0.196,
|
||||
1, 1, 1, 0.196, 0.196, 0.196,
|
||||
1, -1, 1, 0.196, 0.196, 0.196,
|
||||
1, -1, -1, 0.196, 0.196, 0.196,
|
||||
1, 1, -1, 0.196, 0.196, 0.196,
|
||||
1, 1, 1, 0.196, 0.196, 0.196,
|
||||
|
||||
// Top face
|
||||
-1, 1, -1, 0.196, 0.196, 0.196,
|
||||
-1, 1, 1, 0.196, 0.196, 0.196,
|
||||
1, 1, 1, 0.196, 0.196, 0.196,
|
||||
-1, 1, -1, 0.196, 0.196, 0.196,
|
||||
1, 1, 1, 0.196, 0.196, 0.196,
|
||||
1, 1, -1, 0.196, 0.196, 0.196,
|
||||
|
||||
// Bottom face
|
||||
-1, -1, -1, 0.196, 0.196, 0.196,
|
||||
1, -1, 1, 0.196, 0.196, 0.196,
|
||||
-1, -1, 1, 0.196, 0.196, 0.196,
|
||||
-1, -1, -1, 0.196, 0.196, 0.196,
|
||||
1, -1, -1, 0.196, 0.196, 0.196,
|
||||
1, -1, 1, 0.196, 0.196, 0.196,
|
||||
|
||||
// Lens (light gray)
|
||||
// Front face
|
||||
-0.5, -0.5, -1.6, 0.706, 0.706, 0.706,
|
||||
0.5, 0.5, -1.6, 0.706, 0.706, 0.706,
|
||||
0.5, -0.5, -1.6, 0.706, 0.706, 0.706,
|
||||
-0.5, -0.5, -1.6, 0.706, 0.706, 0.706,
|
||||
-0.5, 0.5, -1.6, 0.706, 0.706, 0.706,
|
||||
0.5, 0.5, -1.6, 0.706, 0.706, 0.706,
|
||||
|
||||
// Back face
|
||||
-0.5, -0.5, -1.0, 0.706, 0.706, 0.706,
|
||||
0.5, -0.5, -1.0, 0.706, 0.706, 0.706,
|
||||
0.5, 0.5, -1.0, 0.706, 0.706, 0.706,
|
||||
-0.5, -0.5, -1.0, 0.706, 0.706, 0.706,
|
||||
0.5, 0.5, -1.0, 0.706, 0.706, 0.706,
|
||||
-0.5, 0.5, -1.0, 0.706, 0.706, 0.706,
|
||||
|
||||
// Left face
|
||||
-0.5, 0.5, -1.6, 0.706, 0.706, 0.706,
|
||||
-0.5, -0.5, -1.0, 0.706, 0.706, 0.706,
|
||||
-0.5, 0.5, -1.0, 0.706, 0.706, 0.706,
|
||||
-0.5, -0.5, -1.6, 0.706, 0.706, 0.706,
|
||||
-0.5, -0.5, -1.0, 0.706, 0.706, 0.706,
|
||||
-0.5, 0.5, -1.6, 0.706, 0.706, 0.706,
|
||||
|
||||
// Right face
|
||||
0.5, 0.5, -1.0, 0.706, 0.706, 0.706,
|
||||
0.5, -0.5, -1.0, 0.706, 0.706, 0.706,
|
||||
0.5, 0.5, -1.6, 0.706, 0.706, 0.706,
|
||||
0.5, 0.5, -1.6, 0.706, 0.706, 0.706,
|
||||
0.5, -0.5, -1.0, 0.706, 0.706, 0.706,
|
||||
0.5, -0.5, -1.6, 0.706, 0.706, 0.706,
|
||||
|
||||
// Top face
|
||||
0.5, 0.5, -1.6, 0.706, 0.706, 0.706,
|
||||
-0.5, 0.5, -1.0, 0.706, 0.706, 0.706,
|
||||
0.5, 0.5, -1.0, 0.706, 0.706, 0.706,
|
||||
-0.5, 0.5, -1.6, 0.706, 0.706, 0.706,
|
||||
-0.5, 0.5, -1.0, 0.706, 0.706, 0.706,
|
||||
0.5, 0.5, -1.6, 0.706, 0.706, 0.706,
|
||||
|
||||
// Bottom face
|
||||
-0.5, -0.5, -1.0, 0.706, 0.706, 0.706,
|
||||
0.5, -0.5, -1.0, 0.706, 0.706, 0.706,
|
||||
0.5, -0.5, -1.6, 0.706, 0.706, 0.706,
|
||||
-0.5, -0.5, -1.0, 0.706, 0.706, 0.706,
|
||||
0.5, -0.5, -1.6, 0.706, 0.706, 0.706,
|
||||
-0.5, -0.5, -1.6, 0.706, 0.706, 0.706
|
||||
];
|
||||
|
||||
hVertexBuffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, hVertexBuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(hVertices), gl.STATIC_DRAW);
|
||||
|
||||
cubeVertexBuffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexBuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(cubeVertices), gl.STATIC_DRAW);
|
||||
|
||||
lineCubeVertexBuffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, lineCubeVertexBuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(lineCubeVertices), gl.STATIC_DRAW);
|
||||
|
||||
originVertexBuffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, originVertexBuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(originVertices), gl.STATIC_DRAW);
|
||||
|
||||
floorVertexBuffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, floorVertexBuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(floorVertices), gl.STATIC_DRAW);
|
||||
|
||||
cameraVertexBuffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, cameraVertexBuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(cameraVertices), gl.STATIC_DRAW);
|
||||
|
||||
// unbind buffer
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, null);
|
||||
|
||||
|
||||
// set clear colour
|
||||
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);
|
||||
|
||||
gl.enable( gl.LINE_SMOOTH );
|
||||
gl.enable( gl.POLYGON_SMOOTH );
|
||||
gl.hint( gl.LINE_SMOOTH_HINT, gl.NICEST );
|
||||
gl.hint( gl.POLYGON_SMOOTH_HINT, gl.NICEST )
|
||||
|
||||
// start drawing
|
||||
requestAnimationFrame(draw);
|
||||
}
|
||||
|
||||
function setAttribPointers() {
|
||||
let positionAttribLocation = gl.getAttribLocation(program, "vertPosition");
|
||||
let normalAttribLocation = gl.getAttribLocation(program, "vertNormal");
|
||||
let textureAttribLocation = gl.getAttribLocation(program, "vertTexture");
|
||||
let colorAttribLocation = gl.getAttribLocation(program, "vertColor");
|
||||
|
||||
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.vertexAttribPointer(positionAttribLocation, 3, gl.FLOAT, gl.FALSE, 6 * Float32Array.BYTES_PER_ELEMENT, 0);
|
||||
gl.vertexAttribPointer(colorAttribLocation, 3, gl.FLOAT, gl.FALSE, 6 * Float32Array.BYTES_PER_ELEMENT, 3 * Float32Array.BYTES_PER_ELEMENT);
|
||||
|
||||
gl.enableVertexAttribArray(positionAttribLocation);
|
||||
gl.enableVertexAttribArray(textureAttribLocation);
|
||||
gl.enableVertexAttribArray(normalAttribLocation);
|
||||
gl.enableVertexAttribArray(colorAttribLocation);
|
||||
}
|
||||
|
||||
let frameCount = 0;
|
||||
|
@ -153,48 +464,193 @@ async function draw() {
|
|||
hue += deltaTime / 5;
|
||||
if (hue > 1) hue = 0;
|
||||
|
||||
if (displayMatricesVirtually) {
|
||||
virtualRealInterpolation = Math.min(virtualRealInterpolation + deltaTime * 2, 1);
|
||||
} else {
|
||||
virtualRealInterpolation = Math.max(virtualRealInterpolation - deltaTime * 2, 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 realProjectionMatrix = [];
|
||||
mat4BuildPerspective(realProjectionMatrix, 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 realViewMatrix = [];
|
||||
let realCameraPosition = [Math.cos(cameraYaw) * smoothCameraDistance * Math.cos(cameraPitch), Math.sin(cameraPitch) * smoothCameraDistance, Math.sin(cameraYaw) * smoothCameraDistance * Math.cos(cameraPitch)];
|
||||
let realCameraLookAt = [0, 0, 0];
|
||||
let realCameraUp = [0, 1, 0];
|
||||
mat4BuildLookAt(realViewMatrix, realCameraPosition, realCameraLookAt, realCameraUp);
|
||||
|
||||
let normalMatrix = [];
|
||||
mat3MakeNormal(normalMatrix, viewMatrix);
|
||||
mat4Interpolate(realProjectionMatrix, identity, realProjectionMatrix, virtualRealInterpolation * virtualRealInterpolation);
|
||||
mat4Interpolate(realViewMatrix, identity, realViewMatrix, virtualRealInterpolation);
|
||||
|
||||
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.uniformMatrix4fv(gl.getUniformLocation(program, "realProjectionMatrix"), gl.FALSE, new Float32Array(realProjectionMatrix));
|
||||
gl.uniformMatrix4fv(gl.getUniformLocation(program, "realViewMatrix"), gl.FALSE, new Float32Array(realViewMatrix));
|
||||
|
||||
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.useProgram(floorProgram);
|
||||
gl.uniformMatrix4fv(gl.getUniformLocation(floorProgram, "realProjectionMatrix"), gl.FALSE, new Float32Array(realProjectionMatrix));
|
||||
|
||||
gl.uniform3f(gl.getUniformLocation(program, "Light.position"), ...lightPosition.slice(0, 3));
|
||||
gl.uniform3f(gl.getUniformLocation(program, "Light.color"), 1, 1, 1);
|
||||
// Virtual Matrices
|
||||
gl.useProgram(program);
|
||||
let virtualModelViewLocation = gl.getUniformLocation(program, "virtualModelViewMatrix");
|
||||
let virtualProjectionLocation = gl.getUniformLocation(program, "virtualProjectionMatrix");
|
||||
let colorOverrideLocation = gl.getUniformLocation(program, "colorOverride");
|
||||
|
||||
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);
|
||||
let virtualProjectionMatrix = [];
|
||||
mat4BuildPerspective(virtualProjectionMatrix, 90.0 / 180.0 * Math.PI, cv.width / cv.height, 0.9, 5);
|
||||
|
||||
if (!invertZAxis) {
|
||||
let zAxisFlipMatrix = [];
|
||||
mat4Identity(zAxisFlipMatrix);
|
||||
zAxisFlipMatrix[10] = -1;
|
||||
mat4Interpolate(zAxisFlipMatrix, identity, zAxisFlipMatrix, virtualRealInterpolation);
|
||||
mat4Multiply(virtualProjectionMatrix, zAxisFlipMatrix, virtualProjectionMatrix);
|
||||
}
|
||||
|
||||
let inverseVirtualProjectionMatrix = [];
|
||||
mat4Inverse(inverseVirtualProjectionMatrix, virtualProjectionMatrix);
|
||||
|
||||
let virtualViewMatrix = [];
|
||||
let virtualCameraPosition = [1.2, 1.2, 2];
|
||||
let virtualCameraLookAt = [0, 0, -1];
|
||||
let virtualCameraUp = [0, 1, 0];
|
||||
mat4BuildLookAt(virtualViewMatrix, virtualCameraPosition, virtualCameraLookAt, virtualCameraUp);
|
||||
|
||||
let inverseVirtualViewMatrix = [];
|
||||
mat4Inverse(inverseVirtualViewMatrix, virtualViewMatrix);
|
||||
|
||||
mat4Interpolate(virtualProjectionMatrix, identity, virtualProjectionMatrix, interpolateProjection);
|
||||
mat4Interpolate(virtualViewMatrix, identity, virtualViewMatrix, interpolateLookAt);
|
||||
|
||||
gl.uniformMatrix4fv(virtualProjectionLocation, gl.FALSE, new Float32Array(virtualProjectionMatrix));
|
||||
|
||||
|
||||
let modelMatrix = [];
|
||||
mat4Identity(modelMatrix);
|
||||
|
||||
let modelViewMatrix = [];
|
||||
mat4Multiply(modelViewMatrix, virtualViewMatrix, modelMatrix);
|
||||
|
||||
gl.uniformMatrix4fv(virtualModelViewLocation, gl.FALSE, new Float32Array(modelViewMatrix));
|
||||
|
||||
|
||||
// draw scene
|
||||
|
||||
// draw H
|
||||
gl.useProgram(program);
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, hVertexBuffer);
|
||||
setAttribPointers();
|
||||
gl.drawArrays(gl.TRIANGLES, 0, o.numVertices);
|
||||
gl.drawArrays(gl.TRIANGLES, 0, hVertices.length / 6);
|
||||
|
||||
// draw line cube
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, lineCubeVertexBuffer);
|
||||
setAttribPointers();
|
||||
gl.uniform3fv(colorOverrideLocation, [1, 1, 0.5]);
|
||||
gl.drawArrays(gl.LINES, 0, lineCubeVertices.length / 6);
|
||||
gl.uniform3fv(colorOverrideLocation, [0, 0, 0]);
|
||||
|
||||
// draw solid cube 1
|
||||
let cube1ModelView = [];
|
||||
mat4Identity(cube1ModelView);
|
||||
mat4Scale(cube1ModelView, cube1ModelView, [0.3, 0.3, 0.3]);
|
||||
mat4RotateY(cube1ModelView, cube1ModelView, 0.3);
|
||||
mat4Translate(cube1ModelView, cube1ModelView, [-0.5, 0.3, -0.7]);
|
||||
mat4Multiply(cube1ModelView, virtualViewMatrix, cube1ModelView);
|
||||
|
||||
gl.uniformMatrix4fv(virtualModelViewLocation, gl.FALSE, new Float32Array(cube1ModelView));
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexBuffer);
|
||||
setAttribPointers();
|
||||
gl.drawArrays(gl.TRIANGLES, 0, cubeVertices.length / 6);
|
||||
|
||||
// draw solid cube 2
|
||||
let cube2ModelView = [];
|
||||
mat4Identity(cube2ModelView);
|
||||
mat4Scale(cube2ModelView, cube2ModelView, [0.4, 0.4, 0.4]);
|
||||
mat4RotateY(cube2ModelView, cube2ModelView, 2.6);
|
||||
mat4Translate(cube2ModelView, cube2ModelView, [1.6, 0.3, -1]);
|
||||
mat4Multiply(cube2ModelView, virtualViewMatrix, cube2ModelView);
|
||||
|
||||
gl.uniformMatrix4fv(virtualModelViewLocation, gl.FALSE, new Float32Array(cube2ModelView));
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexBuffer);
|
||||
setAttribPointers();
|
||||
gl.drawArrays(gl.TRIANGLES, 0, cubeVertices.length / 6);
|
||||
|
||||
// draw virtual camera
|
||||
let virtualCameraModelView = [];
|
||||
mat4Identity(virtualCameraModelView);
|
||||
mat4Scale(virtualCameraModelView, virtualCameraModelView, [0.1, 0.1, 0.1]);
|
||||
mat4Translate(virtualCameraModelView, virtualCameraModelView, [0, 0, 0.16]);
|
||||
|
||||
mat4Multiply(virtualCameraModelView, inverseVirtualViewMatrix, virtualCameraModelView);
|
||||
mat4Multiply(virtualCameraModelView, virtualViewMatrix, virtualCameraModelView);
|
||||
|
||||
gl.uniformMatrix4fv(virtualModelViewLocation, gl.FALSE, new Float32Array(virtualCameraModelView));
|
||||
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, cameraVertexBuffer);
|
||||
setAttribPointers();
|
||||
if (displayMatricesVirtually && interpolateProjection <= 0) {
|
||||
gl.drawArrays(gl.TRIANGLES, 0, cameraVertices.length / 6);
|
||||
}
|
||||
|
||||
let frustomModelMatrix = [];
|
||||
mat4Multiply(frustomModelMatrix, inverseVirtualViewMatrix, inverseVirtualProjectionMatrix);
|
||||
mat4Multiply(frustomModelMatrix, virtualViewMatrix, frustomModelMatrix);
|
||||
// mat4Copy(inverseVirtualProjectionMatrix, frustomModelMatrix);
|
||||
|
||||
gl.uniformMatrix4fv(virtualModelViewLocation, gl.FALSE, new Float32Array(frustomModelMatrix));
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, lineCubeVertexBuffer);
|
||||
setAttribPointers();
|
||||
gl.uniform3fv(colorOverrideLocation, [1, 0, 1]);
|
||||
gl.drawArrays(gl.LINES, 0, lineCubeVertices.length / 6);
|
||||
gl.uniform3fv(colorOverrideLocation, [0, 0, 0]);
|
||||
|
||||
|
||||
|
||||
// draw origin
|
||||
|
||||
gl.uniformMatrix4fv(virtualModelViewLocation, gl.FALSE, new Float32Array(identity));
|
||||
gl.uniformMatrix4fv(virtualProjectionLocation, gl.FALSE, new Float32Array(identity));
|
||||
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, originVertexBuffer);
|
||||
setAttribPointers();
|
||||
gl.drawArrays(gl.LINES, 0, originVertices.length / 6);
|
||||
|
||||
// draw origin cube
|
||||
|
||||
if (interpolateProjection < 1 && interpolateLookAt > 0) {
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, lineCubeVertexBuffer);
|
||||
setAttribPointers();
|
||||
gl.uniform3fv(colorOverrideLocation, [1, 0, 0]);
|
||||
gl.drawArrays(gl.LINES, 0, lineCubeVertices.length / 6);
|
||||
gl.uniform3fv(colorOverrideLocation, [0, 0, 0]);
|
||||
}
|
||||
|
||||
// draw floor
|
||||
|
||||
gl.useProgram(floorProgram);
|
||||
|
||||
let floorModelView = [];
|
||||
mat4Identity(floorModelView);
|
||||
mat4Scale(floorModelView, floorModelView, [10, 0, 10]);
|
||||
mat4Multiply(floorModelView, realViewMatrix, floorModelView);
|
||||
gl.uniformMatrix4fv(gl.getUniformLocation(floorProgram, "realModelViewMatrix"), gl.FALSE, new Float32Array(floorModelView));
|
||||
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, floorVertexBuffer);
|
||||
setAttribPointers();
|
||||
gl.drawArrays(gl.TRIANGLES, 0, floorVertices.length / 6);
|
||||
|
||||
|
||||
frameTimes.push(performance.now() - frameStart);
|
||||
lastFrame = now;
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
precision mediump float;
|
||||
varying vec3 vPosition;
|
||||
|
||||
void main() {
|
||||
gl_FragColor = mix(vec4(1,1,1,0.5), vec4(0.8,0.8,0.8,0.5), step(0.0, sin(vPosition.x * 3.14159 * 20.0) * sin(vPosition.z * 3.14159 * 20.0)));
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
precision mediump float;
|
||||
|
||||
attribute vec3 vertPosition;
|
||||
attribute vec3 vertColor;
|
||||
|
||||
uniform mat4 realModelViewMatrix;
|
||||
uniform mat4 realProjectionMatrix;
|
||||
|
||||
varying vec3 vPosition;
|
||||
|
||||
void main() {
|
||||
vPosition = vertPosition;
|
||||
gl_Position = realProjectionMatrix * realModelViewMatrix * vec4(vertPosition, 1.0);
|
||||
}
|
|
@ -1,33 +1,6 @@
|
|||
precision mediump float;
|
||||
|
||||
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;
|
||||
varying vec3 fragColor;
|
||||
|
||||
void main() {
|
||||
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);
|
||||
gl_FragColor = vec4(fragColor, 1.0);
|
||||
}
|
|
@ -1,21 +1,21 @@
|
|||
precision mediump float;
|
||||
|
||||
attribute vec3 vertPosition;
|
||||
attribute vec3 vertNormal;
|
||||
attribute vec2 vertTexture;
|
||||
attribute vec3 vertColor;
|
||||
|
||||
uniform mat4 modelViewMatrix;
|
||||
uniform mat4 projectionMatrix;
|
||||
uniform mat3 normalMatrix;
|
||||
uniform mat4 virtualModelViewMatrix;
|
||||
uniform mat4 virtualProjectionMatrix;
|
||||
|
||||
varying vec3 vNormal;
|
||||
varying vec2 vTexture;
|
||||
varying vec3 vPosition;
|
||||
uniform mat4 realViewMatrix;
|
||||
uniform mat4 realProjectionMatrix;
|
||||
|
||||
uniform vec3 colorOverride;
|
||||
|
||||
varying vec3 fragColor;
|
||||
|
||||
void main() {
|
||||
vNormal = normalize(normalMatrix * vertNormal);
|
||||
vTexture = vertTexture;
|
||||
vPosition = (modelViewMatrix * vec4(vertPosition, 1.0)).xyz;
|
||||
float colorOverrideActive = step(0.001, length(colorOverride));
|
||||
fragColor = colorOverride * colorOverrideActive + vertColor * (1.0 - colorOverrideActive);
|
||||
|
||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(vertPosition, 1.0);
|
||||
gl_Position = realProjectionMatrix * realViewMatrix * virtualProjectionMatrix * virtualModelViewMatrix * vec4(vertPosition, 1.0);
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
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