@photivra/engine 2.9.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 +223 -1
- package/CITATION.cff +1 -1
- package/NODE_SUPPORT.md +21 -3
- package/README.md +6 -6
- package/SECURITY.md +1 -1
- package/THIRD_PARTY.md +2 -0
- package/dist/capture/native-environment-lean.js +89 -5
- package/dist/capture/native-environment-lean.js.map +1 -1
- package/dist/capture/native-environment-tabulated.d.ts +37 -0
- package/dist/capture/native-environment-tabulated.js +42 -6
- package/dist/capture/native-environment-tabulated.js.map +1 -1
- package/dist/core/portable-math.d.ts +19 -0
- package/dist/core/portable-math.js +82 -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/channel-response.d.ts +15 -0
- package/dist/facade/channel-response.js +33 -0
- package/dist/facade/channel-response.js.map +1 -0
- 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 +120 -16
- 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 +123 -1
- package/dist/facade/display-view.js +478 -116
- 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 +18 -1
- package/dist/facade/expected-signal-setup.js.map +1 -1
- package/dist/facade/expected-signal.d.ts +80 -6
- package/dist/facade/expected-signal.js +200 -24
- 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 +81 -7
- package/dist/facade/simulate-capture.js +276 -53
- package/dist/facade/simulate-capture.js.map +1 -1
- package/dist/facade/simulate-display-view.d.ts +54 -3
- package/dist/facade/simulate-display-view.js +120 -27
- 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 +60 -3
- package/dist/gpu/image-kernel-execution.js +2 -2
- 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 +6 -3
- package/dist/index.js +4 -2
- 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/dist/optics/irradiance-convolution.d.ts +11 -0
- package/dist/optics/irradiance-convolution.js +64 -24
- package/dist/optics/irradiance-convolution.js.map +1 -1
- package/dist/optics/scene-to-sensor-irradiance.d.ts +13 -0
- package/dist/optics/scene-to-sensor-irradiance.js +58 -24
- package/dist/optics/scene-to-sensor-irradiance.js.map +1 -1
- package/dist/optics/sensor-aperture-rays.js +2 -1
- package/dist/optics/sensor-aperture-rays.js.map +1 -1
- package/dist/optics/sensor-environment-query.js +4 -3
- package/dist/optics/sensor-environment-query.js.map +1 -1
- package/dist/optics/site-diffraction-kernel.d.ts +16 -0
- package/dist/optics/site-diffraction-kernel.js +60 -8
- package/dist/optics/site-diffraction-kernel.js.map +1 -1
- package/dist/processing/demosaic.js +114 -37
- package/dist/processing/demosaic.js.map +1 -1
- package/dist/schema/scene-radiance.d.ts +8 -0
- package/dist/schema/scene-radiance.js +28 -17
- package/dist/schema/scene-radiance.js.map +1 -1
- package/dist/sensor/environment-photo-signal.d.ts +21 -0
- package/dist/sensor/environment-photo-signal.js +68 -2
- package/dist/sensor/environment-photo-signal.js.map +1 -1
- package/docs/API_REFERENCE.md +60 -1
- package/docs/QUICK_START.md +120 -11
- package/docs/USAGE.md +82 -2
- package/docs/api/core-version.md +1 -1
- package/docs/api/exports.json +157 -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-display-view.md +50 -0
- package/docs/api/facade-scene-radiance.md +3 -2
- package/docs/api/facade-simulate-capture.md +81 -12
- package/docs/api/facade-simulate-display-view.md +39 -2
- package/docs/api/gpu-image-kernel-accelerator.md +10 -3
- package/docs/api/gpu-image-kernel-execution.md +76 -4
- package/docs/api/gpu-webgpu-switch.md +23 -0
- package/package.json +3 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// SPDX-License-Identifier: Apache-2.0
|
|
2
2
|
import { InvalidConfigurationError } from "../core/configuration-error.js";
|
|
3
|
+
import { hypot3 } from "../core/portable-math.js";
|
|
3
4
|
import { apertureRadianceQuery } from "../sensor/environment-photo-signal.js";
|
|
4
5
|
import { createSensorEqeTemporalPhotoSignal } from "../sensor/temporal-photo-signal.js";
|
|
5
6
|
import { isDeeplyFrozen } from "../core/internal-radiance-evaluator.js";
|
|
@@ -273,7 +274,7 @@ function geometry(t, k, frame, environment, index, access) {
|
|
|
273
274
|
if (!Number.isFinite(reference.z) || reference.z <= 0)
|
|
274
275
|
return undefined;
|
|
275
276
|
const rx = pd * (reference.x / reference.z), ry = pd * (reference.y / reference.z);
|
|
276
|
-
const length =
|
|
277
|
+
const length = hypot3(rx, ry, pd);
|
|
277
278
|
const ray = { x: rx / length, y: ry / length, z: pd / length };
|
|
278
279
|
// Build the parseSceneRadianceEvaluationRequest output directly. Every other field is a template constant already
|
|
279
280
|
// parsed for the template site. The sample ID is a public opaque ID (trimming cannot change it) and the time is
|
|
@@ -281,7 +282,7 @@ function geometry(t, k, frame, environment, index, access) {
|
|
|
281
282
|
const direction = { x: -ray.x, y: -ray.y, z: -ray.z };
|
|
282
283
|
if (!Number.isFinite(direction.x) || !Number.isFinite(direction.y) || !Number.isFinite(direction.z))
|
|
283
284
|
return undefined;
|
|
284
|
-
const norm =
|
|
285
|
+
const norm = hypot3(direction.x, direction.y, direction.z);
|
|
285
286
|
if (!Number.isFinite(norm) || Math.abs(norm - 1) > 1e-9)
|
|
286
287
|
return undefined;
|
|
287
288
|
// #394: the key the evaluator would read for this request (undefined where it would throw: the full path decides).
|
|
@@ -1011,6 +1012,84 @@ function leanSensorSite(t, h, index, seed) {
|
|
|
1011
1012
|
flags: Number(physicalSaturation) | Number(preAdcSaturation) << 1 | Number(quantized >= digitalSaturationCode) << 2,
|
|
1012
1013
|
whiteCode: t.whiteCode, photoRealized, darkRealized };
|
|
1013
1014
|
}
|
|
1015
|
+
function flatSensorStage(t) {
|
|
1016
|
+
const regime = t.readout.regime;
|
|
1017
|
+
return { darkRate: t.darkRate, capacity: t.capacity, pattern: t.pattern, whiteCode: t.whiteCode, regime, adcMaximumCode: t.readout.adcMaximumCode,
|
|
1018
|
+
inlDefined: regime.adc.integralNonLinearity !== undefined, gain: regime.systemConversionGainElectronsPerCode.value, black: regime.adc.blackLevelCode,
|
|
1019
|
+
digitalGain: regime.adc.digitalGain, digitalSaturationCode: regime.adc.digitalSaturationCode, threshold: regime.preAdcSaturationElectronEquivalent.value,
|
|
1020
|
+
rms: Float64Array.from(regime.readNoiseComponents, (component) => component.rmsElectrons.value), darkMean: NaN, darkThreshold: NaN,
|
|
1021
|
+
out: { rawCode: 0, blackLevelCode: 0, digitalSaturationCode: 0, flags: 0, whiteCode: 0 } };
|
|
1022
|
+
}
|
|
1023
|
+
/** Writes the site's outputs into `f.out`; false where leanSensorSite returns undefined. */
|
|
1024
|
+
function flatSensorSite(f, photoE, darkE, total, x, y, index, seed) {
|
|
1025
|
+
const ratio = total / f.capacity, headroom = f.capacity - total;
|
|
1026
|
+
if (!Number.isFinite(ratio) || !Number.isFinite(headroom))
|
|
1027
|
+
return false;
|
|
1028
|
+
const pattern = f.pattern === undefined ? null : evaluateParsedFixedPatternSite(f.pattern, { x, y });
|
|
1029
|
+
const photoMean = pattern === null ? photoE : photoE * pattern.photoResponseGainFactor;
|
|
1030
|
+
const darkMean = pattern === null ? darkE : darkE * pattern.darkCurrentFactor;
|
|
1031
|
+
if (!Number.isFinite(photoMean) || photoMean < 0 || !Number.isFinite(darkMean) || darkMean < 0)
|
|
1032
|
+
return false;
|
|
1033
|
+
const random = chargeStream;
|
|
1034
|
+
random.reset(deriveNativeSiteStreamSeedUint32(seed, index, NATIVE_SITE_CHARGE_STREAM_ID));
|
|
1035
|
+
const photoRealized = samplePoisson(photoMean, random);
|
|
1036
|
+
let darkRealized;
|
|
1037
|
+
if (darkMean > 0 && darkMean < 30) {
|
|
1038
|
+
// samplePoisson's branch for 0 < mean < 30 (Knuth's product of uniforms) with its threshold Math.exp(−mean) kept while the
|
|
1039
|
+
// mean repeats: the same draws from the same stream. (createPoissonSampler would also do this, but it brings the
|
|
1040
|
+
// portable-math functions into capture-only bundles.)
|
|
1041
|
+
if (darkMean !== f.darkMean) {
|
|
1042
|
+
f.darkMean = darkMean;
|
|
1043
|
+
f.darkThreshold = Math.exp(-darkMean);
|
|
1044
|
+
}
|
|
1045
|
+
const threshold = f.darkThreshold;
|
|
1046
|
+
let product = 1, count = 0;
|
|
1047
|
+
do {
|
|
1048
|
+
count += 1;
|
|
1049
|
+
product *= random.next();
|
|
1050
|
+
} while (product > threshold);
|
|
1051
|
+
darkRealized = count - 1;
|
|
1052
|
+
}
|
|
1053
|
+
else
|
|
1054
|
+
darkRealized = samplePoisson(darkMean, random);
|
|
1055
|
+
const realized = photoRealized + darkRealized + 0;
|
|
1056
|
+
if (!Number.isFinite(realized) || realized < 0)
|
|
1057
|
+
return false;
|
|
1058
|
+
const readRandom = readNoiseStream;
|
|
1059
|
+
readRandom.reset(deriveNativeSiteStreamSeedUint32(seed, index, NATIVE_SITE_READ_NOISE_STREAM_ID));
|
|
1060
|
+
const capacity = f.capacity;
|
|
1061
|
+
const afterPhysical = Math.min(realized, capacity), physicalSaturation = afterPhysical < realized;
|
|
1062
|
+
const rmsAll = f.rms;
|
|
1063
|
+
let totalReadNoise = 0;
|
|
1064
|
+
for (let k = 0; k < rmsAll.length; k++) {
|
|
1065
|
+
const rms = rmsAll[k];
|
|
1066
|
+
totalReadNoise = totalReadNoise + (rms === 0 ? 0 : sampleDeterministicStandardNormal(readRandom) * rms);
|
|
1067
|
+
}
|
|
1068
|
+
const afterReadNoise = afterPhysical + totalReadNoise + (pattern === null ? 0 : pattern.readoutOffsetElectrons);
|
|
1069
|
+
const threshold = f.threshold;
|
|
1070
|
+
const afterPreAdc = Math.min(afterReadNoise, threshold), preAdcSaturation = afterReadNoise > threshold;
|
|
1071
|
+
let quantized;
|
|
1072
|
+
if (f.inlDefined)
|
|
1073
|
+
quantized = adcTransfer(f.regime, f.adcMaximumCode, afterPreAdc).quantized;
|
|
1074
|
+
else {
|
|
1075
|
+
// adcTransfer without integral non-linearity: ideal = e/G + black, plus the zero INL offset, rounded half up (Math.round + 0),
|
|
1076
|
+
// then with a digital gain the ADC clamp and the gain's own rounding about the black level.
|
|
1077
|
+
const ideal = afterPreAdc / f.gain + f.black, quantizedAdc = Math.round(ideal + 0) + 0, digitalGain = f.digitalGain;
|
|
1078
|
+
if (digitalGain === undefined)
|
|
1079
|
+
quantized = quantizedAdc;
|
|
1080
|
+
else {
|
|
1081
|
+
const adcCode = Math.max(0, Math.min(quantizedAdc, f.adcMaximumCode));
|
|
1082
|
+
quantized = Math.round((adcCode - f.black) * digitalGain + f.black) + 0;
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
const digitalSaturationCode = f.digitalSaturationCode, out = f.out;
|
|
1086
|
+
out.rawCode = Math.max(0, Math.min(quantized, digitalSaturationCode));
|
|
1087
|
+
out.blackLevelCode = f.black;
|
|
1088
|
+
out.digitalSaturationCode = digitalSaturationCode;
|
|
1089
|
+
out.flags = Number(physicalSaturation) | Number(preAdcSaturation) << 1 | Number(quantized >= digitalSaturationCode) << 2;
|
|
1090
|
+
out.whiteCode = f.whiteCode;
|
|
1091
|
+
return true;
|
|
1092
|
+
}
|
|
1014
1093
|
/** The Kahan (compensated) total that composeSensorAccumulatedCharge computes, for photo and dark charge only. */
|
|
1015
1094
|
function chargeTotal(photoE, darkE) {
|
|
1016
1095
|
let sum = 0, correction = 0;
|
|
@@ -1039,17 +1118,22 @@ export function createVerifiedNativeSiteReadout(parsed, result, whiteCode, photo
|
|
|
1039
1118
|
realization.additionalComponents.length !== 0 || out.rawCode !== r.rawCode || out.blackLevelCode !== r.blackLevelCode || out.digitalSaturationCode !== r.digitalSaturationCode ||
|
|
1040
1119
|
out.flags !== (Number(r.physicalScalarSaturationApplied) | Number(r.preAdcSaturationApplied) << 1 | Number(r.digitalSaturationApplied) << 2))
|
|
1041
1120
|
return undefined;
|
|
1121
|
+
// #449: the flat stage must reproduce the verification site too.
|
|
1122
|
+
const flat = flatSensorStage(t), fo = flat.out;
|
|
1123
|
+
if (!flatSensorSite(flat, photo.expectedGeneratedElectronCount, darkE, total, x, y, index, seed) || fo.rawCode !== out.rawCode || fo.blackLevelCode !== out.blackLevelCode ||
|
|
1124
|
+
fo.digitalSaturationCode !== out.digitalSaturationCode || fo.flags !== out.flags || fo.whiteCode !== out.whiteCode)
|
|
1125
|
+
return undefined;
|
|
1042
1126
|
return {
|
|
1043
1127
|
compute(photoE, duration, sx, sy, siteIndex, siteSeed) {
|
|
1044
1128
|
// The parse-phase predicates of the full path (claim()): finite non-negative dark and total charge.
|
|
1045
|
-
const siteDark =
|
|
1129
|
+
const siteDark = flat.darkRate * duration;
|
|
1046
1130
|
if (!Number.isFinite(photoE) || photoE < 0 || !Number.isFinite(siteDark) || siteDark < 0)
|
|
1047
1131
|
return undefined;
|
|
1048
1132
|
const siteTotal = chargeTotal(photoE, siteDark);
|
|
1049
1133
|
if (!Number.isFinite(siteTotal) || siteTotal < 0)
|
|
1050
1134
|
return undefined;
|
|
1051
|
-
//
|
|
1052
|
-
return
|
|
1135
|
+
// One record for every site (#449): the caller copies the five RAW fields before its next call.
|
|
1136
|
+
return flatSensorSite(flat, photoE, siteDark, siteTotal, sx, sy, siteIndex, siteSeed) ? fo : undefined;
|
|
1053
1137
|
}
|
|
1054
1138
|
};
|
|
1055
1139
|
}
|