@photivra/engine 2.4.1 → 2.6.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.
- package/CHANGELOG.md +53 -1
- package/CITATION.cff +1 -1
- package/README.md +6 -6
- package/SECURITY.md +1 -1
- package/THIRD_PARTY.md +1 -0
- package/dist/capture/native-environment-lean.d.ts +1 -1
- package/dist/capture/native-environment-lean.js +17 -3
- package/dist/capture/native-environment-lean.js.map +1 -1
- package/dist/capture/native-environment-raw.d.ts +0 -4
- package/dist/capture/native-environment-raw.js +6 -2
- package/dist/capture/native-environment-raw.js.map +1 -1
- package/dist/color/illuminants.d.ts +15 -0
- package/dist/color/illuminants.js +81 -24
- package/dist/color/illuminants.js.map +1 -1
- package/dist/color/srgb-transfer.d.ts +6 -0
- package/dist/color/srgb-transfer.js +9 -0
- package/dist/color/srgb-transfer.js.map +1 -1
- package/dist/color/white-balance.d.ts +6 -0
- package/dist/color/white-balance.js +15 -2
- package/dist/color/white-balance.js.map +1 -1
- package/dist/core/internal-radiance-evaluator.d.ts +6 -0
- package/dist/core/internal-radiance-evaluator.js +33 -0
- package/dist/core/internal-radiance-evaluator.js.map +1 -0
- package/dist/core/portable-math.d.ts +33 -0
- package/dist/core/portable-math.js +342 -0
- package/dist/core/portable-math.js.map +1 -1
- package/dist/core/version.d.ts +1 -1
- package/dist/core/version.js +1 -1
- package/dist/core/version.js.map +1 -1
- package/dist/facade/chart-scenes.d.ts +9 -0
- package/dist/facade/chart-scenes.js +17 -4
- package/dist/facade/chart-scenes.js.map +1 -1
- package/dist/facade/diffraction-provider.d.ts +10 -0
- package/dist/facade/diffraction-provider.js +38 -17
- package/dist/facade/diffraction-provider.js.map +1 -1
- package/dist/facade/display-view.d.ts +208 -0
- package/dist/facade/display-view.js +1461 -0
- package/dist/facade/display-view.js.map +1 -0
- package/dist/facade/scene-radiance.d.ts +7 -0
- package/dist/facade/scene-radiance.js +18 -5
- package/dist/facade/scene-radiance.js.map +1 -1
- package/dist/facade/simulate-capture.d.ts +229 -5
- package/dist/facade/simulate-capture.js +119 -35
- package/dist/facade/simulate-capture.js.map +1 -1
- package/dist/facade/simulate-display-view.d.ts +21 -0
- package/dist/facade/simulate-display-view.js +168 -0
- package/dist/facade/simulate-display-view.js.map +1 -0
- package/dist/facade/subject-framing.d.ts +78 -0
- package/dist/facade/subject-framing.js +69 -20
- package/dist/facade/subject-framing.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/optics/diffraction-psf-profile.d.ts +59 -3
- package/dist/optics/diffraction-psf-profile.js +147 -5
- package/dist/optics/diffraction-psf-profile.js.map +1 -1
- package/dist/optics/irradiance-convolution.js +1 -1
- package/dist/optics/irradiance-convolution.js.map +1 -1
- package/dist/optics/scene-to-sensor-irradiance.d.ts +7 -0
- package/dist/optics/scene-to-sensor-irradiance.js +10 -5
- package/dist/optics/scene-to-sensor-irradiance.js.map +1 -1
- package/dist/output/print-plan.d.ts +8 -1
- package/dist/output/print-plan.js +8 -1
- package/dist/output/print-plan.js.map +1 -1
- package/dist/schema/scene-radiance.d.ts +16 -0
- package/dist/schema/scene-radiance.js +25 -4
- package/dist/schema/scene-radiance.js.map +1 -1
- package/dist/sensor/raw-readout.d.ts +12 -0
- package/dist/sensor/raw-readout.js +131 -9
- package/dist/sensor/raw-readout.js.map +1 -1
- package/dist/sensor/stochastic-seed.d.ts +13 -0
- package/dist/sensor/stochastic-seed.js +42 -8
- package/dist/sensor/stochastic-seed.js.map +1 -1
- package/docs/AGENT_GUIDE.md +1 -0
- package/docs/API_REFERENCE.md +16 -1
- package/docs/QUICK_START.md +245 -9
- package/docs/USAGE.md +15 -0
- package/docs/api/core-version.md +1 -1
- package/docs/api/exports.json +37 -2
- package/docs/api/facade-simulate-capture.md +70 -2
- package/docs/api/facade-simulate-display-view.md +18 -0
- package/docs/api/facade-subject-framing.md +83 -0
- package/docs/api/optics-diffraction-psf-profile.md +8 -1
- package/docs/api/output-print-plan.md +8 -1
- package/package.json +3 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scene-radiance.js","sourceRoot":"","sources":["../../src/facade/scene-radiance.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Turns a facade scene and an illuminant into a scene radiance provider for the existing native\n * environment RAW contract (`NativeEnvironmentRawProvider.evaluateRadiance` and, for pupil sampling,\n * `evaluateApertureRadiance`). The scene is an engine chart, a caller reflectance function or a caller\n * radiance function.\n *\n * Geometry: one plane perpendicular to the optical axis at `distanceM` in front of the camera. A query's\n * outgoing direction o (scene toward camera, see docs/SENSOR_ENVIRONMENT_QUERY.md) gives the look\n * direction l = -o; the plane point is l·distanceM/l.z. With a pupil ray, the plane point is the ray from\n * its lens origin to z = distanceM.\n *\n * Radiometry: a Lambertian reflector of reflectance ρ(λ) under irradiance E(λ) has radiance\n * L(λ) = ρ(λ)·E(λ)/π (W·m⁻²·sr⁻¹·nm⁻¹). The illuminant spectral shape S(λ) is scaled so that the\n * plane illuminance is E_v = K_m ∫ E(λ) V(λ) dλ with K_m = 683 lm/W (CIE photometric definition) and\n * V(λ) = ȳ(λ) from the engine's analytic CIE 1931 fit. The light is uniform\n * over the plane, with no shadows. Inter-reflection, gloss and fluorescence are not modelled.\n * @see docs/QUICK_START.md\n */\n\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport { requireInputObject } from \"../core/record-validation.js\";\nimport { estimateCie1931ColorMatchingFunctions, prepareColorimetricSpectrum, type ColorimetricSpectrum,\n type PreparedColorimetricSpectrum } from \"../color/color-matching-functions.js\";\nimport { createCieIlluminantASpectrum, createCieDaylightSpectrum, createPlanckianSpectrum, type CieDaylightBasis } from \"../color/illuminants.js\";\nimport type { SceneRadianceEvaluationRequest, SceneRadianceEvaluationResult } from \"../schema/scene-radiance.js\";\nimport type { EvidenceProvenance } from \"../core/evidence-provenance.js\";\nimport type { SensorApertureRay } from \"../optics/sensor-aperture-rays.js\";\nimport { resolveChartScene, type ChartScene, type ResolvedChartScene } from \"./chart-scenes.js\";\n\n/** CIE maximum luminous efficacy for photopic vision, lm/W. */\nexport const PHOTOPIC_MAXIMUM_LUMINOUS_EFFICACY_LM_PER_W = 683;\n/** Wavelength range of every facade spectrum and of the facade sensor quadrature, nm. */\nexport const FACADE_SPECTRAL_RANGE_NANOMETERS = Object.freeze({ minimum: 380, maximum: 780 });\n\n/**\n * Illuminant choices. CIE D65 is not bundled: its S0/S1/S2 basis tables must come from the caller\n * (`daylight`). `planckian` is Planck's law; `cie-a` is CIE illuminant A from its defining formula.\n */\nexport type CaptureIlluminant =\n | \"cie-a\"\n | { kind: \"planckian\"; temperatureKelvin: number }\n | { kind: \"cie-a\" }\n | { kind: \"daylight\"; correlatedColorTemperatureKelvin: number; basis: CieDaylightBasis }\n | { kind: \"spectrum\"; spectrum: ColorimetricSpectrum; label?: string };\n\nexport interface ResolvedCaptureIlluminant {\n /** Short public description, for example \"planckian-6500K\". */\n id: string;\n description: string;\n /** Relative spectral shape (arbitrary scale) over at least 380-780 nm. */\n shape: PreparedColorimetricSpectrum;\n /** Original spectrum, for colorimetric white-balance calculations. */\n spectrum: ColorimetricSpectrum;\n}\n\nexport function resolveCaptureIlluminant(value: CaptureIlluminant): ResolvedCaptureIlluminant {\n if (value === \"cie-a\") return resolveCaptureIlluminant({ kind: \"cie-a\" });\n requireInputObject(value, \"illuminant\");\n const record = value as unknown as Record<string, unknown>;\n const allowed: Record<string, readonly string[]> = { planckian: [\"kind\", \"temperatureKelvin\"], \"cie-a\": [\"kind\"],\n daylight: [\"kind\", \"correlatedColorTemperatureKelvin\", \"basis\"], spectrum: [\"kind\", \"spectrum\", \"label\"] };\n const keys = typeof record.kind === \"string\" ? allowed[record.kind] : undefined;\n if (!keys) throw new InvalidConfigurationError(\"Unknown illuminant kind.\");\n for (const key of Object.keys(record)) if (!keys.includes(key)) throw new InvalidConfigurationError(\"Unknown illuminant field: \" + key + \".\");\n let spectrum: ColorimetricSpectrum, id: string, description: string;\n try {\n switch (value.kind) {\n case \"planckian\": {\n const t = value.temperatureKelvin;\n if (typeof t !== \"number\" || !Number.isFinite(t) || t < 1000 || t > 25000) throw new InvalidConfigurationError(\"Planckian temperature must be 1000-25000 K.\");\n spectrum = createPlanckianSpectrum({ temperatureKelvin: t, wavelengthRangeNanometers: { ...FACADE_SPECTRAL_RANGE_NANOMETERS } });\n id = \"planckian-\" + t + \"K\"; description = \"Planck blackbody spectrum at \" + t + \" K (Planck's law).\";\n break;\n }\n case \"cie-a\":\n spectrum = createCieIlluminantASpectrum(); id = \"cie-a\"; description = \"CIE standard illuminant A from its defining formula: Planck's law with c2 = 1.435e-2 m·K and T = 2848 K, 100 at 560 nm.\";\n break;\n case \"daylight\":\n spectrum = createCieDaylightSpectrum({ correlatedColorTemperatureKelvin: value.correlatedColorTemperatureKelvin, coefficientRounding: \"cie-three-decimals\", basis: value.basis });\n id = \"cie-daylight-\" + value.correlatedColorTemperatureKelvin + \"K\"; description = \"CIE daylight from the caller's S0/S1/S2 basis (\" + value.basis.datasetId + \").\";\n break;\n case \"spectrum\":\n spectrum = value.spectrum; id = \"caller-spectrum\";\n description = \"Caller illuminant spectrum\" + (typeof value.label === \"string\" ? \" (\" + value.label + \")\" : \"\") + \".\";\n break;\n }\n } catch (error) {\n if (error instanceof InvalidConfigurationError) throw error;\n throw new InvalidConfigurationError(\"Invalid illuminant: \" + (error instanceof Error ? error.message : \"invalid\"));\n }\n let shape: PreparedColorimetricSpectrum;\n try { shape = prepareColorimetricSpectrum(spectrum, \"illuminant\"); } catch (error) {\n throw new InvalidConfigurationError(\"Invalid illuminant spectrum: \" + (error instanceof Error ? error.message : \"invalid\"));\n }\n const range = shape.wavelengthRangeNanometers;\n if (range.minimum > FACADE_SPECTRAL_RANGE_NANOMETERS.minimum || range.maximum < FACADE_SPECTRAL_RANGE_NANOMETERS.maximum)\n throw new InvalidConfigurationError(\"The illuminant spectrum must cover 380-780 nm.\");\n for (let nm = FACADE_SPECTRAL_RANGE_NANOMETERS.minimum; nm <= FACADE_SPECTRAL_RANGE_NANOMETERS.maximum; nm += 1) {\n const s = shape.evaluate(nm);\n if (!(s >= 0)) throw new InvalidConfigurationError(\"The illuminant spectrum must be non-negative over 380-780 nm.\");\n }\n return Object.freeze({ id, description, shape, spectrum });\n}\n\n/**\n * Factor k such that k·S(λ) (W·m⁻²·nm⁻¹) gives `illuminanceLux` on the plane: E_v = 683 ∫ k S ȳ dλ,\n * integrated with the 1 nm trapezoid rule over 380-780 nm (ȳ outside this range is below 4e-5 of its peak).\n */\nexport function calculateIlluminantIrradianceScale(shape: PreparedColorimetricSpectrum, illuminanceLux: number): number {\n if (typeof shape !== \"object\" || shape === null || typeof shape.evaluate !== \"function\") throw new InvalidConfigurationError(\"A prepared illuminant spectrum is required.\");\n if (typeof illuminanceLux !== \"number\" || !Number.isFinite(illuminanceLux) || illuminanceLux <= 0 || illuminanceLux > 1e7)\n throw new InvalidConfigurationError(\"Illuminance must be a positive number of lux up to 1e7.\");\n let sum = 0;\n for (let nm = FACADE_SPECTRAL_RANGE_NANOMETERS.minimum; nm <= FACADE_SPECTRAL_RANGE_NANOMETERS.maximum; nm++) {\n const w = nm === FACADE_SPECTRAL_RANGE_NANOMETERS.minimum || nm === FACADE_SPECTRAL_RANGE_NANOMETERS.maximum ? 0.5 : 1;\n sum += w * shape.evaluate(nm) * estimateCie1931ColorMatchingFunctions(nm).y;\n }\n if (!(sum > 0)) throw new InvalidConfigurationError(\"The illuminant has no luminous power.\");\n return illuminanceLux / (PHOTOPIC_MAXIMUM_LUMINOUS_EFFICACY_LM_PER_W * sum);\n}\n\n/** A point of the scene plane passed to caller scene functions. */\nexport interface ScenePlanePoint {\n /** Metres on the plane, from the optical axis: +x right, +y up (as seen from the camera). */\n xM: number;\n yM: number;\n /** The same point in frame units (u = ±1 at the left/right frame edges, v up on the same scale). */\n u: number;\n v: number;\n wavelengthNanometers: number;\n /**\n * 2.3, only with a fixed-size chart (`chartSize`): the point in chart-local frame units (±1 at the chart's\n * left/right edges, v up on the same scale, ±chart height/width at its top/bottom). The function is then\n * called only for points on the chart; the surround is the placement's surround reflectance.\n */\n chartU?: number;\n chartV?: number;\n}\n/** Caller Lambertian reflectance (in [0, 1]) lit by the facade illuminant. */\nexport interface CallerReflectanceScene { kind: \"reflectance-function\"; sceneId: string; evaluate(point: Readonly<ScenePlanePoint>): number }\n/** Caller absolute spectral radiance in W·m⁻²·sr⁻¹·nm⁻¹; the facade illuminant is not used. */\nexport interface CallerRadianceScene { kind: \"radiance-function\"; sceneId: string; evaluate(point: Readonly<ScenePlanePoint>): number }\n\nexport interface PlanarSceneGeometry {\n distanceM: number;\n /** Metres per frame unit on the plane (half the framed width). */\n metresPerFrameUnit: number;\n /**\n * 2.3, opt-in fixed-size chart: the chart is `widthM` × `heightM` on the plane, centred on the optical axis;\n * outside it the plane is a neutral Lambertian surround of `surroundReflectance`, lit by the same illuminant.\n * A chart preset is then resolved in its own frame (aspect heightM / widthM). Without it the chart fills the frame.\n */\n chart?: { widthM: number; heightM: number; surroundReflectance: number };\n}\n\nexport interface PlanarSceneRadianceProvider {\n sceneId: string;\n providerProfileId: string;\n evaluateRadiance(request: Readonly<SceneRadianceEvaluationRequest>): SceneRadianceEvaluationResult;\n evaluateApertureRadiance(request: Readonly<SceneRadianceEvaluationRequest>, ray: Readonly<SensorApertureRay>): SceneRadianceEvaluationResult;\n /** Spectral radiance at a plane point (frame units), the same value the callbacks return. */\n radianceAt(u: number, v: number, wavelengthNanometers: number): number;\n /**\n * 2.3, chart scenes only: the chart material at a plane point (frame units), or `materials.length` for the\n * surround of a fixed-size chart; `materialRadiance` gives that material's spectral radiance, the same value\n * `radianceAt` returns at its points.\n */\n chartMaterialAt?(u: number, v: number): number;\n materialRadiance?(material: number, wavelengthNanometers: number): number;\n}\n\nconst UNCERTAINTY = Object.freeze({ kind: \"not-quantified\" as const, limitation: \"Analytic planar Lambertian scene; no measured scene, BRDF or illumination.\" });\n\n/**\n * Wraps a chart or caller scene as a provider for the native environment RAW task. `irradianceScale` is\n * from {@link calculateIlluminantIrradianceScale}; caller radiance scenes ignore the illuminant.\n */\nexport function buildPlanarSceneRadianceProvider(input: {\n scene: ResolvedChartScene | CallerReflectanceScene | CallerRadianceScene;\n sceneId: string;\n providerProfileId: string;\n illuminant: ResolvedCaptureIlluminant;\n irradianceScale: number;\n geometry: PlanarSceneGeometry;\n evidence: readonly EvidenceProvenance[];\n limitations: readonly string[];\n}): PlanarSceneRadianceProvider {\n const { scene, illuminant, irradianceScale, geometry } = input;\n const scale = geometry.metresPerFrameUnit, distance = geometry.distanceM, sceneId = input.sceneId, providerProfileId = input.providerProfileId;\n const evidence = input.evidence, limitations = input.limitations;\n const caller = \"kind\" in scene ? scene : undefined, chart = caller ? undefined : scene as ResolvedChartScene;\n const placed = geometry.chart, half = placed ? placed.widthM / 2 : 0, chartAspect = placed ? placed.heightM / placed.widthM : 0;\n function radianceAt(u: number, v: number, nm: number): number {\n if (placed) {\n // Fixed-size chart (2.3): chart-local frame units from the plane point in metres.\n const xM = u * scale, yM = v * scale, cu = xM / half, cv = yM / half;\n if (!(Math.abs(cu) <= 1 && Math.abs(cv) <= chartAspect)) return placed.surroundReflectance * irradianceScale * illuminant.shape.evaluate(nm) / Math.PI;\n if (chart) return chart.reflectanceAt(cu, cv, nm) * irradianceScale * illuminant.shape.evaluate(nm) / Math.PI;\n return callerValue(Object.freeze({ xM, yM, u, v, wavelengthNanometers: nm, chartU: cu, chartV: cv }), nm);\n }\n if (chart) return chart.reflectanceAt(u, v, nm) * irradianceScale * illuminant.shape.evaluate(nm) / Math.PI;\n return callerValue(Object.freeze({ xM: u * scale, yM: v * scale, u, v, wavelengthNanometers: nm }), nm);\n }\n function callerValue(point: Readonly<ScenePlanePoint>, nm: number): number {\n const value = caller!.evaluate(point);\n if (caller!.kind === \"reflectance-function\") {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value < 0 || value > 1) throw new InvalidConfigurationError(\"Scene reflectance function must return a value in [0, 1].\");\n return value * irradianceScale * illuminant.shape.evaluate(nm) / Math.PI;\n }\n if (typeof value !== \"number\" || !Number.isFinite(value) || value < 0) throw new InvalidConfigurationError(\"Scene radiance function must return a finite non-negative radiance.\");\n return value;\n }\n function result(request: Readonly<SceneRadianceEvaluationRequest>, radiance: number): SceneRadianceEvaluationResult {\n return { schemaVersion: \"0.1.0\", sampleId: request.sampleId, sceneId, providerProfileId, wavelengthNanometers: request.wavelengthNanometers,\n wavelengthBasis: request.wavelengthBasis as SceneRadianceEvaluationResult[\"wavelengthBasis\"], quantity: \"outgoing-spectral-radiance\", unit: \"W/m^2/sr/nm\",\n spectralRadianceWattsPerSquareMeterSteradianNanometer: radiance, scientificStatus: \"approximation\", uncertainty: UNCERTAINTY, evidence, limitations };\n }\n const chartAccess = chart ? {\n chartMaterialAt(u: number, v: number): number {\n if (!placed) return chart.materialAt(u, v);\n const cu = u * scale / half, cv = v * scale / half;\n return Math.abs(cu) <= 1 && Math.abs(cv) <= chartAspect ? chart.materialAt(cu, cv) : chart.materials.length;\n },\n materialRadiance(material: number, nm: number): number {\n const m = chart.materials[material];\n let value: number;\n if (m === undefined) value = placed ? placed.surroundReflectance : NaN;\n else if (m.kind === \"neutral\") value = m.reflectance;\n else {\n value = m.spectrum.evaluate(nm);\n if (!(value >= 0 && value <= 1)) throw new InvalidConfigurationError(\"Chart reflectance spectrum left [0, 1].\");\n }\n if (!(value >= 0)) throw new InvalidConfigurationError(\"Unknown chart material.\");\n return value * irradianceScale * illuminant.shape.evaluate(nm) / Math.PI;\n }\n } : {};\n return {\n sceneId, providerProfileId, radianceAt, ...chartAccess,\n evaluateRadiance(request): SceneRadianceEvaluationResult {\n const target = request.target;\n if (target.kind !== \"environment-direction\") throw new InvalidConfigurationError(\"Planar scene provider needs environment-direction queries.\");\n const o = target.outgoingDirectionUnitVector, lz = -o.z;\n if (!(lz > 0)) throw new InvalidConfigurationError(\"Planar scene query does not point toward the scene plane.\");\n const t = distance / lz;\n return result(request, radianceAt(-o.x * t / scale, -o.y * t / scale, request.wavelengthNanometers));\n },\n evaluateApertureRadiance(request, ray): SceneRadianceEvaluationResult {\n const d = ray.directionUnitVector, origin = ray.originM;\n if (!(d.z > 0)) throw new InvalidConfigurationError(\"Planar scene pupil ray does not point toward the scene plane.\");\n const t = (distance - origin.z) / d.z;\n return result(request, radianceAt((origin.x + d.x * t) / scale, (origin.y + d.y * t) / scale, request.wavelengthNanometers));\n }\n };\n}\n\n/** 2.3: a chart's physical size on the scene plane (`simulateCapture` `chartSize`, `createPlanarSceneRadianceProvider` `chartSize`). */\nexport interface ChartSizeOption {\n /** Chart width in metres, (0, 10 000]. */\n widthM: number;\n /** Chart height in metres. Default: widthM × the frame aspect (height / width), so the chart has the frame's shape. */\n heightM?: number;\n /** Neutral reflectance of the plane around the chart, lit by the same illuminant. Default 0.18. */\n surroundReflectance?: number;\n}\n/** Default surround of a fixed-size chart: an 18 % grey plane. */\nexport const CHART_SIZE_DEFAULT_SURROUND_REFLECTANCE = 0.18;\n/** Internal: validates a chart size and fills its defaults; `defaulted` names the fields taken from defaults. */\nexport function resolveChartSizeOption(value: unknown, frameAspect: number): { widthM: number; heightM: number; surroundReflectance: number; defaulted: (\"heightM\" | \"surroundReflectance\")[] } {\n requireInputObject(value, \"chartSize\");\n const record = value as Record<string, unknown>;\n for (const key of Object.keys(record)) if (![\"widthM\", \"heightM\", \"surroundReflectance\"].includes(key)) throw new InvalidConfigurationError(\"Unknown chartSize field: \" + key + \".\");\n const size = (x: unknown, name: string): number => {\n if (typeof x !== \"number\" || !Number.isFinite(x) || x <= 0 || x > 10_000) throw new InvalidConfigurationError(\"chartSize.\" + name + \" must be a positive number of metres up to 10000.\");\n return x;\n };\n const defaulted: (\"heightM\" | \"surroundReflectance\")[] = [];\n const widthM = size(record.widthM, \"widthM\");\n const heightM = record.heightM === undefined ? (defaulted.push(\"heightM\"), widthM * frameAspect) : size(record.heightM, \"heightM\");\n const surround = record.surroundReflectance === undefined ? (defaulted.push(\"surroundReflectance\"), CHART_SIZE_DEFAULT_SURROUND_REFLECTANCE) : record.surroundReflectance;\n if (typeof surround !== \"number\" || !Number.isFinite(surround) || surround < 0 || surround > 1) throw new InvalidConfigurationError(\"chartSize.surroundReflectance must be a reflectance in [0, 1].\");\n return { widthM, heightM, surroundReflectance: surround, defaulted };\n}\n\n/**\n * Public scene-preset provider. Places an engine chart (or a caller reflectance or radiance function) on\n * a plane `distanceM` in front of the camera and `framedWidthM` wide (frame units u = ±1 at its edges),\n * lit by `illuminant` at `illuminanceLux`. The returned `evaluateRadiance` and `evaluateApertureRadiance`\n * follow the native environment RAW provider contract. They answer requests for scene `sceneId` and\n * provider `providerProfileId`.\n */\nexport function createPlanarSceneRadianceProvider(input: {\n scene: ChartScene | CallerReflectanceScene | CallerRadianceScene;\n illuminant: CaptureIlluminant;\n illuminanceLux: number;\n distanceM: number;\n framedWidthM: number;\n /** Frame height / width. */\n aspect: number;\n sceneId: string;\n providerProfileId: string;\n /**\n * 2.3, opt-in: place the chart at this physical size, centred, instead of filling the frame; the chart preset\n * is resolved with aspect heightM / widthM and the rest of the plane is the surround.\n */\n chartSize?: ChartSizeOption;\n}): PlanarSceneRadianceProvider & { chart: ResolvedChartScene | null } {\n requireInputObject(input, \"createPlanarSceneRadianceProvider input\");\n const keys = [\"scene\", \"illuminant\", \"illuminanceLux\", \"distanceM\", \"framedWidthM\", \"aspect\", \"sceneId\", \"providerProfileId\", \"chartSize\"];\n for (const key of Object.keys(input)) if (!keys.includes(key)) throw new InvalidConfigurationError(\"createPlanarSceneRadianceProvider input has unknown field \\\"\" + key + \"\\\".\");\n for (const key of [\"illuminanceLux\", \"distanceM\", \"framedWidthM\", \"aspect\"] as const) {\n const value = input[key];\n if (typeof value !== \"number\" || !Number.isFinite(value) || value <= 0) throw new InvalidConfigurationError(key + \" must be a positive finite number.\");\n }\n for (const key of [\"sceneId\", \"providerProfileId\"] as const) if (typeof input[key] !== \"string\" || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(input[key])) throw new InvalidConfigurationError(key + \" must be a public opaque ID.\");\n requireInputObject(input.scene, \"scene\");\n const caller = \"kind\" in input.scene ? requireCallerScene(input.scene) : undefined;\n const size = input.chartSize === undefined ? undefined : resolveChartSizeOption(input.chartSize, input.aspect);\n const chart = caller ? null : resolveChartScene({ scene: input.scene as ChartScene, aspect: size ? size.heightM / size.widthM : input.aspect });\n const illuminant = resolveCaptureIlluminant(input.illuminant);\n const provider = buildPlanarSceneRadianceProvider({ scene: chart ?? caller!, sceneId: input.sceneId, providerProfileId: input.providerProfileId, illuminant,\n irradianceScale: calculateIlluminantIrradianceScale(illuminant.shape, input.illuminanceLux),\n geometry: { distanceM: input.distanceM, metresPerFrameUnit: input.framedWidthM / 2,\n ...(size ? { chart: { widthM: size.widthM, heightM: size.heightM, surroundReflectance: size.surroundReflectance } } : {}) },\n evidence: [{ sourceOrigin: \"photivra\", sourceReference: \"photivra:planar-scene-provider\", reuseStatus: \"photivra-owned\" }],\n limitations: [\"Planar Lambertian scene under uniform illumination; no shadows, inter-reflection, gloss or fluorescence.\"] });\n return { ...provider, chart };\n}\n\n/** Validates a caller scene function record. */\nexport function requireCallerScene(value: unknown): CallerReflectanceScene | CallerRadianceScene {\n requireInputObject(value, \"scene\");\n const record = value as Record<string, unknown>;\n for (const key of Object.keys(record)) if (key !== \"kind\" && key !== \"sceneId\" && key !== \"evaluate\") throw new InvalidConfigurationError(\"Unknown scene field: \" + key + \".\");\n if ((record.kind !== \"reflectance-function\" && record.kind !== \"radiance-function\") || typeof record.evaluate !== \"function\" ||\n typeof record.sceneId !== \"string\" || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,63}$/.test(record.sceneId)) throw new InvalidConfigurationError(\"A caller scene needs kind, a public sceneId and an evaluate function.\");\n return record as unknown as CallerReflectanceScene | CallerRadianceScene;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"scene-radiance.js","sourceRoot":"","sources":["../../src/facade/scene-radiance.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Turns a facade scene and an illuminant into a scene radiance provider for the existing native\n * environment RAW contract (`NativeEnvironmentRawProvider.evaluateRadiance` and, for pupil sampling,\n * `evaluateApertureRadiance`). The scene is an engine chart, a caller reflectance function or a caller\n * radiance function.\n *\n * Geometry: one plane perpendicular to the optical axis at `distanceM` in front of the camera. A query's\n * outgoing direction o (scene toward camera, see docs/SENSOR_ENVIRONMENT_QUERY.md) gives the look\n * direction l = -o; the plane point is l·distanceM/l.z. With a pupil ray, the plane point is the ray from\n * its lens origin to z = distanceM.\n *\n * Radiometry: a Lambertian reflector of reflectance ρ(λ) under irradiance E(λ) has radiance\n * L(λ) = ρ(λ)·E(λ)/π (W·m⁻²·sr⁻¹·nm⁻¹). The illuminant spectral shape S(λ) is scaled so that the\n * plane illuminance is E_v = K_m ∫ E(λ) V(λ) dλ with K_m = 683 lm/W (CIE photometric definition) and\n * V(λ) = ȳ(λ) from the engine's analytic CIE 1931 fit. The light is uniform\n * over the plane, with no shadows. Inter-reflection, gloss and fluorescence are not modelled.\n * @see docs/QUICK_START.md\n */\n\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport { requireInputObject } from \"../core/record-validation.js\";\nimport { estimateCie1931ColorMatchingFunctions, prepareColorimetricSpectrum, type ColorimetricSpectrum,\n type PreparedColorimetricSpectrum } from \"../color/color-matching-functions.js\";\nimport { createCieIlluminantASpectrum, createCieDaylightSpectrum, createPlanckianSpectrum, createPortableCieDaylightSpectrum, createPortableCieIlluminantASpectrum,\n createPortablePlanckianSpectrum, type CieDaylightBasis } from \"../color/illuminants.js\";\nimport type { SceneRadianceEvaluationRequest, SceneRadianceEvaluationResult } from \"../schema/scene-radiance.js\";\nimport type { EvidenceProvenance } from \"../core/evidence-provenance.js\";\nimport type { SensorApertureRay } from \"../optics/sensor-aperture-rays.js\";\nimport { resolveChartScene, type ChartScene, type ResolvedChartScene } from \"./chart-scenes.js\";\n\n/** CIE maximum luminous efficacy for photopic vision, lm/W. */\nexport const PHOTOPIC_MAXIMUM_LUMINOUS_EFFICACY_LM_PER_W = 683;\n/** Wavelength range of every facade spectrum and of the facade sensor quadrature, nm. */\nexport const FACADE_SPECTRAL_RANGE_NANOMETERS = Object.freeze({ minimum: 380, maximum: 780 });\n\n/**\n * Illuminant choices. CIE D65 is not bundled: its S0/S1/S2 basis tables must come from the caller\n * (`daylight`). `planckian` is Planck's law; `cie-a` is CIE illuminant A from its defining formula.\n */\nexport type CaptureIlluminant =\n | \"cie-a\"\n | { kind: \"planckian\"; temperatureKelvin: number }\n | { kind: \"cie-a\" }\n | { kind: \"daylight\"; correlatedColorTemperatureKelvin: number; basis: CieDaylightBasis }\n | { kind: \"spectrum\"; spectrum: ColorimetricSpectrum; label?: string };\n\nexport interface ResolvedCaptureIlluminant {\n /** Short public description, for example \"planckian-6500K\". */\n id: string;\n description: string;\n /** Relative spectral shape (arbitrary scale) over at least 380-780 nm. */\n shape: PreparedColorimetricSpectrum;\n /** Original spectrum, for colorimetric white-balance calculations. */\n spectrum: ColorimetricSpectrum;\n}\n\nexport function resolveCaptureIlluminant(value: CaptureIlluminant): ResolvedCaptureIlluminant {\n return resolveIlluminant(value, CAPTURE_SPECTRA);\n}\n/**\n * The spectrum constructors of the engine's own illuminant formulas: the capture's, or the portable ones (the display view).\n * They are passed in rather than chosen inside {@link resolveIlluminant}, so a bundle that only captures does not contain the\n * portable ones.\n */\ninterface IlluminantSpectra { planckian: typeof createPlanckianSpectrum; cieA: typeof createCieIlluminantASpectrum; daylight: typeof createCieDaylightSpectrum }\nconst CAPTURE_SPECTRA: IlluminantSpectra = { planckian: createPlanckianSpectrum, cieA: createCieIlluminantASpectrum, daylight: createCieDaylightSpectrum };\n/**\n * Internal (not exported from the package): {@link resolveCaptureIlluminant} with the engine's own formulas (Planckian,\n * CIE A, daylight locus) evaluated with the portable power and e^x − 1 (`portablePow`, `portableExpm1`), so the spectrum\n * has the same bits in every JavaScript engine. The display view uses it; captures keep {@link resolveCaptureIlluminant}.\n * A caller spectrum is the caller's own.\n */\nexport function resolvePortableCaptureIlluminant(value: CaptureIlluminant): ResolvedCaptureIlluminant {\n return resolveIlluminant(value, { planckian: createPortablePlanckianSpectrum, cieA: createPortableCieIlluminantASpectrum, daylight: createPortableCieDaylightSpectrum });\n}\nfunction resolveIlluminant(value: CaptureIlluminant, spectra: IlluminantSpectra): ResolvedCaptureIlluminant {\n if (value === \"cie-a\") return resolveIlluminant({ kind: \"cie-a\" }, spectra);\n requireInputObject(value, \"illuminant\");\n const record = value as unknown as Record<string, unknown>;\n const allowed: Record<string, readonly string[]> = { planckian: [\"kind\", \"temperatureKelvin\"], \"cie-a\": [\"kind\"],\n daylight: [\"kind\", \"correlatedColorTemperatureKelvin\", \"basis\"], spectrum: [\"kind\", \"spectrum\", \"label\"] };\n const keys = typeof record.kind === \"string\" ? allowed[record.kind] : undefined;\n if (!keys) throw new InvalidConfigurationError(\"Unknown illuminant kind.\");\n for (const key of Object.keys(record)) if (!keys.includes(key)) throw new InvalidConfigurationError(\"Unknown illuminant field: \" + key + \".\");\n let spectrum: ColorimetricSpectrum, id: string, description: string;\n try {\n switch (value.kind) {\n case \"planckian\": {\n const t = value.temperatureKelvin;\n if (typeof t !== \"number\" || !Number.isFinite(t) || t < 1000 || t > 25000) throw new InvalidConfigurationError(\"Planckian temperature must be 1000-25000 K.\");\n spectrum = spectra.planckian({ temperatureKelvin: t, wavelengthRangeNanometers: { ...FACADE_SPECTRAL_RANGE_NANOMETERS } });\n id = \"planckian-\" + t + \"K\"; description = \"Planck blackbody spectrum at \" + t + \" K (Planck's law).\";\n break;\n }\n case \"cie-a\":\n spectrum = spectra.cieA(); id = \"cie-a\"; description = \"CIE standard illuminant A from its defining formula: Planck's law with c2 = 1.435e-2 m·K and T = 2848 K, 100 at 560 nm.\";\n break;\n case \"daylight\":\n spectrum = spectra.daylight({ correlatedColorTemperatureKelvin: value.correlatedColorTemperatureKelvin, coefficientRounding: \"cie-three-decimals\", basis: value.basis });\n id = \"cie-daylight-\" + value.correlatedColorTemperatureKelvin + \"K\"; description = \"CIE daylight from the caller's S0/S1/S2 basis (\" + value.basis.datasetId + \").\";\n break;\n case \"spectrum\":\n spectrum = value.spectrum; id = \"caller-spectrum\";\n description = \"Caller illuminant spectrum\" + (typeof value.label === \"string\" ? \" (\" + value.label + \")\" : \"\") + \".\";\n break;\n }\n } catch (error) {\n if (error instanceof InvalidConfigurationError) throw error;\n throw new InvalidConfigurationError(\"Invalid illuminant: \" + (error instanceof Error ? error.message : \"invalid\"));\n }\n let shape: PreparedColorimetricSpectrum;\n try { shape = prepareColorimetricSpectrum(spectrum, \"illuminant\"); } catch (error) {\n throw new InvalidConfigurationError(\"Invalid illuminant spectrum: \" + (error instanceof Error ? error.message : \"invalid\"));\n }\n const range = shape.wavelengthRangeNanometers;\n if (range.minimum > FACADE_SPECTRAL_RANGE_NANOMETERS.minimum || range.maximum < FACADE_SPECTRAL_RANGE_NANOMETERS.maximum)\n throw new InvalidConfigurationError(\"The illuminant spectrum must cover 380-780 nm.\");\n for (let nm = FACADE_SPECTRAL_RANGE_NANOMETERS.minimum; nm <= FACADE_SPECTRAL_RANGE_NANOMETERS.maximum; nm += 1) {\n const s = shape.evaluate(nm);\n if (!(s >= 0)) throw new InvalidConfigurationError(\"The illuminant spectrum must be non-negative over 380-780 nm.\");\n }\n return Object.freeze({ id, description, shape, spectrum });\n}\n\n/**\n * Factor k such that k·S(λ) (W·m⁻²·nm⁻¹) gives `illuminanceLux` on the plane: E_v = 683 ∫ k S ȳ dλ,\n * integrated with the 1 nm trapezoid rule over 380-780 nm (ȳ outside this range is below 4e-5 of its peak).\n */\nexport function calculateIlluminantIrradianceScale(shape: PreparedColorimetricSpectrum, illuminanceLux: number): number {\n if (typeof shape !== \"object\" || shape === null || typeof shape.evaluate !== \"function\") throw new InvalidConfigurationError(\"A prepared illuminant spectrum is required.\");\n if (typeof illuminanceLux !== \"number\" || !Number.isFinite(illuminanceLux) || illuminanceLux <= 0 || illuminanceLux > 1e7)\n throw new InvalidConfigurationError(\"Illuminance must be a positive number of lux up to 1e7.\");\n let sum = 0;\n for (let nm = FACADE_SPECTRAL_RANGE_NANOMETERS.minimum; nm <= FACADE_SPECTRAL_RANGE_NANOMETERS.maximum; nm++) {\n const w = nm === FACADE_SPECTRAL_RANGE_NANOMETERS.minimum || nm === FACADE_SPECTRAL_RANGE_NANOMETERS.maximum ? 0.5 : 1;\n sum += w * shape.evaluate(nm) * estimateCie1931ColorMatchingFunctions(nm).y;\n }\n if (!(sum > 0)) throw new InvalidConfigurationError(\"The illuminant has no luminous power.\");\n return illuminanceLux / (PHOTOPIC_MAXIMUM_LUMINOUS_EFFICACY_LM_PER_W * sum);\n}\n\n/** A point of the scene plane passed to caller scene functions. */\nexport interface ScenePlanePoint {\n /** Metres on the plane, from the optical axis: +x right, +y up (as seen from the camera). */\n xM: number;\n yM: number;\n /** The same point in frame units (u = ±1 at the left/right frame edges, v up on the same scale). */\n u: number;\n v: number;\n wavelengthNanometers: number;\n /**\n * 2.3, only with a fixed-size chart (`chartSize`): the point in chart-local frame units (±1 at the chart's\n * left/right edges, v up on the same scale, ±chart height/width at its top/bottom). The function is then\n * called only for points on the chart; the surround is the placement's surround reflectance.\n */\n chartU?: number;\n chartV?: number;\n}\n/** Caller Lambertian reflectance (in [0, 1]) lit by the facade illuminant. */\nexport interface CallerReflectanceScene { kind: \"reflectance-function\"; sceneId: string; evaluate(point: Readonly<ScenePlanePoint>): number }\n/** Caller absolute spectral radiance in W·m⁻²·sr⁻¹·nm⁻¹; the facade illuminant is not used. */\nexport interface CallerRadianceScene { kind: \"radiance-function\"; sceneId: string; evaluate(point: Readonly<ScenePlanePoint>): number }\n\nexport interface PlanarSceneGeometry {\n distanceM: number;\n /** Metres per frame unit on the plane (half the framed width). */\n metresPerFrameUnit: number;\n /**\n * 2.3, opt-in fixed-size chart: the chart is `widthM` × `heightM` on the plane, centred on the optical axis;\n * outside it the plane is a neutral Lambertian surround of `surroundReflectance`, lit by the same illuminant.\n * A chart preset is then resolved in its own frame (aspect heightM / widthM). Without it the chart fills the frame.\n */\n chart?: { widthM: number; heightM: number; surroundReflectance: number };\n}\n\nexport interface PlanarSceneRadianceProvider {\n sceneId: string;\n providerProfileId: string;\n evaluateRadiance(request: Readonly<SceneRadianceEvaluationRequest>): SceneRadianceEvaluationResult;\n evaluateApertureRadiance(request: Readonly<SceneRadianceEvaluationRequest>, ray: Readonly<SensorApertureRay>): SceneRadianceEvaluationResult;\n /** Spectral radiance at a plane point (frame units), the same value the callbacks return. */\n radianceAt(u: number, v: number, wavelengthNanometers: number): number;\n /**\n * 2.3, chart scenes only: the chart material at a plane point (frame units), or `materials.length` for the\n * surround of a fixed-size chart; `materialRadiance` gives that material's spectral radiance, the same value\n * `radianceAt` returns at its points.\n */\n chartMaterialAt?(u: number, v: number): number;\n materialRadiance?(material: number, wavelengthNanometers: number): number;\n}\n\nconst UNCERTAINTY = Object.freeze({ kind: \"not-quantified\" as const, limitation: \"Analytic planar Lambertian scene; no measured scene, BRDF or illumination.\" });\n\n/**\n * Wraps a chart or caller scene as a provider for the native environment RAW task. `irradianceScale` is\n * from {@link calculateIlluminantIrradianceScale}; caller radiance scenes ignore the illuminant.\n */\nexport function buildPlanarSceneRadianceProvider(input: {\n scene: ResolvedChartScene | CallerReflectanceScene | CallerRadianceScene;\n sceneId: string;\n providerProfileId: string;\n illuminant: ResolvedCaptureIlluminant;\n irradianceScale: number;\n geometry: PlanarSceneGeometry;\n evidence: readonly EvidenceProvenance[];\n limitations: readonly string[];\n}): PlanarSceneRadianceProvider {\n const { scene, illuminant, irradianceScale, geometry } = input;\n const scale = geometry.metresPerFrameUnit, distance = geometry.distanceM, sceneId = input.sceneId, providerProfileId = input.providerProfileId;\n const evidence = input.evidence, limitations = input.limitations;\n const caller = \"kind\" in scene ? scene : undefined, chart = caller ? undefined : scene as ResolvedChartScene;\n const placed = geometry.chart, half = placed ? placed.widthM / 2 : 0, chartAspect = placed ? placed.heightM / placed.widthM : 0;\n function radianceAt(u: number, v: number, nm: number): number {\n if (placed) {\n // Fixed-size chart (2.3): chart-local frame units from the plane point in metres.\n const xM = u * scale, yM = v * scale, cu = xM / half, cv = yM / half;\n if (!(Math.abs(cu) <= 1 && Math.abs(cv) <= chartAspect)) return placed.surroundReflectance * irradianceScale * illuminant.shape.evaluate(nm) / Math.PI;\n if (chart) return chart.reflectanceAt(cu, cv, nm) * irradianceScale * illuminant.shape.evaluate(nm) / Math.PI;\n return callerValue(Object.freeze({ xM, yM, u, v, wavelengthNanometers: nm, chartU: cu, chartV: cv }), nm);\n }\n if (chart) return chart.reflectanceAt(u, v, nm) * irradianceScale * illuminant.shape.evaluate(nm) / Math.PI;\n return callerValue(Object.freeze({ xM: u * scale, yM: v * scale, u, v, wavelengthNanometers: nm }), nm);\n }\n function callerValue(point: Readonly<ScenePlanePoint>, nm: number): number {\n const value = caller!.evaluate(point);\n if (caller!.kind === \"reflectance-function\") {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value < 0 || value > 1) throw new InvalidConfigurationError(\"Scene reflectance function must return a value in [0, 1].\");\n return value * irradianceScale * illuminant.shape.evaluate(nm) / Math.PI;\n }\n if (typeof value !== \"number\" || !Number.isFinite(value) || value < 0) throw new InvalidConfigurationError(\"Scene radiance function must return a finite non-negative radiance.\");\n return value;\n }\n function result(request: Readonly<SceneRadianceEvaluationRequest>, radiance: number): SceneRadianceEvaluationResult {\n return { schemaVersion: \"0.1.0\", sampleId: request.sampleId, sceneId, providerProfileId, wavelengthNanometers: request.wavelengthNanometers,\n wavelengthBasis: request.wavelengthBasis as SceneRadianceEvaluationResult[\"wavelengthBasis\"], quantity: \"outgoing-spectral-radiance\", unit: \"W/m^2/sr/nm\",\n spectralRadianceWattsPerSquareMeterSteradianNanometer: radiance, scientificStatus: \"approximation\", uncertainty: UNCERTAINTY, evidence, limitations };\n }\n const chartAccess = chart ? {\n chartMaterialAt(u: number, v: number): number {\n if (!placed) return chart.materialAt(u, v);\n const cu = u * scale / half, cv = v * scale / half;\n return Math.abs(cu) <= 1 && Math.abs(cv) <= chartAspect ? chart.materialAt(cu, cv) : chart.materials.length;\n },\n materialRadiance(material: number, nm: number): number {\n const m = chart.materials[material];\n let value: number;\n if (m === undefined) value = placed ? placed.surroundReflectance : NaN;\n else if (m.kind === \"neutral\") value = m.reflectance;\n else {\n value = m.spectrum.evaluate(nm);\n if (!(value >= 0 && value <= 1)) throw new InvalidConfigurationError(\"Chart reflectance spectrum left [0, 1].\");\n }\n if (!(value >= 0)) throw new InvalidConfigurationError(\"Unknown chart material.\");\n return value * irradianceScale * illuminant.shape.evaluate(nm) / Math.PI;\n }\n } : {};\n return {\n sceneId, providerProfileId, radianceAt, ...chartAccess,\n evaluateRadiance(request): SceneRadianceEvaluationResult {\n const target = request.target;\n if (target.kind !== \"environment-direction\") throw new InvalidConfigurationError(\"Planar scene provider needs environment-direction queries.\");\n const o = target.outgoingDirectionUnitVector, lz = -o.z;\n if (!(lz > 0)) throw new InvalidConfigurationError(\"Planar scene query does not point toward the scene plane.\");\n const t = distance / lz;\n return result(request, radianceAt(-o.x * t / scale, -o.y * t / scale, request.wavelengthNanometers));\n },\n evaluateApertureRadiance(request, ray): SceneRadianceEvaluationResult {\n const d = ray.directionUnitVector, origin = ray.originM;\n if (!(d.z > 0)) throw new InvalidConfigurationError(\"Planar scene pupil ray does not point toward the scene plane.\");\n const t = (distance - origin.z) / d.z;\n return result(request, radianceAt((origin.x + d.x * t) / scale, (origin.y + d.y * t) / scale, request.wavelengthNanometers));\n }\n };\n}\n\n/** 2.3: a chart's physical size on the scene plane (`simulateCapture` `chartSize`, `createPlanarSceneRadianceProvider` `chartSize`). */\nexport interface ChartSizeOption {\n /** Chart width in metres, (0, 10 000]. */\n widthM: number;\n /** Chart height in metres. Default: widthM × the frame aspect (height / width), so the chart has the frame's shape. */\n heightM?: number;\n /** Neutral reflectance of the plane around the chart, lit by the same illuminant. Default 0.18. */\n surroundReflectance?: number;\n}\n/** Default surround of a fixed-size chart: an 18 % grey plane. */\nexport const CHART_SIZE_DEFAULT_SURROUND_REFLECTANCE = 0.18;\n/** Internal: validates a chart size and fills its defaults; `defaulted` names the fields taken from defaults. */\nexport function resolveChartSizeOption(value: unknown, frameAspect: number): { widthM: number; heightM: number; surroundReflectance: number; defaulted: (\"heightM\" | \"surroundReflectance\")[] } {\n requireInputObject(value, \"chartSize\");\n const record = value as Record<string, unknown>;\n for (const key of Object.keys(record)) if (![\"widthM\", \"heightM\", \"surroundReflectance\"].includes(key)) throw new InvalidConfigurationError(\"Unknown chartSize field: \" + key + \".\");\n const size = (x: unknown, name: string): number => {\n if (typeof x !== \"number\" || !Number.isFinite(x) || x <= 0 || x > 10_000) throw new InvalidConfigurationError(\"chartSize.\" + name + \" must be a positive number of metres up to 10000.\");\n return x;\n };\n const defaulted: (\"heightM\" | \"surroundReflectance\")[] = [];\n const widthM = size(record.widthM, \"widthM\");\n const heightM = record.heightM === undefined ? (defaulted.push(\"heightM\"), widthM * frameAspect) : size(record.heightM, \"heightM\");\n const surround = record.surroundReflectance === undefined ? (defaulted.push(\"surroundReflectance\"), CHART_SIZE_DEFAULT_SURROUND_REFLECTANCE) : record.surroundReflectance;\n if (typeof surround !== \"number\" || !Number.isFinite(surround) || surround < 0 || surround > 1) throw new InvalidConfigurationError(\"chartSize.surroundReflectance must be a reflectance in [0, 1].\");\n return { widthM, heightM, surroundReflectance: surround, defaulted };\n}\n\n/**\n * Public scene-preset provider. Places an engine chart (or a caller reflectance or radiance function) on\n * a plane `distanceM` in front of the camera and `framedWidthM` wide (frame units u = ±1 at its edges),\n * lit by `illuminant` at `illuminanceLux`. The returned `evaluateRadiance` and `evaluateApertureRadiance`\n * follow the native environment RAW provider contract. They answer requests for scene `sceneId` and\n * provider `providerProfileId`.\n */\nexport function createPlanarSceneRadianceProvider(input: {\n scene: ChartScene | CallerReflectanceScene | CallerRadianceScene;\n illuminant: CaptureIlluminant;\n illuminanceLux: number;\n distanceM: number;\n framedWidthM: number;\n /** Frame height / width. */\n aspect: number;\n sceneId: string;\n providerProfileId: string;\n /**\n * 2.3, opt-in: place the chart at this physical size, centred, instead of filling the frame; the chart preset\n * is resolved with aspect heightM / widthM and the rest of the plane is the surround.\n */\n chartSize?: ChartSizeOption;\n}): PlanarSceneRadianceProvider & { chart: ResolvedChartScene | null } {\n requireInputObject(input, \"createPlanarSceneRadianceProvider input\");\n const keys = [\"scene\", \"illuminant\", \"illuminanceLux\", \"distanceM\", \"framedWidthM\", \"aspect\", \"sceneId\", \"providerProfileId\", \"chartSize\"];\n for (const key of Object.keys(input)) if (!keys.includes(key)) throw new InvalidConfigurationError(\"createPlanarSceneRadianceProvider input has unknown field \\\"\" + key + \"\\\".\");\n for (const key of [\"illuminanceLux\", \"distanceM\", \"framedWidthM\", \"aspect\"] as const) {\n const value = input[key];\n if (typeof value !== \"number\" || !Number.isFinite(value) || value <= 0) throw new InvalidConfigurationError(key + \" must be a positive finite number.\");\n }\n for (const key of [\"sceneId\", \"providerProfileId\"] as const) if (typeof input[key] !== \"string\" || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(input[key])) throw new InvalidConfigurationError(key + \" must be a public opaque ID.\");\n requireInputObject(input.scene, \"scene\");\n const caller = \"kind\" in input.scene ? requireCallerScene(input.scene) : undefined;\n const size = input.chartSize === undefined ? undefined : resolveChartSizeOption(input.chartSize, input.aspect);\n const chart = caller ? null : resolveChartScene({ scene: input.scene as ChartScene, aspect: size ? size.heightM / size.widthM : input.aspect });\n const illuminant = resolveCaptureIlluminant(input.illuminant);\n const provider = buildPlanarSceneRadianceProvider({ scene: chart ?? caller!, sceneId: input.sceneId, providerProfileId: input.providerProfileId, illuminant,\n irradianceScale: calculateIlluminantIrradianceScale(illuminant.shape, input.illuminanceLux),\n geometry: { distanceM: input.distanceM, metresPerFrameUnit: input.framedWidthM / 2,\n ...(size ? { chart: { widthM: size.widthM, heightM: size.heightM, surroundReflectance: size.surroundReflectance } } : {}) },\n evidence: [{ sourceOrigin: \"photivra\", sourceReference: \"photivra:planar-scene-provider\", reuseStatus: \"photivra-owned\" }],\n limitations: [\"Planar Lambertian scene under uniform illumination; no shadows, inter-reflection, gloss or fluorescence.\"] });\n return { ...provider, chart };\n}\n\n/** Validates a caller scene function record. */\nexport function requireCallerScene(value: unknown): CallerReflectanceScene | CallerRadianceScene {\n requireInputObject(value, \"scene\");\n const record = value as Record<string, unknown>;\n for (const key of Object.keys(record)) if (key !== \"kind\" && key !== \"sceneId\" && key !== \"evaluate\") throw new InvalidConfigurationError(\"Unknown scene field: \" + key + \".\");\n if ((record.kind !== \"reflectance-function\" && record.kind !== \"radiance-function\") || typeof record.evaluate !== \"function\" ||\n typeof record.sceneId !== \"string\" || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,63}$/.test(record.sceneId)) throw new InvalidConfigurationError(\"A caller scene needs kind, a public sceneId and an evaluate function.\");\n return record as unknown as CallerReflectanceScene | CallerRadianceScene;\n}\n"]}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { EvidenceProvenance } from "../core/evidence-provenance.js";
|
|
2
2
|
import { type GenericEquipmentTier, type GenericEquipmentTierPreset } from "../equipment/generic-tier-assets.js";
|
|
3
|
-
import { type ResolvedWhiteBalanceState } from "../color/white-balance.js";
|
|
3
|
+
import { resolveColorTemperatureWhiteBalance, type ResolvedWhiteBalanceState } from "../color/white-balance.js";
|
|
4
|
+
import { type CaptureWhiteBalanceIntent } from "../capture/simulated-capture.js";
|
|
4
5
|
import { type NativeRawOutput, type NativeRawPlan } from "../capture/native-raw.js";
|
|
5
6
|
import { type NativeEnvironmentRawInput } from "../capture/native-environment-raw.js";
|
|
6
7
|
import { type NativeRawDevelopmentInput, type RawHighlightDiagnostics } from "../capture/native-raw-development.js";
|
|
8
|
+
import type { RawFrameReconstructionPhaseProfile } from "../capture/raw-frame-reconstruction.js";
|
|
7
9
|
import { type SdrToneCurve, type SdrToneCurveParameters, type SdrRenderingResult } from "../output/sdr-rendering.js";
|
|
8
10
|
import type { RawHighlightMode } from "../color/sensor-color-development.js";
|
|
9
11
|
import type { SimulateEnvironmentSensorRawFrameInput } from "../capture/environment-raw-producer.js";
|
|
@@ -12,11 +14,12 @@ import { type LensProjectionModel } from "../camera/lens-projection.js";
|
|
|
12
14
|
import type { RadialDistortionProfile } from "../optics/radial-distortion.js";
|
|
13
15
|
import type { BrownConradyDistortionProfile } from "../optics/brown-conrady-distortion.js";
|
|
14
16
|
import type { IlluminationVignettingProfile } from "../optics/illumination-vignetting.js";
|
|
17
|
+
import type { CalculateSensorPsfIrradianceQuadratureInput } from "../optics/sensor-psf-quadrature.js";
|
|
15
18
|
import type { CalculateEnvironmentSensorPhotoSignalInput } from "../sensor/environment-photo-signal.js";
|
|
16
19
|
import { type DiffractionLimitedPsfProfile } from "../optics/diffraction-psf-profile.js";
|
|
17
20
|
import { type AntiAliasingPointSplitComponent } from "../sensor/optical-stack.js";
|
|
18
|
-
import { type ChartScene } from "./chart-scenes.js";
|
|
19
|
-
import { type ChartSizeOption, type CaptureIlluminant, type CallerRadianceScene, type CallerReflectanceScene } from "./scene-radiance.js";
|
|
21
|
+
import { type ChartScene, type ResolvedChartScene } from "./chart-scenes.js";
|
|
22
|
+
import { type ChartSizeOption, type CaptureIlluminant, type CallerRadianceScene, type CallerReflectanceScene, type PlanarSceneRadianceProvider, type ResolvedCaptureIlluminant } from "./scene-radiance.js";
|
|
20
23
|
/** Version of how the facade builds requests. It changes whenever the same input would build a different request. */
|
|
21
24
|
export declare const SIMULATE_CAPTURE_FACADE_VERSION: "1.0.0";
|
|
22
25
|
export type SimulateCaptureExposureMode = "manual" | "aperture-priority" | "shutter-priority" | "program";
|
|
@@ -227,7 +230,9 @@ export interface SimulateCaptureOptions {
|
|
|
227
230
|
* the whole render: framing, metering, exposure, noise seeds (absolute native site indices), rolling-shutter row
|
|
228
231
|
* timing, diffraction and demosaic all use the whole frame. Use it to tile a large frame across workers or to
|
|
229
232
|
* render a 100 % crop. `result.image` is the region; `result.region` reports it. Not combinable with
|
|
230
|
-
* `whiteBalance: "auto"`, whose statistics would come from the region only.
|
|
233
|
+
* `whiteBalance: "auto"`, whose statistics would come from the region only. From 2.6 the diffraction convolution
|
|
234
|
+
* covers only the region plus the kernel and filter reach, so a small region of a large frame costs about as much
|
|
235
|
+
* as a capture of the region's size.
|
|
231
236
|
*/
|
|
232
237
|
region?: {
|
|
233
238
|
x: number;
|
|
@@ -239,7 +244,11 @@ export interface SimulateCaptureOptions {
|
|
|
239
244
|
/** Camera motion and shutter type. Default: still camera, global electronic shutter. */
|
|
240
245
|
motion?: SimulateCaptureMotion;
|
|
241
246
|
sensor?: {
|
|
242
|
-
/**
|
|
247
|
+
/**
|
|
248
|
+
* Pixel pitch in micrometres, 0.5–1000. Default 6. The simulated sensor is output width × pitch wide. 2.5: above 100 µm the
|
|
249
|
+
* capture is a downsized view of a whole frame (for example 36 mm / 48 pixels = 750 µm), recorded in the assumption
|
|
250
|
+
* `sensor.wholeFrameView`: brightness is unchanged and the noise is that of a binned view, not of the real sensor's pixels.
|
|
251
|
+
*/
|
|
243
252
|
pixelPitchMicrometers?: number;
|
|
244
253
|
/** Maximum spectral quadrature subinterval in nm. Default 20. */
|
|
245
254
|
spectralStepNanometers?: number;
|
|
@@ -447,12 +456,37 @@ export interface SimulateCaptureResult {
|
|
|
447
456
|
};
|
|
448
457
|
assumptions: readonly SimulateCaptureAssumption[];
|
|
449
458
|
}
|
|
459
|
+
export declare const FACADE_EVIDENCE: readonly EvidenceProvenance[];
|
|
450
460
|
/**
|
|
451
461
|
* Default illuminance, lux: an 18 % Lambertian grey card (L = 0.18·E/π) then gets exactly the CIPA DC-004 standard
|
|
452
462
|
* output sensitivity reference exposure H = 10/S at f/8, 1/125 s, ISO 100:
|
|
453
463
|
* E = π·10·N²/(0.65·t·S·0.18) = π·80 000/11.7 ≈ 21 480.98 lux.
|
|
454
464
|
*/
|
|
455
465
|
export declare const SIMULATE_CAPTURE_DEFAULT_ILLUMINANCE_LUX: number;
|
|
466
|
+
interface ParsedAntiAliasing {
|
|
467
|
+
kind: SimulateCaptureSensorAntiAliasing["kind"];
|
|
468
|
+
separationSites?: number;
|
|
469
|
+
axis?: "horizontal" | "vertical";
|
|
470
|
+
components: AntiAliasingPointSplitComponent[];
|
|
471
|
+
}
|
|
472
|
+
/** Midpoint nodes of an N × N rule over a square photosite, as offsets from its centre in sites (+x right, +y down). */
|
|
473
|
+
export declare function apertureNodeOffsets(n: number): {
|
|
474
|
+
x: number;
|
|
475
|
+
y: number;
|
|
476
|
+
}[];
|
|
477
|
+
export declare const CHANNELS: readonly ["red", "green", "blue"];
|
|
478
|
+
type Channel = typeof CHANNELS[number];
|
|
479
|
+
export declare const CAMERA_TO_XYZ: readonly (readonly number[])[];
|
|
480
|
+
/** Synthetic dark current per site at the operating temperature, e⁻/s. */
|
|
481
|
+
export declare const DARK_CURRENT_ELECTRONS_PER_SECOND = 1;
|
|
482
|
+
export declare function fail(message: string): never;
|
|
483
|
+
type ReadoutProfile = GenericEquipmentTierPreset["body"]["readout"][number]["profile"];
|
|
484
|
+
/** Diagnostic clock for the 2.1 stage timings: `performance.now()` where the host has it. Never affects output. */
|
|
485
|
+
export declare function clockMs(): number;
|
|
486
|
+
/** The white balance measured from a perfect white diffuser under the scene illuminant ("scene-illuminant"). */
|
|
487
|
+
export declare function sceneIlluminantWhiteBalance(illuminant: ResolvedCaptureIlluminant): ResolvedWhiteBalanceState;
|
|
488
|
+
/** Bilinear RGGB demosaic as explicit linear neighbourhood kernels (weights sum to one per output channel). */
|
|
489
|
+
export declare function bilinearPhaseProfiles(): RawFrameReconstructionPhaseProfile[];
|
|
456
490
|
/**
|
|
457
491
|
* Simulates one still capture of a planar scene and returns the developed image, the packed RAW, the full
|
|
458
492
|
* underlying request/plan, provenance and every assumption made. See docs/QUICK_START.md.
|
|
@@ -520,5 +554,195 @@ export interface IdealReferenceResult {
|
|
|
520
554
|
/** The capture request's assumptions, then `reference.kind`, `reference.excludes`, `reference.exposure` and `reference.sampling`. */
|
|
521
555
|
assumptions: readonly SimulateCaptureAssumption[];
|
|
522
556
|
}
|
|
557
|
+
/** Default stratified samples per axis of a display view (`view.samplesPerAxis`): 16 × 16 sampled real pixels per display pixel with detail, 4 × 4 where it is uniform. */
|
|
558
|
+
export declare const SIMULATE_DISPLAY_VIEW_DEFAULT_SAMPLES_PER_AXIS = 16;
|
|
559
|
+
/** The display size and sampling of {@link simulateDisplayView}. */
|
|
560
|
+
export interface SimulateDisplayViewOptions {
|
|
561
|
+
/** Display pixels, 1 to the capture's output width and height. */
|
|
562
|
+
width: number;
|
|
563
|
+
height: number;
|
|
564
|
+
/** Stratified Monte Carlo samples per axis for each display pixel's expected value (1–32, default 8: 64 real pixels). */
|
|
565
|
+
samplesPerAxis?: number;
|
|
566
|
+
/** "srgb-8" (default) or "srgb-16". */
|
|
567
|
+
format?: "srgb-8" | "srgb-16";
|
|
568
|
+
/** Render only this rectangle of the display view, in display pixels; byte-identical to the same pixels of the whole view. */
|
|
569
|
+
region?: {
|
|
570
|
+
x: number;
|
|
571
|
+
y: number;
|
|
572
|
+
width: number;
|
|
573
|
+
height: number;
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
/** Result of {@link simulateDisplayView}: the full-resolution capture resized for display, estimated; not a capture. */
|
|
577
|
+
export interface DisplayViewResult {
|
|
578
|
+
kind: "display-view";
|
|
579
|
+
/** Human-readable label for a user interface. */
|
|
580
|
+
label: string;
|
|
581
|
+
facadeVersion: typeof SIMULATE_CAPTURE_FACADE_VERSION;
|
|
582
|
+
engineApiVersion: string;
|
|
583
|
+
/** The display view (or its region): interleaved sRGB samples, row by row from the top-left. */
|
|
584
|
+
image: {
|
|
585
|
+
width: number;
|
|
586
|
+
height: number;
|
|
587
|
+
format: "srgb-8" | "srgb-16";
|
|
588
|
+
samples: Uint8Array | Uint16Array;
|
|
589
|
+
};
|
|
590
|
+
/**
|
|
591
|
+
* The view: display size, the capture frame it shows (output pixels), real pixels per display pixel along each axis,
|
|
592
|
+
* the samples per axis and, with `view.region`, the rendered rectangle.
|
|
593
|
+
*/
|
|
594
|
+
view: {
|
|
595
|
+
width: number;
|
|
596
|
+
height: number;
|
|
597
|
+
frameWidth: number;
|
|
598
|
+
frameHeight: number;
|
|
599
|
+
scaleX: number;
|
|
600
|
+
scaleY: number;
|
|
601
|
+
samplesPerAxis: number;
|
|
602
|
+
region?: {
|
|
603
|
+
x: number;
|
|
604
|
+
y: number;
|
|
605
|
+
width: number;
|
|
606
|
+
height: number;
|
|
607
|
+
};
|
|
608
|
+
};
|
|
609
|
+
/** The resolved exposure of the capture this view shows. */
|
|
610
|
+
exposure: {
|
|
611
|
+
mode: SimulateCaptureExposureMode;
|
|
612
|
+
settings: {
|
|
613
|
+
fNumber: number;
|
|
614
|
+
shutterSeconds: number;
|
|
615
|
+
iso: number;
|
|
616
|
+
};
|
|
617
|
+
ev100: number;
|
|
618
|
+
};
|
|
619
|
+
scene: SimulateCaptureResult["scene"];
|
|
620
|
+
/**
|
|
621
|
+
* Work done: real pixels sampled, real-site expectations evaluated, scene queries, display pixels sampled in full (detail) or with
|
|
622
|
+
* a quarter of the samples per axis (uniform), display pixels whose value includes the AHD low-signal correction, and wall-clock
|
|
623
|
+
* milliseconds (diagnostic only; never affects the samples).
|
|
624
|
+
*/
|
|
625
|
+
diagnostics: {
|
|
626
|
+
sampleCount: number;
|
|
627
|
+
siteEvaluations: number;
|
|
628
|
+
sceneLookups: number;
|
|
629
|
+
detailPixelCount: number;
|
|
630
|
+
uniformPixelCount: number;
|
|
631
|
+
ahdCorrectedPixelCount: number;
|
|
632
|
+
timingsMs: {
|
|
633
|
+
view: number;
|
|
634
|
+
total: number;
|
|
635
|
+
};
|
|
636
|
+
};
|
|
637
|
+
provenance: {
|
|
638
|
+
scientificStatus: "approximation";
|
|
639
|
+
cameraPresetId: string;
|
|
640
|
+
cameraPresetVersion: string;
|
|
641
|
+
evidence: readonly EvidenceProvenance[];
|
|
642
|
+
composedContracts: readonly string[];
|
|
643
|
+
limitations: readonly string[];
|
|
644
|
+
};
|
|
645
|
+
/** The capture request's assumptions, then `view.definition`, `view.estimation`, `view.noise`, `view.demosaic` and `view.source`. */
|
|
646
|
+
assumptions: readonly SimulateCaptureAssumption[];
|
|
647
|
+
}
|
|
648
|
+
/** Internal: the resolved request state that the display view's renderer (simulate-display-view.ts) reads. */
|
|
649
|
+
export interface DisplayViewRunContext {
|
|
650
|
+
ahd: boolean;
|
|
651
|
+
antiAliasing: ParsedAntiAliasing | undefined;
|
|
652
|
+
aspect: number;
|
|
653
|
+
assume: (id: string, kind: SimulateCaptureAssumption["kind"], value: unknown, explanation: string) => void;
|
|
654
|
+
assumptions: SimulateCaptureAssumption[];
|
|
655
|
+
axisChannelResponse: (caller: string) => {
|
|
656
|
+
electronsPerRadiance: Record<Channel, Map<number, number>>;
|
|
657
|
+
wavelengths: number[];
|
|
658
|
+
relativePerElectron: Record<Channel, number>;
|
|
659
|
+
};
|
|
660
|
+
boxSamples: number;
|
|
661
|
+
buildProvider: (sceneIlluminant: ResolvedCaptureIlluminant, scale: number) => PlanarSceneRadianceProvider;
|
|
662
|
+
callerScene: CallerReflectanceScene | CallerRadianceScene | undefined;
|
|
663
|
+
chart: ResolvedChartScene | undefined;
|
|
664
|
+
chartReport: {
|
|
665
|
+
widthM: number;
|
|
666
|
+
heightM: number;
|
|
667
|
+
surroundReflectance: number;
|
|
668
|
+
frameWidthFraction: number;
|
|
669
|
+
frameHeightFraction: number;
|
|
670
|
+
magnification: number;
|
|
671
|
+
imageWidthMm: number;
|
|
672
|
+
imageHeightMm: number;
|
|
673
|
+
imageWidthPixels: number;
|
|
674
|
+
imageHeightPixels: number;
|
|
675
|
+
} | undefined;
|
|
676
|
+
chartSize: {
|
|
677
|
+
widthM: number;
|
|
678
|
+
heightM: number;
|
|
679
|
+
surroundReflectance: number;
|
|
680
|
+
defaulted: ("heightM" | "surroundReflectance")[];
|
|
681
|
+
} | undefined;
|
|
682
|
+
diffraction: DiffractionLimitedPsfProfile | undefined;
|
|
683
|
+
diffractionPsf: {
|
|
684
|
+
kind: "sampled-local";
|
|
685
|
+
configuration: Pick<CalculateSensorPsfIrradianceQuadratureInput, "psf" | "psfWavelengthBasis" | "spatialModel">;
|
|
686
|
+
} | undefined;
|
|
687
|
+
fNumber: number;
|
|
688
|
+
focalLengthMm: number;
|
|
689
|
+
focusDistanceM: number;
|
|
690
|
+
height: number;
|
|
691
|
+
highlightMode: RawHighlightMode;
|
|
692
|
+
illuminanceLux: number;
|
|
693
|
+
illuminant: ResolvedCaptureIlluminant;
|
|
694
|
+
illuminantOption: CaptureIlluminant;
|
|
695
|
+
imagingArea: {
|
|
696
|
+
widthMm: number;
|
|
697
|
+
heightMm: number;
|
|
698
|
+
};
|
|
699
|
+
intentOf: (state: ResolvedWhiteBalanceState | null) => CaptureWhiteBalanceIntent | null;
|
|
700
|
+
metresPerFrameUnit: number;
|
|
701
|
+
noiseSeed: number;
|
|
702
|
+
outputOptions: Record<string, unknown>;
|
|
703
|
+
parsedView: ParsedDisplayView | undefined;
|
|
704
|
+
pitch: number;
|
|
705
|
+
preset: GenericEquipmentTierPreset;
|
|
706
|
+
provider: PlanarSceneRadianceProvider;
|
|
707
|
+
regimeByChannel: Record<"red" | "green" | "blue", {
|
|
708
|
+
readoutProfile: ReadoutProfile;
|
|
709
|
+
regimeId: string;
|
|
710
|
+
}>;
|
|
711
|
+
resolvedIso: number;
|
|
712
|
+
sceneOption: unknown;
|
|
713
|
+
scenePreset: "composite" | "uniform" | "patches" | "slanted-edge" | "siemens-star" | "step-wedge" | "grey-ramp" | "checkerboard" | "point-grid" | "dead-leaves" | "bar-groups" | "hyperbolic-wedge" | "zone-plate" | "slanted-squares" | "line-grid" | "fiducial" | "reflectance-function" | "radiance-function";
|
|
714
|
+
shutterSeconds: number;
|
|
715
|
+
started: number;
|
|
716
|
+
subjectDistanceM: number;
|
|
717
|
+
toneCurve: SdrToneCurve;
|
|
718
|
+
whiteBalanceOption: SimulateCaptureWhiteBalance;
|
|
719
|
+
whiteBalanceState: ResolvedWhiteBalanceState | null;
|
|
720
|
+
width: number;
|
|
721
|
+
checkAbort: () => void;
|
|
722
|
+
margin: number;
|
|
723
|
+
mode: SimulateCaptureExposureMode;
|
|
724
|
+
nativeHeight: number;
|
|
725
|
+
nativeWidth: number;
|
|
726
|
+
sourceSha256: string;
|
|
727
|
+
yieldControl: () => Promise<void>;
|
|
728
|
+
/** The Kelvin white balance request, which the view resolves with the portable functions. */
|
|
729
|
+
kelvinWhiteBalanceInput: Parameters<typeof resolveColorTemperatureWhiteBalance>[0] | undefined;
|
|
730
|
+
}
|
|
731
|
+
export interface ParsedDisplayView {
|
|
732
|
+
width: number;
|
|
733
|
+
height: number;
|
|
734
|
+
samplesPerAxis: number;
|
|
735
|
+
bitDepth: 8 | 16;
|
|
736
|
+
format: "srgb-8" | "srgb-16";
|
|
737
|
+
region?: {
|
|
738
|
+
x: number;
|
|
739
|
+
y: number;
|
|
740
|
+
width: number;
|
|
741
|
+
height: number;
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
/** Internal: the request path shared by {@link simulateCapture}, {@link simulateIdealReference} and the display view, whose renderer is passed in. */
|
|
745
|
+
export declare function runCapture(options: SimulateCaptureOptions, run: "capture" | "ideal-reference" | "display-view", viewOption?: unknown, renderView?: (context: DisplayViewRunContext) => Promise<DisplayViewResult>): Promise<SimulateCaptureResult | IdealReferenceResult | DisplayViewResult>;
|
|
523
746
|
/** Chart preset ids accepted by `simulateCapture({ scene: { preset } })`. */
|
|
524
747
|
export declare const SIMULATE_CAPTURE_CHART_PRESETS: readonly ("composite" | "uniform" | "patches" | "slanted-edge" | "siemens-star" | "step-wedge" | "grey-ramp" | "checkerboard" | "point-grid" | "dead-leaves" | "bar-groups" | "hyperbolic-wedge" | "zone-plate" | "slanted-squares" | "line-grid" | "fiducial")[];
|
|
748
|
+
export {};
|