visualise everything.

This commit is contained in:
Luca Conte 2025-04-25 19:00:33 +02:00
parent 505aee8ecc
commit 4c4087a8a9
6 changed files with 436 additions and 25 deletions

View File

@ -37,10 +37,24 @@
</style>
</head>
<body>
<canvas id="cv" width="800" height="600"></canvas>
<canvas id="cv" width="1000" height="700"></canvas>
<div id="stats">
<div>FPS: <span id="fps"></span></div>
<div>Frame time: <span id="ms"></span></div>
<div id="controls">
<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>
<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>

View File

@ -79,7 +79,7 @@ function mat4Translate(out, inm, v) {
t[13] = v[1];
t[14] = v[2];
mat4Multiply(out, t, inv);
mat4Multiply(out, t, inm);
}
/**

View File

@ -3,6 +3,10 @@
let cv, gl;
let program;
let floorProgram;
let hVertices;
let hVertexBuffer;
let cubeVertices;
let cubeVertexBuffer;
@ -16,21 +20,139 @@ 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 cameraPitch = Math.PI / 4;
let cameraYaw = Math.PI / 4;
let cameraDistance = 4;
let mouseDragging = false;
async function init() {
cv = document.getElementById("cv");
gl = cv.getContext("webgl");
if (!gl) {
window.alert("WebGL not supported");
}
// 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("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;
});
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;
}
});
document.addEventListener("mouseup", (e) => {
if (e.button == 0) {
mouseDragging = false;
}
});
document.addEventListener("mouseleave", (e) => {
mouseDragging = false;
});
document.addEventListener("mousemove", (e) => {
if (mouseDragging && displayMatricesVirtually) {
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 > 10) cameraDistance = 10;
});
// 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
// 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,
-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,
@ -126,6 +248,110 @@ async function init() {
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);
@ -142,13 +368,19 @@ async function init() {
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.CULL_FACE);
gl.enable(gl.DEPTH_TEST);
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
// start drawing
requestAnimationFrame(draw);
@ -196,56 +428,192 @@ 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);
}
updateStats(deltaTime);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
let identity = [];
mat4Identity(identity);
// Real Matrices
let realProjectionMatrix = [];
mat4BuildPerspective(realProjectionMatrix, 90.0 / 180.0 * Math.PI, cv.width / cv.height, 0.1, 30);
let realViewMatrix = [];
let realCameraPosition = [Math.cos(cameraYaw) * cameraDistance * Math.cos(cameraPitch), Math.sin(cameraPitch) * cameraDistance, Math.sin(cameraYaw) * cameraDistance * Math.cos(cameraPitch)];
let realCameraLookAt = [0, 0, 0];
let realCameraUp = [0, 1, 0];
// if (cameraPitch > -0.1) {
// realCameraUp = [Math.cos(cameraYaw), 0, Math.sin(cameraYaw)];
// }
mat4BuildLookAt(realViewMatrix, realCameraPosition, realCameraLookAt, realCameraUp);
mat4Interpolate(realProjectionMatrix, identity, realProjectionMatrix, virtualRealInterpolation * virtualRealInterpolation);
mat4Interpolate(realViewMatrix, identity, realViewMatrix, virtualRealInterpolation);
gl.useProgram(program);
gl.uniformMatrix4fv(gl.getUniformLocation(program, "realProjectionMatrix"), gl.FALSE, new Float32Array(realProjectionMatrix));
gl.uniformMatrix4fv(gl.getUniformLocation(program, "realViewMatrix"), gl.FALSE, new Float32Array(realViewMatrix));
let modelViewLocation = gl.getUniformLocation(program, "modelViewMatrix");
let projectionLocation = gl.getUniformLocation(program, "projectionMatrix");
gl.useProgram(floorProgram);
gl.uniformMatrix4fv(gl.getUniformLocation(floorProgram, "realProjectionMatrix"), gl.FALSE, new Float32Array(realProjectionMatrix));
// Virtual Matrices
gl.useProgram(program);
let virtualModelViewLocation = gl.getUniformLocation(program, "virtualModelViewMatrix");
let virtualProjectionLocation = gl.getUniformLocation(program, "virtualProjectionMatrix");
let colorOverrideLocation = gl.getUniformLocation(program, "colorOverride");
let projectionMatrix = [];
mat4BuildPerspective(projectionMatrix, 90.0 / 180.0 * Math.PI, cv.width / cv.height, 0.1, 20);
gl.uniformMatrix4fv(projectionLocation, gl.FALSE, new Float32Array(projectionMatrix));
let virtualProjectionMatrix = [];
mat4BuildPerspective(virtualProjectionMatrix, 90.0 / 180.0 * Math.PI, cv.width / cv.height, 1, 5);
if (displayMatricesVirtually) {
// virtualProjectionMatrix[8] *= -1;
// virtualProjectionMatrix[9] *= -1;
// virtualProjectionMatrix[10] *= -1;
// virtualProjectionMatrix[11] *= -1;
}
let inverseVirtualProjectionMatrix = [];
mat4Inverse(inverseVirtualProjectionMatrix, virtualProjectionMatrix);
let viewMatrix = [];
let cameraPosition = [2, 2, 2];
let cameraLookAt = [0, 0, -1];
let cameraUp = [0, 1, 0];
mat4BuildLookAt(viewMatrix, cameraPosition, cameraLookAt, cameraUp);
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);
mat4RotateX(modelMatrix, modelMatrix, hue * 2 * Math.PI);
mat4RotateY(modelMatrix, modelMatrix, hue * 2 * Math.PI);
let modelViewMatrix = [];
mat4Multiply(modelViewMatrix, viewMatrix, modelMatrix);
mat4Multiply(modelViewMatrix, virtualViewMatrix, modelMatrix);
gl.uniformMatrix4fv(modelViewLocation, gl.FALSE, new Float32Array(modelViewMatrix));
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, 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);
gl.lineWidth(3);
// 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.01) {
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]);
gl.uniformMatrix4fv(modelViewLocation, gl.FALSE, new Float32Array(viewMatrix));
// 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 < 0.99 && interpolateLookAt > 0.01) {
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);
lastFrame = now;
requestAnimationFrame(draw);
}

View File

@ -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)));
}

View File

@ -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);
}

View File

@ -3,12 +3,21 @@ precision mediump float;
attribute vec3 vertPosition;
attribute vec3 vertColor;
uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform mat4 virtualModelViewMatrix;
uniform mat4 virtualProjectionMatrix;
uniform mat4 realViewMatrix;
uniform mat4 realProjectionMatrix;
uniform vec3 colorOverride;
varying vec3 fragColor;
void main() {
fragColor = vertColor;
gl_Position = projectionMatrix * modelViewMatrix * vec4(vertPosition, 1.0);
if (colorOverride != vec3(0)) {
fragColor = colorOverride;
} else {
fragColor = vertColor;
}
gl_Position = realProjectionMatrix * realViewMatrix * virtualProjectionMatrix * virtualModelViewMatrix * vec4(vertPosition, 1.0);
}