mirror of
https://github.com/storytold/spark.git
synced 2026-10-18 07:40:38 +00:00
Merge pull request #2 from forge-gfx/multiview
Tweak multiple viewports example
This commit is contained in:
@@ -86,5 +86,9 @@
|
|||||||
"cat.spz": {
|
"cat.spz": {
|
||||||
"url": "https://forge-gfx.github.io/assets/splats/cat.spz",
|
"url": "https://forge-gfx.github.io/assets/splats/cat.spz",
|
||||||
"directory": "splats"
|
"directory": "splats"
|
||||||
|
},
|
||||||
|
"arrow.glb": {
|
||||||
|
"url": "https://forge-gfx.github.io/assets/models/arrow.glb",
|
||||||
|
"directory": "models"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,34 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Forge • Multiple Viewpoints</title>
|
<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>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
<header>
|
||||||
|
<input type="range" min="-100" max="100" id="camera1">
|
||||||
|
<input type="range" min="-100" max="100" id="camera2">
|
||||||
|
</header>
|
||||||
|
|
||||||
<script type="importmap">
|
<script type="importmap">
|
||||||
{
|
{
|
||||||
"imports": {
|
"imports": {
|
||||||
@@ -16,25 +40,27 @@
|
|||||||
<script type="module">
|
<script type="module">
|
||||||
import * as THREE from "three";
|
import * as THREE from "three";
|
||||||
import { ForgeRenderer, ForgeViewpoint, SplatMesh } from "@forge-gfx/forge";
|
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";
|
import { getAssetFileURL } from "/examples/js/get-asset-url.js";
|
||||||
|
|
||||||
const scene = new THREE.Scene();
|
const scene = new THREE.Scene();
|
||||||
scene.background = new THREE.Color(0x000000);
|
scene.background = new THREE.Color(0x000000);
|
||||||
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
|
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
|
||||||
const renderer = new THREE.WebGLRenderer();
|
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)
|
document.body.appendChild(renderer.domElement)
|
||||||
|
|
||||||
// Explicitly create a ForgeRenderer in the scene to spawn new viewpoints
|
// Explicitly create a ForgeRenderer in the scene to spawn new viewpoints
|
||||||
const forge = new ForgeRenderer({ renderer });
|
const forge = new ForgeRenderer({ renderer });
|
||||||
|
|
||||||
const splatURL = await getAssetFileURL("butterfly.spz");
|
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.quaternion.set(1, 0, 0, 0);
|
||||||
butterfly.position.set(0, 0, -1);
|
butterfly.position.set(0, 0, -3);
|
||||||
scene.add(butterfly);
|
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
|
// Create a textured rectangle at the near plane to show the viewpoint
|
||||||
const width = 320;
|
const width = 320;
|
||||||
const height = 240;
|
const height = 240;
|
||||||
@@ -49,15 +75,30 @@
|
|||||||
viewCamera.position.copy(origin);
|
viewCamera.position.copy(origin);
|
||||||
viewCamera.lookAt(butterfly.position);
|
viewCamera.lookAt(butterfly.position);
|
||||||
|
|
||||||
// Create a cone to show the viewpoint camera
|
// Load arrow object to show where each camera is
|
||||||
const cone = new THREE.Mesh(
|
const arrowURL = await getAssetFileURL("arrow.glb");
|
||||||
new THREE.ConeGeometry(0.1, 0.1, 32),
|
new GLTFLoader().load(arrowURL, gltf => {
|
||||||
new THREE.MeshNormalMaterial(),
|
// Different material for each camera
|
||||||
);
|
const arrowMaterial = new THREE.MeshMatcapMaterial({
|
||||||
cone.position.copy(viewCamera.position);
|
matcap: [
|
||||||
cone.quaternion.copy(viewCamera.quaternion);
|
new THREE.TextureLoader().load("https://raw.githubusercontent.com/nidorx/matcaps/master/128/1A2461_3D70DB_2C3C8F_2C6CAC-128px.png"),
|
||||||
cone.rotateX(Math.PI / 2);
|
new THREE.TextureLoader().load("https://raw.githubusercontent.com/nidorx/matcaps/master/128/9D282A_38191D_DFC6CD_D6495A-128px.png")
|
||||||
scene.add(cone);
|
][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
|
// Spawn a new viewpoint that auto-updates its sort order, double
|
||||||
// buffered in case the texture is used recursively in the scene
|
// buffered in case the texture is used recursively in the scene
|
||||||
@@ -70,12 +111,13 @@
|
|||||||
screen.material.map = texture;
|
screen.material.map = texture;
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return viewpoint;
|
return viewpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
const viewpoints = [
|
const viewpoints = [
|
||||||
createViewpoint(new THREE.Vector3(0, 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),
|
||||||
createViewpoint(new THREE.Vector3(0.5, -0.5, -1), new THREE.Vector2(-0.5, -0.5)),
|
await createViewpoint(new THREE.Vector3(0.5, -1, -3), new THREE.Vector2(0.5, -0.5), 1),
|
||||||
];
|
];
|
||||||
|
|
||||||
renderer.setAnimationLoop(function animate(time) {
|
renderer.setAnimationLoop(function animate(time) {
|
||||||
@@ -83,12 +125,13 @@
|
|||||||
renderer.render(scene, camera);
|
renderer.render(scene, camera);
|
||||||
butterfly.rotation.y += 0.01;
|
butterfly.rotation.y += 0.01;
|
||||||
|
|
||||||
// Adjust the background for visibility and render the viewpoints
|
// Render each viewpoint (with a different background each)
|
||||||
scene.background.set(0x000040);
|
for (let i = 0; i < viewpoints.length; i++) {
|
||||||
for (const viewpoint of viewpoints) {
|
scene.background.set([0x202040, 0x302020][i]);
|
||||||
viewpoint.renderTarget({ scene, camera: viewpoint.camera });
|
viewpoints[i].renderTarget({ scene, camera: viewpoints[i].camera });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user