Spaces:
Running
Running
antimatter15
commited on
Commit
·
59df0c8
1
Parent(s):
3695c57
changing camera controls
Browse files- README.md +32 -8
- index.html +74 -3
- main.js +131 -72
README.md
CHANGED
|
@@ -8,16 +8,40 @@ https://github.com/antimatter15/splat/assets/30054/6534558e-5ddd-4ca5-a4ba-48d7b
|
|
| 8 |
|
| 9 |
## controls
|
| 10 |
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
- `w`/`s` to tilt camera up/down
|
| 15 |
-
- `
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
-
|
| 19 |
-
- right
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
- press 0-9 to switch to one of the pre-loaded camera views
|
|
|
|
| 21 |
|
| 22 |
## other features
|
| 23 |
|
|
|
|
| 8 |
|
| 9 |
## controls
|
| 10 |
|
| 11 |
+
movement (arrow keys)
|
| 12 |
+
|
| 13 |
+
- left/right arrow keys to strafe side to side
|
| 14 |
+
- up/down arrow keys to move forward/back
|
| 15 |
+
- `space` to jump
|
| 16 |
+
|
| 17 |
+
camera angle (wasd)
|
| 18 |
+
|
| 19 |
+
- `a`/`d` to turn camera left/right
|
| 20 |
- `w`/`s` to tilt camera up/down
|
| 21 |
+
- `q`/`e` to roll camera counterclockwise/clockwise
|
| 22 |
+
|
| 23 |
+
trackpad
|
| 24 |
+
- scroll up/down to orbit down
|
| 25 |
+
- scroll left/right to orbit left/right
|
| 26 |
+
- pinch to move forward/back
|
| 27 |
+
- ctrl key + scroll up/down to move forward/back
|
| 28 |
+
- shift + scroll up/down to move up/down
|
| 29 |
+
- shift + scroll left/right to strafe side to side
|
| 30 |
+
|
| 31 |
+
mouse
|
| 32 |
+
- click and drag to orbit
|
| 33 |
+
- right click (or ctrl/cmd key) and drag up/down to move forward/back
|
| 34 |
+
- right click (or ctrl/cmd key) and drag left/right to strafe side to side
|
| 35 |
+
|
| 36 |
+
touch (mobile)
|
| 37 |
+
- one finger to orbit
|
| 38 |
+
- two finger pinch to move forward/back
|
| 39 |
+
- two finger rotate to rotate camera clockwise/counterclockwise
|
| 40 |
+
- two finger pan to move side-to-side and up-down
|
| 41 |
+
|
| 42 |
+
other
|
| 43 |
- press 0-9 to switch to one of the pre-loaded camera views
|
| 44 |
+
- press `p` to resume default animation
|
| 45 |
|
| 46 |
## other features
|
| 47 |
|
index.html
CHANGED
|
@@ -18,7 +18,6 @@
|
|
| 18 |
margin: 0;
|
| 19 |
height: 100vh;
|
| 20 |
width: 100vw;
|
| 21 |
-
touch-action: none;
|
| 22 |
font-family: sans-serif;
|
| 23 |
background: black;
|
| 24 |
text-shadow: 0 0 3px black;
|
|
@@ -133,6 +132,11 @@
|
|
| 133 |
font-weight: bold;
|
| 134 |
font-size: large;
|
| 135 |
color: red;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 136 |
}
|
| 137 |
|
| 138 |
#progress {
|
|
@@ -143,18 +147,81 @@
|
|
| 143 |
z-index: 99;
|
| 144 |
transition: width 0.1s ease-in-out;
|
| 145 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 146 |
</style>
|
| 147 |
</head>
|
| 148 |
<body>
|
| 149 |
<div id="info">
|
| 150 |
<h3>WebGL 3D Gaussian Splat Viewer</h3>
|
| 151 |
-
<p>
|
| 152 |
<small>
|
| 153 |
By <a href="https://twitter.com/antimatter15">Kevin Kwok</a>.
|
| 154 |
Code on
|
| 155 |
<a href="https://github.com/antimatter15/splat">Github</a
|
| 156 |
>.
|
| 157 |
</small>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 158 |
</div>
|
| 159 |
|
| 160 |
<div id="progress"></div>
|
|
@@ -174,7 +241,11 @@
|
|
| 174 |
</div>
|
| 175 |
</div>
|
| 176 |
</div>
|
|
|
|
| 177 |
|
| 178 |
-
<
|
|
|
|
|
|
|
|
|
|
| 179 |
</body>
|
| 180 |
</html>
|
|
|
|
| 18 |
margin: 0;
|
| 19 |
height: 100vh;
|
| 20 |
width: 100vw;
|
|
|
|
| 21 |
font-family: sans-serif;
|
| 22 |
background: black;
|
| 23 |
text-shadow: 0 0 3px black;
|
|
|
|
| 132 |
font-weight: bold;
|
| 133 |
font-size: large;
|
| 134 |
color: red;
|
| 135 |
+
pointer-events: none;
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
details {
|
| 139 |
+
font-size: small;
|
| 140 |
}
|
| 141 |
|
| 142 |
#progress {
|
|
|
|
| 147 |
z-index: 99;
|
| 148 |
transition: width 0.1s ease-in-out;
|
| 149 |
}
|
| 150 |
+
|
| 151 |
+
#quality {
|
| 152 |
+
position: absolute;
|
| 153 |
+
bottom: 10px;
|
| 154 |
+
z-index: 999;
|
| 155 |
+
right: 10px;
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
#canvas {
|
| 159 |
+
display: block;
|
| 160 |
+
position: absolute;
|
| 161 |
+
top: 0;
|
| 162 |
+
left: 0;
|
| 163 |
+
width: 100%;
|
| 164 |
+
height: 100%;
|
| 165 |
+
touch-action: none;
|
| 166 |
+
}
|
| 167 |
+
|
| 168 |
+
#instructions {
|
| 169 |
+
background: rgba(0,0,0,0.6);
|
| 170 |
+
white-space: pre-wrap;
|
| 171 |
+
padding: 10px;
|
| 172 |
+
border-radius: 10px;
|
| 173 |
+
font-size: x-small;
|
| 174 |
+
}
|
| 175 |
</style>
|
| 176 |
</head>
|
| 177 |
<body>
|
| 178 |
<div id="info">
|
| 179 |
<h3>WebGL 3D Gaussian Splat Viewer</h3>
|
| 180 |
+
<p>
|
| 181 |
<small>
|
| 182 |
By <a href="https://twitter.com/antimatter15">Kevin Kwok</a>.
|
| 183 |
Code on
|
| 184 |
<a href="https://github.com/antimatter15/splat">Github</a
|
| 185 |
>.
|
| 186 |
</small>
|
| 187 |
+
</p>
|
| 188 |
+
|
| 189 |
+
<details>
|
| 190 |
+
<summary>Use mouse or arrow keys to navigate.</summary>
|
| 191 |
+
|
| 192 |
+
<div id="instructions">movement (arrow keys)
|
| 193 |
+
- left/right arrow keys to strafe side to side
|
| 194 |
+
- up/down arrow keys to move forward/back
|
| 195 |
+
- space to jump
|
| 196 |
+
|
| 197 |
+
camera angle (wasd)
|
| 198 |
+
- a/d to turn camera left/right
|
| 199 |
+
- w/s to tilt camera up/down
|
| 200 |
+
- q/e to roll camera counterclockwise/clockwise
|
| 201 |
+
|
| 202 |
+
trackpad
|
| 203 |
+
- scroll up/down/left/right to orbit
|
| 204 |
+
- pinch to move forward/back
|
| 205 |
+
- ctrl key + scroll to move forward/back
|
| 206 |
+
- shift + scroll to move up/down or strafe
|
| 207 |
+
|
| 208 |
+
mouse
|
| 209 |
+
- click and drag to orbit
|
| 210 |
+
- right click (or ctrl/cmd key) and drag up/down to move
|
| 211 |
+
|
| 212 |
+
touch (mobile)
|
| 213 |
+
- one finger to orbit
|
| 214 |
+
- two finger pinch to move forward/back
|
| 215 |
+
- two finger rotate to rotate camera clockwise/counterclockwise
|
| 216 |
+
- two finger pan to move side-to-side and up-down
|
| 217 |
+
|
| 218 |
+
other
|
| 219 |
+
- press 0-9 to switch to one of the pre-loaded camera views
|
| 220 |
+
- press p to resume default animation
|
| 221 |
+
</div>
|
| 222 |
+
|
| 223 |
+
</details>
|
| 224 |
+
|
| 225 |
</div>
|
| 226 |
|
| 227 |
<div id="progress"></div>
|
|
|
|
| 241 |
</div>
|
| 242 |
</div>
|
| 243 |
</div>
|
| 244 |
+
<canvas id="canvas"></canvas>
|
| 245 |
|
| 246 |
+
<div id="quality">
|
| 247 |
+
<span id="fps"></span>
|
| 248 |
+
</div>
|
| 249 |
+
<script src="main.js?"></script>
|
| 250 |
</body>
|
| 251 |
</html>
|
main.js
CHANGED
|
@@ -642,6 +642,8 @@ async function main() {
|
|
| 642 |
carousel = false;
|
| 643 |
} catch (err) {}
|
| 644 |
const url = new URL(
|
|
|
|
|
|
|
| 645 |
params.get("url") || "train.splat",
|
| 646 |
"https://antimatter15.com/splat-data/",
|
| 647 |
);
|
|
@@ -657,6 +659,9 @@ async function main() {
|
|
| 657 |
const reader = req.body.getReader();
|
| 658 |
let splatData = new Uint8Array(req.headers.get("content-length"));
|
| 659 |
|
|
|
|
|
|
|
|
|
|
| 660 |
const worker = new Worker(
|
| 661 |
URL.createObjectURL(
|
| 662 |
new Blob(["(", createWorker.toString(), ")(self)"], {
|
|
@@ -665,25 +670,15 @@ async function main() {
|
|
| 665 |
),
|
| 666 |
);
|
| 667 |
|
| 668 |
-
const canvas = document.
|
| 669 |
-
canvas.width = innerWidth /
|
| 670 |
-
canvas.height = innerHeight /
|
| 671 |
-
|
| 672 |
-
|
| 673 |
-
canvas.style.left = 0;
|
| 674 |
-
canvas.style.width = "100%";
|
| 675 |
-
canvas.style.height = "100%";
|
| 676 |
-
document.body.appendChild(canvas);
|
| 677 |
-
|
| 678 |
-
const fps = document.createElement("div");
|
| 679 |
-
fps.style.position = "absolute";
|
| 680 |
-
fps.style.bottom = "10px";
|
| 681 |
-
fps.style.right = "10px";
|
| 682 |
-
document.body.appendChild(fps);
|
| 683 |
|
| 684 |
let projectionMatrix = getProjectionMatrix(
|
| 685 |
-
camera.fx /
|
| 686 |
-
camera.fy /
|
| 687 |
canvas.width,
|
| 688 |
canvas.height,
|
| 689 |
);
|
|
@@ -738,7 +733,10 @@ async function main() {
|
|
| 738 |
|
| 739 |
// focal
|
| 740 |
const u_focal = gl.getUniformLocation(program, "focal");
|
| 741 |
-
gl.uniform2fv(
|
|
|
|
|
|
|
|
|
|
| 742 |
|
| 743 |
// view
|
| 744 |
const u_view = gl.getUniformLocation(program, "view");
|
|
@@ -826,6 +824,7 @@ async function main() {
|
|
| 826 |
let activeKeys = [];
|
| 827 |
|
| 828 |
window.addEventListener("keydown", (e) => {
|
|
|
|
| 829 |
carousel = false;
|
| 830 |
if (!activeKeys.includes(e.key)) activeKeys.push(e.key);
|
| 831 |
if (/\d/.test(e.key)) {
|
|
@@ -857,52 +856,66 @@ async function main() {
|
|
| 857 |
: e.deltaMode == 2
|
| 858 |
? innerHeight
|
| 859 |
: 1;
|
| 860 |
-
const dy = e.deltaY * scale;
|
| 861 |
let inv = invert4(viewMatrix);
|
| 862 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 863 |
viewMatrix = invert4(inv);
|
| 864 |
},
|
| 865 |
{ passive: false },
|
| 866 |
);
|
| 867 |
|
| 868 |
let startX, startY, down;
|
| 869 |
-
|
| 870 |
carousel = false;
|
| 871 |
e.preventDefault();
|
| 872 |
startX = e.clientX;
|
| 873 |
startY = e.clientY;
|
| 874 |
-
down = 1;
|
| 875 |
});
|
| 876 |
-
|
| 877 |
carousel = false;
|
| 878 |
e.preventDefault();
|
| 879 |
startX = e.clientX;
|
| 880 |
startY = e.clientY;
|
| 881 |
down = 2;
|
| 882 |
});
|
| 883 |
-
|
| 884 |
e.preventDefault();
|
| 885 |
if (down == 1) {
|
| 886 |
let inv = invert4(viewMatrix);
|
| 887 |
-
|
| 888 |
-
|
| 889 |
-
|
| 890 |
-
|
| 891 |
-
|
| 892 |
-
|
| 893 |
-
);
|
| 894 |
-
inv =
|
| 895 |
-
|
| 896 |
-
(5 * (e.clientX - startX)) / innerWidth,
|
| 897 |
-
0,
|
| 898 |
-
0,
|
| 899 |
-
);
|
| 900 |
-
inv = translate4(
|
| 901 |
-
inv,
|
| 902 |
-
0,
|
| 903 |
-
0,
|
| 904 |
-
(10 * (e.clientY - startY)) / innerHeight,
|
| 905 |
-
);
|
| 906 |
viewMatrix = invert4(inv);
|
| 907 |
|
| 908 |
startX = e.clientX;
|
|
@@ -913,8 +926,8 @@ async function main() {
|
|
| 913 |
inv = translate4(
|
| 914 |
inv,
|
| 915 |
(-10 * (e.clientX - startX)) / innerWidth,
|
| 916 |
-
(-10 * (e.clientY - startY)) / innerHeight,
|
| 917 |
0,
|
|
|
|
| 918 |
);
|
| 919 |
viewMatrix = invert4(inv);
|
| 920 |
|
|
@@ -922,14 +935,16 @@ async function main() {
|
|
| 922 |
startY = e.clientY;
|
| 923 |
}
|
| 924 |
});
|
| 925 |
-
|
| 926 |
e.preventDefault();
|
| 927 |
down = false;
|
| 928 |
startX = 0;
|
| 929 |
startY = 0;
|
| 930 |
});
|
| 931 |
|
| 932 |
-
|
|
|
|
|
|
|
| 933 |
"touchstart",
|
| 934 |
(e) => {
|
| 935 |
e.preventDefault();
|
|
@@ -938,38 +953,79 @@ async function main() {
|
|
| 938 |
startX = e.touches[0].clientX;
|
| 939 |
startY = e.touches[0].clientY;
|
| 940 |
down = 1;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 941 |
}
|
| 942 |
},
|
| 943 |
{ passive: false },
|
| 944 |
);
|
| 945 |
-
|
| 946 |
"touchmove",
|
| 947 |
(e) => {
|
| 948 |
e.preventDefault();
|
| 949 |
if (e.touches.length === 1 && down) {
|
| 950 |
let inv = invert4(viewMatrix);
|
| 951 |
-
|
| 952 |
-
|
| 953 |
-
|
| 954 |
-
|
| 955 |
-
|
| 956 |
-
|
| 957 |
-
);
|
| 958 |
-
inv =
|
| 959 |
-
|
| 960 |
-
|
| 961 |
-
|
| 962 |
-
|
| 963 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 964 |
viewMatrix = invert4(inv);
|
| 965 |
|
| 966 |
startX = e.touches[0].clientX;
|
|
|
|
| 967 |
startY = e.touches[0].clientY;
|
|
|
|
| 968 |
}
|
| 969 |
},
|
| 970 |
{ passive: false },
|
| 971 |
);
|
| 972 |
-
|
| 973 |
"touchend",
|
| 974 |
(e) => {
|
| 975 |
e.preventDefault();
|
|
@@ -985,7 +1041,7 @@ async function main() {
|
|
| 985 |
|
| 986 |
let lastFrame = 0;
|
| 987 |
let avgFps = 0;
|
| 988 |
-
let start =
|
| 989 |
|
| 990 |
const frame = (now) => {
|
| 991 |
let inv = invert4(viewMatrix);
|
|
@@ -993,11 +1049,13 @@ async function main() {
|
|
| 993 |
if (activeKeys.includes("ArrowUp")) inv = translate4(inv, 0, 0, 0.1);
|
| 994 |
if (activeKeys.includes("ArrowDown")) inv = translate4(inv, 0, 0, -0.1);
|
| 995 |
if (activeKeys.includes("ArrowLeft"))
|
| 996 |
-
inv =
|
|
|
|
| 997 |
if (activeKeys.includes("ArrowRight"))
|
| 998 |
-
inv =
|
| 999 |
-
|
| 1000 |
-
if (activeKeys.includes("
|
|
|
|
| 1001 |
if (activeKeys.includes("q")) inv = rotate4(inv, 0.01, 0, 0, 1);
|
| 1002 |
if (activeKeys.includes("e")) inv = rotate4(inv, -0.01, 0, 0, 1);
|
| 1003 |
if (activeKeys.includes("w")) inv = rotate4(inv, 0.005, 1, 0, 0);
|
|
@@ -1009,8 +1067,8 @@ async function main() {
|
|
| 1009 |
let inv = invert4(defaultViewMatrix);
|
| 1010 |
|
| 1011 |
const t = Math.sin((Date.now() - start) / 5000);
|
| 1012 |
-
inv = translate4(inv, 2.5 * t, 0,
|
| 1013 |
-
inv = rotate4(inv, -0.
|
| 1014 |
|
| 1015 |
viewMatrix = invert4(inv);
|
| 1016 |
}
|
|
@@ -1023,7 +1081,7 @@ async function main() {
|
|
| 1023 |
|
| 1024 |
let inv2 = invert4(viewMatrix);
|
| 1025 |
inv2[13] -= jumpDelta;
|
| 1026 |
-
inv2 = rotate4(inv2, -0.
|
| 1027 |
let actualViewMatrix = invert4(inv2);
|
| 1028 |
|
| 1029 |
const viewProj = multiply4(projectionMatrix, actualViewMatrix);
|
|
@@ -1039,6 +1097,7 @@ async function main() {
|
|
| 1039 |
} else {
|
| 1040 |
gl.clear(gl.COLOR_BUFFER_BIT);
|
| 1041 |
document.getElementById("spinner").style.display = "";
|
|
|
|
| 1042 |
}
|
| 1043 |
const progress = (100 * vertexCount) / (splatData.length / rowLength);
|
| 1044 |
if (progress < 100) {
|
|
@@ -1060,8 +1119,8 @@ async function main() {
|
|
| 1060 |
cameras = JSON.parse(fr.result);
|
| 1061 |
viewMatrix = getViewMatrix(cameras[0]);
|
| 1062 |
projectionMatrix = getProjectionMatrix(
|
| 1063 |
-
camera.fx /
|
| 1064 |
-
camera.fy /
|
| 1065 |
canvas.width,
|
| 1066 |
canvas.height,
|
| 1067 |
);
|
|
@@ -1105,7 +1164,7 @@ async function main() {
|
|
| 1105 |
const preventDefault = (e) => {
|
| 1106 |
e.preventDefault();
|
| 1107 |
e.stopPropagation();
|
| 1108 |
-
}
|
| 1109 |
document.addEventListener("dragenter", preventDefault);
|
| 1110 |
document.addEventListener("dragover", preventDefault);
|
| 1111 |
document.addEventListener("dragleave", preventDefault);
|
|
|
|
| 642 |
carousel = false;
|
| 643 |
} catch (err) {}
|
| 644 |
const url = new URL(
|
| 645 |
+
// "nike.splat",
|
| 646 |
+
// location.href,
|
| 647 |
params.get("url") || "train.splat",
|
| 648 |
"https://antimatter15.com/splat-data/",
|
| 649 |
);
|
|
|
|
| 659 |
const reader = req.body.getReader();
|
| 660 |
let splatData = new Uint8Array(req.headers.get("content-length"));
|
| 661 |
|
| 662 |
+
const downsample = splatData.length / rowLength > 500000 ? 2 : 1;
|
| 663 |
+
console.log(splatData.length / rowLength, downsample);
|
| 664 |
+
|
| 665 |
const worker = new Worker(
|
| 666 |
URL.createObjectURL(
|
| 667 |
new Blob(["(", createWorker.toString(), ")(self)"], {
|
|
|
|
| 670 |
),
|
| 671 |
);
|
| 672 |
|
| 673 |
+
const canvas = document.getElementById("canvas");
|
| 674 |
+
canvas.width = innerWidth / downsample;
|
| 675 |
+
canvas.height = innerHeight / downsample;
|
| 676 |
+
|
| 677 |
+
const fps = document.getElementById("fps");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 678 |
|
| 679 |
let projectionMatrix = getProjectionMatrix(
|
| 680 |
+
camera.fx / downsample,
|
| 681 |
+
camera.fy / downsample,
|
| 682 |
canvas.width,
|
| 683 |
canvas.height,
|
| 684 |
);
|
|
|
|
| 733 |
|
| 734 |
// focal
|
| 735 |
const u_focal = gl.getUniformLocation(program, "focal");
|
| 736 |
+
gl.uniform2fv(
|
| 737 |
+
u_focal,
|
| 738 |
+
new Float32Array([camera.fx / downsample, camera.fy / downsample]),
|
| 739 |
+
);
|
| 740 |
|
| 741 |
// view
|
| 742 |
const u_view = gl.getUniformLocation(program, "view");
|
|
|
|
| 824 |
let activeKeys = [];
|
| 825 |
|
| 826 |
window.addEventListener("keydown", (e) => {
|
| 827 |
+
if (document.activeElement != document.body) return;
|
| 828 |
carousel = false;
|
| 829 |
if (!activeKeys.includes(e.key)) activeKeys.push(e.key);
|
| 830 |
if (/\d/.test(e.key)) {
|
|
|
|
| 856 |
: e.deltaMode == 2
|
| 857 |
? innerHeight
|
| 858 |
: 1;
|
|
|
|
| 859 |
let inv = invert4(viewMatrix);
|
| 860 |
+
if (e.shiftKey) {
|
| 861 |
+
inv = translate4(
|
| 862 |
+
inv,
|
| 863 |
+
(e.deltaX * scale) / innerWidth,
|
| 864 |
+
(e.deltaY * scale) / innerHeight,
|
| 865 |
+
0,
|
| 866 |
+
);
|
| 867 |
+
} else if (e.ctrlKey || e.metaKey) {
|
| 868 |
+
// inv = rotate4(inv, (e.deltaX * scale) / innerWidth, 0, 0, 1);
|
| 869 |
+
// inv = translate4(inv, 0, (e.deltaY * scale) / innerHeight, 0);
|
| 870 |
+
|
| 871 |
+
inv = translate4(
|
| 872 |
+
inv,
|
| 873 |
+
0,
|
| 874 |
+
0,
|
| 875 |
+
(-10 * (e.deltaY * scale)) / innerHeight,
|
| 876 |
+
);
|
| 877 |
+
} else {
|
| 878 |
+
let d = 4;
|
| 879 |
+
inv = translate4(inv, 0, 0, d);
|
| 880 |
+
inv = rotate4(inv, -(e.deltaX * scale) / innerWidth, 0, 1, 0);
|
| 881 |
+
inv = rotate4(inv, (e.deltaY * scale) / innerHeight, 1, 0, 0);
|
| 882 |
+
inv = translate4(inv, 0, 0, -d);
|
| 883 |
+
|
| 884 |
+
}
|
| 885 |
+
|
| 886 |
viewMatrix = invert4(inv);
|
| 887 |
},
|
| 888 |
{ passive: false },
|
| 889 |
);
|
| 890 |
|
| 891 |
let startX, startY, down;
|
| 892 |
+
canvas.addEventListener("mousedown", (e) => {
|
| 893 |
carousel = false;
|
| 894 |
e.preventDefault();
|
| 895 |
startX = e.clientX;
|
| 896 |
startY = e.clientY;
|
| 897 |
+
down = e.ctrlKey || e.metaKey ? 2 : 1;
|
| 898 |
});
|
| 899 |
+
canvas.addEventListener("contextmenu", (e) => {
|
| 900 |
carousel = false;
|
| 901 |
e.preventDefault();
|
| 902 |
startX = e.clientX;
|
| 903 |
startY = e.clientY;
|
| 904 |
down = 2;
|
| 905 |
});
|
| 906 |
+
canvas.addEventListener("mousemove", (e) => {
|
| 907 |
e.preventDefault();
|
| 908 |
if (down == 1) {
|
| 909 |
let inv = invert4(viewMatrix);
|
| 910 |
+
let dx = 5 * (e.clientX - startX) / innerWidth;
|
| 911 |
+
let dy = 5 * (e.clientY - startY) / innerHeight;
|
| 912 |
+
let d = 4;
|
| 913 |
+
inv = translate4(inv, 0, 0, d);
|
| 914 |
+
// inv = translate4(inv, -x, -y, -z);
|
| 915 |
+
// inv = translate4(inv, x, y, z);
|
| 916 |
+
inv = rotate4(inv, dx, 0, 1, 0);
|
| 917 |
+
inv = rotate4(inv, -dy, 1, 0, 0);
|
| 918 |
+
inv = translate4(inv, 0, 0, -d);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 919 |
viewMatrix = invert4(inv);
|
| 920 |
|
| 921 |
startX = e.clientX;
|
|
|
|
| 926 |
inv = translate4(
|
| 927 |
inv,
|
| 928 |
(-10 * (e.clientX - startX)) / innerWidth,
|
|
|
|
| 929 |
0,
|
| 930 |
+
(10 * (e.clientY - startY)) / innerHeight,
|
| 931 |
);
|
| 932 |
viewMatrix = invert4(inv);
|
| 933 |
|
|
|
|
| 935 |
startY = e.clientY;
|
| 936 |
}
|
| 937 |
});
|
| 938 |
+
canvas.addEventListener("mouseup", (e) => {
|
| 939 |
e.preventDefault();
|
| 940 |
down = false;
|
| 941 |
startX = 0;
|
| 942 |
startY = 0;
|
| 943 |
});
|
| 944 |
|
| 945 |
+
let altX = 0,
|
| 946 |
+
altY = 0;
|
| 947 |
+
canvas.addEventListener(
|
| 948 |
"touchstart",
|
| 949 |
(e) => {
|
| 950 |
e.preventDefault();
|
|
|
|
| 953 |
startX = e.touches[0].clientX;
|
| 954 |
startY = e.touches[0].clientY;
|
| 955 |
down = 1;
|
| 956 |
+
} else if (e.touches.length === 2) {
|
| 957 |
+
// console.log('beep')
|
| 958 |
+
carousel = false;
|
| 959 |
+
startX = e.touches[0].clientX;
|
| 960 |
+
altX = e.touches[1].clientX;
|
| 961 |
+
startY = e.touches[0].clientY;
|
| 962 |
+
altY = e.touches[1].clientY;
|
| 963 |
+
down = 1;
|
| 964 |
}
|
| 965 |
},
|
| 966 |
{ passive: false },
|
| 967 |
);
|
| 968 |
+
canvas.addEventListener(
|
| 969 |
"touchmove",
|
| 970 |
(e) => {
|
| 971 |
e.preventDefault();
|
| 972 |
if (e.touches.length === 1 && down) {
|
| 973 |
let inv = invert4(viewMatrix);
|
| 974 |
+
let dx = (4 * (e.touches[0].clientX - startX)) / innerWidth;
|
| 975 |
+
let dy = (4 * (e.touches[0].clientY - startY)) / innerHeight;
|
| 976 |
+
|
| 977 |
+
let d = 4;
|
| 978 |
+
inv = translate4(inv, 0, 0, d);
|
| 979 |
+
// inv = translate4(inv, -x, -y, -z);
|
| 980 |
+
// inv = translate4(inv, x, y, z);
|
| 981 |
+
inv = rotate4(inv, dx, 0, 1, 0);
|
| 982 |
+
inv = rotate4(inv, -dy, 1, 0, 0);
|
| 983 |
+
inv = translate4(inv, 0, 0, -d);
|
| 984 |
+
|
| 985 |
+
viewMatrix = invert4(inv);
|
| 986 |
+
|
| 987 |
+
startX = e.touches[0].clientX;
|
| 988 |
+
startY = e.touches[0].clientY;
|
| 989 |
+
} else if (e.touches.length === 2) {
|
| 990 |
+
// alert('beep')
|
| 991 |
+
const dtheta =
|
| 992 |
+
Math.atan2(startY - altY, startX - altX) -
|
| 993 |
+
Math.atan2(
|
| 994 |
+
e.touches[0].clientY - e.touches[1].clientY,
|
| 995 |
+
e.touches[0].clientX - e.touches[1].clientX,
|
| 996 |
+
);
|
| 997 |
+
const dscale =
|
| 998 |
+
Math.hypot(startX - altX, startY - altY) /
|
| 999 |
+
Math.hypot(
|
| 1000 |
+
e.touches[0].clientX - e.touches[1].clientX,
|
| 1001 |
+
e.touches[0].clientY - e.touches[1].clientY,
|
| 1002 |
+
);
|
| 1003 |
+
const dx =
|
| 1004 |
+
(e.touches[0].clientX +
|
| 1005 |
+
e.touches[1].clientX -
|
| 1006 |
+
(startX + altX)) /
|
| 1007 |
+
2;
|
| 1008 |
+
const dy =
|
| 1009 |
+
(e.touches[0].clientY +
|
| 1010 |
+
e.touches[1].clientY -
|
| 1011 |
+
(startY + altY)) /
|
| 1012 |
+
2;
|
| 1013 |
+
let inv = invert4(viewMatrix);
|
| 1014 |
+
// inv = translate4(inv, 0, 0, d);
|
| 1015 |
+
inv = rotate4(inv, dtheta, 0, 0, 1);
|
| 1016 |
+
inv = translate4(inv, -dx / innerWidth, -dy / innerHeight, 1 - dscale);
|
| 1017 |
+
|
| 1018 |
viewMatrix = invert4(inv);
|
| 1019 |
|
| 1020 |
startX = e.touches[0].clientX;
|
| 1021 |
+
altX = e.touches[1].clientX;
|
| 1022 |
startY = e.touches[0].clientY;
|
| 1023 |
+
altY = e.touches[1].clientY;
|
| 1024 |
}
|
| 1025 |
},
|
| 1026 |
{ passive: false },
|
| 1027 |
);
|
| 1028 |
+
canvas.addEventListener(
|
| 1029 |
"touchend",
|
| 1030 |
(e) => {
|
| 1031 |
e.preventDefault();
|
|
|
|
| 1041 |
|
| 1042 |
let lastFrame = 0;
|
| 1043 |
let avgFps = 0;
|
| 1044 |
+
let start = 0;
|
| 1045 |
|
| 1046 |
const frame = (now) => {
|
| 1047 |
let inv = invert4(viewMatrix);
|
|
|
|
| 1049 |
if (activeKeys.includes("ArrowUp")) inv = translate4(inv, 0, 0, 0.1);
|
| 1050 |
if (activeKeys.includes("ArrowDown")) inv = translate4(inv, 0, 0, -0.1);
|
| 1051 |
if (activeKeys.includes("ArrowLeft"))
|
| 1052 |
+
inv = translate4(inv, -0.03, 0, 0);
|
| 1053 |
+
//
|
| 1054 |
if (activeKeys.includes("ArrowRight"))
|
| 1055 |
+
inv = translate4(inv, 0.03, 0, 0);
|
| 1056 |
+
// inv = rotate4(inv, 0.01, 0, 1, 0);
|
| 1057 |
+
if (activeKeys.includes("a")) inv = rotate4(inv, -0.01, 0, 1, 0);
|
| 1058 |
+
if (activeKeys.includes("d")) inv = rotate4(inv, 0.01, 0, 1, 0);
|
| 1059 |
if (activeKeys.includes("q")) inv = rotate4(inv, 0.01, 0, 0, 1);
|
| 1060 |
if (activeKeys.includes("e")) inv = rotate4(inv, -0.01, 0, 0, 1);
|
| 1061 |
if (activeKeys.includes("w")) inv = rotate4(inv, 0.005, 1, 0, 0);
|
|
|
|
| 1067 |
let inv = invert4(defaultViewMatrix);
|
| 1068 |
|
| 1069 |
const t = Math.sin((Date.now() - start) / 5000);
|
| 1070 |
+
inv = translate4(inv, 2.5 * t, 0, 6 * (1 - Math.cos(t)));
|
| 1071 |
+
inv = rotate4(inv, -0.6 * t, 0, 1, 0);
|
| 1072 |
|
| 1073 |
viewMatrix = invert4(inv);
|
| 1074 |
}
|
|
|
|
| 1081 |
|
| 1082 |
let inv2 = invert4(viewMatrix);
|
| 1083 |
inv2[13] -= jumpDelta;
|
| 1084 |
+
inv2 = rotate4(inv2, -0.1 * jumpDelta, 1, 0, 0);
|
| 1085 |
let actualViewMatrix = invert4(inv2);
|
| 1086 |
|
| 1087 |
const viewProj = multiply4(projectionMatrix, actualViewMatrix);
|
|
|
|
| 1097 |
} else {
|
| 1098 |
gl.clear(gl.COLOR_BUFFER_BIT);
|
| 1099 |
document.getElementById("spinner").style.display = "";
|
| 1100 |
+
start = Date.now() + 2000
|
| 1101 |
}
|
| 1102 |
const progress = (100 * vertexCount) / (splatData.length / rowLength);
|
| 1103 |
if (progress < 100) {
|
|
|
|
| 1119 |
cameras = JSON.parse(fr.result);
|
| 1120 |
viewMatrix = getViewMatrix(cameras[0]);
|
| 1121 |
projectionMatrix = getProjectionMatrix(
|
| 1122 |
+
camera.fx / downsample,
|
| 1123 |
+
camera.fy / downsample,
|
| 1124 |
canvas.width,
|
| 1125 |
canvas.height,
|
| 1126 |
);
|
|
|
|
| 1164 |
const preventDefault = (e) => {
|
| 1165 |
e.preventDefault();
|
| 1166 |
e.stopPropagation();
|
| 1167 |
+
};
|
| 1168 |
document.addEventListener("dragenter", preventDefault);
|
| 1169 |
document.addEventListener("dragover", preventDefault);
|
| 1170 |
document.addEventListener("dragleave", preventDefault);
|