Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,25 @@ export const controls = ({ observer, ReactPCUI, React, jsx, fragment }) => {
if (observer.get('shader') === undefined) {
observer.set('shader', false);
}
const { Button } = ReactPCUI;
const { BindingTwoWay, Button, LabelGroup, SelectInput } = ReactPCUI;
return fragment(
jsx(
LabelGroup,
{ text: 'Renderer' },
jsx(SelectInput, {
type: 'number',
binding: new BindingTwoWay(),
link: { observer, path: 'renderer' },
value: observer.get('renderer') ?? 0,
options: [
{ v: 0, t: 'Auto' },
{ v: 1, t: 'Raster (CPU Sort)' },
{ v: 2, t: 'Raster (GPU Sort)' },
{ v: 3, t: 'Compute' },
{ v: 4, t: 'Raster (Hybrid)' }
]
})
),
jsx(Button, {
text: 'Custom Shader',
onClick: () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,15 @@ const assetListLoader = new pc.AssetListLoader(Object.values(assets), app.assets
assetListLoader.load(() => {
app.start();

data.on('renderer:set', () => {
app.scene.gsplat.renderer = data.get('renderer');
const current = app.scene.gsplat.currentRenderer;
if (current !== data.get('renderer')) {
setTimeout(() => data.set('renderer', current), 0);
}
});
data.set('renderer', pc.GSPLAT_RENDERER_AUTO);

// camera placement
const ORBIT_PIVOT = new pc.Vec3(0, 0.8, 0);
const ORBIT_DISTANCE = 5;
Expand Down
26 changes: 26 additions & 0 deletions examples/src/examples/gaussian-splatting/simple.controls.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* @param {import('../../app/components/Example.mjs').ControlOptions} options - The options.
* @returns {JSX.Element} The returned JSX Element.
*/
export const controls = ({ observer, ReactPCUI, jsx, fragment }) => {
const { BindingTwoWay, LabelGroup, SelectInput } = ReactPCUI;
return fragment(
jsx(
LabelGroup,
{ text: 'Renderer' },
jsx(SelectInput, {
type: 'number',
binding: new BindingTwoWay(),
link: { observer, path: 'renderer' },
value: observer.get('renderer') ?? 0,
options: [
{ v: 0, t: 'Auto' },
{ v: 1, t: 'Raster (CPU Sort)' },
{ v: 2, t: 'Raster (GPU Sort)' },
{ v: 3, t: 'Compute' },
{ v: 4, t: 'Raster (Hybrid)' }
]
})
)
);
};
38 changes: 29 additions & 9 deletions examples/src/examples/gaussian-splatting/simple.example.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// @config DESCRIPTION Basic example showing a simple Gaussian Splat with orbit camera controls.
import { data } from 'examples/observer';
import { deviceType, rootPath } from 'examples/utils';
import * as pc from 'playcanvas';

Expand Down Expand Up @@ -52,41 +53,60 @@ const assetListLoader = new pc.AssetListLoader(Object.values(assets), app.assets
assetListLoader.load(() => {
app.start();

data.on('renderer:set', () => {
app.scene.gsplat.renderer = data.get('renderer');
const current = app.scene.gsplat.currentRenderer;
if (current !== data.get('renderer')) {
setTimeout(() => data.set('renderer', current), 0);
}
});
data.set('renderer', pc.GSPLAT_RENDERER_AUTO);

// create a splat entity and place it in the world
const biker = new pc.Entity();
biker.addComponent('gsplat', {
asset: assets.biker,
castShadows: true
castShadows: true,
unified: true
});
biker.setLocalPosition(-1.5, 0.05, 0);
biker.setLocalEulerAngles(180, 90, 0);
biker.setLocalScale(0.7, 0.7, 0.7);
app.root.addChild(biker);

// set alpha clip value, used by shadows and picking
biker.gsplat.material.setParameter('alphaClip', 0.4);
// Orbit pivot at splat (unified gsplats have no mesh AABB for focusEntity framing).
const ORBIT_PIVOT = new pc.Vec3().copy(biker.getPosition());
ORBIT_PIVOT.y += 1;
const ORBIT_DISTANCE = 4;
const ORBIT_INITIAL_YAW = 32;
const ORBIT_INITIAL_PITCH = -10;

// alpha clip for unified splats (shadows); scene-level for unified path
app.scene.gsplat.alphaClip = 0.4;

// Create an Entity with a camera component
const camera = new pc.Entity();
camera.addComponent('camera', {
clearColor: new pc.Color(0.2, 0.2, 0.2),
toneMapping: pc.TONEMAP_ACES
});
camera.setLocalPosition(-0.8, 2, 3);
app.root.addChild(camera);

// add orbit camera script with a mouse and a touch support
camera.addComponent('script');
camera.script.create('orbitCamera', {
const orbitCam = /** @type {any} */ (camera.script.create('orbitCamera', {
attributes: {
inertiaFactor: 0.2,
focusEntity: biker,
distanceMax: 60,
frameOnStart: false
}
});
}));
if (orbitCam) {
orbitCam.pivotPoint.copy(ORBIT_PIVOT);
orbitCam.reset(ORBIT_INITIAL_YAW, ORBIT_INITIAL_PITCH, ORBIT_DISTANCE);
orbitCam._updatePosition();
}
camera.script.create('orbitCameraInputMouse');
camera.script.create('orbitCameraInputTouch');
app.root.addChild(camera);

// create ground to receive shadows
const material = new pc.StandardMaterial();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* @param {import('../../app/components/Example.mjs').ControlOptions} options - The options.
* @returns {JSX.Element} The returned JSX Element.
*/
export const controls = ({ observer, ReactPCUI, jsx, fragment }) => {
const { BindingTwoWay, LabelGroup, SelectInput } = ReactPCUI;
return fragment(
jsx(
LabelGroup,
{ text: 'Renderer' },
jsx(SelectInput, {
type: 'number',
binding: new BindingTwoWay(),
link: { observer, path: 'renderer' },
value: observer.get('renderer') ?? 0,
options: [
{ v: 0, t: 'Auto' },
{ v: 1, t: 'Raster (CPU Sort)' },
{ v: 2, t: 'Raster (GPU Sort)' },
{ v: 3, t: 'Compute' },
{ v: 4, t: 'Raster (Hybrid)' }
]
})
)
);
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// @config DESCRIPTION Shows view-dependent color effects using spherical harmonics with Gaussian Splats.
import { data } from 'examples/observer';
import { deviceType, rootPath } from 'examples/utils';
import * as pc from 'playcanvas';

Expand Down Expand Up @@ -52,42 +53,60 @@ const assetListLoader = new pc.AssetListLoader(Object.values(assets), app.assets
assetListLoader.load(() => {
app.start();

data.on('renderer:set', () => {
app.scene.gsplat.renderer = data.get('renderer');
const current = app.scene.gsplat.currentRenderer;
if (current !== data.get('renderer')) {
setTimeout(() => data.set('renderer', current), 0);
}
});
data.set('renderer', pc.GSPLAT_RENDERER_AUTO);

// create a splat entity and place it in the world
const skull = new pc.Entity();
skull.addComponent('gsplat', {
asset: assets.skull,
castShadows: true
castShadows: true,
unified: true
});
skull.setLocalPosition(-1.5, 0.05, 0);
skull.setLocalEulerAngles(180, 90, 0);
skull.setLocalScale(0.7, 0.7, 0.7);
app.root.addChild(skull);

// set alpha clip value, used by shadows and picking
skull.gsplat.material.setParameter('alphaClip', 0.4);
skull.gsplat.material.setParameter('alphaClip', 0.1);
// Orbit pivot at splat (unified gsplats have no mesh AABB for focusEntity framing).
const ORBIT_PIVOT = new pc.Vec3().copy(skull.getPosition());
ORBIT_PIVOT.y += 0.2;
const ORBIT_DISTANCE = 4;
const ORBIT_INITIAL_YAW = 32;
const ORBIT_INITIAL_PITCH = -10;

// alpha clip for unified splats (shadows / cutout); scene-level for unified path
app.scene.gsplat.alphaClip = 0.1;

// Create an Entity with a camera component
const camera = new pc.Entity();
camera.addComponent('camera', {
clearColor: new pc.Color(0.2, 0.2, 0.2),
toneMapping: pc.TONEMAP_ACES
});
camera.setLocalPosition(-2, 1.5, 2);
app.root.addChild(camera);

// add orbit camera script with a mouse and a touch support
camera.addComponent('script');
camera.script.create('orbitCamera', {
const orbitCam = /** @type {any} */ (camera.script.create('orbitCamera', {
attributes: {
inertiaFactor: 0.2,
focusEntity: skull,
distanceMax: 60,
frameOnStart: false
}
});
}));
if (orbitCam) {
orbitCam.pivotPoint.copy(ORBIT_PIVOT);
orbitCam.reset(ORBIT_INITIAL_YAW, ORBIT_INITIAL_PITCH, ORBIT_DISTANCE);
orbitCam._updatePosition();
}
camera.script.create('orbitCameraInputMouse');
camera.script.create('orbitCameraInputTouch');
app.root.addChild(camera);

// create ground to receive shadows
const material = new pc.StandardMaterial();
Expand Down