@rydr/game-sdk 9.10.0 → 9.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +1 -0
  2. package/dist/client/PlatformClient.d.ts +31 -2
  3. package/dist/client/PlatformClient.d.ts.map +1 -1
  4. package/dist/client/PlatformClient.js +42 -0
  5. package/dist/client/PlatformClient.js.map +1 -1
  6. package/dist/host/PlatformHost.d.ts +16 -1
  7. package/dist/host/PlatformHost.d.ts.map +1 -1
  8. package/dist/host/PlatformHost.js +18 -1
  9. package/dist/host/PlatformHost.js.map +1 -1
  10. package/dist/index.d.ts +1 -0
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +1 -0
  13. package/dist/index.js.map +1 -1
  14. package/dist/protocol/guards.d.ts.map +1 -1
  15. package/dist/protocol/guards.js +1 -0
  16. package/dist/protocol/guards.js.map +1 -1
  17. package/dist/protocol/messages.d.ts +11 -2
  18. package/dist/protocol/messages.d.ts.map +1 -1
  19. package/dist/protocol/rideHud.d.ts +33 -0
  20. package/dist/protocol/rideHud.d.ts.map +1 -1
  21. package/dist/protocol/rideHud.js +37 -0
  22. package/dist/protocol/rideHud.js.map +1 -1
  23. package/dist/protocol/version.d.ts +2 -2
  24. package/dist/protocol/version.d.ts.map +1 -1
  25. package/dist/protocol/version.js +13 -2
  26. package/dist/protocol/version.js.map +1 -1
  27. package/dist/protocol/worlds.d.ts +181 -0
  28. package/dist/protocol/worlds.d.ts.map +1 -1
  29. package/dist/protocol/worlds.js +9 -0
  30. package/dist/protocol/worlds.js.map +1 -1
  31. package/dist/three/README.md +25 -0
  32. package/dist/three/baked-lighting.d.ts +144 -0
  33. package/dist/three/baked-lighting.d.ts.map +1 -0
  34. package/dist/three/baked-lighting.js +289 -0
  35. package/dist/three/baked-lighting.js.map +1 -0
  36. package/dist/three/index.d.ts +2 -0
  37. package/dist/three/index.d.ts.map +1 -1
  38. package/dist/three/index.js +2 -0
  39. package/dist/three/index.js.map +1 -1
  40. package/dist/three/preset-lighting.d.ts +65 -0
  41. package/dist/three/preset-lighting.d.ts.map +1 -0
  42. package/dist/three/preset-lighting.js +163 -0
  43. package/dist/three/preset-lighting.js.map +1 -0
  44. package/dist/world-lighting.d.ts +105 -0
  45. package/dist/world-lighting.d.ts.map +1 -0
  46. package/dist/world-lighting.js +230 -0
  47. package/dist/world-lighting.js.map +1 -0
  48. package/package.json +1 -1
@@ -0,0 +1,289 @@
1
+ /**
2
+ * baked-lighting — load a BAKED scene ({@link SceneBake}) and render it with its lightmaps.
3
+ *
4
+ * A baked scene is one self-contained glb produced by the platform's bake pipeline (Blender, see the
5
+ * platform repo's `docs/baked-lighting.md`): the world plus whatever a game baked with it, every static
6
+ * mesh carrying a second UV set (`TEXCOORD_1`) and a material extension, `RYDR_lightmap`, that points at
7
+ * the lightmap atlas it was baked into.
8
+ *
9
+ * ## What a lightmap holds, and how it is shown
10
+ *
11
+ * The light each surface RECEIVES (sun, sky, lamps, bounce) — not its colour. So a baked material is
12
+ * `albedo × lightmap`, which keeps the full detail of the colour textures at a low lightmap resolution,
13
+ * and it is a `MeshBasicMaterial`: the scene's live lights must not light it a second time. That is
14
+ * also why a baked world is CHEAPER than a live one — no per-pixel lighting at all.
15
+ *
16
+ * The atlas is an 8-bit sRGB PNG: the bake divides the light by a per-atlas `scale` before encoding,
17
+ * the GPU's sRGB decode undoes the curve for free, and `intensity` (= π × scale, the π cancelling
18
+ * `MeshBasicMaterial`'s Lambert term) puts the range back. No custom shader, no alpha channel for
19
+ * a browser to premultiply.
20
+ *
21
+ * ## What stays live
22
+ *
23
+ * Anything that moves. A car is still lit by the game's own sun + environment, and its shadow is put
24
+ * on the baked ground by a SHADOW CATCHER ({@link createShadowCatcher}): a `ShadowMaterial` overlay on
25
+ * the meshes the export marked as receivers (the road, the ground around it). Everything else in the
26
+ * baked scene casts and receives nothing live — its shadows are in the lightmap.
27
+ */
28
+ import * as THREE from "three";
29
+ import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
30
+ import { DRACOLoader } from "three/addons/loaders/DRACOLoader.js";
31
+ import { DRACO_DECODER_PATH } from "./world-loader.js";
32
+ import { createGlbCache } from "./glb-cache.js";
33
+ import { mergeByMaterial } from "./merge.js";
34
+ /** The glTF material extension a baked glb carries. */
35
+ export const RYDR_LIGHTMAP_EXTENSION = "RYDR_lightmap";
36
+ /** Node extras the export writes and the bake carries through (see the platform's bake docs). */
37
+ export const BAKE_EXTRAS = {
38
+ /** `"static"` (gets a lightmap) or `"occluder"` (casts in the bake, then dropped). */
39
+ role: "rydr_role",
40
+ /** true on meshes a moving object's live shadow must land on (a road). */
41
+ receiveShadow: "rydr_receive_shadow",
42
+ /** Texels per metre wanted for this mesh. */
43
+ density: "rydr_lm_density",
44
+ /** Atlas preference, e.g. `"near-road"`. */
45
+ atlasHint: "rydr_atlas_hint",
46
+ /** Written BY the bake: the atlas a mesh ended up in. */
47
+ lightmap: "rydr_lightmap",
48
+ /**
49
+ * `"world"` (the platform world's geometry) or `"game"` (what the game added: a road, walls). Lets a
50
+ * game tell the two apart in a baked scene — racing probes the drivable height off the WORLD alone.
51
+ */
52
+ layer: "rydr_layer",
53
+ };
54
+ /** Name of the empty node carrying the bake manifest (a JSON string in its extras). */
55
+ export const BAKE_MANIFEST_NODE = "RYDR_BAKE_MANIFEST";
56
+ /** The extras key on {@link BAKE_MANIFEST_NODE}. */
57
+ export const BAKE_MANIFEST_KEY = "rydr_bake_manifest";
58
+ /**
59
+ * GLTFLoader plugin for `RYDR_lightmap`: assigns the atlas as the material's `lightMap` on UV channel 1
60
+ * with the extension's intensity. Register it on any GLTFLoader that may meet a baked glb:
61
+ * `loader.register((parser) => new RydrLightmapPlugin(parser))`.
62
+ */
63
+ export class RydrLightmapPlugin {
64
+ parser;
65
+ name = RYDR_LIGHTMAP_EXTENSION;
66
+ constructor(parser) {
67
+ this.parser = parser;
68
+ }
69
+ extendMaterialParams(materialIndex, materialParams) {
70
+ const def = this.parser.json.materials?.[materialIndex];
71
+ const ext = def?.extensions?.[RYDR_LIGHTMAP_EXTENSION];
72
+ if (!ext)
73
+ return Promise.resolve();
74
+ materialParams.lightMapIntensity = ext.intensity;
75
+ return this.parser.assignTexture(materialParams, "lightMap", { index: ext.index, texCoord: ext.texCoord ?? 1 }, THREE.SRGBColorSpace);
76
+ }
77
+ }
78
+ /** Add the {@link RydrLightmapPlugin} to a loader (idempotent per loader instance is the caller's job). */
79
+ export function registerBakedLighting(loader) {
80
+ loader.register((parser) => new RydrLightmapPlugin(parser));
81
+ return loader;
82
+ }
83
+ /**
84
+ * The material a baked mesh renders with: `albedo × lightmap`, unlit by the live rig.
85
+ *
86
+ * Returns `src` untouched when it has no lightmap (a mesh the bake skipped stays lit live, rather than
87
+ * turning black). Emissive surfaces keep their glow — a lit window IS its emission — via a two-line
88
+ * shader addition, since `MeshBasicMaterial` has no emissive of its own.
89
+ */
90
+ export function toBakedMaterial(src) {
91
+ const s = src;
92
+ if (!s.lightMap)
93
+ return src;
94
+ const m = new THREE.MeshBasicMaterial({
95
+ name: s.name,
96
+ color: s.color?.clone() ?? new THREE.Color(0xffffff),
97
+ map: s.map,
98
+ alphaMap: s.alphaMap,
99
+ alphaTest: s.alphaTest,
100
+ transparent: s.transparent,
101
+ opacity: s.opacity,
102
+ side: s.side,
103
+ vertexColors: s.vertexColors,
104
+ lightMap: s.lightMap,
105
+ lightMapIntensity: s.lightMapIntensity,
106
+ depthWrite: s.depthWrite,
107
+ fog: true,
108
+ });
109
+ m.userData = { ...s.userData, rydrBaked: true };
110
+ const emissive = s.emissive ? s.emissive.clone().multiplyScalar(s.emissiveIntensity ?? 1) : null;
111
+ const hasEmissive = !!emissive && (emissive.r > 0 || emissive.g > 0 || emissive.b > 0);
112
+ if (hasEmissive) {
113
+ // The emissive map is only honoured when it shares the colour map's UV channel, which is the only
114
+ // case the fragment already has a UV for. Otherwise the flat emissive colour still shows.
115
+ const emissiveMap = s.emissiveMap && s.map && s.emissiveMap.channel === s.map.channel ? s.emissiveMap : null;
116
+ m.onBeforeCompile = (shader) => {
117
+ shader.uniforms.rydrEmissive = { value: emissive };
118
+ if (emissiveMap)
119
+ shader.uniforms.rydrEmissiveMap = { value: emissiveMap };
120
+ shader.fragmentShader = shader.fragmentShader
121
+ .replace("#include <common>", `#include <common>\nuniform vec3 rydrEmissive;\n${emissiveMap ? "uniform sampler2D rydrEmissiveMap;" : ""}`)
122
+ .replace("#include <opaque_fragment>", `${emissiveMap
123
+ ? "outgoingLight += rydrEmissive * texture2D( rydrEmissiveMap, vMapUv ).rgb;"
124
+ : "outgoingLight += rydrEmissive;"}\n#include <opaque_fragment>`);
125
+ };
126
+ m.customProgramCacheKey = () => (emissiveMap ? "rydr-baked-emissive-map" : "rydr-baked-emissive");
127
+ }
128
+ return m;
129
+ }
130
+ const bakedCache = new Map();
131
+ /**
132
+ * Load (and cache by glb path) a baked scene, with every lightmapped material swapped for its
133
+ * {@link toBakedMaterial}. Pass the {@link SceneBake} (or its url). Rejects if the glb fails to load —
134
+ * the caller falls back to rendering live.
135
+ */
136
+ export function loadBakedScene(bake, opts = {}) {
137
+ const url = typeof bake === "string" ? bake : bake.glbUrl;
138
+ const cut = url.search(/[?#]/);
139
+ const key = cut === -1 ? url : url.slice(0, cut);
140
+ let p = bakedCache.get(key);
141
+ if (!p) {
142
+ p = buildBakedScene(url, key, opts);
143
+ p.catch(() => {
144
+ if (bakedCache.get(key) === p)
145
+ bakedCache.delete(key);
146
+ });
147
+ bakedCache.set(key, p);
148
+ }
149
+ return p;
150
+ }
151
+ async function buildBakedScene(url, key, opts) {
152
+ const loader = registerBakedLighting(new GLTFLoader());
153
+ const draco = new DRACOLoader();
154
+ draco.setDecoderPath(opts.dracoDecoderPath ?? DRACO_DECODER_PATH);
155
+ loader.setDRACOLoader(draco);
156
+ const cache = opts.cache === false ? null : createGlbCache(opts.cache);
157
+ const path = key.slice(0, key.lastIndexOf("/") + 1);
158
+ const gltf = cache
159
+ ? await cache.bytes(url).then((buf) => loader.parseAsync(buf, path))
160
+ : await loader.loadAsync(url);
161
+ draco.dispose();
162
+ const group = new THREE.Group();
163
+ group.name = "baked-scene";
164
+ group.add(gltf.scene);
165
+ const receivers = [];
166
+ let manifest = null;
167
+ const swapped = new Map();
168
+ const swap = (mat) => {
169
+ let out = swapped.get(mat);
170
+ if (!out) {
171
+ out = toBakedMaterial(mat);
172
+ if (out !== mat)
173
+ mat.dispose();
174
+ swapped.set(mat, out);
175
+ }
176
+ return out;
177
+ };
178
+ gltf.scene.traverse((o) => {
179
+ const raw = o.userData?.[BAKE_MANIFEST_KEY];
180
+ if (typeof raw === "string" && !manifest) {
181
+ try {
182
+ manifest = JSON.parse(raw);
183
+ }
184
+ catch {
185
+ /* a malformed manifest only costs the diagnostics */
186
+ }
187
+ }
188
+ const mesh = o;
189
+ if (!mesh.isMesh)
190
+ return;
191
+ mesh.material = Array.isArray(mesh.material) ? mesh.material.map(swap) : swap(mesh.material);
192
+ // The lightmap already holds every static shadow; nothing in here takes part in the live pass.
193
+ mesh.castShadow = false;
194
+ mesh.receiveShadow = false;
195
+ if (o.userData?.[BAKE_EXTRAS.receiveShadow]) {
196
+ receivers.push(mesh);
197
+ // A merged receiver would take its catcher's geometry reference with it.
198
+ mesh.userData.__noMerge = true;
199
+ }
200
+ });
201
+ if (opts.mergeStatics)
202
+ mergeByMaterial(group, { groupBy: "instance", disposeConsumed: false });
203
+ return {
204
+ id: key,
205
+ group,
206
+ receivers,
207
+ manifest,
208
+ attach: (parent) => void parent.add(group),
209
+ detach: () => void group.removeFromParent(),
210
+ dispose: () => {
211
+ group.removeFromParent();
212
+ const textures = new Set();
213
+ group.traverse((o) => {
214
+ const mesh = o;
215
+ if (!mesh.isMesh)
216
+ return;
217
+ mesh.geometry?.dispose();
218
+ for (const m of Array.isArray(mesh.material) ? mesh.material : [mesh.material]) {
219
+ const mm = m;
220
+ if (mm.lightMap)
221
+ textures.add(mm.lightMap);
222
+ m.dispose();
223
+ }
224
+ });
225
+ // Lightmaps belong to this scene alone (unlike shared colour textures), so free them here.
226
+ for (const t of textures)
227
+ t.dispose();
228
+ if (bakedCache.has(key))
229
+ bakedCache.delete(key);
230
+ },
231
+ };
232
+ }
233
+ /** Drop cached baked scenes (all, or one glb path) and free them. */
234
+ export function clearBakedSceneCache(url) {
235
+ const drop = (k, p) => {
236
+ bakedCache.delete(k);
237
+ void p.then((s) => s.dispose()).catch(() => { });
238
+ };
239
+ if (url !== undefined) {
240
+ const cut = url.search(/[?#]/);
241
+ const k = cut === -1 ? url : url.slice(0, cut);
242
+ const p = bakedCache.get(k);
243
+ if (p)
244
+ drop(k, p);
245
+ return;
246
+ }
247
+ for (const [k, p] of bakedCache)
248
+ drop(k, p);
249
+ }
250
+ /**
251
+ * Put a moving object's LIVE shadow on baked ground: one `ShadowMaterial` overlay per receiver, sharing
252
+ * its geometry and parented to it (so it follows exactly, at zero extra memory), drawn just in front
253
+ * of it with a polygon offset.
254
+ *
255
+ * It only darkens, which is the point — the receiver's own lighting is the lightmap and must not
256
+ * change. The catcher needs the game's sun to cast shadows as it already does; nothing else about the
257
+ * live rig changes.
258
+ */
259
+ export function createShadowCatcher(receivers, opts = {}) {
260
+ const material = new THREE.ShadowMaterial({
261
+ opacity: opts.opacity ?? 0.45,
262
+ transparent: true,
263
+ depthWrite: false,
264
+ polygonOffset: true,
265
+ polygonOffsetFactor: -1,
266
+ polygonOffsetUnits: -1,
267
+ });
268
+ const meshes = [];
269
+ for (const r of receivers) {
270
+ const catcher = new THREE.Mesh(r.geometry, material);
271
+ catcher.name = "__shadow-catcher";
272
+ catcher.receiveShadow = true;
273
+ catcher.castShadow = false;
274
+ catcher.renderOrder = 1;
275
+ catcher.raycast = () => { }; // never pickable: it is a coat of paint, not geometry
276
+ r.add(catcher);
277
+ meshes.push(catcher);
278
+ }
279
+ return {
280
+ meshes,
281
+ setOpacity: (o) => void (material.opacity = o),
282
+ dispose: () => {
283
+ for (const m of meshes)
284
+ m.removeFromParent();
285
+ material.dispose();
286
+ },
287
+ };
288
+ }
289
+ //# sourceMappingURL=baked-lighting.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baked-lighting.js","sourceRoot":"","sources":["../../src/three/baked-lighting.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,8 @@
6
6
  * `GLTFLoader` + DRACO + caching per game.
7
7
  */
8
8
  export * from "./world-loader.js";
9
+ export * from "./baked-lighting.js";
10
+ export * from "./preset-lighting.js";
9
11
  export * from "./glb-cache.js";
10
12
  export * from "./merge.js";
11
13
  export * from "./perf-marks.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/three/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/three/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC"}
@@ -6,6 +6,8 @@
6
6
  * `GLTFLoader` + DRACO + caching per game.
7
7
  */
8
8
  export * from "./world-loader.js";
9
+ export * from "./baked-lighting.js";
10
+ export * from "./preset-lighting.js";
9
11
  export * from "./glb-cache.js";
10
12
  export * from "./merge.js";
11
13
  export * from "./perf-marks.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/three/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/three/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * preset-lighting — light a three.js scene LIVE from a {@link WorldLightingPreset}, and turn a world's
3
+ * placed lights into real three.js lights (opt-in, capped).
4
+ *
5
+ * The rig is the one a preset describes, field for field: a shadow-casting sun, an unshadowed fill
6
+ * opposite it, a hemisphere, a flat ambient, and a gradient sky that is both `scene.background` and
7
+ * the PMREM environment. The platform's bake lights the same scene in Blender from the same fields,
8
+ * with the same gradient ({@link buildSkyTexture}), which is what makes a baked scene and a live one
9
+ * of the same preset look alike.
10
+ *
11
+ * A game with its own rig (racing's `installSceneLighting`) does not need this module: it reads the
12
+ * preset's fields into its own. This is for games and tools that don't have one.
13
+ */
14
+ import * as THREE from "three";
15
+ import type { CoreWorld, WorldLight, WorldLightingPreset } from "../protocol/worlds.js";
16
+ /**
17
+ * The sky gradient, as a small equirect canvas texture (sRGB). The stops are the contract the bake's
18
+ * world shader reproduces: zenith down to 14.4° above the horizon, horizon haze AT the horizon, ground
19
+ * from 3.6° below it. Tiny on purpose — PMREM blurs it anyway.
20
+ */
21
+ export declare function buildSkyTexture(sky: WorldLightingPreset["sky"]): THREE.CanvasTexture;
22
+ /** The gradient stops (0 = straight up, 0.5 = horizon, 1 = straight down). Mirrored by the bake script. */
23
+ export declare function skyStops(sky: WorldLightingPreset["sky"]): Array<[number, string]>;
24
+ export interface PresetRigOptions {
25
+ /** Needed for the environment probe. Without it the sky is only a background. */
26
+ renderer?: THREE.WebGLRenderer;
27
+ /** Distance the sun sits from its target. Default 200. */
28
+ sunDistance?: number;
29
+ /** Cast the sun's shadow. Default false (the caller sizes the frustum). */
30
+ shadows?: boolean;
31
+ /** Apply fog. Default true. */
32
+ fog?: boolean;
33
+ }
34
+ /** A live rig built from a preset. `apply` re-lights it from another preset without rebuilding. */
35
+ export interface PresetRig {
36
+ readonly sun: THREE.DirectionalLight;
37
+ readonly fill: THREE.DirectionalLight;
38
+ readonly hemisphere: THREE.HemisphereLight;
39
+ readonly ambient: THREE.AmbientLight;
40
+ apply(preset: WorldLightingPreset): void;
41
+ dispose(): void;
42
+ }
43
+ /**
44
+ * Light `scene` from `preset`: adds the rig's lights, sets background / environment / fog, and the
45
+ * renderer's exposure (ACES filmic) when a renderer is given.
46
+ */
47
+ export declare function applyLightingPreset(scene: THREE.Scene, preset: WorldLightingPreset, opts?: PresetRigOptions): PresetRig;
48
+ export interface WorldLightsOptions {
49
+ /**
50
+ * At most this many live lights (default 8): each one costs every lit pixel of the frame in WebGL.
51
+ * The strongest are kept — or the nearest to `near`, when given.
52
+ */
53
+ max?: number;
54
+ near?: THREE.Vector3;
55
+ /** Let them cast shadows. Default false (a point light's shadow is six renders). */
56
+ shadows?: boolean;
57
+ }
58
+ /**
59
+ * Real three.js lights for a world's placed {@link WorldLight}s, under a preset's groups. Area lights
60
+ * are skipped (bake-only). For a LIVE scene only — a baked one already has their light.
61
+ */
62
+ export declare function createWorldLights(world: Pick<CoreWorld, "map">, preset: WorldLightingPreset | null, opts?: WorldLightsOptions): THREE.Group;
63
+ /** One {@link WorldLight} as a three.js light (an area light is approximated as a point). Intensity already includes the preset. */
64
+ export declare function threeLight(l: WorldLight, intensity: number): THREE.Light;
65
+ //# sourceMappingURL=preset-lighting.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preset-lighting.d.ts","sourceRoot":"","sources":["../../src/three/preset-lighting.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAGxF;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,mBAAmB,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,aAAa,CAepF;AAED,2GAA2G;AAC3G,wBAAgB,QAAQ,CAAC,GAAG,EAAE,mBAAmB,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAQjF;AAED,MAAM,WAAW,gBAAgB;IAC/B,iFAAiF;IACjF,QAAQ,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC/B,0DAA0D;IAC1D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,2EAA2E;IAC3E,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,+BAA+B;IAC/B,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,mGAAmG;AACnG,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,GAAG,EAAE,KAAK,CAAC,gBAAgB,CAAC;IACrC,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC,gBAAgB,CAAC;IACtC,QAAQ,CAAC,UAAU,EAAE,KAAK,CAAC,eAAe,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,YAAY,CAAC;IACrC,KAAK,CAAC,MAAM,EAAE,mBAAmB,GAAG,IAAI,CAAC;IACzC,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,KAAK,CAAC,KAAK,EAClB,MAAM,EAAE,mBAAmB,EAC3B,IAAI,GAAE,gBAAqB,GAC1B,SAAS,CA2DX;AAED,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC;IACrB,oFAAoF;IACpF,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,EAC7B,MAAM,EAAE,mBAAmB,GAAG,IAAI,EAClC,IAAI,GAAE,kBAAuB,GAC5B,KAAK,CAAC,KAAK,CAgBb;AAED,oIAAoI;AACpI,wBAAgB,UAAU,CAAC,CAAC,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,KAAK,CAAC,KAAK,CAqBxE"}
@@ -0,0 +1,163 @@
1
+ /**
2
+ * preset-lighting — light a three.js scene LIVE from a {@link WorldLightingPreset}, and turn a world's
3
+ * placed lights into real three.js lights (opt-in, capped).
4
+ *
5
+ * The rig is the one a preset describes, field for field: a shadow-casting sun, an unshadowed fill
6
+ * opposite it, a hemisphere, a flat ambient, and a gradient sky that is both `scene.background` and
7
+ * the PMREM environment. The platform's bake lights the same scene in Blender from the same fields,
8
+ * with the same gradient ({@link buildSkyTexture}), which is what makes a baked scene and a live one
9
+ * of the same preset look alike.
10
+ *
11
+ * A game with its own rig (racing's `installSceneLighting`) does not need this module: it reads the
12
+ * preset's fields into its own. This is for games and tools that don't have one.
13
+ */
14
+ import * as THREE from "three";
15
+ import { effectiveLights, sunDirection } from "../world-lighting.js";
16
+ /**
17
+ * The sky gradient, as a small equirect canvas texture (sRGB). The stops are the contract the bake's
18
+ * world shader reproduces: zenith down to 14.4° above the horizon, horizon haze AT the horizon, ground
19
+ * from 3.6° below it. Tiny on purpose — PMREM blurs it anyway.
20
+ */
21
+ export function buildSkyTexture(sky) {
22
+ const canvas = document.createElement("canvas");
23
+ canvas.width = 32;
24
+ canvas.height = 128;
25
+ const ctx = canvas.getContext("2d");
26
+ if (!ctx)
27
+ throw new Error("[rydr-sdk] buildSkyTexture: 2D context unavailable");
28
+ const grad = ctx.createLinearGradient(0, 0, 0, canvas.height);
29
+ for (const [at, colour] of skyStops(sky))
30
+ grad.addColorStop(at, colour);
31
+ ctx.fillStyle = grad;
32
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
33
+ const tex = new THREE.CanvasTexture(canvas);
34
+ tex.mapping = THREE.EquirectangularReflectionMapping;
35
+ tex.colorSpace = THREE.SRGBColorSpace;
36
+ tex.needsUpdate = true;
37
+ return tex;
38
+ }
39
+ /** The gradient stops (0 = straight up, 0.5 = horizon, 1 = straight down). Mirrored by the bake script. */
40
+ export function skyStops(sky) {
41
+ return [
42
+ [0, sky.zenith],
43
+ [0.42, sky.zenith],
44
+ [0.5, sky.horizon],
45
+ [0.52, sky.ground],
46
+ [1, sky.ground],
47
+ ];
48
+ }
49
+ /**
50
+ * Light `scene` from `preset`: adds the rig's lights, sets background / environment / fog, and the
51
+ * renderer's exposure (ACES filmic) when a renderer is given.
52
+ */
53
+ export function applyLightingPreset(scene, preset, opts = {}) {
54
+ const dist = opts.sunDistance ?? 200;
55
+ const sun = new THREE.DirectionalLight();
56
+ sun.name = "preset-sun";
57
+ sun.castShadow = !!opts.shadows;
58
+ const fill = new THREE.DirectionalLight();
59
+ fill.name = "preset-fill";
60
+ const hemisphere = new THREE.HemisphereLight();
61
+ const ambient = new THREE.AmbientLight();
62
+ scene.add(sun, sun.target, fill, fill.target, hemisphere, ambient);
63
+ let sky = null;
64
+ let env = null;
65
+ const apply = (p) => {
66
+ const d = sunDirection(p.sun);
67
+ sun.color.set(p.sun.color);
68
+ sun.intensity = p.sun.intensity;
69
+ sun.position.set(d[0] * dist, d[1] * dist, d[2] * dist);
70
+ fill.color.set(p.fill?.color ?? p.hemisphere?.sky ?? "#ffffff");
71
+ fill.intensity = p.fill?.intensity ?? 0;
72
+ fill.position.set(-d[0] * dist, Math.max(0.2, d[1] * 0.4) * dist, -d[2] * dist);
73
+ hemisphere.color.set(p.hemisphere?.sky ?? "#ffffff");
74
+ hemisphere.groundColor.set(p.hemisphere?.ground ?? "#000000");
75
+ hemisphere.intensity = p.hemisphere?.intensity ?? 0;
76
+ ambient.color.set(p.ambient?.color ?? "#ffffff");
77
+ ambient.intensity = p.ambient?.intensity ?? 0;
78
+ sky?.dispose();
79
+ env?.dispose();
80
+ sky = buildSkyTexture(p.sky);
81
+ scene.background = sky;
82
+ if (opts.renderer) {
83
+ const pmrem = new THREE.PMREMGenerator(opts.renderer);
84
+ env = pmrem.fromEquirectangular(sky);
85
+ pmrem.dispose();
86
+ scene.environment = env.texture;
87
+ scene.environmentIntensity = p.sky.intensity;
88
+ opts.renderer.toneMapping = THREE.ACESFilmicToneMapping;
89
+ opts.renderer.toneMappingExposure = p.exposure ?? 1;
90
+ }
91
+ scene.fog = opts.fog !== false && p.fog ? new THREE.Fog(p.fog.color, p.fog.near, p.fog.far) : null;
92
+ };
93
+ apply(preset);
94
+ return {
95
+ sun,
96
+ fill,
97
+ hemisphere,
98
+ ambient,
99
+ apply,
100
+ dispose: () => {
101
+ for (const l of [sun, sun.target, fill, fill.target, hemisphere, ambient])
102
+ l.removeFromParent();
103
+ sky?.dispose();
104
+ env?.dispose();
105
+ if (scene.background === sky)
106
+ scene.background = null;
107
+ if (env && scene.environment === env.texture)
108
+ scene.environment = null;
109
+ },
110
+ };
111
+ }
112
+ /**
113
+ * Real three.js lights for a world's placed {@link WorldLight}s, under a preset's groups. Area lights
114
+ * are skipped (bake-only). For a LIVE scene only — a baked one already has their light.
115
+ */
116
+ export function createWorldLights(world, preset, opts = {}) {
117
+ const group = new THREE.Group();
118
+ group.name = "world-lights";
119
+ const max = opts.max ?? 8;
120
+ const candidates = effectiveLights(world, preset)
121
+ .filter((l) => l.type !== "area")
122
+ .map((l) => ({ l, i: l.intensity }));
123
+ const near = opts.near;
124
+ candidates.sort((a, b) => (near ? dist2(a.l, near) - dist2(b.l, near) : b.i - a.i));
125
+ for (const { l, i } of candidates.slice(0, max)) {
126
+ const light = threeLight(l, i);
127
+ light.castShadow = !!opts.shadows && l.castShadow !== false;
128
+ group.add(light);
129
+ if (light.target)
130
+ group.add(light.target);
131
+ }
132
+ return group;
133
+ }
134
+ /** One {@link WorldLight} as a three.js light (an area light is approximated as a point). Intensity already includes the preset. */
135
+ export function threeLight(l, intensity) {
136
+ const pos = new THREE.Vector3(...l.position);
137
+ const q = l.rotation ? new THREE.Quaternion(...l.rotation) : new THREE.Quaternion();
138
+ // A light shines down its local -Y (see WorldLight.rotation): aim targets one metre along it.
139
+ const aim = new THREE.Vector3(0, -1, 0).applyQuaternion(q).add(pos);
140
+ let light;
141
+ if (l.type === "directional") {
142
+ const d = new THREE.DirectionalLight(l.color, intensity);
143
+ d.target.position.copy(aim);
144
+ light = d;
145
+ }
146
+ else if (l.type === "spot") {
147
+ const s = new THREE.SpotLight(l.color, intensity, l.range ?? 0, l.angle ?? Math.PI / 6, l.penumbra ?? 0.2, 2);
148
+ s.target.position.copy(aim);
149
+ light = s;
150
+ }
151
+ else {
152
+ light = new THREE.PointLight(l.color, intensity, l.range ?? 0, 2);
153
+ }
154
+ light.position.copy(pos);
155
+ light.name = l.name ?? l.id;
156
+ light.userData.worldLightId = l.id;
157
+ return light;
158
+ }
159
+ function dist2(l, p) {
160
+ const [x, y, z] = l.position;
161
+ return (x - p.x) ** 2 + (y - p.y) ** 2 + (z - p.z) ** 2;
162
+ }
163
+ //# sourceMappingURL=preset-lighting.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preset-lighting.js","sourceRoot":"","sources":["../../src/three/preset-lighting.ts"],"names":[],"mappings":"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"}