Coder Social home page Coder Social logo

lumalabs / luma-web-examples Goto Github PK

View Code? Open in Web Editor NEW
258.0 12.0 21.0 6.64 MB

Luma Web Examples, use lumalabs.ai captures directly in your three.js or other WebGL projects!

Home Page: https://lumalabs.ai/luma-web-library

License: MIT License

HTML 12.77% TypeScript 79.64% Shell 7.59%
gaussian-splatting three webgl webgl2

luma-web-examples's Introduction

luma-logo Luma WebGL Library

luma-web is a npm package for rendering photoreal interactive scenes captured by the Luma app. It includes LumaSplatsWebGL, which is a WebGL-only gaussian splatting implementation designed to be integrated with 3D frameworks, and LumaSplatsThree, which is a Three.js implementation that uses LumaSplatsWebGL under the hood. For these examples we'll use Three.js.

Request features and report bugs on our github-logo GitHub repo

Contents

Getting Started

hello-world-demo

The simplest way to get started is to create a .html file and load the library from a CDN. Here we load three.js and the luma library and setup a minimal scene with mouse controls. Copy and paste this into a file named index.html and open it in your browser (no server needed).

minimal.html

<canvas></canvas>
<script type="importmap">
{
	"imports": {
		"three": "https://unpkg.com/[email protected]/build/three.module.js",
		"three/addons/": "https://unpkg.com/[email protected]/examples/jsm/",
		"@lumaai/luma-web": "https://unpkg.com/@lumaai/[email protected]/dist/library/luma-web.module.js"
	}
}
</script>
<script type="module">
import { WebGLRenderer, PerspectiveCamera, Scene } from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { LumaSplatsThree } from '@lumaai/luma-web';

let canvas = document.querySelector('canvas');

let renderer = new WebGLRenderer({
	canvas: canvas,
	antialias: false
});

renderer.setSize(window.innerWidth, window.innerHeight, false);

let scene = new Scene();

let camera = new PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 2;

let controls = new OrbitControls(camera, canvas);
controls.enableDamping = true;

let splat = new LumaSplatsThree({
	source: 'https://lumalabs.ai/capture/d80d4876-cf71-4b8a-8b5b-49ffac44cd4a'
});
scene.add(splat);

renderer.setAnimationLoop(() => {
	controls.update();
	renderer.render(scene, camera);
});
</script>

Alternatively you can install the library from npm:

npm install @lumaai/luma-web

Usage

Import the LumaSplatsThree class:

import { LumaSplatsThree } from "@lumaai/luma-web";

Then create an instance of LumaSplatsThree with a splat source, and add it to your scene.

source can be either of:

  • URL to a capture on lumalabs.ai
  • path to a luma splats file or folder containing a luma splats artifacts

DemoHelloWorld.ts

let splats = new LumaSplatsThree({
	source: 'https://lumalabs.ai/capture/ca9ea966-ca24-4ec1-ab0f-af665cb546ff',
	// controls the particle entrance animation
	particleRevealEnabled: true,
});

scene.add(splats);

Splats will integrate with the three.js rendering pipeline and interact with other objects via depth testing. However, splats do not currently write to the depth buffer themselves.

Performance tips

  • Use antialias: false when creating the renderer to disable MSAA on the canvas. Splats are already anti-aliased and the high instance count in splats is expensive to render with MSAA
  • Set enableThreeShaderIntegration: false to disable integration with the three.js rendering pipeline. This will disable features like fog and tone mapping, but will improve performance

Background Removal

background-removal-demo

Luma scenes can include multiple semantic layers. By default, all layers are rendered. To filter layers, use the semanticsMask property. This is a bit mask, so for example, to show only the foreground layer, set semanticsMask = LumaSplatsSemantics.FOREGROUND. To show both foreground and background, set semanticsMask = LumaSplatsSemantics.FOREGROUND | LumaSplatsSemantics.BACKGROUND

DemoBackgroundRemoval.ts

import { LumaSplatsSemantics, LumaSplatsThree } from "@lumaai/luma-web";

let splats = new LumaSplatsThree({
	source: 'https://lumalabs.ai/capture/1b5f3e33-3900-4398-8795-b585ae13fd2d',
});

scene.add(splats);

// filter splats to only show foreground layers
splats.semanticsMask = LumaSplatsSemantics.FOREGROUND;

Three Fog

three.js-fog-demo

Luma splats integrate with the three.js rendering pipeline including features like tone mapping, color spaces and fog. Ensure enableThreeShaderIntegration is set to true (the default) and set the scene fog

DemoFog.ts

scene.fog = new FogExp2(new Color(0xe0e1ff).convertLinearToSRGB(), 0.15);
scene.background = scene.fog.color;

Scene Lighting

scene-lighting-demo

It's possible to illuminate three.js scenes with Luma splats. To do so, we can render a cubemap of the splats and use it as the scene environment. This is done by calling captureCubemap() on the splats object. We first wait for the splats to fully load before capturing the cubemap. To ensure the splats are fully rendered at the time of capture, we disable the loading animation.

DemoLighting.ts

let splats = new LumaSplatsThree({
	source: 'https://lumalabs.ai/capture/4da7cf32-865a-4515-8cb9-9dfc574c90c2',

	// disable loading animation so model is fully rendered after onLoad
	loadingAnimationEnabled: false,
});

splats.onLoad = () => {
	splats.captureCubemap(renderer).then((capturedTexture) => {
		scene.environment = capturedTexture;
		scene.background = capturedTexture;
		scene.backgroundBlurriness = 0.5;
	});
}

Custom Shaders

custom-shaders-demo

You can inject code into the splat shaders to customize them. To do this, call setShaderHooks({ ... }) on your splat and provide GLSL functions, uniforms and globals to override default behavior. For example, in this demo we apply a transform matrix to each splat by setting the vertex shader hook getSplatTransform. It generates a transform matrix for time-varying sinusoidal offset to the y coordinate.

The syntax for shader hook function is a GLSL function without a function name. The GLSL function arguments and return are given as documentation on the shader hook fields (see below).

DemoCustomShaders.ts

splats.setShaderHooks({
	vertexShaderHooks: {
		additionalUniforms: {
			time_s: ['float', uniformTime],
		},

		getSplatTransform: /*glsl*/`
			(vec3 position, uint layersBitmask) {
				// sin wave on x-axis
				float x = 0.;
				float z = 0.;
				float y = sin(position.x * 1.0 + time_s) * 0.1;
				return mat4(
					1., 0., 0., 0,
					0., 1., 0., 0,
					0., 0., 1., 0,
					x,  y,  z, 1.
				);
			}
		`,
	}
});

Shader Hook API

type LumaShaderHooks = {

	/** Hooks added to the vertex shader */
	vertexShaderHooks?: {
		additionalUniforms?: { [name: string]: [UniformTypeGLSL, { value: any }] },

		/** Inject into global space (for example, to add a varying) */
		additionalGlobals?: string,

		/**
		 * Example `(vec3 splatPosition, uint layersBitmask) { return mat4(1.); }`
		 * @param {vec3} splatPosition, object-space
		 * @param {uint} layersBitmask, bit mask of layers, where bit 0 is background and bit 1 is foreground
		 * @returns {mat4} per-splat local transform
		 */
		getSplatTransform?: string,

		/**
		 * Executed at the end of the main function after gl_Position is set
		 * 
		 * Example `() {
		 *  vPosition = gl_Position;
		 * }`
		 * @returns {void}
		 */
		onMainEnd?: string,

		/**
		 * Example `(vec4 splatColor, vec3 splatPosition) { return pow(splatColor.rgb, vec3(2.2), splatColor.a); }`
		 * Use `gl_Position` is available
		 * @param {vec4} splatColor, default splat color
		 * @param {vec3} splatPosition, object-space
		 * @param {uint} layersBitmask, bit mask of layers, where bit 0 is background and bit 1 is foreground
		 * @returns {vec4} updated splat color
		 */
		getSplatColor?: string,
	},

	/** Hooks added to the fragment shader */
	fragmentShaderHooks?: {
		additionalUniforms?: { [name: string]: [UniformTypeGLSL, { value: any }] },

		/** Inject into global space (for example, to add a varying) */
		additionalGlobals?: string,

		/**
		 * Example `(vec4 fragColor) { return tonemap(fragColor); }`
		 * @param {vec4} fragColor, default fragment color
		 * @returns {vec4} updated fragment color
		 */
		getFragmentColor?: string,
	}
}

React Three Fiber

react-three-fiber-demo

Luma splats can be used with React Three Fiber, a React renderer for Three.js. To do so, we need to extend R3F to include the LumaSplatsThree class. This is done by calling extend with the class and a name (in this case LumaSplats which will be used as the component name). If using TypeScript, we also need to declare the component type.

DemoReactThreeFiber.tsx

import { Object3DNode, extend } from '@react-three/fiber';
import { LumaSplatsThree, LumaSplatsSemantics } from "@lumaai/luma-web";

// Make LumaSplatsThree available to R3F
extend( { LumaSplats: LumaSplatsThree } );

// For typeScript support:
declare module '@react-three/fiber' {
  interface ThreeElements {
    lumaSplats: Object3DNode<LumaSplatsThree, typeof LumaSplatsThree>
  }
}

function Scene() {
	return <lumaSplats
		semanticsMask={LumaSplatsSemantics.FOREGROUND}
		source='https://lumalabs.ai/capture/822bac8d-70d6-404e-aaae-f89f46672c67'
		position={[-1, 0, 0]}
		scale={0.5}
	/>
}

Transmission

transmission-demo

Splats can be used in combination with three.js transmission effects, however some care should be taken to make this work. Splats are considered transparent materials in three.js which means by default they're not rendered in the transmissive pass, so initially you won't see your splats in transmissive materials. To fix we set splats.material.transparent = false;.

In this example, we draw two splat scenes, one inside a refractive globe and the other outside. To make this work, we want the inner splat scene to only render to the transmission buffer and the outer to the canvas. We do this by checking the render target before rendering and selectively disabling.

DemoTransmission.ts

// inner splat
let globeSplats = new LumaSplatsThree({
	// Chateau de Menthon - Annecy
	source: 'https://lumalabs.ai/capture/da82625c-9c8d-4d05-a9f7-3367ecab438c',
	enableThreeShaderIntegration: true,
	onBeforeRender: (renderer) => {
		// disable MSAA on render targets (in this case the transmission render target)
		// this improves splatting performance
		let target = renderer.getRenderTarget();
		if (target) {
			target.samples = 0;
		}

		// only render in targets and not the canvas
		globeSplats.preventDraw = target == null;
	}
});

// disable transparency so the renderer considers it an opaque object
// opaque objects are rendered in the transmission pass (whereas transparent objects are not)
globeSplats.material.transparent = false;

scene.add(globeSplats);

// outer splat
let environmentSplats = new LumaSplatsThree({
	// Arosa Hörnli - Switzerland
	source: 'https://lumalabs.ai/capture/4da7cf32-865a-4515-8cb9-9dfc574c90c2',
	// disable animation for lighting capture
	loadingAnimationEnabled: false,
	// disable three.js shader integration for performance
	enableThreeShaderIntegration: false,
});

scene.add(environmentSplats);

// add a refractive transmissive sphere
let glassSphere = new Mesh(
	new SphereGeometry(1, 32, 32),
	new MeshPhysicalMaterial({
		roughness: 0,
		metalness: 0,
		transmission: 1,
		ior: 1.341,
		thickness: 1.52,
		envMapIntensity: 1.2,
		clearcoat: 1,
		side: FrontSide,
		transparent: true,
	})
);

scene.add(glassSphere);

VR

vr-demo

Viewing your splats in VR is as simple as enabling XR in three.js and adding a VR button. View this demo with a VR headset (or through a headset browser) and click "Enter VR"! It will work best on PC VR, standalone VR tends to struggle with splats presently

DemoVR.ts

import { VRButton } from "three/examples/jsm/webxr/VRButton.js";

renderer.xr.enabled = true;

let vrButton = VRButton.createButton(renderer);

document.body.appendChild(vrButton);

let splats = new LumaSplatsThree({
	// Kind Humanoid @RyanHickman
	source: 'https://lumalabs.ai/capture/83e9aae8-7023-448e-83a6-53ccb377ec86',
});

scene.add(splats);

luma-web-examples's People

Contributors

haxiomic avatar lovelovetrb avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

luma-web-examples's Issues

User-defined Masks for Splat Points

Is there support for user-defined masks within the LumaWebGL renderer? i.e. can we use a given mesh to define a group of points in the splat that are part of the same group & then toggle the visibility of that group in a Three.js scene?

Editing splat created from lumalabs app

I've been experimenting with integrating splats from the lumalabs app into a threejs experience, and it's amazing! I found a splat editor online and would love to use this to edit my splats. It looks like I need to upload a file, and just provide a link to the capture as in the webgl library. I was wondering if there's a way to get the file from the luma app downloaded so I can edit it before importing it to my threejs app?

Thanks!

raycaster

how would one go about raycasting the splat?

Uncaught TypeError: Cannot read properties of undefined (reading 'equals')

Hello.
I am enjoying using Luma AI.
I am posting this issue because I have tried the WebGL library for Luma AI, but I have encountered some problems.

I wrote code based on three.js and the Luma WebGL example, but when I ran the code, nothing was rendered in the browser and I got a lot of errors in the console on the browser.
Below is the full text of the errors.

Uncaught TypeError: Cannot read properties of undefined (reading 'equals')
    at setBlending (three.module.js:23355:19)
    at Object.setMaterial (three.module.js:23382:6)
    at WebGLRenderer.renderBufferDirect (three.module.js:29149:10)
    at renderObject (three.module.js:29945:11)
    at renderObjects (three.module.js:29914:6)
    at renderScene (three.module.js:29777:41)
    at WebGLRenderer.render (three.module.js:29593:5)
    at animate (main.js:31:12)

I think it might be a Luma AI WebGL issue, since the problem did not occur with the normal three.js example. Any advice would be appreciated.

Here is some information about my environment

Code

code is here

package.json

{
  "name": "luma-app-vanila",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "devDependencies": {
    "vite": "^5.0.0"
  },
  "dependencies": {
    "@lumaai/luma-web": "^0.1.14",
    "three": "^0.159.0"
  }
}

Node.js version

$ bun run node -v
v20.5.1

Package Management Tools

$ bun --version
1.0.7

LumaSplatsThree git version?

(This information is output to the browser console)

LumaSplatsThree git version #8f3367e

Can not download Capture by Calling API

Hi all,

I just successfully created capture by calling Luma AI API and got it shown in my Google browser through given url, but I do not find any api call can help with downloading this capture to my local machine, is there any api doc can assist in that?

Thanks!

Luma is slowing my website drastically

Hello, I am trying to play around with the new luma library. However, when I try to load a model the fps drops a lot and the website pretty much becomes unusable. I have the following code:

import { Object3DNode, extend } from '@react-three/fiber';
import { LumaSplatsThree } from "@lumaai/luma-web";

// Make LumaSplatsThree available to R3F
extend( { LumaSplats: LumaSplatsThree } );

declare module '@react-three/fiber' {
  interface ThreeElements {
    lumaSplats: Object3DNode<LumaSplatsThree, typeof LumaSplatsThree>
  }
}
import { LumaSplatsSemantics } from "@lumaai/luma-web";
import React from 'react';
import './LumaSplatsReact';

export const LumaModel = () => {
	return <>
		<lumaSplats
			semanticsMask={LumaSplatsSemantics.ALL}
            // onBeforeRender={}
            enableThreeShaderIntegration= {false}
			source='https://lumalabs.ai/capture/ca9ea966-ca24-4ec1-ab0f-af665cb546ff'
			position={[1, 0, 0]}
			scale={2}
			rotation={[0, 0, 0]}
		/>
	</>;
}
import React, { useRef, useState } from 'react';
import {OrbitControls, PerspectiveCamera} from '@react-three/drei';
import { Camera, Scene, WebGLRenderer } from "three";
import { OrbitControls as OrbitControlsStdLib } from 'three-stdlib';

export type DemoProps = {
	renderer: WebGLRenderer,
	scene: Scene,
	camera: Camera,
	controls: OrbitControlsStdLib,
}

export const ModelViewer = (props: {
	modelReactFn: React.FC<{}> | null,
}) => {
	let controlsRef = useRef<OrbitControlsStdLib | null>(null);

	return <>
		<PerspectiveCamera />
		<OrbitControls
			ref={controlsRef}
			autoRotate={false}
			autoRotateSpeed={0.5}
			enableDamping={false}
            keys={{
                LEFT: 'ArrowLeft', //left arrow
                UP: 'ArrowUp', // up arrow
                RIGHT: 'ArrowRight', // right arrow
                BOTTOM: 'ArrowDown' // down arrow
            }}
			makeDefault
		/>
		{props.modelReactFn && <props.modelReactFn/>}
	</>
}

And I am trying to load the model onto a canvas like this:

                                    <Canvas shadows={false} 
                                        camera={{
                                            position: [-6, 7, 7],
                                        }}>
                                            <ModelViewer
                                                key={0}
                                                modelReactFn={LumaModel}
                                            />
                                    </Canvas>

Can you point me into exactly why my website is slowing so much? Because from your demo I can see that it is indeed possible to load the model and still have a good website performance.

Thanks in advance!

Library looking for specific files to load

I have given it a try and created an online Luma SPLAT Viewer using this library and three.js r159.

It currently only supports URL loading and it does work when using Luma URLs, like this:

  • https://lumalabs.ai/capture/ca9ea966-ca24-4ec1-ab0f-af665cb546ff

The issue can be seen in the attached picture below when I use a URL like this:

  • https://raw.githubusercontent.com/GitHubDragonFly/GitHubDragonFly.github.io/main/viewers/examples/legobrick.splat

The library is treating this URL as a "folder", or a location that hosts multiple files, and is trying to get 1 bin and 3 json files out of it.

If I try to use the WebGL Gaussian Splat Viewer then it works, and the following URL can just be entered in a browser:

  • https://antimatter15.com/splat/?url=https://raw.githubusercontent.com/GitHubDragonFly/GitHubDragonFly.github.io/main/viewers/examples/legobrick.splat

This legobrick.splat file is just a lego brick made of points and was created from a ply file which was converted to splat by using the above mentioned WebGL Gaussian Splat Viewer.

The library also does not seem to be able to handle local blob URLs either, created with URL.createObjectURL( splat_file ) , which is another issue.

I might be doing something wrong all together but just looking for a second opinion.

SPLAT Viewer - Error

It runs in WebXR (Quest3)! But how to improve/subsample for faster rendering?

Congrats for the great work!

I did run some captures in WebXR with my Quest3 and I was surprised it runs! It's smooth but get slow when looking at detailed objects in the scene (main subject).

Is there a way to optimize the splat or add some options in the viewer to make the rendering faster for Mixed reality devices?

  • Subsample the number of splats?
  • Reduce the volume of the scene? (remove parts)
  • Other optimization?

Thanks!

Is Loading .ply files supported

I have a 3D Gaussian Splat output as a .ply file, generated from the original code accompanying the 3DGS publication. Is it possible to load that .ply into the LumaWebGL Renderer?

Uncaught TypeError: this.material.updateUniformsAndDefines is not a function

I am getting this error when trying to use Luma splats with React Three Fiber

luma-web.module.js:60 Uncaught TypeError: this.material.updateUniformsAndDefines is not a function
    at a.onBeforeRender (luma-web.module.js:60:354411)
    at renderObject (three.module.js:29444:1)
    at renderObjects (three.module.js:29434:1)
    at renderScene (three.module.js:29303:1)
    at WebGLRenderer.render (three.module.js:29121:1)

I am following the example you have exactly here

Any idea what might be causing this error?

Add a LICENSE file

Hello,
Thank you for this library, gaussian splatting are progressing fast !

It seems that this repository lacks a proper mention of the licence applied. Could you specify it in the README and add a LICENSE file so that we know if it is opensource or not ?

The licence of the code can be different from the terms and conditions of the Luma service of course.

no inline-worker-plugin.d.ts

attempting to compile the demo scripts and getting this error ~/luma-web-examples/node_modules/@lumaai/luma-web/misc/inline-worker-plugin.d.ts' not found. doesn't look like the misc directory is even in the package. wondering if this is something I need to manually create

Raycasting to splat

Default raycaster doesn't detect splat mesh.

This feature would be great for camera navigation tools like click to move. It's implemented in example below, so shouldn't be hard to add to this library.

Example: HOLLYWOOD

Proper depth occlusion for multi-splats scenes

First of all, thanks for this great library and docs! Two quick questions:

  • Could you implement better z-depth based occlusion for multiple splats in the same scene? Might not be the simplest feature since the whole renderer/rasterizer projects transparent ellipsoids onto the camera plane. But since the color rendering is so good, blending ellipsoids z-depth with the same transparency blending could lead to a pretty correct z-depth for the splat - which would therefore lead to correct depth-fighting for multi-splats scenes, which is atm pretty terrible.
  • Will the LumaSplatsWebGL/LumaSplatsThree libraries themselves be open-sourced at some point?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.