antimatter15 commited on
Commit
db8e2ca
1 Parent(s): e22c65e

improvements to splat quality

Browse files
Files changed (1) hide show
  1. main.js +144 -114
main.js CHANGED
@@ -162,7 +162,7 @@ function getProjectionMatrix(fx, fy, width, height) {
162
  const zfar = 200;
163
  return [
164
  [(2 * fx) / width, 0, 0, 0],
165
- [0, (2 * fy) / height, 0, 0],
166
  [0, 0, zfar / (zfar - znear), 1],
167
  [0, 0, -(zfar * znear) / (zfar - znear), 0],
168
  ].flat();
@@ -307,8 +307,9 @@ function createWorker(self) {
307
  const f_buffer = new Float32Array(buffer);
308
  const u_buffer = new Uint8Array(buffer);
309
 
310
- const quat = new Float32Array(4 * vertexCount);
311
- const scale = new Float32Array(3 * vertexCount);
 
312
  const center = new Float32Array(3 * vertexCount);
313
  const color = new Float32Array(4 * vertexCount);
314
 
@@ -348,10 +349,6 @@ function createWorker(self) {
348
  for (let j = 0; j < vertexCount; j++) {
349
  const i = indexMix[2 * j];
350
 
351
- quat[4 * j + 0] = (u_buffer[32 * i + 28 + 0] - 128) / 128;
352
- quat[4 * j + 1] = (u_buffer[32 * i + 28 + 1] - 128) / 128;
353
- quat[4 * j + 2] = (u_buffer[32 * i + 28 + 2] - 128) / 128;
354
- quat[4 * j + 3] = (u_buffer[32 * i + 28 + 3] - 128) / 128;
355
 
356
  center[3 * j + 0] = f_buffer[8 * i + 0];
357
  center[3 * j + 1] = f_buffer[8 * i + 1];
@@ -362,16 +359,50 @@ function createWorker(self) {
362
  color[4 * j + 2] = u_buffer[32 * i + 24 + 2] / 255;
363
  color[4 * j + 3] = u_buffer[32 * i + 24 + 3] / 255;
364
 
365
- scale[3 * j + 0] = f_buffer[8 * i + 3 + 0];
366
- scale[3 * j + 1] = f_buffer[8 * i + 3 + 1];
367
- scale[3 * j + 2] = f_buffer[8 * i + 3 + 2];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
368
  }
369
 
370
- self.postMessage({ quat, center, color, scale, viewProj }, [
371
- quat.buffer,
372
  center.buffer,
373
  color.buffer,
374
- scale.buffer,
375
  ]);
376
 
377
  // console.timeEnd("sort");
@@ -559,96 +590,94 @@ function createWorker(self) {
559
  }
560
 
561
  const vertexShaderSource = `
562
- precision mediump float;
563
- attribute vec2 position;
564
-
565
- attribute vec4 color;
566
- attribute vec4 quat;
567
- attribute vec3 scale;
568
- attribute vec3 center;
569
-
570
- uniform mat4 projection, view;
571
- uniform vec2 focal;
572
-
573
- varying vec4 vColor;
574
- varying vec3 vConic;
575
- varying vec2 vCenter;
576
- varying vec2 vPosition;
577
- uniform vec2 viewport;
578
-
579
- mat3 transpose(mat3 m) { return mat3(m[0][0], m[1][0], m[2][0], m[0][1], m[1][1], m[2][1], m[0][2], m[1][2], m[2][2]); }
580
-
581
- mat3 compute_cov3d(vec3 scale, vec4 rot) {
582
- mat3 S = mat3(
583
- scale.x, 0.0, 0.0,
584
- 0.0, scale.y, 0.0,
585
- 0.0, 0.0, scale.z
586
- );
587
- mat3 R = mat3(
588
- 1.0 - 2.0 * (rot.z * rot.z + rot.w * rot.w), 2.0 * (rot.y * rot.z - rot.x * rot.w), 2.0 * (rot.y * rot.w + rot.x * rot.z),
589
- 2.0 * (rot.y * rot.z + rot.x * rot.w), 1.0 - 2.0 * (rot.y * rot.y + rot.w * rot.w), 2.0 * (rot.z * rot.w - rot.x * rot.y),
590
- 2.0 * (rot.y * rot.w - rot.x * rot.z), 2.0 * (rot.z * rot.w + rot.x * rot.y), 1.0 - 2.0 * (rot.y * rot.y + rot.z * rot.z)
591
  );
592
- mat3 M = S * R;
593
- return transpose(M) * M;
594
- }
595
 
596
- vec3 compute_cov2d(vec3 center, vec3 scale, vec4 rot){
597
- mat3 Vrk = compute_cov3d(scale, rot);
598
- vec4 t = view * vec4(center, 1.0);
599
- vec2 lims = 1.3 * 0.5 * viewport / focal;
600
- t.xy = min(lims, max(-lims, t.xy / t.z)) * t.z;
 
 
 
 
 
 
 
 
 
 
 
 
601
  mat3 J = mat3(
602
- focal.x / t.z, 0., -(focal.x * t.x) / (t.z * t.z),
603
- 0., focal.y / t.z, -(focal.y * t.y) / (t.z * t.z),
604
  0., 0., 0.
605
  );
 
606
  mat3 W = transpose(mat3(view));
607
  mat3 T = W * J;
608
- mat3 cov = transpose(T) * transpose(Vrk) * T;
609
- return vec3(cov[0][0] + 0.3, cov[0][1], cov[1][1] + 0.3);
610
- }
611
 
612
- void main () {
613
- vec4 camspace = view * vec4(center, 1);
614
- vec4 pos2d = projection * mat4(1,0,0,0,0,-1,0,0,0,0,1,0,0,0,0,1) * camspace;
 
 
 
 
 
 
 
 
615
 
616
- vec3 cov2d = compute_cov2d(center, scale, quat);
617
- float det = cov2d.x * cov2d.z - cov2d.y * cov2d.y;
618
- vec3 conic = vec3(cov2d.z, cov2d.y, cov2d.x) / det;
619
- float mid = 0.5 * (cov2d.x + cov2d.z);
620
- float lambda1 = mid + sqrt(max(0.1, mid * mid - det));
621
- float lambda2 = mid - sqrt(max(0.1, mid * mid - det));
622
- vec2 v1 = 7.0 * sqrt(lambda1) * normalize(vec2(cov2d.y, lambda1 - cov2d.x));
623
- vec2 v2 = 7.0 * sqrt(lambda2) * normalize(vec2(-(lambda1 - cov2d.x),cov2d.y));
624
 
625
  vColor = color;
626
- vConic = conic;
627
- vCenter = vec2(pos2d) / pos2d.w;
628
 
629
- vPosition = vec2(vCenter + position.x * (position.y < 0.0 ? v1 : v2) / viewport);
630
- gl_Position = vec4(vPosition, pos2d.z / pos2d.w, 1);
631
- }
 
 
 
632
  `;
633
 
634
  const fragmentShaderSource = `
635
  precision mediump float;
636
 
637
- varying vec4 vColor;
638
- varying vec3 vConic;
639
- varying vec2 vCenter;
640
- uniform vec2 viewport;
641
- uniform vec2 focal;
642
-
643
- void main () {
644
- vec2 d = (vCenter - 2.0 * (gl_FragCoord.xy/viewport - vec2(0.5, 0.5))) * viewport * 0.5;
645
- float power = -0.5 * (vConic.x * d.x * d.x + vConic.z * d.y * d.y) - vConic.y * d.x * d.y;
646
- if (power > 0.0) discard;
647
- float alpha = min(0.99, vColor.a * exp(power));
648
- if(alpha < 0.02) discard;
649
 
650
- gl_FragColor = vec4(alpha * vColor.rgb, alpha);
651
- }
 
 
 
 
652
  `;
653
 
654
  let defaultViewMatrix = [
@@ -682,7 +711,9 @@ async function main() {
682
  const reader = req.body.getReader();
683
  let splatData = new Uint8Array(req.headers.get("content-length"));
684
 
685
- const downsample = splatData.length / rowLength > 500000 ? 2 : 1;
 
 
686
  console.log(splatData.length / rowLength, downsample);
687
 
688
  const worker = new Worker(
@@ -766,7 +797,7 @@ async function main() {
766
  gl.uniformMatrix4fv(u_view, false, viewMatrix);
767
 
768
  // positions
769
- const triangleVertices = new Float32Array([1, -1, 1, 1, -1, 1, -1, -1]);
770
  const vertexBuffer = gl.createBuffer();
771
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
772
  gl.bufferData(gl.ARRAY_BUFFER, triangleVertices, gl.STATIC_DRAW);
@@ -795,25 +826,20 @@ async function main() {
795
  gl.vertexAttribPointer(a_color, 4, gl.FLOAT, false, 0, 0);
796
  ext.vertexAttribDivisorANGLE(a_color, 1); // Use the extension here
797
 
798
- // quat
799
- const quatBuffer = gl.createBuffer();
800
- // gl.bindBuffer(gl.ARRAY_BUFFER, quatBuffer);
801
- // gl.bufferData(gl.ARRAY_BUFFER, quat, gl.STATIC_DRAW);
802
- const a_quat = gl.getAttribLocation(program, "quat");
803
- gl.enableVertexAttribArray(a_quat);
804
- gl.bindBuffer(gl.ARRAY_BUFFER, quatBuffer);
805
- gl.vertexAttribPointer(a_quat, 4, gl.FLOAT, false, 0, 0);
806
- ext.vertexAttribDivisorANGLE(a_quat, 1); // Use the extension here
807
-
808
- // scale
809
- const scaleBuffer = gl.createBuffer();
810
- // gl.bindBuffer(gl.ARRAY_BUFFER, scaleBuffer);
811
- // gl.bufferData(gl.ARRAY_BUFFER, scale, gl.STATIC_DRAW);
812
- const a_scale = gl.getAttribLocation(program, "scale");
813
- gl.enableVertexAttribArray(a_scale);
814
- gl.bindBuffer(gl.ARRAY_BUFFER, scaleBuffer);
815
- gl.vertexAttribPointer(a_scale, 3, gl.FLOAT, false, 0, 0);
816
- ext.vertexAttribDivisorANGLE(a_scale, 1); // Use the extension here
817
 
818
  let lastProj = []
819
  let lastData
@@ -830,11 +856,11 @@ async function main() {
830
  document.body.appendChild(link);
831
  link.click();
832
  } else {
833
- let { quat, scale, center, color, viewProj } = e.data;
834
  lastData = e.data;
835
 
836
  lastProj = viewProj
837
- vertexCount = quat.length / 4;
838
 
839
  gl.bindBuffer(gl.ARRAY_BUFFER, centerBuffer);
840
  gl.bufferData(gl.ARRAY_BUFFER, center, gl.STATIC_DRAW);
@@ -842,11 +868,13 @@ async function main() {
842
  gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
843
  gl.bufferData(gl.ARRAY_BUFFER, color, gl.STATIC_DRAW);
844
 
845
- gl.bindBuffer(gl.ARRAY_BUFFER, quatBuffer);
846
- gl.bufferData(gl.ARRAY_BUFFER, quat, gl.STATIC_DRAW);
 
 
 
 
847
 
848
- gl.bindBuffer(gl.ARRAY_BUFFER, scaleBuffer);
849
- gl.bufferData(gl.ARRAY_BUFFER, scale, gl.STATIC_DRAW);
850
  }
851
  };
852
 
@@ -1179,8 +1207,10 @@ async function main() {
1179
 
1180
  if (vertexCount > 0) {
1181
  document.getElementById("spinner").style.display = "none";
 
1182
  gl.uniformMatrix4fv(u_view, false, actualViewMatrix);
1183
- ext.drawArraysInstancedANGLE(gl.TRIANGLE_STRIP, 0, 4, vertexCount);
 
1184
  } else {
1185
  gl.clear(gl.COLOR_BUFFER_BIT);
1186
  document.getElementById("spinner").style.display = "";
@@ -1190,7 +1220,7 @@ async function main() {
1190
  if (progress < 100) {
1191
  document.getElementById("progress").style.width = progress + "%";
1192
  } else {
1193
- document.getElementById("progress").style.display = "none";
1194
  }
1195
  fps.innerText = Math.round(avgFps) + " fps";
1196
  lastFrame = now;
 
162
  const zfar = 200;
163
  return [
164
  [(2 * fx) / width, 0, 0, 0],
165
+ [0, -(2 * fy) / height, 0, 0],
166
  [0, 0, zfar / (zfar - znear), 1],
167
  [0, 0, -(zfar * znear) / (zfar - znear), 0],
168
  ].flat();
 
307
  const f_buffer = new Float32Array(buffer);
308
  const u_buffer = new Uint8Array(buffer);
309
 
310
+ const covA = new Float32Array(3 * vertexCount);
311
+ const covB = new Float32Array(3 * vertexCount);
312
+
313
  const center = new Float32Array(3 * vertexCount);
314
  const color = new Float32Array(4 * vertexCount);
315
 
 
349
  for (let j = 0; j < vertexCount; j++) {
350
  const i = indexMix[2 * j];
351
 
 
 
 
 
352
 
353
  center[3 * j + 0] = f_buffer[8 * i + 0];
354
  center[3 * j + 1] = f_buffer[8 * i + 1];
 
359
  color[4 * j + 2] = u_buffer[32 * i + 24 + 2] / 255;
360
  color[4 * j + 3] = u_buffer[32 * i + 24 + 3] / 255;
361
 
362
+ let scale = [ f_buffer[8 * i + 3 + 0], f_buffer[8 * i + 3 + 1], f_buffer[8 * i + 3 + 2]];
363
+ let rot = [(u_buffer[32 * i + 28 + 0] - 128) / 128, (u_buffer[32 * i + 28 + 1] - 128) / 128, (u_buffer[32 * i + 28 + 2] - 128) / 128, (u_buffer[32 * i + 28 + 3] - 128) / 128]
364
+
365
+ const R = [
366
+ 1.0 - 2.0 * (rot[2] * rot[2] + rot[3] * rot[3]),
367
+ 2.0 * (rot[1] * rot[2] + rot[0] * rot[3]),
368
+ 2.0 * (rot[1] * rot[3] - rot[0] * rot[2]),
369
+
370
+ 2.0 * (rot[1] * rot[2] - rot[0] * rot[3]),
371
+ 1.0 - 2.0 * (rot[1] * rot[1] + rot[3] * rot[3]),
372
+ 2.0 * (rot[2] * rot[3] + rot[0] * rot[1]),
373
+
374
+ 2.0 * (rot[1] * rot[3] + rot[0] * rot[2]),
375
+ 2.0 * (rot[2] * rot[3] - rot[0] * rot[1]),
376
+ 1.0 - 2.0 * (rot[1] * rot[1] + rot[2] * rot[2]),
377
+ ];
378
+
379
+ // Compute the matrix product of S and R (M = S * R)
380
+ const M = [
381
+ scale[0] * R[0],
382
+ scale[0] * R[1],
383
+ scale[0] * R[2],
384
+ scale[1] * R[3],
385
+ scale[1] * R[4],
386
+ scale[1] * R[5],
387
+ scale[2] * R[6],
388
+ scale[2] * R[7],
389
+ scale[2] * R[8],
390
+ ];
391
+
392
+
393
+ covA[3 * j + 0] = M[0] * M[0] + M[3] * M[3] + M[6] * M[6];
394
+ covA[3 * j + 1] = M[0] * M[1] + M[3] * M[4] + M[6] * M[7];
395
+ covA[3 * j + 2] = M[0] * M[2] + M[3] * M[5] + M[6] * M[8];
396
+ covB[3 * j + 0] = M[1] * M[1] + M[4] * M[4] + M[7] * M[7];
397
+ covB[3 * j + 1] = M[1] * M[2] + M[4] * M[5] + M[7] * M[8];
398
+ covB[3 * j + 2] = M[2] * M[2] + M[5] * M[5] + M[8] * M[8];
399
  }
400
 
401
+ self.postMessage({ covA, center, color, covB, viewProj }, [
402
+ covA.buffer,
403
  center.buffer,
404
  color.buffer,
405
+ covB.buffer,
406
  ]);
407
 
408
  // console.timeEnd("sort");
 
590
  }
591
 
592
  const vertexShaderSource = `
593
+ precision mediump float;
594
+ attribute vec2 position;
595
+
596
+ attribute vec4 color;
597
+ attribute vec3 center;
598
+ attribute vec3 covA;
599
+ attribute vec3 covB;
600
+
601
+ uniform mat4 projection, view;
602
+ uniform vec2 focal;
603
+ uniform vec2 viewport;
604
+
605
+ varying vec4 vColor;
606
+ varying vec2 vPosition;
607
+
608
+ mat3 transpose(mat3 m) {
609
+ return mat3(
610
+ m[0][0], m[1][0], m[2][0],
611
+ m[0][1], m[1][1], m[2][1],
612
+ m[0][2], m[1][2], m[2][2]
 
 
 
 
 
 
 
 
 
613
  );
614
+ }
 
 
615
 
616
+ void main () {
617
+ vec4 camspace = view * vec4(center, 1);
618
+ vec4 pos2d = projection * camspace;
619
+
620
+ float bounds = 1.2 * pos2d.w;
621
+ if (pos2d.z < -pos2d.w || pos2d.x < -bounds || pos2d.x > bounds
622
+ || pos2d.y < -bounds || pos2d.y > bounds) {
623
+ gl_Position = vec4(0.0, 0.0, 2.0, 1.0);
624
+ return;
625
+ }
626
+
627
+ mat3 Vrk = mat3(
628
+ covA.x, covA.y, covA.z,
629
+ covA.y, covB.x, covB.y,
630
+ covA.z, covB.y, covB.z
631
+ );
632
+
633
  mat3 J = mat3(
634
+ focal.x / camspace.z, 0., -(focal.x * camspace.x) / (camspace.z * camspace.z),
635
+ 0., -focal.y / camspace.z, (focal.y * camspace.y) / (camspace.z * camspace.z),
636
  0., 0., 0.
637
  );
638
+
639
  mat3 W = transpose(mat3(view));
640
  mat3 T = W * J;
641
+ mat3 cov = transpose(T) * Vrk * T;
642
+
643
+ vec2 vCenter = vec2(pos2d) / pos2d.w;
644
 
645
+ float diagonal1 = cov[0][0] + 0.3;
646
+ float offDiagonal = cov[0][1];
647
+ float diagonal2 = cov[1][1] + 0.3;
648
+
649
+ float mid = 0.5 * (diagonal1 + diagonal2);
650
+ float radius = length(vec2((diagonal1 - diagonal2) / 2.0, offDiagonal));
651
+ float lambda1 = mid + radius;
652
+ float lambda2 = max(mid - radius, 0.1);
653
+ vec2 diagonalVector = normalize(vec2(offDiagonal, lambda1 - diagonal1));
654
+ vec2 v1 = min(sqrt(2.0 * lambda1), 1024.0) * diagonalVector;
655
+ vec2 v2 = min(sqrt(2.0 * lambda2), 1024.0) * vec2(diagonalVector.y, -diagonalVector.x);
656
 
 
 
 
 
 
 
 
 
657
 
658
  vColor = color;
659
+ vPosition = position;
 
660
 
661
+ gl_Position = vec4(
662
+ vCenter
663
+ + position.x * v1 / viewport * 2.0
664
+ + position.y * v2 / viewport * 2.0, 0.0, 1.0);
665
+
666
+ }
667
  `;
668
 
669
  const fragmentShaderSource = `
670
  precision mediump float;
671
 
672
+ varying vec4 vColor;
673
+ varying vec2 vPosition;
 
 
 
 
 
 
 
 
 
 
674
 
675
+ void main () {
676
+ float A = -dot(vPosition, vPosition);
677
+ if (A < -4.0) discard;
678
+ float B = exp(A) * vColor.a;
679
+ gl_FragColor = vec4(B * vColor.rgb, B);
680
+ }
681
  `;
682
 
683
  let defaultViewMatrix = [
 
711
  const reader = req.body.getReader();
712
  let splatData = new Uint8Array(req.headers.get("content-length"));
713
 
714
+ const downsample = splatData.length / rowLength > 500000 ? 1 : 1 / devicePixelRatio;
715
+ // const downsample = 1 / devicePixelRatio;
716
+ // const downsample = 1;
717
  console.log(splatData.length / rowLength, downsample);
718
 
719
  const worker = new Worker(
 
797
  gl.uniformMatrix4fv(u_view, false, viewMatrix);
798
 
799
  // positions
800
+ const triangleVertices = new Float32Array([-2, -2, 2, -2, 2, 2, -2, 2]);
801
  const vertexBuffer = gl.createBuffer();
802
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
803
  gl.bufferData(gl.ARRAY_BUFFER, triangleVertices, gl.STATIC_DRAW);
 
826
  gl.vertexAttribPointer(a_color, 4, gl.FLOAT, false, 0, 0);
827
  ext.vertexAttribDivisorANGLE(a_color, 1); // Use the extension here
828
 
829
+ // cov
830
+ const covABuffer = gl.createBuffer();
831
+ const a_covA = gl.getAttribLocation(program, "covA");
832
+ gl.enableVertexAttribArray(a_covA);
833
+ gl.bindBuffer(gl.ARRAY_BUFFER, covABuffer);
834
+ gl.vertexAttribPointer(a_covA, 3, gl.FLOAT, false, 0, 0);
835
+ ext.vertexAttribDivisorANGLE(a_covA, 1); // Use the extension here
836
+
837
+ const covBBuffer = gl.createBuffer();
838
+ const a_covB = gl.getAttribLocation(program, "covB");
839
+ gl.enableVertexAttribArray(a_covB);
840
+ gl.bindBuffer(gl.ARRAY_BUFFER, covBBuffer);
841
+ gl.vertexAttribPointer(a_covB, 3, gl.FLOAT, false, 0, 0);
842
+ ext.vertexAttribDivisorANGLE(a_covB, 1); // Use the extension here
 
 
 
 
 
843
 
844
  let lastProj = []
845
  let lastData
 
856
  document.body.appendChild(link);
857
  link.click();
858
  } else {
859
+ let { covA, covB, center, color, viewProj } = e.data;
860
  lastData = e.data;
861
 
862
  lastProj = viewProj
863
+ vertexCount = center.length / 3;
864
 
865
  gl.bindBuffer(gl.ARRAY_BUFFER, centerBuffer);
866
  gl.bufferData(gl.ARRAY_BUFFER, center, gl.STATIC_DRAW);
 
868
  gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
869
  gl.bufferData(gl.ARRAY_BUFFER, color, gl.STATIC_DRAW);
870
 
871
+
872
+ gl.bindBuffer(gl.ARRAY_BUFFER, covABuffer);
873
+ gl.bufferData(gl.ARRAY_BUFFER, covA, gl.STATIC_DRAW);
874
+
875
+ gl.bindBuffer(gl.ARRAY_BUFFER, covBBuffer);
876
+ gl.bufferData(gl.ARRAY_BUFFER, covB, gl.STATIC_DRAW);
877
 
 
 
878
  }
879
  };
880
 
 
1207
 
1208
  if (vertexCount > 0) {
1209
  document.getElementById("spinner").style.display = "none";
1210
+ // console.time('render')
1211
  gl.uniformMatrix4fv(u_view, false, actualViewMatrix);
1212
+ ext.drawArraysInstancedANGLE(gl.TRIANGLE_FAN, 0, 4, vertexCount);
1213
+ // console.timeEnd('render')
1214
  } else {
1215
  gl.clear(gl.COLOR_BUFFER_BIT);
1216
  document.getElementById("spinner").style.display = "";
 
1220
  if (progress < 100) {
1221
  document.getElementById("progress").style.width = progress + "%";
1222
  } else {
1223
+ document.getElementById("progress").style.display = "none";
1224
  }
1225
  fps.innerText = Math.round(avgFps) + " fps";
1226
  lastFrame = now;