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
4 changes: 4 additions & 0 deletions examples/assets.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,5 +86,9 @@
"cat.spz": {
"url": "https://forge-gfx.github.io/assets/splats/cat.spz",
"directory": "splats"
},
"arrow.glb": {
"url": "https://forge-gfx.github.io/assets/models/arrow.glb",
"directory": "models"
}
}
83 changes: 63 additions & 20 deletions examples/multiple-viewpoints/index.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,34 @@
<!DOCTYPE html>

<head>
<meta charset="utf-8">
<title>Forge • Multiple Viewpoints</title>
<style> body {margin: 0;} </style>
<style>
body {
margin: 0;
background-color: black;
}

header {
margin: 0 auto;
padding: 10px 0;
min-width: 400px;
width: 50%;
}

input {
width: 100%;
padding: 10px 0;
}
</style>
</head>

<body>
<header>
<input type="range" min="-100" max="100" id="camera1">
<input type="range" min="-100" max="100" id="camera2">
</header>

<script type="importmap">
{
"imports": {
Expand All @@ -16,25 +40,27 @@
<script type="module">
import * as THREE from "three";
import { ForgeRenderer, ForgeViewpoint, SplatMesh } from "@forge-gfx/forge";
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { getAssetFileURL } from "/examples/js/get-asset-url.js";

const scene = new THREE.Scene();
scene.background = new THREE.Color(0x000000);
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
const header_height = document.querySelector('header').getBoundingClientRect().height;
renderer.setSize(window.innerWidth, window.innerHeight - header_height);
document.body.appendChild(renderer.domElement)

// Explicitly create a ForgeRenderer in the scene to spawn new viewpoints
const forge = new ForgeRenderer({ renderer });

const splatURL = await getAssetFileURL("butterfly.spz");
const butterfly = new SplatMesh({ url: splatURL});
const butterfly = new SplatMesh({ url: splatURL });
butterfly.quaternion.set(1, 0, 0, 0);
butterfly.position.set(0, 0, -1);
butterfly.position.set(0, 0, -3);
scene.add(butterfly);

function createViewpoint(origin, screenPos) {
async function createViewpoint(origin, screenPos, index) {
// Create a textured rectangle at the near plane to show the viewpoint
const width = 320;
const height = 240;
Expand All @@ -49,15 +75,30 @@
viewCamera.position.copy(origin);
viewCamera.lookAt(butterfly.position);

// Create a cone to show the viewpoint camera
const cone = new THREE.Mesh(
new THREE.ConeGeometry(0.1, 0.1, 32),
new THREE.MeshNormalMaterial(),
);
cone.position.copy(viewCamera.position);
cone.quaternion.copy(viewCamera.quaternion);
cone.rotateX(Math.PI / 2);
scene.add(cone);
// Load arrow object to show where each camera is
const arrowURL = await getAssetFileURL("arrow.glb");
new GLTFLoader().load(arrowURL, gltf => {
// Different material for each camera
const arrowMaterial = new THREE.MeshMatcapMaterial({
matcap: [
new THREE.TextureLoader().load("https://raw.githubusercontent.com/nidorx/matcaps/master/128/1A2461_3D70DB_2C3C8F_2C6CAC-128px.png"),
new THREE.TextureLoader().load("https://raw.githubusercontent.com/nidorx/matcaps/master/128/9D282A_38191D_DFC6CD_D6495A-128px.png")
][index]
});

const arrow = gltf.scene.children[0];
arrow.material = arrowMaterial;
arrow.position.copy(viewCamera.position);
arrow.lookAt(butterfly.position);
scene.add(arrow);

// Connect slider to both camera and arrow
document.getElementById("camera" + (index + 1)).oninput = ev => {
viewCamera.position.x = (ev.target.value / 100);
arrow.position.x = viewCamera.position.x;
arrow.lookAt(butterfly.position);
};
});

// Spawn a new viewpoint that auto-updates its sort order, double
// buffered in case the texture is used recursively in the scene
Expand All @@ -70,25 +111,27 @@
screen.material.map = texture;
},
});

return viewpoint;
}

const viewpoints = [
createViewpoint(new THREE.Vector3(0, 0.5, -1), new THREE.Vector2(-0.5, 0.5)),
createViewpoint(new THREE.Vector3(0.5, -0.5, -1), new THREE.Vector2(-0.5, -0.5)),
await createViewpoint(new THREE.Vector3(0, 1.5, -3), new THREE.Vector2(-0.5, 0.5), 0),
await createViewpoint(new THREE.Vector3(0.5, -1, -3), new THREE.Vector2(0.5, -0.5), 1),
];

renderer.setAnimationLoop(function animate(time) {
scene.background.set(0x000000);
renderer.render(scene, camera);
butterfly.rotation.y += 0.01;

// Adjust the background for visibility and render the viewpoints
scene.background.set(0x000040);
for (const viewpoint of viewpoints) {
viewpoint.renderTarget({ scene, camera: viewpoint.camera });
// Render each viewpoint (with a different background each)
for (let i = 0; i < viewpoints.length; i++) {
scene.background.set([0x202040, 0x302020][i]);
viewpoints[i].renderTarget({ scene, camera: viewpoints[i].camera });
}
});
</script>
</body>

</html>