diff --git a/index.html b/index.html index c25c895..2c128d2 100644 --- a/index.html +++ b/index.html @@ -215,6 +215,8 @@

WebGL 3D Gaussian Splat Viewer

- w/s to tilt camera up/down - q/e to roll camera counterclockwise/clockwise - i/k and j/l to orbit +- m to enable stereo view +- b/n to decrease/increase stereo trackpad - scroll up/down/left/right to orbit diff --git a/main.js b/main.js index 8f7f527..d232870 100644 --- a/main.js +++ b/main.js @@ -1179,6 +1179,10 @@ async function main() { let leftGamepadTrigger, rightGamepadTrigger; + // Globale Variable für Stereo-Basis + let stereoEnabled = false; // Standard: Stereo an + let eyeOffset = 0.03; // Startwert + const frame = (now) => { let inv = invert4(viewMatrix); let shiftKey = @@ -1212,6 +1216,12 @@ async function main() { if (activeKeys.includes("KeyE")) inv = rotate4(inv, -0.01, 0, 0, 1); if (activeKeys.includes("KeyW")) inv = rotate4(inv, 0.005, 1, 0, 0); if (activeKeys.includes("KeyS")) inv = rotate4(inv, -0.005, 1, 0, 0); + if (activeKeys.includes("KeyB")) eyeOffset = Math.max(-0.1, eyeOffset - 0.001); + if (activeKeys.includes("KeyN")) eyeOffset = Math.min(0.1, eyeOffset + 0.001); + if (activeKeys.includes("KeyM")) { + stereoEnabled = !stereoEnabled; + activeKeys = activeKeys.filter(k => k !== "KeyM"); + } const gamepads = navigator.getGamepads ? navigator.getGamepads() : []; let isJumping = activeKeys.includes("Space"); @@ -1357,9 +1367,38 @@ async function main() { if (vertexCount > 0) { document.getElementById("spinner").style.display = "none"; - gl.uniformMatrix4fv(u_view, false, actualViewMatrix); gl.clear(gl.COLOR_BUFFER_BIT); - gl.drawArraysInstanced(gl.TRIANGLE_FAN, 0, 4, vertexCount); + + if (stereoEnabled) { + // Stereo-Rendering (Side-by-Side) + const halfWidth = gl.canvas.width / 2; + // Left Eye + let leftProj = getProjectionMatrix(camera.fx, camera.fy, halfWidth, gl.canvas.height); + let leftInv = translate4(invert4(actualViewMatrix), -eyeOffset, 0, 0); + let leftView = invert4(leftInv); + gl.viewport(0, 0, halfWidth, gl.canvas.height); + gl.uniform2fv(u_viewport, new Float32Array([halfWidth, gl.canvas.height])); + gl.uniformMatrix4fv(u_projection, false, leftProj); + gl.uniformMatrix4fv(u_view, false, leftView); + gl.drawArraysInstanced(gl.TRIANGLE_FAN, 0, 4, vertexCount); + // Right Eye + let rightProj = getProjectionMatrix(camera.fx, camera.fy, halfWidth, gl.canvas.height); + let rightInv = translate4(invert4(actualViewMatrix), eyeOffset, 0, 0); + let rightView = invert4(rightInv); + gl.viewport(halfWidth, 0, halfWidth, gl.canvas.height); + gl.uniform2fv(u_viewport, new Float32Array([halfWidth, gl.canvas.height])); + gl.uniformMatrix4fv(u_projection, false, rightProj); + gl.uniformMatrix4fv(u_view, false, rightView); + gl.drawArraysInstanced(gl.TRIANGLE_FAN, 0, 4, vertexCount); + } else { + // Mono-Rendering + gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); + gl.uniform2fv(u_viewport, new Float32Array([gl.canvas.width, gl.canvas.height])); + gl.uniformMatrix4fv(u_projection, false, projectionMatrix); + gl.uniformMatrix4fv(u_view, false, actualViewMatrix); + gl.drawArraysInstanced(gl.TRIANGLE_FAN, 0, 4, vertexCount); + } + } else { gl.clear(gl.COLOR_BUFFER_BIT); document.getElementById("spinner").style.display = ""; @@ -1371,7 +1410,7 @@ async function main() { } else { document.getElementById("progress").style.display = "none"; } - fps.innerText = Math.round(avgFps) + " fps"; + fps.innerText = Math.round(avgFps) + " fps | stereo=" + (stereoEnabled ? eyeOffset.toFixed(3) : "off"); if (isNaN(currentCameraIndex)) { camid.innerText = ""; }