@bubo-squared/gyroview 0.1.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 +32 -0
- package/LICENSE +21 -0
- package/README.md +216 -0
- package/dist/define.d.ts +3 -0
- package/dist/define.js +4 -0
- package/dist/index.d.ts +959 -0
- package/dist/index.js +13 -0
- package/dist/packages/adapters/blob/src/BlobRandomAccessSource.js +37 -0
- package/dist/packages/adapters/blob/src/index.js +2 -0
- package/dist/packages/adapters/fetch/src/HttpRangeSource.js +194 -0
- package/dist/packages/adapters/fetch/src/HttpResourceLocator.js +35 -0
- package/dist/packages/adapters/fetch/src/httpRequest.js +126 -0
- package/dist/packages/adapters/fetch/src/index.js +3 -0
- package/dist/packages/adapters/mediabunny/src/MediabunnyAudioSegments.js +133 -0
- package/dist/packages/adapters/mediabunny/src/MediabunnyDemuxer.js +63 -0
- package/dist/packages/adapters/mediabunny/src/MediabunnyVideoTrackReader.js +84 -0
- package/dist/packages/adapters/mediabunny/src/SegmentChannel.js +84 -0
- package/dist/packages/adapters/mediabunny/src/bufferSources.js +12 -0
- package/dist/packages/adapters/mediabunny/src/index.js +2 -0
- package/dist/packages/adapters/mse-audio/src/MediaSourceAudioClock.js +139 -0
- package/dist/packages/adapters/mse-audio/src/SourceBufferFeeder.js +174 -0
- package/dist/packages/adapters/mse-audio/src/events.js +26 -0
- package/dist/packages/adapters/mse-audio/src/index.js +2 -0
- package/dist/packages/adapters/mse-audio/src/mediaSourceSupport.js +82 -0
- package/dist/packages/adapters/three/src/ThreeFrameRenderer.js +274 -0
- package/dist/packages/adapters/three/src/compileAndProve.js +14 -0
- package/dist/packages/adapters/three/src/fullscreenPass.js +52 -0
- package/dist/packages/adapters/three/src/index.js +2 -0
- package/dist/packages/adapters/three/src/lensTextures.js +25 -0
- package/dist/packages/adapters/three/src/pictureMaterials.js +44 -0
- package/dist/packages/adapters/three/src/renderInto.js +15 -0
- package/dist/packages/adapters/three/src/rendererUniforms.js +157 -0
- package/dist/packages/adapters/three/src/samplingStrategies.js +26 -0
- package/dist/packages/adapters/three/src/seamMeter/SeamMeterPass.js +79 -0
- package/dist/packages/adapters/three/src/seamMeter/rowMeans.js +38 -0
- package/dist/packages/adapters/three/src/shaderPrograms.js +66 -0
- package/dist/packages/adapters/three/src/shaders/analysis.frag.js +4 -0
- package/dist/packages/adapters/three/src/shaders/equirectangularRays.js +4 -0
- package/dist/packages/adapters/three/src/shaders/fixedJoin.js +4 -0
- package/dist/packages/adapters/three/src/shaders/fullscreen.vert.js +4 -0
- package/dist/packages/adapters/three/src/shaders/header.js +4 -0
- package/dist/packages/adapters/three/src/shaders/lensModels.js +4 -0
- package/dist/packages/adapters/three/src/shaders/lensSampling.js +4 -0
- package/dist/packages/adapters/three/src/shaders/lensTextures.js +4 -0
- package/dist/packages/adapters/three/src/shaders/rawLenses.frag.js +4 -0
- package/dist/packages/adapters/three/src/shaders/rectilinearRays.js +4 -0
- package/dist/packages/adapters/three/src/shaders/screenAreas.js +4 -0
- package/dist/packages/adapters/three/src/shaders/stitch.frag.js +4 -0
- package/dist/packages/adapters/three/src/webglRenderer.js +37 -0
- package/dist/packages/adapters/webcodecs/src/WebCodecsVideoDecoderPort.js +135 -0
- package/dist/packages/adapters/webcodecs/src/index.js +2 -0
- package/dist/packages/core/src/application/gainMatching/GainMatching.js +66 -0
- package/dist/packages/core/src/application/gainMatching/GainMatchingFrameSink.js +62 -0
- package/dist/packages/core/src/application/playback/ClockWatch.js +76 -0
- package/dist/packages/core/src/application/playback/DecodePipeline.js +188 -0
- package/dist/packages/core/src/application/playback/DecodeRun.js +93 -0
- package/dist/packages/core/src/application/playback/FramePairQueue.js +93 -0
- package/dist/packages/core/src/application/playback/FramePairer.js +60 -0
- package/dist/packages/core/src/application/playback/PlaybackSession.js +417 -0
- package/dist/packages/core/src/application/playback/SeekOrder.js +36 -0
- package/dist/packages/core/src/application/playback/SessionLifecycle.js +42 -0
- package/dist/packages/core/src/application/playback/StartGate.js +55 -0
- package/dist/packages/core/src/application/playback/TimeUpdates.js +31 -0
- package/dist/packages/core/src/application/playback/WallClock.js +46 -0
- package/dist/packages/core/src/application/playback/keyframeTimeAt.js +15 -0
- package/dist/packages/core/src/application/playback/probeDecoding.js +168 -0
- package/dist/packages/core/src/application/recording/frameTimesOf.js +22 -0
- package/dist/packages/core/src/application/recording/inspectLayout.js +21 -0
- package/dist/packages/core/src/application/recording/inspectRecording.js +124 -0
- package/dist/packages/core/src/application/recording/locateOtherLensFile.js +18 -0
- package/dist/packages/core/src/application/recording/motionOf.js +39 -0
- package/dist/packages/core/src/application/recording/readRecording.js +31 -0
- package/dist/packages/core/src/application/recording/timeRecording.js +57 -0
- package/dist/packages/core/src/application/stabilization/StabilizingFrameSink.js +31 -0
- package/dist/packages/core/src/domain/format/boxes/BoxLayout.js +7 -0
- package/dist/packages/core/src/domain/format/boxes/boxConstants.js +16 -0
- package/dist/packages/core/src/domain/format/boxes/scanBoxes.js +59 -0
- package/dist/packages/core/src/domain/format/calibration/CalibrationVersion.js +13 -0
- package/dist/packages/core/src/domain/format/calibration/layouts/CalibrationStringLayout.js +34 -0
- package/dist/packages/core/src/domain/format/calibration/layouts/LegacyCalibrationLayout.js +44 -0
- package/dist/packages/core/src/domain/format/calibration/layouts/MeiCalibrationLayout.js +45 -0
- package/dist/packages/core/src/domain/format/calibration/layouts/PolynomialCalibrationLayout.js +44 -0
- package/dist/packages/core/src/domain/format/calibration/offsetTokens.js +65 -0
- package/dist/packages/core/src/domain/format/calibration/parseOffsetString.js +52 -0
- package/dist/packages/core/src/domain/format/calibration/selectCalibration.js +46 -0
- package/dist/packages/core/src/domain/format/captureOrigin.js +20 -0
- package/dist/packages/core/src/domain/format/constants.js +33 -0
- package/dist/packages/core/src/domain/format/info/infoFields.js +110 -0
- package/dist/packages/core/src/domain/format/info/parseInfoRecord.js +90 -0
- package/dist/packages/core/src/domain/format/info/readInfoRecord.js +14 -0
- package/dist/packages/core/src/domain/format/layout/detectLensLayout.js +122 -0
- package/dist/packages/core/src/domain/format/naming/RecordingFileName.js +67 -0
- package/dist/packages/core/src/domain/format/records/TrailerRecords.js +83 -0
- package/dist/packages/core/src/domain/format/records/exposure/parseExposureRecord.js +48 -0
- package/dist/packages/core/src/domain/format/records/gyro/FloatGyroSampleLayout.js +39 -0
- package/dist/packages/core/src/domain/format/records/gyro/RawGyroSampleLayout.js +55 -0
- package/dist/packages/core/src/domain/format/records/gyro/SampleColumns.js +82 -0
- package/dist/packages/core/src/domain/format/records/gyro/gyroLayouts.js +12 -0
- package/dist/packages/core/src/domain/format/records/gyro/parseGyroRecord.js +129 -0
- package/dist/packages/core/src/domain/format/trailer/RecordHeader.js +23 -0
- package/dist/packages/core/src/domain/format/trailer/Trailer.js +23 -0
- package/dist/packages/core/src/domain/format/trailer/TrailerFooter.js +27 -0
- package/dist/packages/core/src/domain/format/trailer/locateRecords.js +80 -0
- package/dist/packages/core/src/domain/format/trailer/parseRecordIndex.js +28 -0
- package/dist/packages/core/src/domain/format/trailer/readTrailer.js +32 -0
- package/dist/packages/core/src/domain/motion/exposure/ExposureRecord.js +53 -0
- package/dist/packages/core/src/domain/motion/gyro/GyroTrack.js +60 -0
- package/dist/packages/core/src/domain/motion/gyro/medianStep.js +11 -0
- package/dist/packages/core/src/domain/motion/gyro/repairedTimeline.js +101 -0
- package/dist/packages/core/src/domain/motion/imu/ImuFrame.js +112 -0
- package/dist/packages/core/src/domain/motion/orientation/OrientationTrack.js +146 -0
- package/dist/packages/core/src/domain/motion/orientation/estimateGyroBias.js +64 -0
- package/dist/packages/core/src/domain/motion/orientation/gravity.js +97 -0
- package/dist/packages/core/src/domain/motion/stabilization/Stabilizer.js +13 -0
- package/dist/packages/core/src/domain/motion/stabilization/stabilizers.js +86 -0
- package/dist/packages/core/src/domain/motion/timing/CaptureClock.js +41 -0
- package/dist/packages/core/src/domain/motion/timing/FrameTimes.js +92 -0
- package/dist/packages/core/src/domain/motion/timing/frameTimeSources.js +61 -0
- package/dist/packages/core/src/domain/motion/timing/resolveFrameTimes.js +68 -0
- package/dist/packages/core/src/domain/optics/EquidistantModel.js +39 -0
- package/dist/packages/core/src/domain/optics/MeiModel.js +45 -0
- package/dist/packages/core/src/domain/optics/PolynomialModel.js +44 -0
- package/dist/packages/core/src/domain/optics/gainMatch.js +62 -0
- package/dist/packages/core/src/domain/optics/lensGeometry.js +18 -0
- package/dist/packages/core/src/domain/optics/lensPose.js +35 -0
- package/dist/packages/core/src/domain/optics/opticsConstants.js +5 -0
- package/dist/packages/core/src/domain/playback/PlayerState.js +83 -0
- package/dist/packages/core/src/domain/stitching/LensLayout.js +21 -0
- package/dist/packages/core/src/domain/stitching/StitchingSetup.js +78 -0
- package/dist/packages/core/src/domain/stitching/seamDisparity.js +4 -0
- package/dist/packages/core/src/domain/stitching/seamDisparityField.js +5 -0
- package/dist/packages/core/src/domain/stitching/seamJoin.js +16 -0
- package/dist/packages/core/src/domain/stitching/seamMismatch.js +1 -0
- package/dist/packages/core/src/domain/stitching/seamRing.js +4 -0
- package/dist/packages/core/src/domain/stitching/seamStrip.js +26 -0
- package/dist/packages/core/src/domain/view/Framing.js +31 -0
- package/dist/packages/core/src/domain/view/PictureQuality.js +26 -0
- package/dist/packages/core/src/domain/view/ViewMode.js +9 -0
- package/dist/packages/core/src/domain/view/ViewState.js +48 -0
- package/dist/packages/core/src/domain/view/lensTilesView.js +63 -0
- package/dist/packages/core/src/domain/view/magnification.js +103 -0
- package/dist/packages/core/src/domain/view/normalView.js +29 -0
- package/dist/packages/core/src/domain/view/panoramaView.js +99 -0
- package/dist/packages/core/src/domain/view/rectilinear.js +40 -0
- package/dist/packages/core/src/domain/view/screenLayout.js +113 -0
- package/dist/packages/core/src/domain/view/viewGestures.js +98 -0
- package/dist/packages/core/src/domain/view/viewModes.js +14 -0
- package/dist/packages/core/src/index.js +59 -0
- package/dist/packages/core/src/ports/FramePair.js +6 -0
- package/dist/packages/core/src/shared/async/Deferred.js +42 -0
- package/dist/packages/core/src/shared/async/RunStop.js +40 -0
- package/dist/packages/core/src/shared/binary/ByteRange.js +38 -0
- package/dist/packages/core/src/shared/binary/ByteReader.js +77 -0
- package/dist/packages/core/src/shared/errors/GyroViewError.js +81 -0
- package/dist/packages/core/src/shared/errors/reportLater.js +11 -0
- package/dist/packages/core/src/shared/events/Outbox.js +68 -0
- package/dist/packages/core/src/shared/events/TypedEmitter.js +55 -0
- package/dist/packages/core/src/shared/keysOf.js +10 -0
- package/dist/packages/core/src/shared/lazy.js +11 -0
- package/dist/packages/core/src/shared/math/Matrix3.js +93 -0
- package/dist/packages/core/src/shared/math/Quaternion.js +133 -0
- package/dist/packages/core/src/shared/math/Vector3.js +54 -0
- package/dist/packages/core/src/shared/math/clamp.js +9 -0
- package/dist/packages/core/src/shared/protobuf/ProtobufMessage.js +157 -0
- package/dist/packages/core/src/shared/text/urlPath.js +31 -0
- package/dist/packages/core/src/shared/text/utf8.js +12 -0
- package/dist/packages/core/src/shared/units/angle.js +22 -0
- package/dist/packages/core/src/shared/units/time.js +13 -0
- package/dist/packages/player/src/PlayerSource.js +15 -0
- package/dist/packages/player/src/browserPlayer.js +18 -0
- package/dist/packages/player/src/choices.js +25 -0
- package/dist/packages/player/src/composition/Disposables.js +31 -0
- package/dist/packages/player/src/composition/browserPorts.js +46 -0
- package/dist/packages/player/src/composition/buildPipeline.js +153 -0
- package/dist/packages/player/src/composition/ensureDecodable.js +63 -0
- package/dist/packages/player/src/composition/openInputs.js +179 -0
- package/dist/packages/player/src/composition/openRecording.js +42 -0
- package/dist/packages/player/src/controls/ChoiceMenu.js +113 -0
- package/dist/packages/player/src/controls/PictureMenus.js +47 -0
- package/dist/packages/player/src/controls/SeekBar.js +125 -0
- package/dist/packages/player/src/controls/SoundControls.js +41 -0
- package/dist/packages/player/src/controls/TransportButtons.js +31 -0
- package/dist/packages/player/src/controls/ViewGestures.js +136 -0
- package/dist/packages/player/src/controls/Wording.js +78 -0
- package/dist/packages/player/src/controls/controlParts.js +36 -0
- package/dist/packages/player/src/controls/controls.js +4 -0
- package/dist/packages/player/src/controls/controlsBar.js +23 -0
- package/dist/packages/player/src/controls/controlsMarkup.js +85 -0
- package/dist/packages/player/src/controls/customControls.js +59 -0
- package/dist/packages/player/src/controls/formatTime.js +19 -0
- package/dist/packages/player/src/controls/icons.js +40 -0
- package/dist/packages/player/src/controls/keyboard.js +118 -0
- package/dist/packages/player/src/controls/messages.js +94 -0
- package/dist/packages/player/src/controls/parseMarkup.js +31 -0
- package/dist/packages/player/src/controls/viewButtons.js +14 -0
- package/dist/packages/player/src/element/ElementLoads.js +119 -0
- package/dist/packages/player/src/element/FullscreenToggle.js +39 -0
- package/dist/packages/player/src/element/GyroViewElement.js +313 -0
- package/dist/packages/player/src/element/IdleWatcher.js +71 -0
- package/dist/packages/player/src/element/TypedEventElement.js +22 -0
- package/dist/packages/player/src/element/accessibleRegion.js +19 -0
- package/dist/packages/player/src/element/attributeNames.js +51 -0
- package/dist/packages/player/src/element/attributes.js +101 -0
- package/dist/packages/player/src/element/defineGyroView.js +21 -0
- package/dist/packages/player/src/element/earlyProperties.js +36 -0
- package/dist/packages/player/src/element/elementSource.js +23 -0
- package/dist/packages/player/src/element/liveSettings.js +138 -0
- package/dist/packages/player/src/element/playbackAttributes.js +53 -0
- package/dist/packages/player/src/element/playerEventMirror.js +33 -0
- package/dist/packages/player/src/element/reflectedProperties.js +78 -0
- package/dist/packages/player/src/element/styles.js +4 -0
- package/dist/packages/player/src/element/template.js +47 -0
- package/dist/packages/player/src/index.js +10 -0
- package/dist/packages/player/src/inspectRecording.js +22 -0
- package/dist/packages/player/src/player/DrawingBufferFit.js +77 -0
- package/dist/packages/player/src/player/FrameLoop.js +40 -0
- package/dist/packages/player/src/player/PictureSettings.js +60 -0
- package/dist/packages/player/src/player/Player.js +377 -0
- package/dist/packages/player/src/player/PlayerEvents.js +28 -0
- package/dist/packages/player/src/player/PlayerPhase.js +21 -0
- package/dist/packages/player/src/player/PlayerSound.js +61 -0
- package/dist/packages/player/src/player/PlayerView.js +113 -0
- package/dist/packages/player/src/player/SessionRelay.js +66 -0
- package/dist/packages/player/src/player/ensureFinite.js +26 -0
- package/dist/packages/player/src/player/loadRecording.js +65 -0
- package/dist/packages/player/src/player/transportEvents.js +29 -0
- package/dist/standalone.js +4919 -0
- package/package.json +73 -0
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import { GyroViewError, ensureInvariant } from "../../../core/src/shared/errors/GyroViewError.js";
|
|
2
|
+
import { DEFAULT_PICTURE_QUALITY } from "../../../core/src/domain/view/PictureQuality.js";
|
|
3
|
+
import { DEFAULT_VIEW_MODE } from "../../../core/src/domain/view/ViewMode.js";
|
|
4
|
+
import { aspectOf } from "../../../core/src/domain/view/screenLayout.js";
|
|
5
|
+
import { DEFAULT_FRAMING } from "../../../core/src/domain/view/Framing.js";
|
|
6
|
+
import { viewModeRulesFor } from "../../../core/src/domain/view/viewModes.js";
|
|
7
|
+
import "../../../core/src/index.js";
|
|
8
|
+
import { SAMPLING_STRATEGIES } from "./samplingStrategies.js";
|
|
9
|
+
import { applyLensGain, applyPicture, applyShaderSampling, applyStabilization, createRendererUniforms } from "./rendererUniforms.js";
|
|
10
|
+
import { createFullscreenTriangle } from "./fullscreenPass.js";
|
|
11
|
+
import { createRenderer } from "./webglRenderer.js";
|
|
12
|
+
import { SeamMeterPass } from "./seamMeter/SeamMeterPass.js";
|
|
13
|
+
import { applyTextureFilters, createLensTextures } from "./lensTextures.js";
|
|
14
|
+
import { PLAYER_SHADERS, compilePictureMaterials, createPictureMaterials, disposePictureMaterials } from "./pictureMaterials.js";
|
|
15
|
+
import { Camera, Mesh, Scene } from "three";
|
|
16
|
+
//#region ../../packages/adapters/three/src/ThreeFrameRenderer.ts
|
|
17
|
+
var PLAYER_PICTURES = {
|
|
18
|
+
shaders: PLAYER_SHADERS,
|
|
19
|
+
uniforms: {}
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* PictureRenderer over Three.js: uploads each lens frame to a texture and draws one fullscreen pass
|
|
23
|
+
* per frame, laid out on the viewport as the view mode's picture for the framing says: the
|
|
24
|
+
* stitched sphere through `stitch.frag.glsl`, turned by the view and stabilization rotations, or
|
|
25
|
+
* each lens image in a tile of its own.
|
|
26
|
+
*/
|
|
27
|
+
var ThreeFrameRenderer = class {
|
|
28
|
+
parts;
|
|
29
|
+
canvas;
|
|
30
|
+
framing = DEFAULT_FRAMING;
|
|
31
|
+
viewMode = DEFAULT_VIEW_MODE;
|
|
32
|
+
/**
|
|
33
|
+
* False until the first pair arrives. The textures then hold the pair on screen, which the
|
|
34
|
+
* session keeps open until it presents the next one.
|
|
35
|
+
*/
|
|
36
|
+
hasFrames = false;
|
|
37
|
+
isDisposed = false;
|
|
38
|
+
meters = /* @__PURE__ */ new Set();
|
|
39
|
+
constructor(parts, canvas) {
|
|
40
|
+
this.parts = parts;
|
|
41
|
+
this.canvas = canvas;
|
|
42
|
+
this.applyFraming();
|
|
43
|
+
canvas.addEventListener("webglcontextrestored", this.onContextRestored);
|
|
44
|
+
}
|
|
45
|
+
static create(canvas, setup, options = {}) {
|
|
46
|
+
const opening = {
|
|
47
|
+
options,
|
|
48
|
+
pictures: PLAYER_PICTURES
|
|
49
|
+
};
|
|
50
|
+
return new this(this.openParts(canvas, setup, opening), canvas);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The context, textures, uniforms and compiled programs of a renderer that draws with the
|
|
54
|
+
* given pictures.
|
|
55
|
+
*/
|
|
56
|
+
static openParts(canvas, setup, opening) {
|
|
57
|
+
ensureDrawable(setup);
|
|
58
|
+
const renderer = createRenderer(canvas, opening.options);
|
|
59
|
+
try {
|
|
60
|
+
return assembleParts(renderer, setup, opening.pictures);
|
|
61
|
+
} catch (error) {
|
|
62
|
+
renderer.dispose();
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
get lensCount() {
|
|
67
|
+
return this.parts.lensCount;
|
|
68
|
+
}
|
|
69
|
+
setFraming(framing) {
|
|
70
|
+
this.ensureLive();
|
|
71
|
+
this.framing = framing;
|
|
72
|
+
this.applyFraming();
|
|
73
|
+
this.render();
|
|
74
|
+
}
|
|
75
|
+
setViewMode(mode) {
|
|
76
|
+
this.ensureLive();
|
|
77
|
+
this.viewMode = mode;
|
|
78
|
+
this.applyFraming();
|
|
79
|
+
this.render();
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* The frames standing on screen are uploaded again with the new filters and mip chain, so the
|
|
83
|
+
* change shows at once, even while paused.
|
|
84
|
+
*/
|
|
85
|
+
setQuality(quality) {
|
|
86
|
+
this.ensureLive();
|
|
87
|
+
const strategy = SAMPLING_STRATEGIES[quality];
|
|
88
|
+
for (const texture of this.parts.textures) {
|
|
89
|
+
applyTextureFilters(texture, strategy);
|
|
90
|
+
if (this.hasFrames) texture.needsUpdate = true;
|
|
91
|
+
}
|
|
92
|
+
applyShaderSampling(this.parts.uniforms, strategy);
|
|
93
|
+
this.render();
|
|
94
|
+
}
|
|
95
|
+
setLensGains(gains) {
|
|
96
|
+
this.ensureLive();
|
|
97
|
+
for (const [lensIndex, gain] of gains.entries()) applyLensGain(this.parts.uniforms, lensIndex, gain);
|
|
98
|
+
this.render();
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* The meter leaves this renderer's list when disposed; the renderer disposes those still live
|
|
102
|
+
* when it goes, since they share its context and uniforms.
|
|
103
|
+
*/
|
|
104
|
+
createSeamMeter() {
|
|
105
|
+
this.ensureLive();
|
|
106
|
+
const pass = new SeamMeterPass(this.parts.renderer, this.parts.uniforms, this.parts.lensCount);
|
|
107
|
+
return this.tracked({
|
|
108
|
+
measure: () => pass.measure(),
|
|
109
|
+
dispose: () => {
|
|
110
|
+
pass.dispose();
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Turns the whole picture: the stabilized frame the viewer looks around in, into the body.
|
|
116
|
+
* Does not redraw by itself: the stabilizing sink calls it right before presenting a pair.
|
|
117
|
+
*/
|
|
118
|
+
setStabilization(rotation) {
|
|
119
|
+
this.ensureLive();
|
|
120
|
+
applyStabilization(this.parts.uniforms, rotation);
|
|
121
|
+
}
|
|
122
|
+
present(presentation) {
|
|
123
|
+
this.ensureLive();
|
|
124
|
+
const { frames } = presentation.pair;
|
|
125
|
+
ensureInvariant(frames.length === this.parts.textures.length, `a pair of ${frames.length} frames does not fit ${this.parts.textures.length} lens textures`);
|
|
126
|
+
for (const [index, texture] of this.parts.textures.entries()) {
|
|
127
|
+
const frame = frames[index];
|
|
128
|
+
if (frame) texture.setFrame(frame.handle);
|
|
129
|
+
}
|
|
130
|
+
this.hasFrames = true;
|
|
131
|
+
this.render();
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Matches the drawing buffer to a new element size, in device pixels.
|
|
135
|
+
*/
|
|
136
|
+
resize(size) {
|
|
137
|
+
this.ensureLive();
|
|
138
|
+
this.parts.renderer.setSize(size.width, size.height, false);
|
|
139
|
+
this.applyFraming();
|
|
140
|
+
this.render();
|
|
141
|
+
}
|
|
142
|
+
dispose() {
|
|
143
|
+
if (this.isDisposed) return;
|
|
144
|
+
this.isDisposed = true;
|
|
145
|
+
this.canvas.removeEventListener("webglcontextrestored", this.onContextRestored);
|
|
146
|
+
for (const meter of this.meters) meter.dispose();
|
|
147
|
+
this.parts.seamProof.dispose();
|
|
148
|
+
for (const texture of this.parts.textures) texture.dispose();
|
|
149
|
+
disposePictureMaterials(this.parts.materials);
|
|
150
|
+
this.parts.pass.geometry.dispose();
|
|
151
|
+
this.parts.renderer.dispose();
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* The WebGL renderer and the shared uniforms, for a subclass's own passes and settings.
|
|
155
|
+
*/
|
|
156
|
+
get webgl() {
|
|
157
|
+
return this.parts.renderer;
|
|
158
|
+
}
|
|
159
|
+
get uniforms() {
|
|
160
|
+
return this.parts.uniforms;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* A meter over a pass that shares this renderer's context, which the renderer disposes with
|
|
164
|
+
* itself unless it is disposed first.
|
|
165
|
+
*/
|
|
166
|
+
tracked(meter) {
|
|
167
|
+
const kept = {
|
|
168
|
+
...meter,
|
|
169
|
+
dispose: () => {
|
|
170
|
+
this.meters.delete(kept);
|
|
171
|
+
meter.dispose();
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
this.meters.add(kept);
|
|
175
|
+
return kept;
|
|
176
|
+
}
|
|
177
|
+
render() {
|
|
178
|
+
if (!this.hasFrames) return;
|
|
179
|
+
this.parts.renderer.render(this.parts.scene, this.parts.camera);
|
|
180
|
+
}
|
|
181
|
+
ensureLive() {
|
|
182
|
+
ensureInvariant(!this.isDisposed, "the renderer has been disposed");
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Three.js builds its state anew on a restored context but draws nothing: a paused picture
|
|
186
|
+
* (iOS drops the context of a tab in the background) comes back only through a redraw, which
|
|
187
|
+
* uploads the frames on screen again.
|
|
188
|
+
*/
|
|
189
|
+
onContextRestored = () => {
|
|
190
|
+
this.render();
|
|
191
|
+
};
|
|
192
|
+
/**
|
|
193
|
+
* Asks the view mode what to draw for the framing on this canvas, and switches to that
|
|
194
|
+
* picture's program.
|
|
195
|
+
*/
|
|
196
|
+
applyFraming() {
|
|
197
|
+
const viewport = {
|
|
198
|
+
width: this.canvas.width,
|
|
199
|
+
height: this.canvas.height
|
|
200
|
+
};
|
|
201
|
+
const picture = viewModeRulesFor(this.viewMode).picture(this.framing, {
|
|
202
|
+
viewport,
|
|
203
|
+
lensCount: this.parts.lensCount
|
|
204
|
+
});
|
|
205
|
+
this.parts.pass.material = this.parts.materials[picture.kind];
|
|
206
|
+
applyPicture(this.parts.uniforms, picture, aspectOf(viewport));
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
/**
|
|
210
|
+
* The shader has room for `MAX_LENSES` lenses from `LENS_TEXTURES` decoded frames; a layout
|
|
211
|
+
* beyond either would be drawn wrong without a word, so it is refused.
|
|
212
|
+
*/
|
|
213
|
+
function ensureDrawable(setup) {
|
|
214
|
+
if (setup.lenses.length <= 2 && setup.frameSlotCount <= 2) return;
|
|
215
|
+
throw new GyroViewError("unsupported-layout", `the renderer draws at most 2 lenses from 2 frames; the layout has ${setup.lenses.length} lenses in ${setup.frameSlotCount} frames`);
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* The textures, uniforms and programs every picture shares, read at the default quality.
|
|
219
|
+
*/
|
|
220
|
+
function sharedParts(setup, pictures) {
|
|
221
|
+
const strategy = SAMPLING_STRATEGIES[DEFAULT_PICTURE_QUALITY];
|
|
222
|
+
const textures = createLensTextures(setup.frameSlotCount, strategy);
|
|
223
|
+
const uniforms = createRendererUniforms(setup, textures);
|
|
224
|
+
applyShaderSampling(uniforms, strategy);
|
|
225
|
+
return {
|
|
226
|
+
textures,
|
|
227
|
+
uniforms,
|
|
228
|
+
materials: createPictureMaterials({
|
|
229
|
+
...uniforms,
|
|
230
|
+
...pictures.uniforms
|
|
231
|
+
}, pictures.shaders)
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
function assembleParts(renderer, setup, pictures) {
|
|
235
|
+
const { textures, uniforms, materials } = sharedParts(setup, pictures);
|
|
236
|
+
const pass = new Mesh(createFullscreenTriangle(), materials.rectilinear);
|
|
237
|
+
const seamProof = provenSeamMeter(renderer, {
|
|
238
|
+
pass,
|
|
239
|
+
materials,
|
|
240
|
+
textures,
|
|
241
|
+
uniforms
|
|
242
|
+
});
|
|
243
|
+
const scene = new Scene();
|
|
244
|
+
scene.add(pass);
|
|
245
|
+
return {
|
|
246
|
+
renderer,
|
|
247
|
+
scene,
|
|
248
|
+
camera: new Camera(),
|
|
249
|
+
pass,
|
|
250
|
+
materials,
|
|
251
|
+
textures,
|
|
252
|
+
uniforms,
|
|
253
|
+
lensCount: setup.lenses.length,
|
|
254
|
+
seamProof
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Compiles and proves every picture program, then opens the seam meter, which proves its own
|
|
259
|
+
* (gain matching asks for one at every load); what was built goes if a program fails.
|
|
260
|
+
*/
|
|
261
|
+
function provenSeamMeter(renderer, built) {
|
|
262
|
+
const { pass, materials, textures, uniforms } = built;
|
|
263
|
+
try {
|
|
264
|
+
compilePictureMaterials(renderer, pass.geometry, materials);
|
|
265
|
+
return new SeamMeterPass(renderer, uniforms, uniforms.uLensCount.value);
|
|
266
|
+
} catch (error) {
|
|
267
|
+
disposePictureMaterials(materials);
|
|
268
|
+
pass.geometry.dispose();
|
|
269
|
+
for (const texture of textures) texture.dispose();
|
|
270
|
+
throw error;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
//#endregion
|
|
274
|
+
export { ThreeFrameRenderer };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//#region ../../packages/adapters/three/src/compileAndProve.ts
|
|
2
|
+
/**
|
|
3
|
+
* Compiles the programs `scene` needs and asks every program the renderer holds for its uniforms.
|
|
4
|
+
* Three checks a program's link at its first use, and that request is one, so a shader the GPU
|
|
5
|
+
* refuses fails here through the renderer's shader-error hook without a draw (which costs a
|
|
6
|
+
* software renderer hundreds of milliseconds on the main thread).
|
|
7
|
+
*/
|
|
8
|
+
function compileAndProve(renderer, scene, camera) {
|
|
9
|
+
renderer.compile(scene, camera);
|
|
10
|
+
const programs = renderer.info.programs ?? [];
|
|
11
|
+
for (const program of programs) program.getUniforms();
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
export { compileAndProve };
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { SHADER_DEFINES } from "./rendererUniforms.js";
|
|
2
|
+
import fullscreen_vert_default from "./shaders/fullscreen.vert.js";
|
|
3
|
+
import { BufferGeometry, Float32BufferAttribute, GLSL3, RawShaderMaterial } from "three";
|
|
4
|
+
//#region ../../packages/adapters/three/src/fullscreenPass.ts
|
|
5
|
+
/**
|
|
6
|
+
* One triangle covering the clip square: two corners lie beyond it so its hypotenuse clears the
|
|
7
|
+
* far edge. The fragment shader decides every pixel.
|
|
8
|
+
*/
|
|
9
|
+
var BEYOND_CLIP = 3;
|
|
10
|
+
var FULLSCREEN_TRIANGLE = [
|
|
11
|
+
-1,
|
|
12
|
+
-1,
|
|
13
|
+
0,
|
|
14
|
+
BEYOND_CLIP,
|
|
15
|
+
-1,
|
|
16
|
+
0,
|
|
17
|
+
-1,
|
|
18
|
+
BEYOND_CLIP,
|
|
19
|
+
0
|
|
20
|
+
];
|
|
21
|
+
var POSITION_COMPONENTS = 3;
|
|
22
|
+
function createFullscreenTriangle() {
|
|
23
|
+
const geometry = new BufferGeometry();
|
|
24
|
+
geometry.setAttribute("position", new Float32BufferAttribute(FULLSCREEN_TRIANGLE, POSITION_COMPONENTS));
|
|
25
|
+
return geometry;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The program of a pass whose chunks refer only to the constants of `rendererUniforms`.
|
|
29
|
+
*/
|
|
30
|
+
function programOf(chunks) {
|
|
31
|
+
return {
|
|
32
|
+
chunks,
|
|
33
|
+
defines: SHADER_DEFINES
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* A fullscreen pass over the shared uniforms. The raw shaders ignore the camera three still
|
|
38
|
+
* wants to render with; each pass keeps its own.
|
|
39
|
+
*/
|
|
40
|
+
function createPassMaterial(uniforms, program) {
|
|
41
|
+
return new RawShaderMaterial({
|
|
42
|
+
glslVersion: GLSL3,
|
|
43
|
+
defines: { ...program.defines },
|
|
44
|
+
vertexShader: fullscreen_vert_default,
|
|
45
|
+
fragmentShader: program.chunks.join("\n"),
|
|
46
|
+
uniforms: { ...uniforms },
|
|
47
|
+
depthTest: false,
|
|
48
|
+
depthWrite: false
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
52
|
+
export { createFullscreenTriangle, createPassMaterial, programOf };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { LinearFilter, NoColorSpace, VideoFrameTexture } from "three";
|
|
2
|
+
//#region ../../packages/adapters/three/src/lensTextures.ts
|
|
3
|
+
/**
|
|
4
|
+
* The textures the decoded frames are uploaded to, one per frame of a pair, read with the
|
|
5
|
+
* given strategy. Three uploads a video frame with `texImage2D` and builds the mip chain after
|
|
6
|
+
* it when asked; the anisotropy applies where the driver offers it and the filter uses the
|
|
7
|
+
* chain.
|
|
8
|
+
*/
|
|
9
|
+
function createLensTextures(count, strategy) {
|
|
10
|
+
return Array.from({ length: count }, () => {
|
|
11
|
+
const texture = new VideoFrameTexture();
|
|
12
|
+
texture.flipY = false;
|
|
13
|
+
texture.colorSpace = NoColorSpace;
|
|
14
|
+
texture.magFilter = LinearFilter;
|
|
15
|
+
applyTextureFilters(texture, strategy);
|
|
16
|
+
return texture;
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
function applyTextureFilters(texture, strategy) {
|
|
20
|
+
texture.minFilter = strategy.minFilter;
|
|
21
|
+
texture.generateMipmaps = strategy.generateMipmaps;
|
|
22
|
+
texture.anisotropy = strategy.anisotropy;
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
export { applyTextureFilters, createLensTextures };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { SHADER_DEFINES } from "./rendererUniforms.js";
|
|
2
|
+
import { createPassMaterial } from "./fullscreenPass.js";
|
|
3
|
+
import { compileAndProve } from "./compileAndProve.js";
|
|
4
|
+
import { PICTURE_PROGRAMS } from "./shaderPrograms.js";
|
|
5
|
+
import { Camera, Mesh, Scene } from "three";
|
|
6
|
+
//#region ../../packages/adapters/three/src/pictureMaterials.ts
|
|
7
|
+
/**
|
|
8
|
+
* The pictures the player draws: the stitch through the fixed seam join.
|
|
9
|
+
*/
|
|
10
|
+
var PLAYER_SHADERS = {
|
|
11
|
+
programs: PICTURE_PROGRAMS,
|
|
12
|
+
defines: SHADER_DEFINES
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* The pictures' materials over the shared uniforms, and any the pictures' programs add.
|
|
16
|
+
*/
|
|
17
|
+
function createPictureMaterials(uniforms, shaders) {
|
|
18
|
+
const materialOf = (kind) => createPassMaterial(uniforms, {
|
|
19
|
+
chunks: shaders.programs[kind],
|
|
20
|
+
defines: shaders.defines
|
|
21
|
+
});
|
|
22
|
+
return {
|
|
23
|
+
rectilinear: materialOf("rectilinear"),
|
|
24
|
+
equirectangular: materialOf("equirectangular"),
|
|
25
|
+
"lens-tiles": materialOf("lens-tiles")
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Compiles and proves every program now: a broken shader then fails here rather than at the first
|
|
30
|
+
* presented frame or the first change of view mode, and a change of mode is instant.
|
|
31
|
+
*/
|
|
32
|
+
function compilePictureMaterials(renderer, geometry, materials) {
|
|
33
|
+
const camera = new Camera();
|
|
34
|
+
for (const material of Object.values(materials)) {
|
|
35
|
+
const scene = new Scene();
|
|
36
|
+
scene.add(new Mesh(geometry, material));
|
|
37
|
+
compileAndProve(renderer, scene, camera);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function disposePictureMaterials(materials) {
|
|
41
|
+
for (const material of Object.values(materials)) material.dispose();
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
export { PLAYER_SHADERS, compilePictureMaterials, createPictureMaterials, disposePictureMaterials };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region ../../packages/adapters/three/src/renderInto.ts
|
|
2
|
+
/**
|
|
3
|
+
* Runs `draw` with `target` bound, the renderer's own target restored however the drawing ends.
|
|
4
|
+
*/
|
|
5
|
+
function renderInto(renderer, target, draw) {
|
|
6
|
+
const previous = renderer.getRenderTarget();
|
|
7
|
+
renderer.setRenderTarget(target);
|
|
8
|
+
try {
|
|
9
|
+
draw();
|
|
10
|
+
} finally {
|
|
11
|
+
renderer.setRenderTarget(previous);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
export { renderInto };
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { ensureIndexInRange, ensureInvariant } from "../../../core/src/shared/errors/GyroViewError.js";
|
|
2
|
+
import { IDENTITY_MATRIX3 } from "../../../core/src/shared/math/Matrix3.js";
|
|
3
|
+
import { aspectOfArea, planeHalfExtentOf } from "../../../core/src/domain/view/rectilinear.js";
|
|
4
|
+
import "../../../core/src/index.js";
|
|
5
|
+
import "./samplingStrategies.js";
|
|
6
|
+
import { Matrix3, Vector2, Vector3, Vector4 } from "three";
|
|
7
|
+
var LENS_MEI = 0;
|
|
8
|
+
var LENS_RADIAL_POLYNOMIAL = 1;
|
|
9
|
+
/**
|
|
10
|
+
* The constants the player's GLSL sources refer to, injected as preprocessor defines so that
|
|
11
|
+
* this file is their only home; the lab adds its own.
|
|
12
|
+
*/
|
|
13
|
+
var SHADER_DEFINES = Object.fromEntries([
|
|
14
|
+
["MAX_LENSES", 2],
|
|
15
|
+
["LENS_MEI", LENS_MEI],
|
|
16
|
+
["LENS_RADIAL_POLYNOMIAL", LENS_RADIAL_POLYNOMIAL],
|
|
17
|
+
["SAMPLING_BILINEAR", 0],
|
|
18
|
+
["SAMPLING_TRILINEAR", 1],
|
|
19
|
+
["SAMPLING_SUPERSAMPLED", 2]
|
|
20
|
+
]);
|
|
21
|
+
function createRendererUniforms(setup, textures) {
|
|
22
|
+
const lenses = padded(setup.lenses, "a stitching setup has one or two lenses");
|
|
23
|
+
return {
|
|
24
|
+
...viewUniforms(setup),
|
|
25
|
+
...projectionUniforms(lenses),
|
|
26
|
+
...samplingUniforms(lenses),
|
|
27
|
+
uTexture0: { value: textures[0] ?? null },
|
|
28
|
+
uTexture1: { value: textures[1] ?? null }
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function viewUniforms(setup) {
|
|
32
|
+
return {
|
|
33
|
+
uLensCount: { value: setup.lenses.length },
|
|
34
|
+
uViewRotation: { value: new Matrix3() },
|
|
35
|
+
uStabilization: { value: new Matrix3() },
|
|
36
|
+
uPlaneHalfExtent: { value: 1 },
|
|
37
|
+
uPictureAspect: { value: 1 },
|
|
38
|
+
uScreenArea: { value: Array.from({ length: 2 }, () => new Vector4(0, 0, 1, 1)) },
|
|
39
|
+
uFeather: { value: new Vector2(setup.feather.start, setup.feather.end) }
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function projectionUniforms(lenses) {
|
|
43
|
+
const slots = lenses.map((lens) => slotOf(lens.projection));
|
|
44
|
+
return {
|
|
45
|
+
uLensRotation: { value: lenses.map((lens) => toThreeMatrix(lens.rotation)) },
|
|
46
|
+
uLensKind: { value: slots.map((slot) => slot.kind) },
|
|
47
|
+
uLensPrincipalPoint: { value: lenses.map((lens) => toVector2(lens.projection.principalPoint)) },
|
|
48
|
+
uLensFocal: { value: slots.map((slot) => slot.focal) },
|
|
49
|
+
uLensXi: { value: slots.map((slot) => slot.xi) },
|
|
50
|
+
uLensRadial: { value: slots.map((slot) => slot.radial) },
|
|
51
|
+
uLensTangential: { value: slots.map((slot) => slot.tangential) },
|
|
52
|
+
uLensPolynomial: { value: slots.map((slot) => slot.polynomial) },
|
|
53
|
+
uLensHalfFov: { value: lenses.map((lens) => lens.halfFieldOfView) }
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Exhaustive over the projection kinds: a new kind does not compile until it is packed.
|
|
58
|
+
*/
|
|
59
|
+
function slotOf(projection) {
|
|
60
|
+
switch (projection.kind) {
|
|
61
|
+
case "mei": return {
|
|
62
|
+
kind: LENS_MEI,
|
|
63
|
+
focal: new Vector2(...projection.focal),
|
|
64
|
+
xi: projection.xi,
|
|
65
|
+
radial: new Vector3(...projection.radial),
|
|
66
|
+
tangential: new Vector2(...projection.tangential),
|
|
67
|
+
polynomial: new Vector4()
|
|
68
|
+
};
|
|
69
|
+
case "radial-polynomial": return {
|
|
70
|
+
kind: LENS_RADIAL_POLYNOMIAL,
|
|
71
|
+
focal: new Vector2(),
|
|
72
|
+
xi: 0,
|
|
73
|
+
radial: new Vector3(),
|
|
74
|
+
tangential: new Vector2(),
|
|
75
|
+
polynomial: new Vector4(...projection.coefficients)
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function samplingUniforms(lenses) {
|
|
80
|
+
return {
|
|
81
|
+
uLensWindow: { value: lenses.map((lens) => new Vector4(lens.window.x, lens.window.y, lens.window.width, lens.window.height)) },
|
|
82
|
+
uLensRegion: { value: lenses.map((lens) => new Vector4(lens.region.x, lens.region.y, lens.region.width, lens.region.height)) },
|
|
83
|
+
uLensTexture: { value: lenses.map((lens) => lens.frameSlot) },
|
|
84
|
+
uLensGain: { value: lenses.map(() => new Vector3(1, 1, 1)) },
|
|
85
|
+
uSampling: { value: 0 }
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function applyShaderSampling(uniforms, strategy) {
|
|
89
|
+
uniforms.uSampling.value = strategy.shaderSampling;
|
|
90
|
+
}
|
|
91
|
+
function applyStabilization(uniforms, rotation) {
|
|
92
|
+
uniforms.uStabilization.value = toThreeMatrix(rotation);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Sets one lens's per-channel multiplier; a lens the setup does not have is a defect.
|
|
96
|
+
*/
|
|
97
|
+
function applyLensGain(uniforms, lensIndex, gain) {
|
|
98
|
+
ensureIndexInRange(lensIndex, uniforms.uLensCount.value, "lens");
|
|
99
|
+
uniforms.uLensGain.value[lensIndex]?.set(...gain);
|
|
100
|
+
}
|
|
101
|
+
var NEUTRAL = {
|
|
102
|
+
rotation: IDENTITY_MATRIX3,
|
|
103
|
+
planeHalfExtent: 1,
|
|
104
|
+
pictureAspect: 1
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Sets the uniforms `picture` is drawn from, on a viewport `viewportAspect` wide per unit of
|
|
108
|
+
* height.
|
|
109
|
+
*/
|
|
110
|
+
function applyPicture(uniforms, picture, viewportAspect) {
|
|
111
|
+
const values = valuesOf(picture, viewportAspect);
|
|
112
|
+
uniforms.uViewRotation.value = toThreeMatrix(values.rotation);
|
|
113
|
+
uniforms.uPlaneHalfExtent.value = values.planeHalfExtent;
|
|
114
|
+
uniforms.uPictureAspect.value = values.pictureAspect;
|
|
115
|
+
uniforms.uScreenArea.value = padded(values.areas, "a picture fills one area per lens at most").map((area) => toVector4(area));
|
|
116
|
+
}
|
|
117
|
+
function valuesOf(picture, viewportAspect) {
|
|
118
|
+
switch (picture.kind) {
|
|
119
|
+
case "rectilinear": return {
|
|
120
|
+
rotation: picture.rotation,
|
|
121
|
+
planeHalfExtent: planeHalfExtentOf(picture.fieldOfView),
|
|
122
|
+
pictureAspect: aspectOfArea(picture.area, viewportAspect),
|
|
123
|
+
areas: [picture.area]
|
|
124
|
+
};
|
|
125
|
+
case "equirectangular": return {
|
|
126
|
+
...NEUTRAL,
|
|
127
|
+
rotation: picture.rotation,
|
|
128
|
+
areas: [picture.area]
|
|
129
|
+
};
|
|
130
|
+
case "lens-tiles": return {
|
|
131
|
+
...NEUTRAL,
|
|
132
|
+
areas: picture.tiles
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
function toVector4(area) {
|
|
137
|
+
return new Vector4(area.x, area.y, area.width, area.height);
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Row-major core matrix into a three matrix, whose `set` takes rows too.
|
|
141
|
+
*/
|
|
142
|
+
function toThreeMatrix(m) {
|
|
143
|
+
return new Matrix3().set(...m);
|
|
144
|
+
}
|
|
145
|
+
function toVector2(point) {
|
|
146
|
+
return new Vector2(point.x, point.y);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Uniform arrays have a fixed length; unused slots repeat the last entry and are never read.
|
|
150
|
+
*/
|
|
151
|
+
function padded(entries, expectation) {
|
|
152
|
+
const last = entries.at(-1);
|
|
153
|
+
ensureInvariant(last !== void 0 && entries.length <= 2, expectation);
|
|
154
|
+
return Array.from({ length: 2 }, (_unused, index) => entries[index] ?? last);
|
|
155
|
+
}
|
|
156
|
+
//#endregion
|
|
157
|
+
export { SHADER_DEFINES, applyLensGain, applyPicture, applyShaderSampling, applyStabilization, createRendererUniforms };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { LinearFilter, LinearMipmapLinearFilter } from "three";
|
|
2
|
+
/**
|
|
3
|
+
* The record keyed by the quality refuses to compile until every tier has a strategy.
|
|
4
|
+
*/
|
|
5
|
+
var SAMPLING_STRATEGIES = {
|
|
6
|
+
fast: {
|
|
7
|
+
minFilter: LinearFilter,
|
|
8
|
+
generateMipmaps: false,
|
|
9
|
+
anisotropy: 1,
|
|
10
|
+
shaderSampling: 0
|
|
11
|
+
},
|
|
12
|
+
balanced: {
|
|
13
|
+
minFilter: LinearMipmapLinearFilter,
|
|
14
|
+
generateMipmaps: true,
|
|
15
|
+
anisotropy: 4,
|
|
16
|
+
shaderSampling: 1
|
|
17
|
+
},
|
|
18
|
+
high: {
|
|
19
|
+
minFilter: LinearMipmapLinearFilter,
|
|
20
|
+
generateMipmaps: true,
|
|
21
|
+
anisotropy: 8,
|
|
22
|
+
shaderSampling: 2
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
//#endregion
|
|
26
|
+
export { SAMPLING_STRATEGIES };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import "../rendererUniforms.js";
|
|
2
|
+
import { createFullscreenTriangle, createPassMaterial, programOf } from "../fullscreenPass.js";
|
|
3
|
+
import { rowMeansOf } from "./rowMeans.js";
|
|
4
|
+
import { compileAndProve } from "../compileAndProve.js";
|
|
5
|
+
import { renderInto } from "../renderInto.js";
|
|
6
|
+
import { SEAM_ANALYSIS } from "../shaderPrograms.js";
|
|
7
|
+
import { Camera, Mesh, Scene, WebGLRenderTarget } from "three";
|
|
8
|
+
//#region ../../packages/adapters/three/src/seamMeter/SeamMeterPass.ts
|
|
9
|
+
/**
|
|
10
|
+
* Samples taken around the seam ring per lens: enough to average out content, few enough that
|
|
11
|
+
* the read-back is negligible.
|
|
12
|
+
*/
|
|
13
|
+
var SEAM_SAMPLES = 64;
|
|
14
|
+
/**
|
|
15
|
+
* SeamMeter over the GPU: renders what each lens sees along the seam ring into one row of a tiny
|
|
16
|
+
* target and reads the rows back, sharing the stitch's uniforms so it always looks at the frames
|
|
17
|
+
* on screen. Compiled and proven when created, so a broken shader fails there and not
|
|
18
|
+
* mid-playback.
|
|
19
|
+
*/
|
|
20
|
+
var SeamMeterPass = class {
|
|
21
|
+
renderer;
|
|
22
|
+
lensCount;
|
|
23
|
+
target = new WebGLRenderTarget(SEAM_SAMPLES, 2, {
|
|
24
|
+
depthBuffer: false,
|
|
25
|
+
stencilBuffer: false
|
|
26
|
+
});
|
|
27
|
+
pixels = new Uint8Array(SEAM_SAMPLES * 2 * 4);
|
|
28
|
+
camera = new Camera();
|
|
29
|
+
scene = new Scene();
|
|
30
|
+
material;
|
|
31
|
+
geometry = createFullscreenTriangle();
|
|
32
|
+
isDisposed = false;
|
|
33
|
+
constructor(renderer, uniforms, lensCount) {
|
|
34
|
+
this.renderer = renderer;
|
|
35
|
+
this.lensCount = lensCount;
|
|
36
|
+
this.material = createPassMaterial(uniforms, programOf(SEAM_ANALYSIS));
|
|
37
|
+
this.scene.add(new Mesh(this.geometry, this.material));
|
|
38
|
+
try {
|
|
39
|
+
compileAndProve(renderer, this.scene, this.camera);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
this.dispose();
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Mean colour (0..1) each lens shows along the seam, or undefined when a lens images none of it.
|
|
47
|
+
*/
|
|
48
|
+
async measure() {
|
|
49
|
+
try {
|
|
50
|
+
await this.readSeam();
|
|
51
|
+
} catch (error) {
|
|
52
|
+
if (this.isDisposed || this.renderer.getContext().isContextLost()) return void 0;
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
return this.isDisposed ? void 0 : rowMeansOf(this.pixels, SEAM_SAMPLES, this.lensCount);
|
|
56
|
+
}
|
|
57
|
+
dispose() {
|
|
58
|
+
if (this.isDisposed) return;
|
|
59
|
+
this.isDisposed = true;
|
|
60
|
+
this.target.dispose();
|
|
61
|
+
this.material.dispose();
|
|
62
|
+
this.geometry.dispose();
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Renders the seam rows into the meter's target, the renderer's own target restored however the
|
|
66
|
+
* drawing ends.
|
|
67
|
+
*/
|
|
68
|
+
draw() {
|
|
69
|
+
renderInto(this.renderer, this.target, () => {
|
|
70
|
+
this.renderer.render(this.scene, this.camera);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
async readSeam() {
|
|
74
|
+
this.draw();
|
|
75
|
+
await this.renderer.readRenderTargetPixelsAsync(this.target, 0, 0, SEAM_SAMPLES, 2, this.pixels);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
//#endregion
|
|
79
|
+
export { SeamMeterPass };
|