catalog.ts

examples/sogs/catalog.ts · raw · open the example · all examples · site home

Exports: SampleSOGSSAMPLESsampleRotationskyTexture

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// Sample SOG files, all on Google Cloud Storage under SOGS (?sogs= reads
// the same names elsewhere, such as /splats/sogs for local copies; every
// host needs CORS headers): mirrors of PlayCanvas's bundled .sog files,
// Spark's SOGS .zip, an unbundled SOGS meta.json and PlayCanvas's SOG LoD
// scenes (lod-meta.json), with their original addresses in `source`; and
// our splat-transform conversions of sutro_2m.ply (see main.ts). Rotations
// and start views are in the viewer's world (y up).
import * as THREE from "three";

export interface Sample {
  label: string;
  url: string;
  credit?: string;
  // Where the mirrored file came from
  source?: string;
  // Turned upright (default a half turn about x: files are usually y-down)
  rotation?: [number, number, number];
  mode?: "orbit" | "fly";
  sky?: boolean;
  // Where the camera starts (else framed from outside)
  view?: { position: [number, number, number]; target: [number, number, number]; fov: number };
}

export const SOGS = new URL(`${new URLSearchParams(location.search).get("sogs") ?? "https://storage.googleapis.com/forge-dev-public/asundqui/radix/261009/sogs"}/`, location.href).href;

const PC = "https://raw.githubusercontent.com/playcanvas/engine/main/examples/assets/splats";
const PC_DATA = "https://code.playcanvas.com/examples_data";

// Half turns about z, as PlayCanvas's examples place some of these
const Z_TURN: [number, number, number] = [0, 0, Math.PI];
const SUTRO_VIEW = { position: [0, 1.5, -1.2], target: [0, 1.5, 0], fov: 60 } satisfies Sample["view"];

export const SAMPLES: Record<string, Sample> = {
  "toy-cat": {
    label: "Toy cat (v2 .sog)", url: `${SOGS}toy-cat.sog`, credit: "PlayCanvas", source: "https://developer.playcanvas.com/assets/toy-cat.sog", rotation: Z_TURN,
  },
  skull: { label: "Skull (v2 .sog)", url: `${SOGS}skull.sog`, credit: "PlayCanvas engine examples", source: `${PC}/skull.sog` },
  bicycle: {
    label: "Bicycle (v2 .sog, 1M)", url: `${SOGS}bicycle.sog`, credit: "Mip-NeRF 360, PlayCanvas engine examples", source: `${PC}/bicycle.sog`, rotation: Z_TURN,
    view: { position: [1.6, 1.2, 2.2], target: [0, 0.575, 0], fov: 60 },
  },
  apartment: {
    label: "Apartment (v2 .sog, no SH)", url: `${SOGS}apartment.sog`, credit: "Stephane Agullo (sa3d.fr), CC-BY-4.0", source: `${PC}/apartment.sog`, mode: "fly",
    view: { position: [-3.8, 0.4, 7.2], target: [0, 0.4, 0], fov: 60 },
  },
  // Orbiting the hall itself (its densest splats), not the whole plot
  hall: {
    label: "Knock Community Hall (v2 .sog)", url: `${SOGS}knock-community-hall.sog`, credit: "scbenoit, CC-BY-4.0", source: `${PC}/knock-community-hall.sog`,
    view: { position: [1, 4.5, 11], target: [-1.5, 2, 0.5], fov: 60 },
  },
  sunnyvale: {
    label: "Sunnyvale (v2 .sog, 58 MB)", url: `${SOGS}sunnyvale.sog`, credit: "PlayCanvas examples", source: `${PC_DATA}/example_sunnyvale/sunnyvale.sog`,
    rotation: Z_TURN, mode: "fly", sky: true, view: { position: [0, 1.15, 0], target: [0, 1.15, -1], fov: 75 },
  },
  sutro: {
    label: "Sutro (SOGS .zip, 2M)", url: `${SOGS}sutro.zip`, credit: "Spark examples", source: "https://sparkjs.dev/assets/splats/sutro.zip", sky: true, view: SUTRO_VIEW,
  },
  logo: {
    label: "PlayCanvas logo (SOGS meta.json)", url: `${SOGS}playcanvas-logo/meta.json`, credit: "PlayCanvas engine examples", source: `${PC}/playcanvas-logo/meta.json`, rotation: Z_TURN,
  },
  playbot: { label: "Playbot (LoD)", url: `${SOGS}playbot/lod-meta.json`, credit: "PlayCanvas engine examples", source: `${PC}/playbot/lod-meta.json` },
  skatepark: {
    label: "Skatepark (LoD, 16M)", url: `${SOGS}skatepark/lod-meta.json`, credit: "PlayCanvas examples", source: `${PC_DATA}/example_skatepark_03/lod-meta.json`,
    rotation: [-Math.PI / 2, 0, 0], mode: "fly", sky: true, view: { position: [32, 2, 2], target: [0, 0.6, 0], fov: 75 },
  },
  "roman-parish": {
    label: "Roman parish (LoD, 69M)", url: `${SOGS}roman-parish/lod-meta.json`, credit: "PlayCanvas examples", source: `${PC_DATA}/example_roman_parish_03/lod-meta.json`,
    rotation: [-Math.PI / 2, 0, 0], mode: "fly", view: { position: [10.3, 2, -10], target: [12, 3, 0], fov: 75 },
  },
  "sutro-2m": { label: "Sutro 2M (v2 .sog, converted)", url: `${SOGS}sutro-2m.sog`, credit: "sutro_2m.ply through splat-transform", sky: true, view: SUTRO_VIEW },
  "sutro-2m-dir": { label: "Sutro 2M (v2 meta.json, converted)", url: `${SOGS}sutro-2m/meta.json`, credit: "sutro_2m.ply through splat-transform", sky: true, view: SUTRO_VIEW },
  "sutro-v1": { label: "Sutro (SOGS v1 meta.json)", url: `${SOGS}sutro-v1/meta.json`, credit: "Spark examples (sutro.zip unbundled)", sky: true, view: SUTRO_VIEW },
  "sutro-lod": { label: "Sutro 2M (LoD, 5 levels, converted)", url: `${SOGS}sutro-lod/lod-meta.json`, credit: "sutro_2m.ply through splat-transform", sky: true, view: SUTRO_VIEW },
};

export function sampleRotation(sample?: Sample) {
  return sample?.rotation ? new THREE.Quaternion().setFromEuler(new THREE.Euler(...sample.rotation)) : new THREE.Quaternion(1, 0, 0, 0);
}

// Outdoor scenes: a sky gradient around the view (zenith blue to a pale
// horizon, hazy below), as an equirectangular background
let sky: THREE.CanvasTexture | undefined;
export function skyTexture() {
  if (!sky) {
    const canvas = Object.assign(document.createElement("canvas"), { width: 4, height: 512 });
    const g = canvas.getContext("2d")!;
    const gradient = g.createLinearGradient(0, 0, 0, 512);
    gradient.addColorStop(0, "#2f6fb8");
    gradient.addColorStop(0.3, "#6fa6dc");
    gradient.addColorStop(0.49, "#d6e7f5");
    gradient.addColorStop(0.52, "#c9cfd4");
    gradient.addColorStop(1, "#5d6166");
    g.fillStyle = gradient;
    g.fillRect(0, 0, 4, 512);
    sky = new THREE.CanvasTexture(canvas);
    sky.mapping = THREE.EquirectangularReflectionMapping;
    sky.colorSpace = THREE.SRGBColorSpace;
  }
  return sky;
}