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