@photivra/engine 2.10.0 → 2.11.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/CHANGELOG.md +139 -1
- package/CITATION.cff +1 -1
- package/NODE_SUPPORT.md +21 -3
- package/README.md +6 -6
- package/SECURITY.md +1 -1
- package/dist/core/portable-math.d.ts +6 -0
- package/dist/core/portable-math.js +39 -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-material-layers.d.ts +115 -0
- package/dist/facade/chart-material-layers.js +224 -0
- package/dist/facade/chart-material-layers.js.map +1 -0
- package/dist/facade/chart-radiance-batch.d.ts +8 -2
- package/dist/facade/chart-radiance-batch.js +11 -4
- package/dist/facade/chart-radiance-batch.js.map +1 -1
- package/dist/facade/chart-scenes.d.ts +134 -0
- package/dist/facade/chart-scenes.js +32 -22
- package/dist/facade/chart-scenes.js.map +1 -1
- package/dist/facade/diffraction-provider.d.ts +8 -2
- package/dist/facade/diffraction-provider.js +71 -2
- package/dist/facade/diffraction-provider.js.map +1 -1
- package/dist/facade/display-view-gpu-session.d.ts +18 -0
- package/dist/facade/display-view-gpu-session.js +280 -0
- package/dist/facade/display-view-gpu-session.js.map +1 -0
- package/dist/facade/display-view-gpu.d.ts +146 -0
- package/dist/facade/display-view-gpu.js +59 -0
- package/dist/facade/display-view-gpu.js.map +1 -0
- package/dist/facade/display-view.d.ts +48 -1
- package/dist/facade/display-view.js +7 -7
- package/dist/facade/display-view.js.map +1 -1
- package/dist/facade/expected-signal-setup.d.ts +5 -0
- package/dist/facade/expected-signal-setup.js +16 -0
- package/dist/facade/expected-signal-setup.js.map +1 -1
- package/dist/facade/expected-signal.d.ts +48 -3
- package/dist/facade/expected-signal.js +8 -0
- package/dist/facade/expected-signal.js.map +1 -1
- package/dist/facade/scene-radiance.d.ts +4 -2
- package/dist/facade/scene-radiance.js +7 -4
- package/dist/facade/scene-radiance.js.map +1 -1
- package/dist/facade/simulate-capture.d.ts +32 -5
- package/dist/facade/simulate-capture.js +148 -24
- package/dist/facade/simulate-capture.js.map +1 -1
- package/dist/facade/simulate-display-view.d.ts +31 -3
- package/dist/facade/simulate-display-view.js +72 -12
- package/dist/facade/simulate-display-view.js.map +1 -1
- package/dist/gpu/chart-composite-gpu.d.ts +119 -0
- package/dist/gpu/chart-composite-gpu.js +572 -0
- package/dist/gpu/chart-composite-gpu.js.map +1 -0
- package/dist/gpu/chart-radiance-gpu.d.ts +6 -6
- package/dist/gpu/chart-radiance-gpu.js +9 -11
- package/dist/gpu/chart-radiance-gpu.js.map +1 -1
- package/dist/gpu/display-view-chart-material-module.d.ts +10 -0
- package/dist/gpu/display-view-chart-material-module.js +58 -0
- package/dist/gpu/display-view-chart-material-module.js.map +1 -0
- package/dist/gpu/display-view-composite-material-module.d.ts +68 -0
- package/dist/gpu/display-view-composite-material-module.js +248 -0
- package/dist/gpu/display-view-composite-material-module.js.map +1 -0
- package/dist/gpu/display-view-quality-gpu.d.ts +185 -0
- package/dist/gpu/display-view-quality-gpu.js +1000 -0
- package/dist/gpu/display-view-quality-gpu.js.map +1 -0
- package/dist/gpu/display-view-speed-gpu.d.ts +156 -0
- package/dist/gpu/display-view-speed-gpu.js +524 -0
- package/dist/gpu/display-view-speed-gpu.js.map +1 -0
- package/dist/gpu/image-kernel-accelerator.d.ts +23 -4
- package/dist/gpu/image-kernel-accelerator.js +58 -10
- package/dist/gpu/image-kernel-accelerator.js.map +1 -1
- package/dist/gpu/image-kernel-execution.d.ts +55 -3
- package/dist/gpu/image-kernel-execution.js.map +1 -1
- package/dist/gpu/sensor-stage-gpu.d.ts +11 -0
- package/dist/gpu/sensor-stage-gpu.js +42 -13
- package/dist/gpu/sensor-stage-gpu.js.map +1 -1
- package/dist/gpu/webgpu-runtime.d.ts +4 -2
- package/dist/gpu/webgpu-runtime.js +13 -4
- package/dist/gpu/webgpu-runtime.js.map +1 -1
- package/dist/gpu/webgpu-switch.d.ts +4 -0
- package/dist/gpu/webgpu-switch.js +29 -0
- package/dist/gpu/webgpu-switch.js.map +1 -0
- package/dist/gpu/wgsl-chart-composite-kernel.d.ts +52 -0
- package/dist/gpu/wgsl-chart-composite-kernel.js +515 -0
- package/dist/gpu/wgsl-chart-composite-kernel.js.map +1 -0
- package/dist/gpu/wgsl-chart-kernel.d.ts +11 -9
- package/dist/gpu/wgsl-chart-kernel.js +33 -27
- package/dist/gpu/wgsl-chart-kernel.js.map +1 -1
- package/dist/gpu/wgsl-display-view-quality-kernel.d.ts +95 -0
- package/dist/gpu/wgsl-display-view-quality-kernel.js +769 -0
- package/dist/gpu/wgsl-display-view-quality-kernel.js.map +1 -0
- package/dist/gpu/wgsl-display-view-speed-kernel.d.ts +75 -0
- package/dist/gpu/wgsl-display-view-speed-kernel.js +386 -0
- package/dist/gpu/wgsl-display-view-speed-kernel.js.map +1 -0
- package/dist/gpu/wgsl-sensor-kernel.d.ts +28 -9
- package/dist/gpu/wgsl-sensor-kernel.js +94 -50
- package/dist/gpu/wgsl-sensor-kernel.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/optics/defocus-disc-kernel.d.ts +61 -0
- package/dist/optics/defocus-disc-kernel.js +191 -0
- package/dist/optics/defocus-disc-kernel.js.map +1 -0
- package/docs/API_REFERENCE.md +45 -1
- package/docs/QUICK_START.md +102 -3
- package/docs/USAGE.md +52 -2
- package/docs/api/core-version.md +1 -1
- package/docs/api/exports.json +117 -2
- package/docs/api/facade-chart-material-layers.md +137 -0
- package/docs/api/facade-chart-radiance-batch.md +7 -2
- package/docs/api/facade-display-view-gpu.md +94 -0
- package/docs/api/facade-scene-radiance.md +3 -2
- package/docs/api/facade-simulate-capture.md +23 -6
- package/docs/api/facade-simulate-display-view.md +17 -2
- package/docs/api/gpu-image-kernel-accelerator.md +10 -3
- package/docs/api/gpu-image-kernel-execution.md +71 -4
- package/docs/api/gpu-webgpu-switch.md +23 -0
- package/package.json +3 -1
|
@@ -31,6 +31,11 @@ export interface ExpectedSignalSetupInput {
|
|
|
31
31
|
psf: Psf;
|
|
32
32
|
profileWavelengths: readonly number[];
|
|
33
33
|
} | undefined;
|
|
34
|
+
/** Defocus (#492): the geometric disc on the site lattice, (2R + 1)² row-major weights; absent or null in focus. */
|
|
35
|
+
defocus?: {
|
|
36
|
+
radius: number;
|
|
37
|
+
weights: Float64Array;
|
|
38
|
+
} | null | undefined;
|
|
34
39
|
/** Material scenes: the materials (neutral reflectances, or radiance per wavelength), the material lookup and the white radiance. */
|
|
35
40
|
materials?: {
|
|
36
41
|
list: readonly ({
|
|
@@ -3,9 +3,18 @@
|
|
|
3
3
|
* Internal (#394, not exported from the package): the input of the tabulated expected signal (`createDisplayViewExpectedSignal`)
|
|
4
4
|
* for a resolved `simulateCapture` request, shared by the display view and the capture's tabulated RAW path so both build it
|
|
5
5
|
* the same way: query offsets of each site, the environment's query points, the diffraction kernels and the scene tables.
|
|
6
|
+
*
|
|
7
|
+
* Defocus (#492, `lens.defocus`): the geometric disc D on the site lattice (`createDefocusDiscSiteKernel`) enters as a site
|
|
8
|
+
* kernel, so every query stays on the lattice. Without diffraction every spectral node takes D itself (a wavelength-independent
|
|
9
|
+
* kernel). With diffraction node λ takes K_λ ∗ D, the full 2-D convolution of the diffraction kernel with the disc (radius
|
|
10
|
+
* R_diff + R_defocus): a labelled approximation, since the defocused wave's PSF is not the in-focus Airy pattern convolved
|
|
11
|
+
* with a geometric disc. The convolution is linear, so Σ_t (K_λ ∗ D)(t)·L(p − t) is the diffracted radiance blurred by D, the
|
|
12
|
+
* order the capture's object-space convolutions apply them in. The kernels are built as the capture builds them
|
|
13
|
+
* (`siteDiffractionKernel`, then `convolveSiteKernels`), so the two have the same bits.
|
|
6
14
|
*/
|
|
7
15
|
import { InvalidConfigurationError } from "../core/configuration-error.js";
|
|
8
16
|
import { siteDiffractionKernel } from "../optics/site-diffraction-kernel.js";
|
|
17
|
+
import { convolveSiteKernels } from "../optics/defocus-disc-kernel.js";
|
|
9
18
|
import { resolveProjectionDistanceMm } from "../motion/camera-rotation.js";
|
|
10
19
|
import { hypot3 } from "../core/portable-math.js";
|
|
11
20
|
/** The query offsets of each site and the expected-signal input (see the module comment). */
|
|
@@ -26,6 +35,13 @@ export function buildExpectedSignalInput(input) {
|
|
|
26
35
|
return siteDiffractionKernel(diffraction.psf, wavelengthNm, pitch, radius, input.caller + ": diffraction kernels must sample the site pitch exactly.");
|
|
27
36
|
}) };
|
|
28
37
|
}
|
|
38
|
+
// Defocus (#492): the disc alone at every node (one shared array), or each node's diffraction kernel convolved with it.
|
|
39
|
+
const defocus = input.defocus;
|
|
40
|
+
if (defocus) {
|
|
41
|
+
const diffracted = kernels;
|
|
42
|
+
kernels = diffracted ? { radius: diffracted.radius + defocus.radius, perNode: diffracted.perNode.map((k) => convolveSiteKernels(k, diffracted.radius, defocus.weights, defocus.radius)) } :
|
|
43
|
+
{ radius: defocus.radius, perNode: wavelengths.map(() => defocus.weights) };
|
|
44
|
+
}
|
|
29
45
|
// Chart presets and (2.7) caller material scenes take the material path: each material tabulated once per node.
|
|
30
46
|
const materials = input.materials;
|
|
31
47
|
const scene = materials ? { kind: "materials", materialAt: materials.materialAt,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"expected-signal-setup.js","sourceRoot":"","sources":["../../src/facade/expected-signal-setup.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Internal (#394, not exported from the package): the input of the tabulated expected signal (`createDisplayViewExpectedSignal`)\n * for a resolved `simulateCapture` request, shared by the display view and the capture's tabulated RAW path so both build it\n * the same way: query offsets of each site, the environment's query points, the diffraction kernels and the scene tables.\n */\n\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport type { resolveLensPsfConvolutionKernels } from \"../optics/lens-psf-kernels.js\";\nimport { siteDiffractionKernel } from \"../optics/site-diffraction-kernel.js\";\nimport { resolveProjectionDistanceMm } from \"../motion/camera-rotation.js\";\nimport { hypot3 } from \"../core/portable-math.js\";\nimport type { DisplayViewExpectedSignalInput, DisplayViewScene } from \"./display-view.js\";\n\ntype Psf = Parameters<typeof resolveLensPsfConvolutionKernels>[0][\"psf\"];\n\nexport interface ExpectedSignalSetupInput {\n nativeWidth: number;\n nativeHeight: number;\n /** Frame output width (plane coordinates are 2 / width frame units per site). */\n width: number;\n wavelengths: readonly number[];\n /** Per CFA channel (red, green, blue): expected electrons per unit spectral radiance at each node. */\n perNode: readonly [Float64Array, Float64Array, Float64Array];\n /** Pixel-aperture nodes in sites from the site centre (`apertureNodeOffsets(boxSamples)`) and the box sample count. */\n apertureNodes: readonly { x: number; y: number }[];\n boxSamples: number;\n antiAliasing?: { components: readonly { offsetMicrometers: { x: number; y: number }; normalizedWeight: number }[] } | undefined;\n pitch: number;\n /** Object-space diffraction: the kernel radius, the PSF and its profile wavelengths. */\n diffraction?: { radius: number; psf: Psf; profileWavelengths: readonly number[] } | undefined;\n /** Material scenes: the materials (neutral reflectances, or radiance per wavelength), the material lookup and the white radiance. */\n materials?: { list: readonly ({ neutral: number } | { radiance: (nm: number) => number })[]; materialAt(u: number, v: number): number; whiteRadiance(nm: number): number } | undefined;\n radianceAt(u: number, v: number, nm: number): number;\n imagingArea: { widthMm: number; heightMm: number };\n focalLengthMm: number;\n focusDistanceM: number;\n subjectDistanceM: number;\n metresPerFrameUnit: number;\n /** Prefix of the error messages (\"simulateDisplayView\", \"simulateCapture\"). */\n caller: string;\n}\n\n/** The query offsets of each site and the expected-signal input (see the module comment). */\nexport function buildExpectedSignalInput(input: ExpectedSignalSetupInput): { offsets: { x: number; y: number; weight: number }[]; signalInput: DisplayViewExpectedSignalInput } {\n const { boxSamples, pitch, wavelengths, imagingArea, subjectDistanceM, metresPerFrameUnit } = input;\n // Query offsets of each site: pixel-aperture nodes minus anti-aliasing split offsets (sites, +x right, +y down), as the environment forms them.\n const spots = input.antiAliasing ? input.antiAliasing.components : [{ offsetMicrometers: { x: 0, y: 0 }, normalizedWeight: 1 }];\n const offsets = input.apertureNodes.flatMap((node) => spots.map((c) => ({ x: node.x - c.offsetMicrometers.x / pitch, y: node.y - c.offsetMicrometers.y / pitch,\n weight: c.normalizedWeight / (boxSamples * boxSamples) })));\n // Diffraction: the same per-node site kernels as the object-space convolution (createDiffractedPlanarProvider).\n let kernels: { radius: number; perNode: Float64Array[] } | undefined;\n const diffraction = input.diffraction;\n if (diffraction) {\n const radius = diffraction.radius;\n kernels = { radius, perNode: wavelengths.map((wavelengthNm) => {\n if (!diffraction.profileWavelengths.includes(wavelengthNm)) throw new InvalidConfigurationError(input.caller + \": a spectral node has no diffraction kernel.\");\n return siteDiffractionKernel(diffraction.psf, wavelengthNm, pitch, radius, input.caller + \": diffraction kernels must sample the site pitch exactly.\");\n }) };\n }\n // Chart presets and (2.7) caller material scenes take the material path: each material tabulated once per node.\n const materials = input.materials;\n const scene: DisplayViewScene = materials ? { kind: \"materials\", materialAt: materials.materialAt,\n materials: materials.list.map((m) => (\"neutral\" in m ? { neutral: m.neutral } : { radiance: Float64Array.from(wavelengths, (nm) => m.radiance(nm)) })),\n whiteRadiance: Float64Array.from(wavelengths, (nm) => materials.whiteRadiance(nm)) } :\n { kind: \"radiance\", radianceAt: input.radianceAt };\n const channelIndex = (x: number, y: number): number => ((y & 1) === 0 ? ((x & 1) === 0 ? 0 : 1) : ((x & 1) === 0 ? 1 : 2));\n // Without diffraction the environment's own query arithmetic (native-environment-lean.ts `geometry`, then the rectilinear\n // still-camera ray and the planar provider's plane point), so boundary points resolve as in the capture.\n const projectionDistance = resolveProjectionDistanceMm(input.focalLengthMm, input.focusDistanceM).projectionDistanceMm, siteWidthMm = pitch / 1000;\n const nodePhases = input.apertureNodes.flatMap((_, index) => spots.map((c) => ({ xPhase: (index % boxSamples + 0.5) / boxSamples, yPhase: (Math.floor(index / boxSamples) + 0.5) / boxSamples,\n aaX: c.offsetMicrometers.x / 1000, aaY: c.offsetMicrometers.y / 1000 })));\n const queryPoint = (x: number, y: number, o: number, out: Float64Array): void => {\n const node = nodePhases[o]!;\n const centerX = -imagingArea.widthMm / 2 + (pitch / 2 + x * pitch + 0) / 1000, centerY = -imagingArea.heightMm / 2 + (pitch / 2 + y * pitch + 0) / 1000;\n const sourceX = (centerX - siteWidthMm / 2 + node.xPhase * siteWidthMm) - node.aaX, sourceY = (centerY - siteWidthMm / 2 + node.yPhase * siteWidthMm) - node.aaY;\n const rx = projectionDistance * (sourceX / projectionDistance), ry = projectionDistance * (-sourceY / projectionDistance);\n const length = hypot3(rx, ry, projectionDistance), t = subjectDistanceM / (projectionDistance / length);\n out[0] = rx / length * t / metresPerFrameUnit; out[1] = ry / length * t / metresPerFrameUnit;\n };\n return { offsets, signalInput: { nativeWidth: input.nativeWidth, nativeHeight: input.nativeHeight, outputWidth: input.width, wavelengthsNm: wavelengths,\n electronsPerRadiance: input.perNode, offsets, ...(kernels ? { kernels } : { queryPoint }), scene, channelAt: channelIndex } };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"expected-signal-setup.js","sourceRoot":"","sources":["../../src/facade/expected-signal-setup.ts"],"names":[],"mappings":"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","sourcesContent":["// SPDX-License-Identifier: Apache-2.0\n\n/**\n * Internal (#394, not exported from the package): the input of the tabulated expected signal (`createDisplayViewExpectedSignal`)\n * for a resolved `simulateCapture` request, shared by the display view and the capture's tabulated RAW path so both build it\n * the same way: query offsets of each site, the environment's query points, the diffraction kernels and the scene tables.\n *\n * Defocus (#492, `lens.defocus`): the geometric disc D on the site lattice (`createDefocusDiscSiteKernel`) enters as a site\n * kernel, so every query stays on the lattice. Without diffraction every spectral node takes D itself (a wavelength-independent\n * kernel). With diffraction node λ takes K_λ ∗ D, the full 2-D convolution of the diffraction kernel with the disc (radius\n * R_diff + R_defocus): a labelled approximation, since the defocused wave's PSF is not the in-focus Airy pattern convolved\n * with a geometric disc. The convolution is linear, so Σ_t (K_λ ∗ D)(t)·L(p − t) is the diffracted radiance blurred by D, the\n * order the capture's object-space convolutions apply them in. The kernels are built as the capture builds them\n * (`siteDiffractionKernel`, then `convolveSiteKernels`), so the two have the same bits.\n */\n\nimport { InvalidConfigurationError } from \"../core/configuration-error.js\";\nimport type { resolveLensPsfConvolutionKernels } from \"../optics/lens-psf-kernels.js\";\nimport { siteDiffractionKernel } from \"../optics/site-diffraction-kernel.js\";\nimport { convolveSiteKernels } from \"../optics/defocus-disc-kernel.js\";\nimport { resolveProjectionDistanceMm } from \"../motion/camera-rotation.js\";\nimport { hypot3 } from \"../core/portable-math.js\";\nimport type { DisplayViewExpectedSignalInput, DisplayViewScene } from \"./display-view.js\";\n\ntype Psf = Parameters<typeof resolveLensPsfConvolutionKernels>[0][\"psf\"];\n\nexport interface ExpectedSignalSetupInput {\n nativeWidth: number;\n nativeHeight: number;\n /** Frame output width (plane coordinates are 2 / width frame units per site). */\n width: number;\n wavelengths: readonly number[];\n /** Per CFA channel (red, green, blue): expected electrons per unit spectral radiance at each node. */\n perNode: readonly [Float64Array, Float64Array, Float64Array];\n /** Pixel-aperture nodes in sites from the site centre (`apertureNodeOffsets(boxSamples)`) and the box sample count. */\n apertureNodes: readonly { x: number; y: number }[];\n boxSamples: number;\n antiAliasing?: { components: readonly { offsetMicrometers: { x: number; y: number }; normalizedWeight: number }[] } | undefined;\n pitch: number;\n /** Object-space diffraction: the kernel radius, the PSF and its profile wavelengths. */\n diffraction?: { radius: number; psf: Psf; profileWavelengths: readonly number[] } | undefined;\n /** Defocus (#492): the geometric disc on the site lattice, (2R + 1)² row-major weights; absent or null in focus. */\n defocus?: { radius: number; weights: Float64Array } | null | undefined;\n /** Material scenes: the materials (neutral reflectances, or radiance per wavelength), the material lookup and the white radiance. */\n materials?: { list: readonly ({ neutral: number } | { radiance: (nm: number) => number })[]; materialAt(u: number, v: number): number; whiteRadiance(nm: number): number } | undefined;\n radianceAt(u: number, v: number, nm: number): number;\n imagingArea: { widthMm: number; heightMm: number };\n focalLengthMm: number;\n focusDistanceM: number;\n subjectDistanceM: number;\n metresPerFrameUnit: number;\n /** Prefix of the error messages (\"simulateDisplayView\", \"simulateCapture\"). */\n caller: string;\n}\n\n/** The query offsets of each site and the expected-signal input (see the module comment). */\nexport function buildExpectedSignalInput(input: ExpectedSignalSetupInput): { offsets: { x: number; y: number; weight: number }[]; signalInput: DisplayViewExpectedSignalInput } {\n const { boxSamples, pitch, wavelengths, imagingArea, subjectDistanceM, metresPerFrameUnit } = input;\n // Query offsets of each site: pixel-aperture nodes minus anti-aliasing split offsets (sites, +x right, +y down), as the environment forms them.\n const spots = input.antiAliasing ? input.antiAliasing.components : [{ offsetMicrometers: { x: 0, y: 0 }, normalizedWeight: 1 }];\n const offsets = input.apertureNodes.flatMap((node) => spots.map((c) => ({ x: node.x - c.offsetMicrometers.x / pitch, y: node.y - c.offsetMicrometers.y / pitch,\n weight: c.normalizedWeight / (boxSamples * boxSamples) })));\n // Diffraction: the same per-node site kernels as the object-space convolution (createDiffractedPlanarProvider).\n let kernels: { radius: number; perNode: Float64Array[] } | undefined;\n const diffraction = input.diffraction;\n if (diffraction) {\n const radius = diffraction.radius;\n kernels = { radius, perNode: wavelengths.map((wavelengthNm) => {\n if (!diffraction.profileWavelengths.includes(wavelengthNm)) throw new InvalidConfigurationError(input.caller + \": a spectral node has no diffraction kernel.\");\n return siteDiffractionKernel(diffraction.psf, wavelengthNm, pitch, radius, input.caller + \": diffraction kernels must sample the site pitch exactly.\");\n }) };\n }\n // Defocus (#492): the disc alone at every node (one shared array), or each node's diffraction kernel convolved with it.\n const defocus = input.defocus;\n if (defocus) {\n const diffracted = kernels;\n kernels = diffracted ? { radius: diffracted.radius + defocus.radius, perNode: diffracted.perNode.map((k) => convolveSiteKernels(k, diffracted.radius, defocus.weights, defocus.radius)) } :\n { radius: defocus.radius, perNode: wavelengths.map(() => defocus.weights) };\n }\n // Chart presets and (2.7) caller material scenes take the material path: each material tabulated once per node.\n const materials = input.materials;\n const scene: DisplayViewScene = materials ? { kind: \"materials\", materialAt: materials.materialAt,\n materials: materials.list.map((m) => (\"neutral\" in m ? { neutral: m.neutral } : { radiance: Float64Array.from(wavelengths, (nm) => m.radiance(nm)) })),\n whiteRadiance: Float64Array.from(wavelengths, (nm) => materials.whiteRadiance(nm)) } :\n { kind: \"radiance\", radianceAt: input.radianceAt };\n const channelIndex = (x: number, y: number): number => ((y & 1) === 0 ? ((x & 1) === 0 ? 0 : 1) : ((x & 1) === 0 ? 1 : 2));\n // Without diffraction the environment's own query arithmetic (native-environment-lean.ts `geometry`, then the rectilinear\n // still-camera ray and the planar provider's plane point), so boundary points resolve as in the capture.\n const projectionDistance = resolveProjectionDistanceMm(input.focalLengthMm, input.focusDistanceM).projectionDistanceMm, siteWidthMm = pitch / 1000;\n const nodePhases = input.apertureNodes.flatMap((_, index) => spots.map((c) => ({ xPhase: (index % boxSamples + 0.5) / boxSamples, yPhase: (Math.floor(index / boxSamples) + 0.5) / boxSamples,\n aaX: c.offsetMicrometers.x / 1000, aaY: c.offsetMicrometers.y / 1000 })));\n const queryPoint = (x: number, y: number, o: number, out: Float64Array): void => {\n const node = nodePhases[o]!;\n const centerX = -imagingArea.widthMm / 2 + (pitch / 2 + x * pitch + 0) / 1000, centerY = -imagingArea.heightMm / 2 + (pitch / 2 + y * pitch + 0) / 1000;\n const sourceX = (centerX - siteWidthMm / 2 + node.xPhase * siteWidthMm) - node.aaX, sourceY = (centerY - siteWidthMm / 2 + node.yPhase * siteWidthMm) - node.aaY;\n const rx = projectionDistance * (sourceX / projectionDistance), ry = projectionDistance * (-sourceY / projectionDistance);\n const length = hypot3(rx, ry, projectionDistance), t = subjectDistanceM / (projectionDistance / length);\n out[0] = rx / length * t / metresPerFrameUnit; out[1] = ry / length * t / metresPerFrameUnit;\n };\n return { offsets, signalInput: { nativeWidth: input.nativeWidth, nativeHeight: input.nativeHeight, outputWidth: input.width, wavelengthsNm: wavelengths,\n electronsPerRadiance: input.perNode, offsets, ...(kernels ? { kernels } : { queryPoint }), scene, channelAt: channelIndex } };\n}\n\n"]}
|
|
@@ -29,7 +29,11 @@ export interface DisplayViewExpectedSignalInput {
|
|
|
29
29
|
wavelengthsNm: readonly number[];
|
|
30
30
|
electronsPerRadiance: readonly [Float64Array, Float64Array, Float64Array];
|
|
31
31
|
offsets: readonly DisplayViewQueryOffset[];
|
|
32
|
-
/**
|
|
32
|
+
/**
|
|
33
|
+
* Diffraction and (#492) defocus: per-node kernels on the site lattice, (2R + 1)² taps in row-major order,
|
|
34
|
+
* out(x) = Σ in(x − t)·K(t). With defocus each node's kernel is its diffraction kernel convolved with the disc, or the
|
|
35
|
+
* disc itself without diffraction (expected-signal-setup.ts).
|
|
36
|
+
*/
|
|
33
37
|
kernels?: {
|
|
34
38
|
radius: number;
|
|
35
39
|
perNode: readonly Float64Array[];
|
|
@@ -38,9 +42,10 @@ export interface DisplayViewExpectedSignalInput {
|
|
|
38
42
|
/** CFA channel index (0 red, 1 green, 2 blue) of native site (x, y). */
|
|
39
43
|
channelAt(x: number, y: number): number;
|
|
40
44
|
/**
|
|
41
|
-
* Without
|
|
45
|
+
* Without kernels: the plane point (frame units) that the environment queries for offset `o` of native site (x, y),
|
|
42
46
|
* computed with the environment's own arithmetic, so points that fall exactly on a chart boundary resolve to the same
|
|
43
|
-
* material as in the capture. With diffraction the facade's object-space convolution uses the
|
|
47
|
+
* material as in the capture. With kernels (diffraction or defocus) the facade's object-space convolution uses the
|
|
48
|
+
* lattice formula, as here.
|
|
44
49
|
*/
|
|
45
50
|
queryPoint?(x: number, y: number, offset: number, out: Float64Array): void;
|
|
46
51
|
}
|
|
@@ -89,6 +94,40 @@ export interface DisplayViewExpectedSignal {
|
|
|
89
94
|
*/
|
|
90
95
|
markReads(xs: Int32Array, ys: Int32Array, values: Float64Array, materials: Int32Array, count: number): void;
|
|
91
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* The tables of `createDisplayViewExpectedSignal` (see there) that are a function of the input's numbers alone: the materials,
|
|
99
|
+
* the lattice groups' geometry and combined kernels, and the per-material sums. Written only while they are built, never after:
|
|
100
|
+
* they are shared by every render of an input and, for chart materials, by every input of the same content (#449). Everything a
|
|
101
|
+
* render changes (each group's window cache and its origin and size, the bands, rings and counts) lives in the render.
|
|
102
|
+
*/
|
|
103
|
+
export interface SignalTables {
|
|
104
|
+
readonly reflectance: Float64Array;
|
|
105
|
+
readonly spectralIndex: Int32Array;
|
|
106
|
+
readonly spectral: readonly Float64Array[];
|
|
107
|
+
readonly groups: readonly GroupTables[];
|
|
108
|
+
readonly neutralDirect: readonly number[];
|
|
109
|
+
readonly spectralDirect: readonly (readonly number[])[];
|
|
110
|
+
readonly uniformSite: readonly Float64Array[];
|
|
111
|
+
}
|
|
112
|
+
/** A lattice group's fixed part: its fractional shift, members, index bounds, rectangle and combined kernels. */
|
|
113
|
+
export interface GroupTables {
|
|
114
|
+
fx: number;
|
|
115
|
+
fy: number;
|
|
116
|
+
members: {
|
|
117
|
+
ix: number;
|
|
118
|
+
iy: number;
|
|
119
|
+
weight: number;
|
|
120
|
+
}[];
|
|
121
|
+
minIx: number;
|
|
122
|
+
maxIx: number;
|
|
123
|
+
minIy: number;
|
|
124
|
+
maxIy: number;
|
|
125
|
+
cw: number;
|
|
126
|
+
ch: number;
|
|
127
|
+
neutral: Float64Array[];
|
|
128
|
+
spectral: Float64Array[][];
|
|
129
|
+
perNode: Float64Array[][];
|
|
130
|
+
}
|
|
92
131
|
/** Chart-material tables kept by content across input objects (#449), least recently used first. */
|
|
93
132
|
export declare const EXPECTED_SIGNAL_TABLE_CACHE_SIZE = 4;
|
|
94
133
|
/** Internal test hook: the kept table entries, and the tables built and found by content so far. */
|
|
@@ -99,6 +138,12 @@ export declare function expectedSignalTableCacheState(): {
|
|
|
99
138
|
};
|
|
100
139
|
/** Internal test hook: forgets the tables kept by content (inputs already prepared keep theirs). */
|
|
101
140
|
export declare function clearExpectedSignalTableCache(): void;
|
|
141
|
+
/**
|
|
142
|
+
* Internal (#479): the read-only tables of an input (the ones `createDisplayViewExpectedSignal` reads), for the GPU display view,
|
|
143
|
+
* which uploads the combined kernels and per-material sums the reference forms in float64. Prepared and cached as a render
|
|
144
|
+
* prepares them, so a GPU render of an input and a CPU render read the same doubles.
|
|
145
|
+
*/
|
|
146
|
+
export declare function displayViewSignalTables(input: DisplayViewExpectedSignalInput): SignalTables;
|
|
102
147
|
/**
|
|
103
148
|
* Expected photo electrons per site: μ_c(i, j) = Σ_o w_o Σ_λ A_c(λ) Σ_t K_λ(t)·L(p_o(i, j) − t, λ), where p_o is the
|
|
104
149
|
* query point of offset o and K the diffraction kernel (a single unit tap without diffraction). This is the sum the
|
|
@@ -94,6 +94,14 @@ function prepareSignal(input) {
|
|
|
94
94
|
PREPARED.set(input, prepared);
|
|
95
95
|
return prepared;
|
|
96
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* Internal (#479): the read-only tables of an input (the ones `createDisplayViewExpectedSignal` reads), for the GPU display view,
|
|
99
|
+
* which uploads the combined kernels and per-material sums the reference forms in float64. Prepared and cached as a render
|
|
100
|
+
* prepares them, so a GPU render of an input and a CPU render read the same doubles.
|
|
101
|
+
*/
|
|
102
|
+
export function displayViewSignalTables(input) {
|
|
103
|
+
return (PREPARED.get(input) ?? prepareSignal(input)).tables;
|
|
104
|
+
}
|
|
97
105
|
function buildTables(input) {
|
|
98
106
|
const nodes = input.wavelengthsNm.length, R = input.kernels ? input.kernels.radius : 0, size = 2 * R + 1;
|
|
99
107
|
const A = input.electronsPerRadiance, scene = input.scene, offsets = input.offsets;
|