three-usd-robot 0.14.0 → 0.14.1

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.
package/dist/rendering.js CHANGED
@@ -84,8 +84,16 @@ function finishDataTexture(texture, colorSpace) {
84
84
  return texture;
85
85
  }
86
86
  function colorTexture(color) {
87
- const data = new Float32Array([color[0], color[1], color[2], 1]);
88
- const texture = new THREE.DataTexture(data, 1, 1, THREE.RGBAFormat, THREE.FloatType);
87
+ const width = 64;
88
+ const height = 32;
89
+ const data = new Float32Array(width * height * 4);
90
+ for (let i = 0; i < width * height; i++) {
91
+ data[i * 4] = color[0];
92
+ data[i * 4 + 1] = color[1];
93
+ data[i * 4 + 2] = color[2];
94
+ data[i * 4 + 3] = 1;
95
+ }
96
+ const texture = new THREE.DataTexture(data, width, height, THREE.RGBAFormat, THREE.FloatType);
89
97
  return finishDataTexture(texture, THREE.LinearSRGBColorSpace);
90
98
  }
91
99
  function domeRotation(robot, dome) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/rendering/environment.ts","../src/rendering/renderDefaults.ts"],"names":["texture","THREE2"],"mappings":"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","file":"rendering.js","sourcesContent":["/**\n * DomeLight → image-based environment lighting (M26).\n *\n * A `DomeLight` is not a discrete light: it is the scene's environment. This\n * module fetches the dome's texture through the robot's captured asset context\n * (so relative CDN paths and `.usdz`-embedded images both work), decodes\n * `.hdr` / `.exr` (via three's addons loaders) or LDR images into an\n * equirectangular texture, and applies it as `scene.environment` — three\n * prefilters equirectangular environments internally, no PMREM setup needed.\n *\n * Orientation: three.js expects the equirect pole along +Y. The dome's pole\n * follows `poleAxis` (`DomeLight_1`) or, for the original `DomeLight` schema,\n * the stage up-axis — composed with the dome prim's own rotation and the\n * loader's up-axis normalization into `scene.environmentRotation` (three\n * r162+; skipped with a warning on older peers when it matters).\n */\n\nimport * as THREE from \"three\";\nimport { EXRLoader } from \"three/addons/loaders/EXRLoader.js\";\nimport { RGBELoader } from \"three/addons/loaders/RGBELoader.js\";\nimport type { LightDescription } from \"../schemas/usdLux.js\";\nimport type { ThreeUsdRobot } from \"../three/ThreeUsdRobot.js\";\nimport { computeWorldTransform } from \"../usd/xformOps.js\";\n\nexport type ApplyUsdEnvironmentOptions = {\n /** Also show the environment as `scene.background` (default `false`). */\n background?: boolean;\n /**\n * Multiplies the dome's authored emission (`intensity × 2^exposure`) into\n * `scene.environmentIntensity`. Defaults to the `lightIntensityScale` the\n * robot was loaded with, so the environment stays in balance with the bound\n * lights (see docs/lighting.md).\n */\n intensityScale?: number;\n /** The dome to apply when the stage has several (default: the first). */\n dome?: LightDescription;\n /** Receives fallback/compatibility diagnostics. */\n onWarn?: (message: string) => void;\n};\n\n/** What {@link applyUsdEnvironment} applied to the scene. */\nexport type UsdEnvironment = {\n dome: LightDescription;\n /** The environment texture — equirectangular HDR/LDR, or 1×1 dome color. */\n texture: THREE.Texture;\n /** Environment orientation applied (identity when unsupported by the peer). */\n rotation: THREE.Euler;\n /** Effective emission written to `scene.environmentIntensity`. */\n intensity: number;\n};\n\n/**\n * Realize the stage's DomeLight as the scene environment. Resolves the dome's\n * texture (falling back to a uniform texture of the dome color when it has\n * none, or when it cannot be fetched or decoded) and sets\n * `scene.environment(+Rotation/+Intensity)` — and, with\n * `options.background`, the matching background properties. Returns `null`\n * when the robot has no DomeLight; the scene is left untouched.\n */\nexport async function applyUsdEnvironment(\n robot: ThreeUsdRobot,\n scene: THREE.Scene,\n options: ApplyUsdEnvironmentOptions = {},\n): Promise<UsdEnvironment | null> {\n const dome = options.dome ?? robot.domeLights[0];\n if (!dome) return null;\n const onWarn = options.onWarn;\n\n let texture: THREE.Texture | null = null;\n if (dome.textureFile) {\n if (\n dome.textureFormat &&\n dome.textureFormat !== \"latlong\" &&\n dome.textureFormat !== \"automatic\"\n ) {\n onWarn?.(\n `DomeLight texture:format \"${dome.textureFormat}\" is not supported; sampling it as latlong (equirectangular)`,\n );\n }\n try {\n texture = await loadDomeTexture(robot, dome.textureFile);\n } catch (err) {\n onWarn?.(\n `DomeLight texture ${dome.textureFile} could not be loaded (${(err as Error).message}); falling back to the dome color`,\n );\n }\n }\n texture ??= colorTexture(dome.color);\n\n const intensity = dome.intensity * (options.intensityScale ?? robot.lightIntensityScale ?? 1);\n const rotation = domeRotation(robot, dome);\n\n scene.environment = texture;\n setSceneEuler(scene, \"environmentRotation\", rotation, onWarn);\n setSceneNumber(scene, \"environmentIntensity\", intensity, onWarn);\n if (options.background) {\n scene.background = texture;\n setSceneEuler(scene, \"backgroundRotation\", rotation, undefined);\n setSceneNumber(scene, \"backgroundIntensity\", intensity, undefined);\n }\n return { dome, texture, rotation, intensity };\n}\n\n/**\n * Fetch and decode the dome image through the robot's asset context: `.hdr`\n * (Radiance RGBE) and `.exr` decode to float data textures; anything else\n * decodes as an LDR image (browser only). The result is equirect-mapped.\n */\nasync function loadDomeTexture(robot: ThreeUsdRobot, assetPath: string): Promise<THREE.Texture> {\n const context = robot.assetContext;\n if (!context) {\n throw new Error(\"robot carries no asset context (was it built by ThreeUsdRobotLoader?)\");\n }\n const url = context.resolver.resolve(assetPath, context.baseUrl);\n const bytes = context.resolver.fetchBytes\n ? await context.resolver.fetchBytes(url)\n : new TextEncoder().encode(await context.resolver.fetchText(url));\n\n if (/\\.hdr$/i.test(url)) {\n const texData = new RGBELoader().parse(toArrayBuffer(bytes));\n const texture = new THREE.DataTexture(\n texData.data as unknown as BufferSource,\n texData.width,\n texData.height,\n THREE.RGBAFormat,\n texData.type,\n );\n texture.flipY = true; // Radiance scanlines run top-down\n return finishDataTexture(texture, THREE.LinearSRGBColorSpace);\n }\n if (/\\.exr$/i.test(url)) {\n const texData = new EXRLoader().parse(toArrayBuffer(bytes));\n const texture = new THREE.DataTexture(\n texData.data as unknown as BufferSource,\n texData.width,\n texData.height,\n texData.format,\n texData.type,\n );\n texture.flipY = false; // EXR rows decode bottom-up already\n return finishDataTexture(texture, texData.colorSpace);\n }\n\n const texture = new THREE.Texture(await decodeImage(bytes, url));\n texture.colorSpace = THREE.SRGBColorSpace;\n texture.mapping = THREE.EquirectangularReflectionMapping;\n texture.needsUpdate = true;\n return texture;\n}\n\nfunction finishDataTexture(texture: THREE.DataTexture, colorSpace: string): THREE.Texture {\n texture.colorSpace = colorSpace;\n texture.magFilter = THREE.LinearFilter;\n texture.minFilter = THREE.LinearFilter;\n texture.generateMipmaps = false;\n texture.mapping = THREE.EquirectangularReflectionMapping;\n texture.needsUpdate = true;\n return texture;\n}\n\n/** 1×1 float environment of the dome's (linear) color — a uniform sky. */\nfunction colorTexture(color: [number, number, number]): THREE.Texture {\n const data = new Float32Array([color[0], color[1], color[2], 1]);\n const texture = new THREE.DataTexture(data, 1, 1, THREE.RGBAFormat, THREE.FloatType);\n return finishDataTexture(texture, THREE.LinearSRGBColorSpace);\n}\n\n/**\n * Environment orientation: (root up-axis normalization) × (dome prim's stage\n * rotation) × (pole correction from three's +Y-pole equirect convention to\n * the dome's pole axis).\n */\nfunction domeRotation(robot: ThreeUsdRobot, dome: LightDescription): THREE.Euler {\n const q = robot.quaternion.clone();\n\n const prim = robot.stage?.GetPrimAtPath(dome.primPath);\n if (prim) {\n const world = new THREE.Matrix4().fromArray(computeWorldTransform(prim));\n const rotation = new THREE.Matrix4().extractRotation(world); // drops the prim chain's scale\n q.multiply(new THREE.Quaternion().setFromRotationMatrix(rotation));\n }\n\n // DomeLight_1 authors poleAxis; the original schema follows the stage up-axis.\n const pole = dome.poleAxis === \"Y\" || dome.poleAxis === \"Z\" ? dome.poleAxis : robot.robot.upAxis;\n if (pole === \"Z\") {\n q.multiply(new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1, 0, 0), Math.PI / 2));\n }\n return new THREE.Euler().setFromQuaternion(q);\n}\n\n/** Set a Scene Euler property when the installed three has it (r162+). */\nfunction setSceneEuler(\n scene: THREE.Scene,\n name: \"environmentRotation\" | \"backgroundRotation\",\n rotation: THREE.Euler,\n onWarn: ((message: string) => void) | undefined,\n): void {\n if (name in scene) {\n scene[name].copy(rotation);\n } else if (Math.abs(rotation.x) + Math.abs(rotation.y) + Math.abs(rotation.z) > 1e-6) {\n onWarn?.(`this three.js has no Scene.${name} (added r162); the dome orientation is dropped`);\n }\n}\n\n/** Set a Scene number property when the installed three has it (r163+). */\nfunction setSceneNumber(\n scene: THREE.Scene,\n name: \"environmentIntensity\" | \"backgroundIntensity\",\n value: number,\n onWarn: ((message: string) => void) | undefined,\n): void {\n if (name in scene) {\n scene[name] = value;\n } else if (Math.abs(value - 1) > 1e-6) {\n onWarn?.(`this three.js has no Scene.${name} (added r163); the dome intensity is dropped`);\n }\n}\n\n/** `RGBELoader.parse` wants an ArrayBuffer aligned to the data. */\nfunction toArrayBuffer(bytes: Uint8Array): ArrayBuffer {\n if (bytes.byteOffset === 0 && bytes.byteLength === bytes.buffer.byteLength) {\n return bytes.buffer as ArrayBuffer;\n }\n return bytes.slice().buffer as ArrayBuffer;\n}\n\n/** Decode LDR image bytes via a blob URL (browser environments). */\nfunction decodeImage(bytes: Uint8Array, url: string): Promise<HTMLImageElement> {\n if (typeof Image === \"undefined\") {\n return Promise.reject(new Error(\"LDR dome textures need a browser image decoder\"));\n }\n const mime = /\\.jpe?g$/i.test(url)\n ? \"image/jpeg\"\n : /\\.webp$/i.test(url)\n ? \"image/webp\"\n : \"image/png\";\n const blob = new Blob([bytes as unknown as BlobPart], { type: mime });\n const objectUrl = URL.createObjectURL(blob);\n return new Promise<HTMLImageElement>((resolve, reject) => {\n const img = new Image();\n img.onload = () => {\n URL.revokeObjectURL(objectUrl);\n resolve(img);\n };\n img.onerror = () => {\n URL.revokeObjectURL(objectUrl);\n reject(new Error(`failed to decode dome texture: ${url}`));\n };\n img.src = objectUrl;\n });\n}\n","/**\n * One-call renderer defaults (M28) — the settings every USD viewer built on\n * this library ends up wanting: filmic tone mapping (USD lights and HDRI\n * domes are HDR values; three's default `NoToneMapping` clips them), soft\n * shadow maps (the loader pre-flags meshes and lights, M25), and optionally\n * an exposure — either a plain multiplier or a `UsdGeomCamera` description,\n * whose USD 24.11 linear exposure scale is applied (M27).\n *\n * Deliberately small: post-processing (AO, SSR, TAA, bloom) stays out of the\n * library — compose three's own passes in your app; the Vite example shows a\n * GTAO setup.\n */\n\nimport * as THREE from \"three\";\nimport { type CameraDescription, computeCameraExposureScale } from \"../schemas/usdGeomCamera.js\";\n\n/** Filmic curve to install. `\"none\"` restores three's linear pass-through. */\nexport type ToneMappingPreset = \"ACES\" | \"AgX\" | \"neutral\" | \"none\";\n\nexport type RenderDefaultsOptions = {\n /** Default `\"ACES\"`. `\"neutral\"` (Khronos PBR Neutral) needs three r162+. */\n toneMapping?: ToneMappingPreset;\n /**\n * Sets `toneMappingExposure`: a number as-is, or a\n * {@link CameraDescription} via its linear exposure scale\n * ({@link computeCameraExposureScale}). Left untouched when omitted.\n */\n exposure?: number | CameraDescription;\n /** Enable `PCFSoftShadowMap` shadow rendering (default `true`). */\n shadows?: boolean;\n /** Receives compatibility diagnostics. */\n onWarn?: (message: string) => void;\n};\n\n/**\n * The renderer surface this helper touches — satisfied by `WebGLRenderer`\n * and `WebGPURenderer` alike, without depending on `three/webgpu` types.\n */\nexport type RenderDefaultsTarget = {\n toneMapping: THREE.ToneMapping;\n toneMappingExposure: number;\n shadowMap: { enabled: boolean; type: THREE.ShadowMapType };\n};\n\n/**\n * Apply viewer defaults to a renderer:\n *\n * ```ts\n * import { applyRenderDefaults } from \"three-usd-robot/rendering\";\n *\n * applyRenderDefaults(renderer); // ACES + soft shadow maps\n * applyRenderDefaults(renderer, { toneMapping: \"AgX\", exposure: robot.cameras[0]?.userData.usdCamera });\n * ```\n *\n * Only ever switches features on or assigns requested values — `shadows:\n * false` skips enabling shadow maps rather than force-disabling them.\n */\nexport function applyRenderDefaults(\n renderer: RenderDefaultsTarget,\n options: RenderDefaultsOptions = {},\n): void {\n renderer.toneMapping = resolveToneMapping(options.toneMapping ?? \"ACES\", options.onWarn);\n if (options.exposure !== undefined) {\n renderer.toneMappingExposure =\n typeof options.exposure === \"number\"\n ? options.exposure\n : computeCameraExposureScale(options.exposure);\n }\n if (options.shadows ?? true) {\n renderer.shadowMap.enabled = true;\n renderer.shadowMap.type = THREE.PCFSoftShadowMap;\n }\n}\n\nfunction resolveToneMapping(\n preset: ToneMappingPreset,\n onWarn: ((message: string) => void) | undefined,\n): THREE.ToneMapping {\n switch (preset) {\n case \"none\":\n return THREE.NoToneMapping;\n case \"AgX\":\n return THREE.AgXToneMapping;\n case \"neutral\": {\n // Runtime lookup: the peer floor (r160) predates NeutralToneMapping (r162).\n const neutral = (THREE as Record<string, unknown>).NeutralToneMapping;\n if (typeof neutral === \"number\") return neutral as THREE.ToneMapping;\n onWarn?.('this three.js has no NeutralToneMapping (added r162); using \"ACES\" instead');\n return THREE.ACESFilmicToneMapping;\n }\n case \"ACES\":\n return THREE.ACESFilmicToneMapping;\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/rendering/environment.ts","../src/rendering/renderDefaults.ts"],"names":["texture","THREE2"],"mappings":";;;;;;;AA2DA,eAAsB,mBAAA,CACpB,KAAA,EACA,KAAA,EACA,OAAA,GAAsC,EAAC,EACP;AAChC,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,IAAA,IAAQ,KAAA,CAAM,WAAW,CAAC,CAAA;AAC/C,EAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAClB,EAAA,MAAM,SAAS,OAAA,CAAQ,MAAA;AAEvB,EAAA,IAAI,OAAA,GAAgC,IAAA;AACpC,EAAA,IAAI,KAAK,WAAA,EAAa;AACpB,IAAA,IACE,KAAK,aAAA,IACL,IAAA,CAAK,kBAAkB,SAAA,IACvB,IAAA,CAAK,kBAAkB,WAAA,EACvB;AACA,MAAA,MAAA;AAAA,QACE,CAAA,0BAAA,EAA6B,KAAK,aAAa,CAAA,4DAAA;AAAA,OACjD;AAAA,IACF;AACA,IAAA,IAAI;AACF,MAAA,OAAA,GAAU,MAAM,eAAA,CAAgB,KAAA,EAAO,IAAA,CAAK,WAAW,CAAA;AAAA,IACzD,SAAS,GAAA,EAAK;AACZ,MAAA,MAAA;AAAA,QACE,CAAA,kBAAA,EAAqB,IAAA,CAAK,WAAW,CAAA,sBAAA,EAA0B,IAAc,OAAO,CAAA,iCAAA;AAAA,OACtF;AAAA,IACF;AAAA,EACF;AACA,EAAA,OAAA,KAAY,YAAA,CAAa,KAAK,KAAK,CAAA;AAEnC,EAAA,MAAM,YAAY,IAAA,CAAK,SAAA,IAAa,OAAA,CAAQ,cAAA,IAAkB,MAAM,mBAAA,IAAuB,CAAA,CAAA;AAC3F,EAAA,MAAM,QAAA,GAAW,YAAA,CAAa,KAAA,EAAO,IAAI,CAAA;AAEzC,EAAA,KAAA,CAAM,WAAA,GAAc,OAAA;AACpB,EAAA,aAAA,CAAc,KAAA,EAAO,qBAAA,EAAuB,QAAA,EAAU,MAAM,CAAA;AAC5D,EAAA,cAAA,CAAe,KAAA,EAAO,sBAAA,EAAwB,SAAA,EAAW,MAAM,CAAA;AAC/D,EAAA,IAAI,QAAQ,UAAA,EAAY;AACtB,IAAA,KAAA,CAAM,UAAA,GAAa,OAAA;AACnB,IAAA,aAAA,CAAc,KAAA,EAAO,oBAAA,EAAsB,QAAA,EAAU,MAAS,CAAA;AAC9D,IAAA,cAAA,CAAe,KAAA,EAAO,qBAAA,EAAuB,SAAA,EAAW,MAAS,CAAA;AAAA,EACnE;AACA,EAAA,OAAO,EAAE,IAAA,EAAM,OAAA,EAAS,QAAA,EAAU,SAAA,EAAU;AAC9C;AAOA,eAAe,eAAA,CAAgB,OAAsB,SAAA,EAA2C;AAC9F,EAAA,MAAM,UAAU,KAAA,CAAM,YAAA;AACtB,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAM,IAAI,MAAM,uEAAuE,CAAA;AAAA,EACzF;AACA,EAAA,MAAM,MAAM,OAAA,CAAQ,QAAA,CAAS,OAAA,CAAQ,SAAA,EAAW,QAAQ,OAAO,CAAA;AAC/D,EAAA,MAAM,QAAQ,OAAA,CAAQ,QAAA,CAAS,aAC3B,MAAM,OAAA,CAAQ,SAAS,UAAA,CAAW,GAAG,IACrC,IAAI,WAAA,GAAc,MAAA,CAAO,MAAM,QAAQ,QAAA,CAAS,SAAA,CAAU,GAAG,CAAC,CAAA;AAElE,EAAA,IAAI,SAAA,CAAU,IAAA,CAAK,GAAG,CAAA,EAAG;AACvB,IAAA,MAAM,UAAU,IAAI,UAAA,GAAa,KAAA,CAAM,aAAA,CAAc,KAAK,CAAC,CAAA;AAC3D,IAAA,MAAMA,WAAU,IAAU,KAAA,CAAA,WAAA;AAAA,MACxB,OAAA,CAAQ,IAAA;AAAA,MACR,OAAA,CAAQ,KAAA;AAAA,MACR,OAAA,CAAQ,MAAA;AAAA,MACF,KAAA,CAAA,UAAA;AAAA,MACN,OAAA,CAAQ;AAAA,KACV;AACA,IAAAA,SAAQ,KAAA,GAAQ,IAAA;AAChB,IAAA,OAAO,iBAAA,CAAkBA,UAAe,KAAA,CAAA,oBAAoB,CAAA;AAAA,EAC9D;AACA,EAAA,IAAI,SAAA,CAAU,IAAA,CAAK,GAAG,CAAA,EAAG;AACvB,IAAA,MAAM,UAAU,IAAI,SAAA,GAAY,KAAA,CAAM,aAAA,CAAc,KAAK,CAAC,CAAA;AAC1D,IAAA,MAAMA,WAAU,IAAU,KAAA,CAAA,WAAA;AAAA,MACxB,OAAA,CAAQ,IAAA;AAAA,MACR,OAAA,CAAQ,KAAA;AAAA,MACR,OAAA,CAAQ,MAAA;AAAA,MACR,OAAA,CAAQ,MAAA;AAAA,MACR,OAAA,CAAQ;AAAA,KACV;AACA,IAAAA,SAAQ,KAAA,GAAQ,KAAA;AAChB,IAAA,OAAO,iBAAA,CAAkBA,QAAAA,EAAS,OAAA,CAAQ,UAAU,CAAA;AAAA,EACtD;AAEA,EAAA,MAAM,UAAU,IAAU,KAAA,CAAA,OAAA,CAAQ,MAAM,WAAA,CAAY,KAAA,EAAO,GAAG,CAAC,CAAA;AAC/D,EAAA,OAAA,CAAQ,UAAA,GAAmB,KAAA,CAAA,cAAA;AAC3B,EAAA,OAAA,CAAQ,OAAA,GAAgB,KAAA,CAAA,gCAAA;AACxB,EAAA,OAAA,CAAQ,WAAA,GAAc,IAAA;AACtB,EAAA,OAAO,OAAA;AACT;AAEA,SAAS,iBAAA,CAAkB,SAA4B,UAAA,EAAmC;AACxF,EAAA,OAAA,CAAQ,UAAA,GAAa,UAAA;AACrB,EAAA,OAAA,CAAQ,SAAA,GAAkB,KAAA,CAAA,YAAA;AAC1B,EAAA,OAAA,CAAQ,SAAA,GAAkB,KAAA,CAAA,YAAA;AAC1B,EAAA,OAAA,CAAQ,eAAA,GAAkB,KAAA;AAC1B,EAAA,OAAA,CAAQ,OAAA,GAAgB,KAAA,CAAA,gCAAA;AACxB,EAAA,OAAA,CAAQ,WAAA,GAAc,IAAA;AACtB,EAAA,OAAO,OAAA;AACT;AAQA,SAAS,aAAa,KAAA,EAAgD;AACpE,EAAA,MAAM,KAAA,GAAQ,EAAA;AACd,EAAA,MAAM,MAAA,GAAS,EAAA;AACf,EAAA,MAAM,IAAA,GAAO,IAAI,YAAA,CAAa,KAAA,GAAQ,SAAS,CAAC,CAAA;AAChD,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,KAAA,GAAQ,QAAQ,CAAA,EAAA,EAAK;AACvC,IAAA,IAAA,CAAK,CAAA,GAAI,CAAC,CAAA,GAAI,KAAA,CAAM,CAAC,CAAA;AACrB,IAAA,IAAA,CAAK,CAAA,GAAI,CAAA,GAAI,CAAC,CAAA,GAAI,MAAM,CAAC,CAAA;AACzB,IAAA,IAAA,CAAK,CAAA,GAAI,CAAA,GAAI,CAAC,CAAA,GAAI,MAAM,CAAC,CAAA;AACzB,IAAA,IAAA,CAAK,CAAA,GAAI,CAAA,GAAI,CAAC,CAAA,GAAI,CAAA;AAAA,EACpB;AACA,EAAA,MAAM,UAAU,IAAU,KAAA,CAAA,WAAA,CAAY,MAAM,KAAA,EAAO,MAAA,EAAc,kBAAkB,KAAA,CAAA,SAAS,CAAA;AAC5F,EAAA,OAAO,iBAAA,CAAkB,SAAe,KAAA,CAAA,oBAAoB,CAAA;AAC9D;AAOA,SAAS,YAAA,CAAa,OAAsB,IAAA,EAAqC;AAC/E,EAAA,MAAM,CAAA,GAAI,KAAA,CAAM,UAAA,CAAW,KAAA,EAAM;AAEjC,EAAA,MAAM,IAAA,GAAO,KAAA,CAAM,KAAA,EAAO,aAAA,CAAc,KAAK,QAAQ,CAAA;AACrD,EAAA,IAAI,IAAA,EAAM;AACR,IAAA,MAAM,QAAQ,IAAU,KAAA,CAAA,OAAA,GAAU,SAAA,CAAU,qBAAA,CAAsB,IAAI,CAAC,CAAA;AACvE,IAAA,MAAM,QAAA,GAAW,IAAU,KAAA,CAAA,OAAA,EAAQ,CAAE,gBAAgB,KAAK,CAAA;AAC1D,IAAA,CAAA,CAAE,SAAS,IAAU,KAAA,CAAA,UAAA,EAAW,CAAE,qBAAA,CAAsB,QAAQ,CAAC,CAAA;AAAA,EACnE;AAGA,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,QAAA,KAAa,GAAA,IAAO,IAAA,CAAK,aAAa,GAAA,GAAM,IAAA,CAAK,QAAA,GAAW,KAAA,CAAM,KAAA,CAAM,MAAA;AAC1F,EAAA,IAAI,SAAS,GAAA,EAAK;AAChB,IAAA,CAAA,CAAE,QAAA,CAAS,IAAU,KAAA,CAAA,UAAA,EAAW,CAAE,iBAAiB,IAAU,KAAA,CAAA,OAAA,CAAQ,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA,EAAG,IAAA,CAAK,EAAA,GAAK,CAAC,CAAC,CAAA;AAAA,EAC7F;AACA,EAAA,OAAO,IAAU,KAAA,CAAA,KAAA,EAAM,CAAE,iBAAA,CAAkB,CAAC,CAAA;AAC9C;AAGA,SAAS,aAAA,CACP,KAAA,EACA,IAAA,EACA,QAAA,EACA,MAAA,EACM;AACN,EAAA,IAAI,QAAQ,KAAA,EAAO;AACjB,IAAA,KAAA,CAAM,IAAI,CAAA,CAAE,IAAA,CAAK,QAAQ,CAAA;AAAA,EAC3B,WAAW,IAAA,CAAK,GAAA,CAAI,QAAA,CAAS,CAAC,IAAI,IAAA,CAAK,GAAA,CAAI,QAAA,CAAS,CAAC,IAAI,IAAA,CAAK,GAAA,CAAI,QAAA,CAAS,CAAC,IAAI,IAAA,EAAM;AACpF,IAAA,MAAA,GAAS,CAAA,2BAAA,EAA8B,IAAI,CAAA,8CAAA,CAAgD,CAAA;AAAA,EAC7F;AACF;AAGA,SAAS,cAAA,CACP,KAAA,EACA,IAAA,EACA,KAAA,EACA,MAAA,EACM;AACN,EAAA,IAAI,QAAQ,KAAA,EAAO;AACjB,IAAA,KAAA,CAAM,IAAI,CAAA,GAAI,KAAA;AAAA,EAChB,WAAW,IAAA,CAAK,GAAA,CAAI,KAAA,GAAQ,CAAC,IAAI,IAAA,EAAM;AACrC,IAAA,MAAA,GAAS,CAAA,2BAAA,EAA8B,IAAI,CAAA,4CAAA,CAA8C,CAAA;AAAA,EAC3F;AACF;AAGA,SAAS,cAAc,KAAA,EAAgC;AACrD,EAAA,IAAI,MAAM,UAAA,KAAe,CAAA,IAAK,MAAM,UAAA,KAAe,KAAA,CAAM,OAAO,UAAA,EAAY;AAC1E,IAAA,OAAO,KAAA,CAAM,MAAA;AAAA,EACf;AACA,EAAA,OAAO,KAAA,CAAM,OAAM,CAAE,MAAA;AACvB;AAGA,SAAS,WAAA,CAAY,OAAmB,GAAA,EAAwC;AAC9E,EAAA,IAAI,OAAO,UAAU,WAAA,EAAa;AAChC,IAAA,OAAO,OAAA,CAAQ,MAAA,CAAO,IAAI,KAAA,CAAM,gDAAgD,CAAC,CAAA;AAAA,EACnF;AACA,EAAA,MAAM,IAAA,GAAO,WAAA,CAAY,IAAA,CAAK,GAAG,CAAA,GAC7B,eACA,UAAA,CAAW,IAAA,CAAK,GAAG,CAAA,GACjB,YAAA,GACA,WAAA;AACN,EAAA,MAAM,IAAA,GAAO,IAAI,IAAA,CAAK,CAAC,KAA4B,CAAA,EAAG,EAAE,IAAA,EAAM,IAAA,EAAM,CAAA;AACpE,EAAA,MAAM,SAAA,GAAY,GAAA,CAAI,eAAA,CAAgB,IAAI,CAAA;AAC1C,EAAA,OAAO,IAAI,OAAA,CAA0B,CAAC,OAAA,EAAS,MAAA,KAAW;AACxD,IAAA,MAAM,GAAA,GAAM,IAAI,KAAA,EAAM;AACtB,IAAA,GAAA,CAAI,SAAS,MAAM;AACjB,MAAA,GAAA,CAAI,gBAAgB,SAAS,CAAA;AAC7B,MAAA,OAAA,CAAQ,GAAG,CAAA;AAAA,IACb,CAAA;AACA,IAAA,GAAA,CAAI,UAAU,MAAM;AAClB,MAAA,GAAA,CAAI,gBAAgB,SAAS,CAAA;AAC7B,MAAA,MAAA,CAAO,IAAI,KAAA,CAAM,CAAA,+BAAA,EAAkC,GAAG,EAAE,CAAC,CAAA;AAAA,IAC3D,CAAA;AACA,IAAA,GAAA,CAAI,GAAA,GAAM,SAAA;AAAA,EACZ,CAAC,CAAA;AACH;AC9MO,SAAS,mBAAA,CACd,QAAA,EACA,OAAA,GAAiC,EAAC,EAC5B;AACN,EAAA,QAAA,CAAS,cAAc,kBAAA,CAAmB,OAAA,CAAQ,WAAA,IAAe,MAAA,EAAQ,QAAQ,MAAM,CAAA;AACvF,EAAA,IAAI,OAAA,CAAQ,aAAa,MAAA,EAAW;AAClC,IAAA,QAAA,CAAS,mBAAA,GACP,OAAO,OAAA,CAAQ,QAAA,KAAa,WACxB,OAAA,CAAQ,QAAA,GACR,0BAAA,CAA2B,OAAA,CAAQ,QAAQ,CAAA;AAAA,EACnD;AACA,EAAA,IAAI,OAAA,CAAQ,WAAW,IAAA,EAAM;AAC3B,IAAA,QAAA,CAAS,UAAU,OAAA,GAAU,IAAA;AAC7B,IAAA,QAAA,CAAS,UAAU,IAAA,GAAaC,KAAA,CAAA,gBAAA;AAAA,EAClC;AACF;AAEA,SAAS,kBAAA,CACP,QACA,MAAA,EACmB;AACnB,EAAA,QAAQ,MAAA;AAAQ,IACd,KAAK,MAAA;AACH,MAAA,OAAaA,KAAA,CAAA,aAAA;AAAA,IACf,KAAK,KAAA;AACH,MAAA,OAAaA,KAAA,CAAA,cAAA;AAAA,IACf,KAAK,SAAA,EAAW;AAEd,MAAA,MAAM,OAAA,GAA6CA,KAAA,CAAA,kBAAA;AACnD,MAAA,IAAI,OAAO,OAAA,KAAY,QAAA,EAAU,OAAO,OAAA;AACxC,MAAA,MAAA,GAAS,4EAA4E,CAAA;AACrF,MAAA,OAAaA,KAAA,CAAA,qBAAA;AAAA,IACf;AAAA,IACA,KAAK,MAAA;AACH,MAAA,OAAaA,KAAA,CAAA,qBAAA;AAAA;AAEnB","file":"rendering.js","sourcesContent":["/**\n * DomeLight → image-based environment lighting (M26).\n *\n * A `DomeLight` is not a discrete light: it is the scene's environment. This\n * module fetches the dome's texture through the robot's captured asset context\n * (so relative CDN paths and `.usdz`-embedded images both work), decodes\n * `.hdr` / `.exr` (via three's addons loaders) or LDR images into an\n * equirectangular texture, and applies it as `scene.environment` — three\n * prefilters equirectangular environments internally, no PMREM setup needed.\n *\n * Orientation: three.js expects the equirect pole along +Y. The dome's pole\n * follows `poleAxis` (`DomeLight_1`) or, for the original `DomeLight` schema,\n * the stage up-axis — composed with the dome prim's own rotation and the\n * loader's up-axis normalization into `scene.environmentRotation` (three\n * r162+; skipped with a warning on older peers when it matters).\n */\n\nimport * as THREE from \"three\";\nimport { EXRLoader } from \"three/addons/loaders/EXRLoader.js\";\nimport { RGBELoader } from \"three/addons/loaders/RGBELoader.js\";\nimport type { LightDescription } from \"../schemas/usdLux.js\";\nimport type { ThreeUsdRobot } from \"../three/ThreeUsdRobot.js\";\nimport { computeWorldTransform } from \"../usd/xformOps.js\";\n\nexport type ApplyUsdEnvironmentOptions = {\n /** Also show the environment as `scene.background` (default `false`). */\n background?: boolean;\n /**\n * Multiplies the dome's authored emission (`intensity × 2^exposure`) into\n * `scene.environmentIntensity`. Defaults to the `lightIntensityScale` the\n * robot was loaded with, so the environment stays in balance with the bound\n * lights (see docs/lighting.md).\n */\n intensityScale?: number;\n /** The dome to apply when the stage has several (default: the first). */\n dome?: LightDescription;\n /** Receives fallback/compatibility diagnostics. */\n onWarn?: (message: string) => void;\n};\n\n/** What {@link applyUsdEnvironment} applied to the scene. */\nexport type UsdEnvironment = {\n dome: LightDescription;\n /** The environment texture — equirectangular HDR/LDR, or 1×1 dome color. */\n texture: THREE.Texture;\n /** Environment orientation applied (identity when unsupported by the peer). */\n rotation: THREE.Euler;\n /** Effective emission written to `scene.environmentIntensity`. */\n intensity: number;\n};\n\n/**\n * Realize the stage's DomeLight as the scene environment. Resolves the dome's\n * texture (falling back to a uniform texture of the dome color when it has\n * none, or when it cannot be fetched or decoded) and sets\n * `scene.environment(+Rotation/+Intensity)` — and, with\n * `options.background`, the matching background properties. Returns `null`\n * when the robot has no DomeLight; the scene is left untouched.\n */\nexport async function applyUsdEnvironment(\n robot: ThreeUsdRobot,\n scene: THREE.Scene,\n options: ApplyUsdEnvironmentOptions = {},\n): Promise<UsdEnvironment | null> {\n const dome = options.dome ?? robot.domeLights[0];\n if (!dome) return null;\n const onWarn = options.onWarn;\n\n let texture: THREE.Texture | null = null;\n if (dome.textureFile) {\n if (\n dome.textureFormat &&\n dome.textureFormat !== \"latlong\" &&\n dome.textureFormat !== \"automatic\"\n ) {\n onWarn?.(\n `DomeLight texture:format \"${dome.textureFormat}\" is not supported; sampling it as latlong (equirectangular)`,\n );\n }\n try {\n texture = await loadDomeTexture(robot, dome.textureFile);\n } catch (err) {\n onWarn?.(\n `DomeLight texture ${dome.textureFile} could not be loaded (${(err as Error).message}); falling back to the dome color`,\n );\n }\n }\n texture ??= colorTexture(dome.color);\n\n const intensity = dome.intensity * (options.intensityScale ?? robot.lightIntensityScale ?? 1);\n const rotation = domeRotation(robot, dome);\n\n scene.environment = texture;\n setSceneEuler(scene, \"environmentRotation\", rotation, onWarn);\n setSceneNumber(scene, \"environmentIntensity\", intensity, onWarn);\n if (options.background) {\n scene.background = texture;\n setSceneEuler(scene, \"backgroundRotation\", rotation, undefined);\n setSceneNumber(scene, \"backgroundIntensity\", intensity, undefined);\n }\n return { dome, texture, rotation, intensity };\n}\n\n/**\n * Fetch and decode the dome image through the robot's asset context: `.hdr`\n * (Radiance RGBE) and `.exr` decode to float data textures; anything else\n * decodes as an LDR image (browser only). The result is equirect-mapped.\n */\nasync function loadDomeTexture(robot: ThreeUsdRobot, assetPath: string): Promise<THREE.Texture> {\n const context = robot.assetContext;\n if (!context) {\n throw new Error(\"robot carries no asset context (was it built by ThreeUsdRobotLoader?)\");\n }\n const url = context.resolver.resolve(assetPath, context.baseUrl);\n const bytes = context.resolver.fetchBytes\n ? await context.resolver.fetchBytes(url)\n : new TextEncoder().encode(await context.resolver.fetchText(url));\n\n if (/\\.hdr$/i.test(url)) {\n const texData = new RGBELoader().parse(toArrayBuffer(bytes));\n const texture = new THREE.DataTexture(\n texData.data as unknown as BufferSource,\n texData.width,\n texData.height,\n THREE.RGBAFormat,\n texData.type,\n );\n texture.flipY = true; // Radiance scanlines run top-down\n return finishDataTexture(texture, THREE.LinearSRGBColorSpace);\n }\n if (/\\.exr$/i.test(url)) {\n const texData = new EXRLoader().parse(toArrayBuffer(bytes));\n const texture = new THREE.DataTexture(\n texData.data as unknown as BufferSource,\n texData.width,\n texData.height,\n texData.format,\n texData.type,\n );\n texture.flipY = false; // EXR rows decode bottom-up already\n return finishDataTexture(texture, texData.colorSpace);\n }\n\n const texture = new THREE.Texture(await decodeImage(bytes, url));\n texture.colorSpace = THREE.SRGBColorSpace;\n texture.mapping = THREE.EquirectangularReflectionMapping;\n texture.needsUpdate = true;\n return texture;\n}\n\nfunction finishDataTexture(texture: THREE.DataTexture, colorSpace: string): THREE.Texture {\n texture.colorSpace = colorSpace;\n texture.magFilter = THREE.LinearFilter;\n texture.minFilter = THREE.LinearFilter;\n texture.generateMipmaps = false;\n texture.mapping = THREE.EquirectangularReflectionMapping;\n texture.needsUpdate = true;\n return texture;\n}\n\n/**\n * Small float equirect filled with the dome's (linear) color — a uniform sky.\n * Deliberately not 1×1: three's PMREM prefilter sizes its cubemap from the\n * equirect width (width / 4), and a degenerate size breaks the shader of\n * every environment-lit material (`useProgram: program not valid`).\n */\nfunction colorTexture(color: [number, number, number]): THREE.Texture {\n const width = 64;\n const height = 32;\n const data = new Float32Array(width * height * 4);\n for (let i = 0; i < width * height; i++) {\n data[i * 4] = color[0];\n data[i * 4 + 1] = color[1];\n data[i * 4 + 2] = color[2];\n data[i * 4 + 3] = 1;\n }\n const texture = new THREE.DataTexture(data, width, height, THREE.RGBAFormat, THREE.FloatType);\n return finishDataTexture(texture, THREE.LinearSRGBColorSpace);\n}\n\n/**\n * Environment orientation: (root up-axis normalization) × (dome prim's stage\n * rotation) × (pole correction from three's +Y-pole equirect convention to\n * the dome's pole axis).\n */\nfunction domeRotation(robot: ThreeUsdRobot, dome: LightDescription): THREE.Euler {\n const q = robot.quaternion.clone();\n\n const prim = robot.stage?.GetPrimAtPath(dome.primPath);\n if (prim) {\n const world = new THREE.Matrix4().fromArray(computeWorldTransform(prim));\n const rotation = new THREE.Matrix4().extractRotation(world); // drops the prim chain's scale\n q.multiply(new THREE.Quaternion().setFromRotationMatrix(rotation));\n }\n\n // DomeLight_1 authors poleAxis; the original schema follows the stage up-axis.\n const pole = dome.poleAxis === \"Y\" || dome.poleAxis === \"Z\" ? dome.poleAxis : robot.robot.upAxis;\n if (pole === \"Z\") {\n q.multiply(new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(1, 0, 0), Math.PI / 2));\n }\n return new THREE.Euler().setFromQuaternion(q);\n}\n\n/** Set a Scene Euler property when the installed three has it (r162+). */\nfunction setSceneEuler(\n scene: THREE.Scene,\n name: \"environmentRotation\" | \"backgroundRotation\",\n rotation: THREE.Euler,\n onWarn: ((message: string) => void) | undefined,\n): void {\n if (name in scene) {\n scene[name].copy(rotation);\n } else if (Math.abs(rotation.x) + Math.abs(rotation.y) + Math.abs(rotation.z) > 1e-6) {\n onWarn?.(`this three.js has no Scene.${name} (added r162); the dome orientation is dropped`);\n }\n}\n\n/** Set a Scene number property when the installed three has it (r163+). */\nfunction setSceneNumber(\n scene: THREE.Scene,\n name: \"environmentIntensity\" | \"backgroundIntensity\",\n value: number,\n onWarn: ((message: string) => void) | undefined,\n): void {\n if (name in scene) {\n scene[name] = value;\n } else if (Math.abs(value - 1) > 1e-6) {\n onWarn?.(`this three.js has no Scene.${name} (added r163); the dome intensity is dropped`);\n }\n}\n\n/** `RGBELoader.parse` wants an ArrayBuffer aligned to the data. */\nfunction toArrayBuffer(bytes: Uint8Array): ArrayBuffer {\n if (bytes.byteOffset === 0 && bytes.byteLength === bytes.buffer.byteLength) {\n return bytes.buffer as ArrayBuffer;\n }\n return bytes.slice().buffer as ArrayBuffer;\n}\n\n/** Decode LDR image bytes via a blob URL (browser environments). */\nfunction decodeImage(bytes: Uint8Array, url: string): Promise<HTMLImageElement> {\n if (typeof Image === \"undefined\") {\n return Promise.reject(new Error(\"LDR dome textures need a browser image decoder\"));\n }\n const mime = /\\.jpe?g$/i.test(url)\n ? \"image/jpeg\"\n : /\\.webp$/i.test(url)\n ? \"image/webp\"\n : \"image/png\";\n const blob = new Blob([bytes as unknown as BlobPart], { type: mime });\n const objectUrl = URL.createObjectURL(blob);\n return new Promise<HTMLImageElement>((resolve, reject) => {\n const img = new Image();\n img.onload = () => {\n URL.revokeObjectURL(objectUrl);\n resolve(img);\n };\n img.onerror = () => {\n URL.revokeObjectURL(objectUrl);\n reject(new Error(`failed to decode dome texture: ${url}`));\n };\n img.src = objectUrl;\n });\n}\n","/**\n * One-call renderer defaults (M28) — the settings every USD viewer built on\n * this library ends up wanting: filmic tone mapping (USD lights and HDRI\n * domes are HDR values; three's default `NoToneMapping` clips them), soft\n * shadow maps (the loader pre-flags meshes and lights, M25), and optionally\n * an exposure — either a plain multiplier or a `UsdGeomCamera` description,\n * whose USD 24.11 linear exposure scale is applied (M27).\n *\n * Deliberately small: post-processing (AO, SSR, TAA, bloom) stays out of the\n * library — compose three's own passes in your app; the Vite example shows a\n * GTAO setup.\n */\n\nimport * as THREE from \"three\";\nimport { type CameraDescription, computeCameraExposureScale } from \"../schemas/usdGeomCamera.js\";\n\n/** Filmic curve to install. `\"none\"` restores three's linear pass-through. */\nexport type ToneMappingPreset = \"ACES\" | \"AgX\" | \"neutral\" | \"none\";\n\nexport type RenderDefaultsOptions = {\n /** Default `\"ACES\"`. `\"neutral\"` (Khronos PBR Neutral) needs three r162+. */\n toneMapping?: ToneMappingPreset;\n /**\n * Sets `toneMappingExposure`: a number as-is, or a\n * {@link CameraDescription} via its linear exposure scale\n * ({@link computeCameraExposureScale}). Left untouched when omitted.\n */\n exposure?: number | CameraDescription;\n /** Enable `PCFSoftShadowMap` shadow rendering (default `true`). */\n shadows?: boolean;\n /** Receives compatibility diagnostics. */\n onWarn?: (message: string) => void;\n};\n\n/**\n * The renderer surface this helper touches — satisfied by `WebGLRenderer`\n * and `WebGPURenderer` alike, without depending on `three/webgpu` types.\n */\nexport type RenderDefaultsTarget = {\n toneMapping: THREE.ToneMapping;\n toneMappingExposure: number;\n shadowMap: { enabled: boolean; type: THREE.ShadowMapType };\n};\n\n/**\n * Apply viewer defaults to a renderer:\n *\n * ```ts\n * import { applyRenderDefaults } from \"three-usd-robot/rendering\";\n *\n * applyRenderDefaults(renderer); // ACES + soft shadow maps\n * applyRenderDefaults(renderer, { toneMapping: \"AgX\", exposure: robot.cameras[0]?.userData.usdCamera });\n * ```\n *\n * Only ever switches features on or assigns requested values — `shadows:\n * false` skips enabling shadow maps rather than force-disabling them.\n */\nexport function applyRenderDefaults(\n renderer: RenderDefaultsTarget,\n options: RenderDefaultsOptions = {},\n): void {\n renderer.toneMapping = resolveToneMapping(options.toneMapping ?? \"ACES\", options.onWarn);\n if (options.exposure !== undefined) {\n renderer.toneMappingExposure =\n typeof options.exposure === \"number\"\n ? options.exposure\n : computeCameraExposureScale(options.exposure);\n }\n if (options.shadows ?? true) {\n renderer.shadowMap.enabled = true;\n renderer.shadowMap.type = THREE.PCFSoftShadowMap;\n }\n}\n\nfunction resolveToneMapping(\n preset: ToneMappingPreset,\n onWarn: ((message: string) => void) | undefined,\n): THREE.ToneMapping {\n switch (preset) {\n case \"none\":\n return THREE.NoToneMapping;\n case \"AgX\":\n return THREE.AgXToneMapping;\n case \"neutral\": {\n // Runtime lookup: the peer floor (r160) predates NeutralToneMapping (r162).\n const neutral = (THREE as Record<string, unknown>).NeutralToneMapping;\n if (typeof neutral === \"number\") return neutral as THREE.ToneMapping;\n onWarn?.('this three.js has no NeutralToneMapping (added r162); using \"ACES\" instead');\n return THREE.ACESFilmicToneMapping;\n }\n case \"ACES\":\n return THREE.ACESFilmicToneMapping;\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "three-usd-robot",
3
- "version": "0.14.0",
3
+ "version": "0.14.1",
4
4
  "description": "Kinematic OpenUSD robot loader for Three.js — load Isaac Sim / OpenUSD robot assets, extract joints and links, and control articulations in the browser.",
5
5
  "type": "module",
6
6
  "license": "MIT",