antimatter15 commited on
Commit
59df0c8
1 Parent(s): 3695c57

changing camera controls

Browse files
Files changed (3) hide show
  1. README.md +32 -8
  2. index.html +74 -3
  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
- - left and right arrows to rotate left and right
12
- - up and down to move forward and back
13
- - space to jump
 
 
 
 
 
 
14
  - `w`/`s` to tilt camera up/down
15
- - `a`/`d` to strafe left and right
16
- - `q`/`e` to tilt camera left/right
17
- - drag left/right with mouse to rotate left and right
18
- - drag up/down with mouse to move forward and back
19
- - right click and drag to move up/down and left/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>Use mouse or arrow keys to navigate.</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
- <script src="main.js"></script>
 
 
 
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.createElement("canvas");
669
- canvas.width = innerWidth / 2;
670
- canvas.height = innerHeight / 2;
671
- canvas.style.position = "absolute";
672
- canvas.style.top = 0;
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 / 2,
686
- camera.fy / 2,
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(u_focal, new Float32Array([camera.fx / 2, camera.fy / 2]));
 
 
 
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
- inv = translate4(inv, 0, 0, (-5 * dy) / innerHeight);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
863
  viewMatrix = invert4(inv);
864
  },
865
  { passive: false },
866
  );
867
 
868
  let startX, startY, down;
869
- document.addEventListener("mousedown", (e) => {
870
  carousel = false;
871
  e.preventDefault();
872
  startX = e.clientX;
873
  startY = e.clientY;
874
- down = 1;
875
  });
876
- document.addEventListener("contextmenu", (e) => {
877
  carousel = false;
878
  e.preventDefault();
879
  startX = e.clientX;
880
  startY = e.clientY;
881
  down = 2;
882
  });
883
- document.addEventListener("mousemove", (e) => {
884
  e.preventDefault();
885
  if (down == 1) {
886
  let inv = invert4(viewMatrix);
887
- inv = rotate4(
888
- inv,
889
- (-2 * (e.clientX - startX)) / innerWidth,
890
- 0,
891
- 1,
892
- 0,
893
- );
894
- inv = translate4(
895
- inv,
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
- document.addEventListener("mouseup", (e) => {
926
  e.preventDefault();
927
  down = false;
928
  startX = 0;
929
  startY = 0;
930
  });
931
 
932
- document.addEventListener(
 
 
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
- document.addEventListener(
946
  "touchmove",
947
  (e) => {
948
  e.preventDefault();
949
  if (e.touches.length === 1 && down) {
950
  let inv = invert4(viewMatrix);
951
- inv = rotate4(
952
- inv,
953
- (-0.6 * (e.touches[0].clientX - startX)) / innerWidth,
954
- 0,
955
- 1,
956
- 0,
957
- );
958
- inv = translate4(
959
- inv,
960
- 0,
961
- 0,
962
- (25 * (e.touches[0].clientY - startY)) / innerHeight,
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
- document.addEventListener(
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 = Date.now() + 2000;
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 = rotate4(inv, -0.01, 0, 1, 0);
 
997
  if (activeKeys.includes("ArrowRight"))
998
- inv = rotate4(inv, 0.01, 0, 1, 0);
999
- if (activeKeys.includes("a")) inv = translate4(inv, -0.02, 0, 0);
1000
- if (activeKeys.includes("d")) inv = translate4(inv, 0.02, 0, 0);
 
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, 10 * (1 - Math.cos(t)));
1013
- inv = rotate4(inv, -0.4 * t, 0, 1, 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.2 * jumpDelta, 1, 0, 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 / 2,
1064
- camera.fy / 2,
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);