@threepipe/plugin-gaussian-splatting 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/worker-dK7pvmNj.js +1569 -0
- package/dist/assets/worker-dK7pvmNj.js.map +1 -0
- package/dist/dependencies.txt +212 -0
- package/dist/gaussian-splats-3d/GaussianSplatsPlugin.d.ts +1 -0
- package/dist/gaussian-splats-3d/GaussianSplatsPlugin.d.ts.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +879 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +876 -0
- package/dist/index.mjs.map +1 -0
- package/dist/three-gaussian-splat/ThreeGaussianSplatPlugin.d.ts +45 -0
- package/dist/three-gaussian-splat/ThreeGaussianSplatPlugin.d.ts.map +1 -0
- package/dist/three-gaussian-splat/cpp-sorter/BufferPool.d.ts +9 -0
- package/dist/three-gaussian-splat/cpp-sorter/BufferPool.d.ts.map +1 -0
- package/dist/three-gaussian-splat/cpp-sorter/SortWorkerManager.d.ts +13 -0
- package/dist/three-gaussian-splat/cpp-sorter/SortWorkerManager.d.ts.map +1 -0
- package/dist/three-gaussian-splat/cpp-sorter/worker.d.ts +18 -0
- package/dist/three-gaussian-splat/cpp-sorter/worker.d.ts.map +1 -0
- package/dist/three-gaussian-splat/geometry/GaussianSplatGeometry.d.ts +25 -0
- package/dist/three-gaussian-splat/geometry/GaussianSplatGeometry.d.ts.map +1 -0
- package/dist/three-gaussian-splat/index.d.ts +22 -0
- package/dist/three-gaussian-splat/index.d.ts.map +1 -0
- package/dist/three-gaussian-splat/loaders/SplatLoader.d.ts +13 -0
- package/dist/three-gaussian-splat/loaders/SplatLoader.d.ts.map +1 -0
- package/dist/three-gaussian-splat/materials/GaussianSplatMaterialExtension.d.ts +28 -0
- package/dist/three-gaussian-splat/materials/GaussianSplatMaterialExtension.d.ts.map +1 -0
- package/dist/three-gaussian-splat/materials/GaussianSplatMaterialPhysical.d.ts +9 -0
- package/dist/three-gaussian-splat/materials/GaussianSplatMaterialPhysical.d.ts.map +1 -0
- package/dist/three-gaussian-splat/materials/GaussianSplatMaterialRaw.d.ts +12 -0
- package/dist/three-gaussian-splat/materials/GaussianSplatMaterialRaw.d.ts.map +1 -0
- package/dist/three-gaussian-splat/materials/GaussianSplatMaterialUnlit.d.ts +9 -0
- package/dist/three-gaussian-splat/materials/GaussianSplatMaterialUnlit.d.ts.map +1 -0
- package/dist/three-gaussian-splat/materials/util.d.ts +3 -0
- package/dist/three-gaussian-splat/materials/util.d.ts.map +1 -0
- package/dist/three-gaussian-splat/mesh/GaussianSplatMesh.d.ts +10 -0
- package/dist/three-gaussian-splat/mesh/GaussianSplatMesh.d.ts.map +1 -0
- package/dist/three-gaussian-splat/shaders/index.d.ts +7 -0
- package/dist/three-gaussian-splat/shaders/index.d.ts.map +1 -0
- package/package.json +34 -0
- package/src/gaussian-splats-3d/GaussianSplatsPlugin.ts +50 -0
- package/src/global.d.ts +40 -0
- package/src/index.ts +5 -0
- package/src/three-gaussian-splat/ThreeGaussianSplatPlugin.css +3 -0
- package/src/three-gaussian-splat/ThreeGaussianSplatPlugin.ts +74 -0
- package/src/three-gaussian-splat/cpp-sorter/BufferPool.ts +30 -0
- package/src/three-gaussian-splat/cpp-sorter/ISort.d.ts +3 -0
- package/src/three-gaussian-splat/cpp-sorter/SortWorkerManager.ts +53 -0
- package/src/three-gaussian-splat/cpp-sorter/build-in-docker.sh +4 -0
- package/src/three-gaussian-splat/cpp-sorter/build.sh +7 -0
- package/src/three-gaussian-splat/cpp-sorter/sort.cpp +107 -0
- package/src/three-gaussian-splat/cpp-sorter/sort.js +16 -0
- package/src/three-gaussian-splat/cpp-sorter/sort.wasm +0 -0
- package/src/three-gaussian-splat/cpp-sorter/watch.sh +9 -0
- package/src/three-gaussian-splat/cpp-sorter/worker.ts +59 -0
- package/src/three-gaussian-splat/geometry/GaussianSplatGeometry.ts +182 -0
- package/src/three-gaussian-splat/index.ts +22 -0
- package/src/three-gaussian-splat/loaders/SplatLoader.ts +51 -0
- package/src/three-gaussian-splat/materials/GaussianSplatMaterialExtension.ts +105 -0
- package/src/three-gaussian-splat/materials/GaussianSplatMaterialPhysical.ts +25 -0
- package/src/three-gaussian-splat/materials/GaussianSplatMaterialRaw.ts +73 -0
- package/src/three-gaussian-splat/materials/GaussianSplatMaterialUnlit.ts +26 -0
- package/src/three-gaussian-splat/materials/util.ts +9 -0
- package/src/three-gaussian-splat/mesh/GaussianSplatMesh.ts +96 -0
- package/src/three-gaussian-splat/shaders/gsplat.main.frag.glsl +18 -0
- package/src/three-gaussian-splat/shaders/gsplat.main.vert.glsl +15 -0
- package/src/three-gaussian-splat/shaders/gsplat.pars.frag.glsl +10 -0
- package/src/three-gaussian-splat/shaders/gsplat.pars.vert.glsl +58 -0
- package/src/three-gaussian-splat/shaders/index.ts +11 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import {FileLoader, ILoader, IMaterial, Loader, LoadingManager} from 'threepipe'
|
|
2
|
+
import {SortWorkerManager, SPLAT_ROW_LENGTH} from '../cpp-sorter/SortWorkerManager'
|
|
3
|
+
import {GaussianSplatGeometry} from '../geometry/GaussianSplatGeometry'
|
|
4
|
+
import {GaussianSplatMesh} from '../mesh/GaussianSplatMesh'
|
|
5
|
+
import {GaussianSplatMaterialUnlit} from '../materials/GaussianSplatMaterialUnlit'
|
|
6
|
+
|
|
7
|
+
export class SplatLoader extends Loader implements ILoader {
|
|
8
|
+
sortWorkerManager: SortWorkerManager
|
|
9
|
+
|
|
10
|
+
materialConstructor = (_: GaussianSplatGeometry): IMaterial|undefined => new GaussianSplatMaterialUnlit()
|
|
11
|
+
|
|
12
|
+
constructor(manager?: LoadingManager) {
|
|
13
|
+
super(manager)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
onGeometryLoad = (_: GaussianSplatGeometry)=>{
|
|
17
|
+
return
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public load(url: string, onLoad?: (data: GaussianSplatMesh) => void, onProgress?: (event: ProgressEvent) => void, onError?: (event: ErrorEvent) => void): void {
|
|
21
|
+
// const path = ( scope.path === '' ) ? LoaderUtils.extractUrlBase( url ) : scope.path;
|
|
22
|
+
const loader = new FileLoader(this.manager)
|
|
23
|
+
loader.setPath(this.path)
|
|
24
|
+
loader.setResponseType('arraybuffer')
|
|
25
|
+
loader.setRequestHeader(this.requestHeader)
|
|
26
|
+
loader.setWithCredentials(this.withCredentials)
|
|
27
|
+
loader.load(url, async(buffer) => {
|
|
28
|
+
try {
|
|
29
|
+
const data = new Uint8Array(buffer as ArrayBuffer)
|
|
30
|
+
const maxSplats = 1000000
|
|
31
|
+
const vertexCount = Math.floor(data.length / SPLAT_ROW_LENGTH)
|
|
32
|
+
const worker = await this.sortWorkerManager.createWorker(data, maxSplats)
|
|
33
|
+
const geometry = new GaussianSplatGeometry(worker, vertexCount, maxSplats, this.onGeometryLoad)
|
|
34
|
+
const mesh = new GaussianSplatMesh(geometry, this.materialConstructor(geometry) as any)
|
|
35
|
+
// const mesh = new GaussianSplatMesh(geometry, new UnlitMaterial() as any)
|
|
36
|
+
mesh.rotation.x = Math.PI
|
|
37
|
+
if (!url.startsWith('blob:') && !url.startsWith('data:'))
|
|
38
|
+
mesh.name = url.split('/').pop()!.split('?')[0]
|
|
39
|
+
onLoad && onLoad(mesh)
|
|
40
|
+
} catch (e) {
|
|
41
|
+
if (onError) onError(e)
|
|
42
|
+
else console.error(e)
|
|
43
|
+
this.manager.itemError(url)
|
|
44
|
+
}
|
|
45
|
+
}, onProgress, onError)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public async loadAsync(url: string, onProgress?: (event: ProgressEvent) => void): Promise<GaussianSplatMesh> {
|
|
49
|
+
return new Promise((resolve, reject) => this.load(url, resolve, onProgress, reject))
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Camera,
|
|
3
|
+
IMaterial,
|
|
4
|
+
MaterialExtension,
|
|
5
|
+
PerspectiveCamera,
|
|
6
|
+
Shader,
|
|
7
|
+
shaderReplaceString,
|
|
8
|
+
Vector2,
|
|
9
|
+
WebGLRenderer,
|
|
10
|
+
} from 'threepipe'
|
|
11
|
+
import {computeFocalLengths} from './util'
|
|
12
|
+
import {gaussianSplatShaders} from '../shaders'
|
|
13
|
+
|
|
14
|
+
export class GaussianSplatMaterialExtension implements MaterialExtension {
|
|
15
|
+
readonly isGaussianSplatMaterialExtension = true
|
|
16
|
+
extraUniforms = {
|
|
17
|
+
viewport: {value: new Vector2()},
|
|
18
|
+
focal: {value: new Vector2()},
|
|
19
|
+
minAlpha: {value: 0.02},
|
|
20
|
+
}
|
|
21
|
+
parsFragmentSnippet = gaussianSplatShaders.pars_frag
|
|
22
|
+
parsVertexSnippet = gaussianSplatShaders.pars_vert
|
|
23
|
+
shaderExtender = (shader: Shader, material: IMaterial) => {
|
|
24
|
+
shader.vertexShader = shaderReplaceString(shader.vertexShader,
|
|
25
|
+
'#include <begin_vertex>',
|
|
26
|
+
'vec3 transformed = vec3( center );')
|
|
27
|
+
if (shader.vertexShader.includes('#include <beginnormal_vertex>')) {
|
|
28
|
+
// todo: get correct normal by rendering to depth and then sampling the normal
|
|
29
|
+
shader.vertexShader = shaderReplaceString(shader.vertexShader,
|
|
30
|
+
'#include <beginnormal_vertex>',
|
|
31
|
+
'\nobjectNormal = vec3(1,0,0);\n', {append: true})
|
|
32
|
+
}
|
|
33
|
+
shader.vertexShader = shaderReplaceString(shader.vertexShader,
|
|
34
|
+
'#include <project_vertex>',
|
|
35
|
+
gaussianSplatShaders.main_vert, {append: true})
|
|
36
|
+
|
|
37
|
+
if (!material.isGBufferMaterial && !material.userData.isGBufferMaterial) {
|
|
38
|
+
shader.fragmentShader = shaderReplaceString(shader.fragmentShader,
|
|
39
|
+
'#include <map_fragment>',
|
|
40
|
+
shaderReplaceString(
|
|
41
|
+
gaussianSplatShaders.main_frag,
|
|
42
|
+
/gl_FragColor\s*=/, // because of minification
|
|
43
|
+
'diffuseColor*='
|
|
44
|
+
), {prepend: true})
|
|
45
|
+
}
|
|
46
|
+
// eslint-disable-next-line no-constant-condition
|
|
47
|
+
if (0)
|
|
48
|
+
shader.fragmentShader = shaderReplaceString(shader.fragmentShader,
|
|
49
|
+
'#include <output_fragment>',
|
|
50
|
+
'\ngl_FragColor=diffuseColor;',
|
|
51
|
+
// '\ngl_FragColor=vec4(reflectedLight.directDiffuse, 1.);',
|
|
52
|
+
// '\ngl_FragColor=vec4(geometryNormal, 1.);',
|
|
53
|
+
{append: true})
|
|
54
|
+
return shader
|
|
55
|
+
}
|
|
56
|
+
isCompatible = (material: IMaterial) =>
|
|
57
|
+
!!material.isPhysicalMaterial ||
|
|
58
|
+
!!material.isUnlitMaterial ||
|
|
59
|
+
!!material.isGBufferMaterial ||
|
|
60
|
+
!!material.userData.isGBufferMaterial
|
|
61
|
+
|
|
62
|
+
setDirty?: () => void
|
|
63
|
+
|
|
64
|
+
private _currentCamera?: PerspectiveCamera | Camera
|
|
65
|
+
private _renderer?: WebGLRenderer
|
|
66
|
+
|
|
67
|
+
public set minAlpha(value: number) {
|
|
68
|
+
this.extraUniforms.minAlpha.value = value
|
|
69
|
+
this.setDirty && this.setDirty()
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
constructor() {
|
|
74
|
+
window.addEventListener('resize', this._refresh)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
dispose() {
|
|
78
|
+
// todo: add again on added to mesh?
|
|
79
|
+
window.removeEventListener('resize', this._refresh)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
update(camera: PerspectiveCamera | Camera, renderer: WebGLRenderer): void {
|
|
83
|
+
if (this._currentCamera === camera && this._renderer === renderer) return
|
|
84
|
+
this._renderer = renderer
|
|
85
|
+
this._currentCamera = camera
|
|
86
|
+
this._refresh()
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
private _refresh = (): void => {
|
|
90
|
+
if (!this._currentCamera) return
|
|
91
|
+
const size = new Vector2()
|
|
92
|
+
this._renderer?.getSize(size)
|
|
93
|
+
const dpr = this._renderer?.getPixelRatio() || 1
|
|
94
|
+
let fov = 75
|
|
95
|
+
let aspect = size.x / size.y
|
|
96
|
+
|
|
97
|
+
if (this._currentCamera instanceof PerspectiveCamera) {
|
|
98
|
+
fov = this._currentCamera.fov
|
|
99
|
+
aspect = this._currentCamera.aspect
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
this.extraUniforms.focal.value = computeFocalLengths(size.x, size.y, fov, aspect, dpr)
|
|
103
|
+
this.extraUniforms.viewport.value = new Vector2(size.x * dpr, size.y * dpr)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import {PhysicalMaterial} from 'threepipe'
|
|
2
|
+
import {GaussianSplatMaterialExtension} from './GaussianSplatMaterialExtension'
|
|
3
|
+
|
|
4
|
+
export class GaussianSplatMaterialPhysical extends PhysicalMaterial {
|
|
5
|
+
readonly isGaussianSplatMaterialPhysical = true
|
|
6
|
+
|
|
7
|
+
gsplatExtension = new GaussianSplatMaterialExtension()
|
|
8
|
+
|
|
9
|
+
constructor() {
|
|
10
|
+
super({
|
|
11
|
+
depthTest: true,
|
|
12
|
+
depthWrite: false,
|
|
13
|
+
transparent: true,
|
|
14
|
+
vertexColors: false,
|
|
15
|
+
})
|
|
16
|
+
// this.userData.renderToGBuffer = true
|
|
17
|
+
// this.userData.renderToDepth = true
|
|
18
|
+
this.registerMaterialExtensions([this.gsplatExtension])
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
dispose() {
|
|
22
|
+
this.gsplatExtension.dispose()
|
|
23
|
+
return super.dispose()
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import {Camera, PerspectiveCamera, ShaderMaterial2, Vector2, WebGLRenderer} from 'threepipe'
|
|
2
|
+
import {computeFocalLengths} from './util'
|
|
3
|
+
import {gaussianSplatShaders} from '../shaders'
|
|
4
|
+
|
|
5
|
+
export class GaussianSplatMaterialRaw extends ShaderMaterial2 {
|
|
6
|
+
private _currentCamera?: PerspectiveCamera | Camera
|
|
7
|
+
private _renderer?: WebGLRenderer
|
|
8
|
+
|
|
9
|
+
readonly isGaussianSplatMaterialRaw = true
|
|
10
|
+
|
|
11
|
+
public set minAlpha(value: number) {
|
|
12
|
+
this.uniforms.minAlpha.value = value
|
|
13
|
+
this.needsUpdate = true
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
constructor() {
|
|
17
|
+
super({
|
|
18
|
+
uniforms: {
|
|
19
|
+
viewport: {value: new Vector2()},
|
|
20
|
+
focal: {value: new Vector2()},
|
|
21
|
+
minAlpha: {value: 0.02},
|
|
22
|
+
},
|
|
23
|
+
fragmentShader: `${gaussianSplatShaders.pars_frag}
|
|
24
|
+
void main () {
|
|
25
|
+
${gaussianSplatShaders.main_frag}
|
|
26
|
+
}`,
|
|
27
|
+
vertexShader: `${gaussianSplatShaders.pars_vert}
|
|
28
|
+
void main () {
|
|
29
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4(center, 1);
|
|
30
|
+
${gaussianSplatShaders.main_vert}
|
|
31
|
+
}`,
|
|
32
|
+
depthTest: true,
|
|
33
|
+
depthWrite: false,
|
|
34
|
+
transparent: true,
|
|
35
|
+
}, true)
|
|
36
|
+
|
|
37
|
+
window.addEventListener('resize', this._refresh)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
private _refresh = (): void => {
|
|
41
|
+
if (!this._currentCamera) return
|
|
42
|
+
|
|
43
|
+
const size = new Vector2()
|
|
44
|
+
this._renderer?.getSize(size)
|
|
45
|
+
const width = size.x
|
|
46
|
+
const height = size.y
|
|
47
|
+
|
|
48
|
+
const dpr = this._renderer?.getPixelRatio() || 1
|
|
49
|
+
|
|
50
|
+
let fov = 75
|
|
51
|
+
let aspect = width / height
|
|
52
|
+
|
|
53
|
+
if (this._currentCamera instanceof PerspectiveCamera) {
|
|
54
|
+
fov = this._currentCamera.fov
|
|
55
|
+
aspect = this._currentCamera.aspect
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
this.uniforms.focal.value = computeFocalLengths(width, height, fov, aspect, dpr)
|
|
59
|
+
this.uniforms.viewport.value = new Vector2(width * dpr, height * dpr)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
dispose() {
|
|
63
|
+
// todo: add again on added to mesh?
|
|
64
|
+
window.removeEventListener('resize', this._refresh)
|
|
65
|
+
return super.dispose()
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
update(camera: PerspectiveCamera | Camera, renderer: WebGLRenderer): void {
|
|
69
|
+
this._renderer = renderer
|
|
70
|
+
this._currentCamera = camera
|
|
71
|
+
this._refresh()
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import {UnlitMaterial} from 'threepipe'
|
|
2
|
+
|
|
3
|
+
import {GaussianSplatMaterialExtension} from './GaussianSplatMaterialExtension'
|
|
4
|
+
|
|
5
|
+
export class GaussianSplatMaterialUnlit extends UnlitMaterial {
|
|
6
|
+
readonly isGaussianSplatMaterialUnlit = true
|
|
7
|
+
gsplatExtension = new GaussianSplatMaterialExtension()
|
|
8
|
+
|
|
9
|
+
constructor() {
|
|
10
|
+
super({
|
|
11
|
+
depthTest: true,
|
|
12
|
+
depthWrite: false,
|
|
13
|
+
transparent: true,
|
|
14
|
+
vertexColors: false,
|
|
15
|
+
})
|
|
16
|
+
// this.userData.renderToGBuffer = true
|
|
17
|
+
// this.userData.renderToDepth = true
|
|
18
|
+
this.registerMaterialExtensions([this.gsplatExtension])
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
dispose() {
|
|
22
|
+
this.gsplatExtension.dispose()
|
|
23
|
+
return super.dispose()
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import {MathUtils, Vector2} from 'threepipe'
|
|
2
|
+
|
|
3
|
+
export const computeFocalLengths = (width: number, height: number, fov: number, aspect: number, dpr: number) => {
|
|
4
|
+
const fovRad = MathUtils.degToRad(fov)
|
|
5
|
+
const fovXRad = 2 * Math.atan(Math.tan(fovRad / 2) * aspect)
|
|
6
|
+
const fy = dpr * height / (2 * Math.tan(fovRad / 2))
|
|
7
|
+
const fx = dpr * width / (2 * Math.tan(fovXRad / 2))
|
|
8
|
+
return new Vector2(fx, fy)
|
|
9
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import {GaussianSplatGeometry} from '../geometry/GaussianSplatGeometry'
|
|
2
|
+
import {Camera, IMaterial, Mesh2, PerspectiveCamera, WebGLRenderer} from 'threepipe'
|
|
3
|
+
import type {GaussianSplatMaterialRaw} from '../materials/GaussianSplatMaterialRaw'
|
|
4
|
+
import {GaussianSplatMaterialUnlit} from '../materials/GaussianSplatMaterialUnlit'
|
|
5
|
+
import {Matrix4, Ray, Raycaster, Sphere, Vector3} from 'three'
|
|
6
|
+
import {GaussianSplatMaterialExtension} from '../materials/GaussianSplatMaterialExtension'
|
|
7
|
+
|
|
8
|
+
export class GaussianSplatMesh extends Mesh2<GaussianSplatGeometry, IMaterial> {
|
|
9
|
+
readonly isGaussianSplatMesh = true
|
|
10
|
+
|
|
11
|
+
constructor(geometry: GaussianSplatGeometry, material: IMaterial) {
|
|
12
|
+
super(geometry, material)
|
|
13
|
+
this.frustumCulled = false
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
public async update(camera: PerspectiveCamera | Camera, renderer: WebGLRenderer) {
|
|
17
|
+
if ((this.material as any as GaussianSplatMaterialRaw)?.isGaussianSplatMaterialRaw) {
|
|
18
|
+
(this.material as any as GaussianSplatMaterialRaw).update(camera, renderer)
|
|
19
|
+
} else if (this.material) {
|
|
20
|
+
const ext =
|
|
21
|
+
(this.material as GaussianSplatMaterialUnlit).gsplatExtension ??
|
|
22
|
+
this.material.materialExtensions.find(e=>
|
|
23
|
+
(e as GaussianSplatMaterialExtension).isGaussianSplatMaterialExtension) as GaussianSplatMaterialExtension
|
|
24
|
+
ext && ext.update(camera, renderer)
|
|
25
|
+
}
|
|
26
|
+
this.updateMatrixWorld(true)
|
|
27
|
+
return this.geometry.update(camera, this.matrixWorld)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
raycast(raycaster: Raycaster, intersects: any[]) {
|
|
31
|
+
|
|
32
|
+
const geometry = this.geometry
|
|
33
|
+
const matrixWorld = this.matrixWorld
|
|
34
|
+
// const threshold = raycaster.params.Points?.threshold ?? .01
|
|
35
|
+
const threshold = .02
|
|
36
|
+
|
|
37
|
+
// Checking boundingSphere distance to ray
|
|
38
|
+
|
|
39
|
+
if (geometry.boundingSphere === null) geometry.computeBoundingSphere()
|
|
40
|
+
|
|
41
|
+
const sphere = new Sphere()
|
|
42
|
+
sphere.copy(geometry.boundingSphere!)
|
|
43
|
+
sphere.applyMatrix4(matrixWorld)
|
|
44
|
+
sphere.radius += threshold
|
|
45
|
+
|
|
46
|
+
if (!raycaster.ray.intersectsSphere(sphere)) return
|
|
47
|
+
|
|
48
|
+
//
|
|
49
|
+
|
|
50
|
+
const inverseMatrix = new Matrix4()
|
|
51
|
+
const ray = new Ray()
|
|
52
|
+
|
|
53
|
+
inverseMatrix.copy(matrixWorld).invert()
|
|
54
|
+
ray.copy(raycaster.ray).applyMatrix4(inverseMatrix)
|
|
55
|
+
|
|
56
|
+
const localThreshold = threshold / ((this.scale.x + this.scale.y + this.scale.z) / 3)
|
|
57
|
+
const localThresholdSq = localThreshold * localThreshold
|
|
58
|
+
|
|
59
|
+
const attributes = geometry.attributes
|
|
60
|
+
const positionAttribute = attributes.center
|
|
61
|
+
|
|
62
|
+
const position = new Vector3()
|
|
63
|
+
for (let i = 0, l = positionAttribute.count; i < l; i++) {
|
|
64
|
+
|
|
65
|
+
position.fromBufferAttribute(positionAttribute, i)
|
|
66
|
+
|
|
67
|
+
const rayPointDistanceSq = ray.distanceSqToPoint(position)
|
|
68
|
+
|
|
69
|
+
if (rayPointDistanceSq < localThresholdSq) {
|
|
70
|
+
|
|
71
|
+
const intersectPoint = new Vector3()
|
|
72
|
+
|
|
73
|
+
ray.closestPointToPoint(position, intersectPoint)
|
|
74
|
+
intersectPoint.applyMatrix4(matrixWorld)
|
|
75
|
+
|
|
76
|
+
const distance = raycaster.ray.origin.distanceTo(intersectPoint)
|
|
77
|
+
|
|
78
|
+
if (distance < raycaster.near || distance > raycaster.far) return
|
|
79
|
+
|
|
80
|
+
intersects.push({
|
|
81
|
+
|
|
82
|
+
distance: distance,
|
|
83
|
+
distanceToRay: Math.sqrt(rayPointDistanceSq),
|
|
84
|
+
point: intersectPoint,
|
|
85
|
+
face: null,
|
|
86
|
+
object: this,
|
|
87
|
+
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
vec2 d = (vCenter - 2.0 * (gl_FragCoord.xy/viewport - vec2(0.5, 0.5))) * viewport * 0.5;
|
|
2
|
+
|
|
3
|
+
float power = -0.5 * (vConic.x * d.x * d.x + vConic.z * d.y * d.y) + vConic.y * d.x * d.y;
|
|
4
|
+
|
|
5
|
+
if (power > 0.0) discard;
|
|
6
|
+
float alpha = min(0.99, vColor.a * exp(power));
|
|
7
|
+
if(alpha < minAlpha) discard;
|
|
8
|
+
|
|
9
|
+
gl_FragColor = vec4(vColor.rgb, alpha);
|
|
10
|
+
//vec2 d = (vCenter - 2.0 * (gl_FragCoord.xy/viewport - vec2(0.5, 0.5))) * viewport * 0.5;
|
|
11
|
+
//
|
|
12
|
+
//float power = -0.5 * (vConic.x * d.x * d.x + vConic.z * d.y * d.y) + vConic.y * d.x * d.y;
|
|
13
|
+
//
|
|
14
|
+
//if (power > 0.0) discard;
|
|
15
|
+
//float alpha = min(0.99, vColor.a * exp(power));
|
|
16
|
+
//if(alpha < minAlpha) discard;
|
|
17
|
+
//
|
|
18
|
+
//diffuseColor *= vec4(vColor.rgb, alpha);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
vec3 cov2d = compute_cov2d(center, scale, quat);
|
|
2
|
+
float det = cov2d.x * cov2d.z - cov2d.y * cov2d.y;
|
|
3
|
+
vec3 conic = vec3(cov2d.z, cov2d.y, cov2d.x) / det;
|
|
4
|
+
float mid = 0.5 * (cov2d.x + cov2d.z);
|
|
5
|
+
float lambda1 = mid + sqrt(max(0.1, mid * mid - det));
|
|
6
|
+
float lambda2 = mid - sqrt(max(0.1, mid * mid - det));
|
|
7
|
+
vec2 v1 = 7.0 * sqrt(lambda1) * normalize(vec2(cov2d.y, lambda1 - cov2d.x));
|
|
8
|
+
vec2 v2 = 7.0 * sqrt(lambda2) * normalize(vec2(-(lambda1 - cov2d.x),cov2d.y));
|
|
9
|
+
|
|
10
|
+
vColor = color;
|
|
11
|
+
vConic = conic;
|
|
12
|
+
vCenter = vec2(gl_Position) / gl_Position.w;
|
|
13
|
+
|
|
14
|
+
vPosition = vec2(vCenter + position.x * (position.y < 0.0 ? v1 : v2) / viewport);
|
|
15
|
+
gl_Position = vec4(vPosition, gl_Position.z / gl_Position.w, 1);
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// https://github.com/vincent-lecrubier-skydio/react-three-fiber-gaussian-splat
|
|
2
|
+
precision mediump float;
|
|
3
|
+
|
|
4
|
+
#ifndef SHADER_NAME // isRawShaderMaterial
|
|
5
|
+
attribute vec3 position;
|
|
6
|
+
uniform mat4 modelViewMatrix;
|
|
7
|
+
uniform mat4 projectionMatrix;
|
|
8
|
+
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]); }
|
|
9
|
+
#endif
|
|
10
|
+
|
|
11
|
+
attribute vec4 color;
|
|
12
|
+
attribute vec4 quat;
|
|
13
|
+
attribute vec3 scale;
|
|
14
|
+
attribute vec3 center;
|
|
15
|
+
|
|
16
|
+
uniform vec2 focal;
|
|
17
|
+
uniform vec2 viewport;
|
|
18
|
+
//uniform vec3 sphereCenter;
|
|
19
|
+
//uniform vec3 planeNormal;
|
|
20
|
+
//uniform float planeDistance;
|
|
21
|
+
|
|
22
|
+
varying vec4 vColor;
|
|
23
|
+
varying vec3 vConic;
|
|
24
|
+
varying vec2 vCenter;
|
|
25
|
+
varying vec2 vPosition;
|
|
26
|
+
//varying float vDistance;
|
|
27
|
+
//varying float vPlaneSide;
|
|
28
|
+
|
|
29
|
+
mat3 compute_cov3d(vec3 scale, vec4 rot) {
|
|
30
|
+
mat3 S = mat3(
|
|
31
|
+
scale.x, 0.0, 0.0,
|
|
32
|
+
0.0, scale.y, 0.0,
|
|
33
|
+
0.0, 0.0, scale.z
|
|
34
|
+
);
|
|
35
|
+
mat3 R = mat3(
|
|
36
|
+
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),
|
|
37
|
+
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),
|
|
38
|
+
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)
|
|
39
|
+
);
|
|
40
|
+
mat3 M = S * R;
|
|
41
|
+
return transpose(M) * M;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
vec3 compute_cov2d(vec3 center, vec3 scale, vec4 rot){
|
|
45
|
+
mat3 Vrk = compute_cov3d(scale, rot);
|
|
46
|
+
vec4 t = modelViewMatrix * vec4(center, 1.0);
|
|
47
|
+
vec2 lims = 1.3 * 0.5 * viewport / focal;
|
|
48
|
+
t.xy = min(lims, max(-lims, t.xy / t.z)) * t.z;
|
|
49
|
+
mat3 J = mat3(
|
|
50
|
+
focal.x / t.z, 0., -(focal.x * t.x) / (t.z * t.z),
|
|
51
|
+
0., focal.y / t.z, -(focal.y * t.y) / (t.z * t.z),
|
|
52
|
+
0., 0., 0.
|
|
53
|
+
);
|
|
54
|
+
mat3 W = transpose(mat3(modelViewMatrix));
|
|
55
|
+
mat3 T = W * J;
|
|
56
|
+
mat3 cov = transpose(T) * transpose(Vrk) * T;
|
|
57
|
+
return vec3(cov[0][0] + 0.3, cov[0][1], cov[1][1] + 0.3);
|
|
58
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import fragmentParsShaderSource from '../shaders/gsplat.pars.frag.glsl'
|
|
2
|
+
import vertexParsShaderSource from '../shaders/gsplat.pars.vert.glsl'
|
|
3
|
+
import vertexShaderSource from '../shaders/gsplat.main.vert.glsl'
|
|
4
|
+
import fragmentShaderSource from '../shaders/gsplat.main.frag.glsl'
|
|
5
|
+
|
|
6
|
+
export const gaussianSplatShaders = {
|
|
7
|
+
main_frag: '\n' + fragmentShaderSource + '\n',
|
|
8
|
+
main_vert: '\n' + vertexShaderSource + '\n',
|
|
9
|
+
pars_frag: fragmentParsShaderSource,
|
|
10
|
+
pars_vert: vertexParsShaderSource,
|
|
11
|
+
}
|