@luma.gl/engine 9.3.0-alpha.6 → 9.3.0-alpha.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/animation-loop/animation-loop.d.ts.map +1 -1
- package/dist/animation-loop/animation-loop.js +3 -0
- package/dist/animation-loop/animation-loop.js.map +1 -1
- package/dist/compute/computation.d.ts +3 -7
- package/dist/compute/computation.d.ts.map +1 -1
- package/dist/compute/computation.js +14 -12
- package/dist/compute/computation.js.map +1 -1
- package/dist/dist.dev.js +1751 -831
- package/dist/dist.min.js +296 -148
- package/dist/dynamic-texture/dynamic-texture.d.ts +9 -2
- package/dist/dynamic-texture/dynamic-texture.d.ts.map +1 -1
- package/dist/dynamic-texture/dynamic-texture.js +54 -5
- package/dist/dynamic-texture/dynamic-texture.js.map +1 -1
- package/dist/dynamic-texture/texture-data.d.ts +4 -1
- package/dist/dynamic-texture/texture-data.d.ts.map +1 -1
- package/dist/dynamic-texture/texture-data.js +19 -2
- package/dist/dynamic-texture/texture-data.js.map +1 -1
- package/dist/geometry/gpu-geometry.d.ts.map +1 -1
- package/dist/geometry/gpu-geometry.js +8 -3
- package/dist/geometry/gpu-geometry.js.map +1 -1
- package/dist/index.cjs +1711 -847
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +12 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -3
- package/dist/index.js.map +1 -1
- package/dist/material/material-factory.d.ts +73 -0
- package/dist/material/material-factory.d.ts.map +1 -0
- package/dist/material/material-factory.js +111 -0
- package/dist/material/material-factory.js.map +1 -0
- package/dist/material/material.d.ts +84 -0
- package/dist/material/material.d.ts.map +1 -0
- package/dist/material/material.js +176 -0
- package/dist/material/material.js.map +1 -0
- package/dist/model/model.d.ts +14 -6
- package/dist/model/model.d.ts.map +1 -1
- package/dist/model/model.js +69 -25
- package/dist/model/model.js.map +1 -1
- package/dist/model/split-uniforms-and-bindings.d.ts +4 -3
- package/dist/model/split-uniforms-and-bindings.d.ts.map +1 -1
- package/dist/model/split-uniforms-and-bindings.js +2 -2
- package/dist/model/split-uniforms-and-bindings.js.map +1 -1
- package/dist/models/directional-light-model.d.ts +7 -0
- package/dist/models/directional-light-model.d.ts.map +1 -0
- package/dist/models/directional-light-model.js +23 -0
- package/dist/models/directional-light-model.js.map +1 -0
- package/dist/models/light-model-utils.d.ts +69 -0
- package/dist/models/light-model-utils.d.ts.map +1 -0
- package/dist/models/light-model-utils.js +395 -0
- package/dist/models/light-model-utils.js.map +1 -0
- package/dist/models/point-light-model.d.ts +7 -0
- package/dist/models/point-light-model.d.ts.map +1 -0
- package/dist/models/point-light-model.js +22 -0
- package/dist/models/point-light-model.js.map +1 -0
- package/dist/models/spot-light-model.d.ts +7 -0
- package/dist/models/spot-light-model.d.ts.map +1 -0
- package/dist/models/spot-light-model.js +23 -0
- package/dist/models/spot-light-model.js.map +1 -0
- package/dist/modules/picking/color-picking.d.ts +5 -9
- package/dist/modules/picking/color-picking.d.ts.map +1 -1
- package/dist/modules/picking/color-picking.js +122 -115
- package/dist/modules/picking/color-picking.js.map +1 -1
- package/dist/modules/picking/index-picking.d.ts +2 -2
- package/dist/modules/picking/index-picking.d.ts.map +1 -1
- package/dist/modules/picking/index-picking.js +36 -10
- package/dist/modules/picking/index-picking.js.map +1 -1
- package/dist/modules/picking/legacy-color-picking.d.ts +26 -0
- package/dist/modules/picking/legacy-color-picking.d.ts.map +1 -0
- package/dist/modules/picking/legacy-color-picking.js +7 -0
- package/dist/modules/picking/legacy-color-picking.js.map +1 -0
- package/dist/modules/picking/picking-manager.d.ts +29 -3
- package/dist/modules/picking/picking-manager.d.ts.map +1 -1
- package/dist/modules/picking/picking-manager.js +188 -41
- package/dist/modules/picking/picking-manager.js.map +1 -1
- package/dist/modules/picking/picking-uniforms.d.ts +12 -11
- package/dist/modules/picking/picking-uniforms.d.ts.map +1 -1
- package/dist/modules/picking/picking-uniforms.js +26 -13
- package/dist/modules/picking/picking-uniforms.js.map +1 -1
- package/dist/modules/picking/picking.d.ts +25 -0
- package/dist/modules/picking/picking.d.ts.map +1 -0
- package/dist/modules/picking/picking.js +18 -0
- package/dist/modules/picking/picking.js.map +1 -0
- package/dist/shader-inputs.d.ts +9 -7
- package/dist/shader-inputs.d.ts.map +1 -1
- package/dist/shader-inputs.js +84 -4
- package/dist/shader-inputs.js.map +1 -1
- package/dist/utils/shader-module-utils.d.ts +7 -0
- package/dist/utils/shader-module-utils.d.ts.map +1 -0
- package/dist/utils/shader-module-utils.js +46 -0
- package/dist/utils/shader-module-utils.js.map +1 -0
- package/package.json +4 -4
- package/src/animation-loop/animation-loop.ts +3 -0
- package/src/compute/computation.ts +31 -17
- package/src/dynamic-texture/dynamic-texture.ts +79 -7
- package/src/dynamic-texture/texture-data.ts +25 -4
- package/src/geometry/gpu-geometry.ts +8 -3
- package/src/index.ts +29 -4
- package/src/material/material-factory.ts +157 -0
- package/src/material/material.ts +254 -0
- package/src/model/model.ts +108 -40
- package/src/model/split-uniforms-and-bindings.ts +8 -6
- package/src/models/directional-light-model.ts +32 -0
- package/src/models/light-model-utils.ts +587 -0
- package/src/models/point-light-model.ts +31 -0
- package/src/models/spot-light-model.ts +32 -0
- package/src/modules/picking/color-picking.ts +123 -122
- package/src/modules/picking/index-picking.ts +36 -10
- package/src/modules/picking/legacy-color-picking.ts +8 -0
- package/src/modules/picking/picking-manager.ts +252 -50
- package/src/modules/picking/picking-uniforms.ts +38 -23
- package/src/modules/picking/picking.ts +22 -0
- package/src/shader-inputs.ts +165 -15
- package/src/utils/shader-module-utils.ts +65 -0
- package/dist/factories/pipeline-factory.d.ts +0 -39
- package/dist/factories/pipeline-factory.d.ts.map +0 -1
- package/dist/factories/pipeline-factory.js +0 -216
- package/dist/factories/pipeline-factory.js.map +0 -1
- package/dist/factories/shader-factory.d.ts +0 -19
- package/dist/factories/shader-factory.d.ts.map +0 -1
- package/dist/factories/shader-factory.js +0 -83
- package/dist/factories/shader-factory.js.map +0 -1
- package/dist/types.d.ts +0 -7
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -5
- package/dist/types.js.map +0 -1
- package/src/factories/pipeline-factory.ts +0 -266
- package/src/factories/shader-factory.ts +0 -101
- package/src/types.ts +0 -11
package/dist/dist.dev.js
CHANGED
|
@@ -70,6 +70,7 @@ var __exports__ = (() => {
|
|
|
70
70
|
ConeGeometry: () => ConeGeometry,
|
|
71
71
|
CubeGeometry: () => CubeGeometry,
|
|
72
72
|
CylinderGeometry: () => CylinderGeometry,
|
|
73
|
+
DirectionalLightModel: () => DirectionalLightModel,
|
|
73
74
|
DynamicTexture: () => DynamicTexture,
|
|
74
75
|
GPUGeometry: () => GPUGeometry,
|
|
75
76
|
Geometry: () => Geometry,
|
|
@@ -77,16 +78,18 @@ var __exports__ = (() => {
|
|
|
77
78
|
IcoSphereGeometry: () => IcoSphereGeometry,
|
|
78
79
|
KeyFrames: () => KeyFrames,
|
|
79
80
|
LegacyPickingManager: () => LegacyPickingManager,
|
|
81
|
+
Material: () => Material,
|
|
82
|
+
MaterialFactory: () => MaterialFactory,
|
|
80
83
|
Model: () => Model,
|
|
81
84
|
ModelNode: () => ModelNode,
|
|
82
85
|
PickingManager: () => PickingManager,
|
|
83
|
-
PipelineFactory: () => PipelineFactory,
|
|
84
86
|
PlaneGeometry: () => PlaneGeometry,
|
|
87
|
+
PointLightModel: () => PointLightModel,
|
|
85
88
|
ScenegraphNode: () => ScenegraphNode,
|
|
86
|
-
ShaderFactory: () => ShaderFactory,
|
|
87
89
|
ShaderInputs: () => ShaderInputs,
|
|
88
90
|
ShaderPassRenderer: () => ShaderPassRenderer,
|
|
89
91
|
SphereGeometry: () => SphereGeometry,
|
|
92
|
+
SpotLightModel: () => SpotLightModel,
|
|
90
93
|
Swap: () => Swap,
|
|
91
94
|
SwapBuffers: () => SwapBuffers,
|
|
92
95
|
SwapFramebuffers: () => SwapFramebuffers,
|
|
@@ -94,14 +97,19 @@ var __exports__ = (() => {
|
|
|
94
97
|
Timeline: () => Timeline,
|
|
95
98
|
TruncatedConeGeometry: () => TruncatedConeGeometry,
|
|
96
99
|
cancelAnimationFramePolyfill: () => cancelAnimationFramePolyfill,
|
|
97
|
-
colorPicking: () =>
|
|
98
|
-
indexPicking: () =>
|
|
100
|
+
colorPicking: () => picking,
|
|
101
|
+
indexPicking: () => picking2,
|
|
102
|
+
legacyColorPicking: () => legacyColorPicking,
|
|
99
103
|
loadImage: () => loadImage,
|
|
100
104
|
loadImageBitmap: () => loadImageBitmap,
|
|
101
105
|
makeAnimationLoop: () => makeAnimationLoop,
|
|
102
106
|
makeRandomGenerator: () => makeRandomGenerator,
|
|
107
|
+
picking: () => picking3,
|
|
103
108
|
requestAnimationFramePolyfill: () => requestAnimationFramePolyfill,
|
|
104
|
-
|
|
109
|
+
resolvePickingBackend: () => resolvePickingBackend,
|
|
110
|
+
resolvePickingMode: () => resolvePickingMode,
|
|
111
|
+
setPathPrefix: () => setPathPrefix,
|
|
112
|
+
supportsIndexPicking: () => supportsIndexPicking
|
|
105
113
|
});
|
|
106
114
|
__reExport(bundle_exports, __toESM(require_core(), 1));
|
|
107
115
|
|
|
@@ -579,6 +587,9 @@ var __exports__ = (() => {
|
|
|
579
587
|
this._initialized = true;
|
|
580
588
|
await this._initDevice();
|
|
581
589
|
this._initialize();
|
|
590
|
+
if (!this._running) {
|
|
591
|
+
return null;
|
|
592
|
+
}
|
|
582
593
|
await this.props.onInitialize(this._getAnimationProps());
|
|
583
594
|
}
|
|
584
595
|
if (!this._running) {
|
|
@@ -966,7 +977,7 @@ var __exports__ = (() => {
|
|
|
966
977
|
}
|
|
967
978
|
|
|
968
979
|
// src/model/model.ts
|
|
969
|
-
var
|
|
980
|
+
var import_core8 = __toESM(require_core(), 1);
|
|
970
981
|
var import_shadertools2 = __toESM(require_shadertools(), 1);
|
|
971
982
|
|
|
972
983
|
// src/geometry/gpu-geometry.ts
|
|
@@ -1069,300 +1080,19 @@ var __exports__ = (() => {
|
|
|
1069
1080
|
id: `${attributeName}-buffer`
|
|
1070
1081
|
});
|
|
1071
1082
|
const { value, size, normalized } = attribute;
|
|
1072
|
-
|
|
1083
|
+
if (size === void 0) {
|
|
1084
|
+
throw new Error(`Attribute ${attributeName} is missing a size`);
|
|
1085
|
+
}
|
|
1086
|
+
bufferLayout.push({
|
|
1087
|
+
name,
|
|
1088
|
+
format: import_core3.vertexFormatDecoder.getVertexFormatFromAttribute(value, size, normalized)
|
|
1089
|
+
});
|
|
1073
1090
|
}
|
|
1074
1091
|
}
|
|
1075
1092
|
const vertexCount = geometry._calculateVertexCount(geometry.attributes, geometry.indices);
|
|
1076
1093
|
return { attributes, bufferLayout, vertexCount };
|
|
1077
1094
|
}
|
|
1078
1095
|
|
|
1079
|
-
// src/factories/pipeline-factory.ts
|
|
1080
|
-
var import_core4 = __toESM(require_core(), 1);
|
|
1081
|
-
var _PipelineFactory = class {
|
|
1082
|
-
/** Get the singleton default pipeline factory for the specified device */
|
|
1083
|
-
static getDefaultPipelineFactory(device) {
|
|
1084
|
-
const moduleData = device.getModuleData("@luma.gl/engine");
|
|
1085
|
-
moduleData.defaultPipelineFactory ||= new _PipelineFactory(device);
|
|
1086
|
-
return moduleData.defaultPipelineFactory;
|
|
1087
|
-
}
|
|
1088
|
-
device;
|
|
1089
|
-
_hashCounter = 0;
|
|
1090
|
-
_hashes = {};
|
|
1091
|
-
_renderPipelineCache = {};
|
|
1092
|
-
_computePipelineCache = {};
|
|
1093
|
-
_sharedRenderPipelineCache = {};
|
|
1094
|
-
get [Symbol.toStringTag]() {
|
|
1095
|
-
return "PipelineFactory";
|
|
1096
|
-
}
|
|
1097
|
-
toString() {
|
|
1098
|
-
return `PipelineFactory(${this.device.id})`;
|
|
1099
|
-
}
|
|
1100
|
-
constructor(device) {
|
|
1101
|
-
this.device = device;
|
|
1102
|
-
}
|
|
1103
|
-
/** Return a RenderPipeline matching supplied props. Reuses an equivalent pipeline if already created. */
|
|
1104
|
-
createRenderPipeline(props) {
|
|
1105
|
-
if (!this.device.props._cachePipelines) {
|
|
1106
|
-
return this.device.createRenderPipeline(props);
|
|
1107
|
-
}
|
|
1108
|
-
const allProps = { ...import_core4.RenderPipeline.defaultProps, ...props };
|
|
1109
|
-
const cache = this._renderPipelineCache;
|
|
1110
|
-
const hash = this._hashRenderPipeline(allProps);
|
|
1111
|
-
let pipeline = cache[hash]?.resource;
|
|
1112
|
-
if (!pipeline) {
|
|
1113
|
-
const sharedRenderPipeline = this.device.type === "webgl" && this.device.props._sharePipelines ? this.createSharedRenderPipeline(allProps) : void 0;
|
|
1114
|
-
pipeline = this.device.createRenderPipeline({
|
|
1115
|
-
...allProps,
|
|
1116
|
-
id: allProps.id ? `${allProps.id}-cached` : uid("unnamed-cached"),
|
|
1117
|
-
_sharedRenderPipeline: sharedRenderPipeline
|
|
1118
|
-
});
|
|
1119
|
-
pipeline.hash = hash;
|
|
1120
|
-
cache[hash] = { resource: pipeline, useCount: 1 };
|
|
1121
|
-
if (this.device.props.debugFactories) {
|
|
1122
|
-
import_core4.log.log(3, `${this}: ${pipeline} created, count=${cache[hash].useCount}`)();
|
|
1123
|
-
}
|
|
1124
|
-
} else {
|
|
1125
|
-
cache[hash].useCount++;
|
|
1126
|
-
if (this.device.props.debugFactories) {
|
|
1127
|
-
import_core4.log.log(
|
|
1128
|
-
3,
|
|
1129
|
-
`${this}: ${cache[hash].resource} reused, count=${cache[hash].useCount}, (id=${props.id})`
|
|
1130
|
-
)();
|
|
1131
|
-
}
|
|
1132
|
-
}
|
|
1133
|
-
return pipeline;
|
|
1134
|
-
}
|
|
1135
|
-
/** Return a ComputePipeline matching supplied props. Reuses an equivalent pipeline if already created. */
|
|
1136
|
-
createComputePipeline(props) {
|
|
1137
|
-
if (!this.device.props._cachePipelines) {
|
|
1138
|
-
return this.device.createComputePipeline(props);
|
|
1139
|
-
}
|
|
1140
|
-
const allProps = { ...import_core4.ComputePipeline.defaultProps, ...props };
|
|
1141
|
-
const cache = this._computePipelineCache;
|
|
1142
|
-
const hash = this._hashComputePipeline(allProps);
|
|
1143
|
-
let pipeline = cache[hash]?.resource;
|
|
1144
|
-
if (!pipeline) {
|
|
1145
|
-
pipeline = this.device.createComputePipeline({
|
|
1146
|
-
...allProps,
|
|
1147
|
-
id: allProps.id ? `${allProps.id}-cached` : void 0
|
|
1148
|
-
});
|
|
1149
|
-
pipeline.hash = hash;
|
|
1150
|
-
cache[hash] = { resource: pipeline, useCount: 1 };
|
|
1151
|
-
if (this.device.props.debugFactories) {
|
|
1152
|
-
import_core4.log.log(3, `${this}: ${pipeline} created, count=${cache[hash].useCount}`)();
|
|
1153
|
-
}
|
|
1154
|
-
} else {
|
|
1155
|
-
cache[hash].useCount++;
|
|
1156
|
-
if (this.device.props.debugFactories) {
|
|
1157
|
-
import_core4.log.log(
|
|
1158
|
-
3,
|
|
1159
|
-
`${this}: ${cache[hash].resource} reused, count=${cache[hash].useCount}, (id=${props.id})`
|
|
1160
|
-
)();
|
|
1161
|
-
}
|
|
1162
|
-
}
|
|
1163
|
-
return pipeline;
|
|
1164
|
-
}
|
|
1165
|
-
release(pipeline) {
|
|
1166
|
-
if (!this.device.props._cachePipelines) {
|
|
1167
|
-
pipeline.destroy();
|
|
1168
|
-
return;
|
|
1169
|
-
}
|
|
1170
|
-
const cache = this._getCache(pipeline);
|
|
1171
|
-
const hash = pipeline.hash;
|
|
1172
|
-
cache[hash].useCount--;
|
|
1173
|
-
if (cache[hash].useCount === 0) {
|
|
1174
|
-
this._destroyPipeline(pipeline);
|
|
1175
|
-
if (this.device.props.debugFactories) {
|
|
1176
|
-
import_core4.log.log(3, `${this}: ${pipeline} released and destroyed`)();
|
|
1177
|
-
}
|
|
1178
|
-
} else if (cache[hash].useCount < 0) {
|
|
1179
|
-
import_core4.log.error(`${this}: ${pipeline} released, useCount < 0, resetting`)();
|
|
1180
|
-
cache[hash].useCount = 0;
|
|
1181
|
-
} else if (this.device.props.debugFactories) {
|
|
1182
|
-
import_core4.log.log(3, `${this}: ${pipeline} released, count=${cache[hash].useCount}`)();
|
|
1183
|
-
}
|
|
1184
|
-
}
|
|
1185
|
-
createSharedRenderPipeline(props) {
|
|
1186
|
-
const sharedPipelineHash = this._hashSharedRenderPipeline(props);
|
|
1187
|
-
let sharedCacheItem = this._sharedRenderPipelineCache[sharedPipelineHash];
|
|
1188
|
-
if (!sharedCacheItem) {
|
|
1189
|
-
const sharedRenderPipeline = this.device._createSharedRenderPipelineWebGL(props);
|
|
1190
|
-
sharedCacheItem = { resource: sharedRenderPipeline, useCount: 0 };
|
|
1191
|
-
this._sharedRenderPipelineCache[sharedPipelineHash] = sharedCacheItem;
|
|
1192
|
-
}
|
|
1193
|
-
sharedCacheItem.useCount++;
|
|
1194
|
-
return sharedCacheItem.resource;
|
|
1195
|
-
}
|
|
1196
|
-
releaseSharedRenderPipeline(pipeline) {
|
|
1197
|
-
if (!pipeline.sharedRenderPipeline) {
|
|
1198
|
-
return;
|
|
1199
|
-
}
|
|
1200
|
-
const sharedPipelineHash = this._hashSharedRenderPipeline(pipeline.sharedRenderPipeline.props);
|
|
1201
|
-
const sharedCacheItem = this._sharedRenderPipelineCache[sharedPipelineHash];
|
|
1202
|
-
if (!sharedCacheItem) {
|
|
1203
|
-
return;
|
|
1204
|
-
}
|
|
1205
|
-
sharedCacheItem.useCount--;
|
|
1206
|
-
if (sharedCacheItem.useCount === 0) {
|
|
1207
|
-
sharedCacheItem.resource.destroy();
|
|
1208
|
-
delete this._sharedRenderPipelineCache[sharedPipelineHash];
|
|
1209
|
-
}
|
|
1210
|
-
}
|
|
1211
|
-
// PRIVATE
|
|
1212
|
-
/** Destroy a cached pipeline, removing it from the cache if configured to do so. */
|
|
1213
|
-
_destroyPipeline(pipeline) {
|
|
1214
|
-
const cache = this._getCache(pipeline);
|
|
1215
|
-
if (!this.device.props._destroyPipelines) {
|
|
1216
|
-
return false;
|
|
1217
|
-
}
|
|
1218
|
-
delete cache[pipeline.hash];
|
|
1219
|
-
pipeline.destroy();
|
|
1220
|
-
if (pipeline instanceof import_core4.RenderPipeline) {
|
|
1221
|
-
this.releaseSharedRenderPipeline(pipeline);
|
|
1222
|
-
}
|
|
1223
|
-
return true;
|
|
1224
|
-
}
|
|
1225
|
-
/** Get the appropriate cache for the type of pipeline */
|
|
1226
|
-
_getCache(pipeline) {
|
|
1227
|
-
let cache;
|
|
1228
|
-
if (pipeline instanceof import_core4.ComputePipeline) {
|
|
1229
|
-
cache = this._computePipelineCache;
|
|
1230
|
-
}
|
|
1231
|
-
if (pipeline instanceof import_core4.RenderPipeline) {
|
|
1232
|
-
cache = this._renderPipelineCache;
|
|
1233
|
-
}
|
|
1234
|
-
if (!cache) {
|
|
1235
|
-
throw new Error(`${this}`);
|
|
1236
|
-
}
|
|
1237
|
-
if (!cache[pipeline.hash]) {
|
|
1238
|
-
throw new Error(`${this}: ${pipeline} matched incorrect entry`);
|
|
1239
|
-
}
|
|
1240
|
-
return cache;
|
|
1241
|
-
}
|
|
1242
|
-
/** Calculate a hash based on all the inputs for a compute pipeline */
|
|
1243
|
-
_hashComputePipeline(props) {
|
|
1244
|
-
const { type } = this.device;
|
|
1245
|
-
const shaderHash = this._getHash(props.shader.source);
|
|
1246
|
-
return `${type}/C/${shaderHash}`;
|
|
1247
|
-
}
|
|
1248
|
-
/** Calculate a hash based on all the inputs for a render pipeline */
|
|
1249
|
-
_hashRenderPipeline(props) {
|
|
1250
|
-
const vsHash = props.vs ? this._getHash(props.vs.source) : 0;
|
|
1251
|
-
const fsHash = props.fs ? this._getHash(props.fs.source) : 0;
|
|
1252
|
-
const varyingHash = this._getWebGLVaryingHash(props);
|
|
1253
|
-
const bufferLayoutHash = this._getHash(JSON.stringify(props.bufferLayout));
|
|
1254
|
-
const { type } = this.device;
|
|
1255
|
-
switch (type) {
|
|
1256
|
-
case "webgl":
|
|
1257
|
-
const webglParameterHash = this._getHash(JSON.stringify(props.parameters));
|
|
1258
|
-
return `${type}/R/${vsHash}/${fsHash}V${varyingHash}T${props.topology}P${webglParameterHash}BL${bufferLayoutHash}`;
|
|
1259
|
-
case "webgpu":
|
|
1260
|
-
default:
|
|
1261
|
-
const parameterHash = this._getHash(JSON.stringify(props.parameters));
|
|
1262
|
-
return `${type}/R/${vsHash}/${fsHash}V${varyingHash}T${props.topology}P${parameterHash}BL${bufferLayoutHash}`;
|
|
1263
|
-
}
|
|
1264
|
-
}
|
|
1265
|
-
_hashSharedRenderPipeline(props) {
|
|
1266
|
-
const vsHash = props.vs ? this._getHash(props.vs.source) : 0;
|
|
1267
|
-
const fsHash = props.fs ? this._getHash(props.fs.source) : 0;
|
|
1268
|
-
const varyingHash = this._getWebGLVaryingHash(props);
|
|
1269
|
-
return `webgl/S/${vsHash}/${fsHash}V${varyingHash}`;
|
|
1270
|
-
}
|
|
1271
|
-
_getHash(key) {
|
|
1272
|
-
if (this._hashes[key] === void 0) {
|
|
1273
|
-
this._hashes[key] = this._hashCounter++;
|
|
1274
|
-
}
|
|
1275
|
-
return this._hashes[key];
|
|
1276
|
-
}
|
|
1277
|
-
_getWebGLVaryingHash(props) {
|
|
1278
|
-
const { varyings = [], bufferMode = null } = props;
|
|
1279
|
-
return this._getHash(JSON.stringify({ varyings, bufferMode }));
|
|
1280
|
-
}
|
|
1281
|
-
};
|
|
1282
|
-
var PipelineFactory = _PipelineFactory;
|
|
1283
|
-
__publicField(PipelineFactory, "defaultProps", { ...import_core4.RenderPipeline.defaultProps });
|
|
1284
|
-
|
|
1285
|
-
// src/factories/shader-factory.ts
|
|
1286
|
-
var import_core5 = __toESM(require_core(), 1);
|
|
1287
|
-
var _ShaderFactory = class {
|
|
1288
|
-
/** Returns the default ShaderFactory for the given {@link Device}, creating one if necessary. */
|
|
1289
|
-
static getDefaultShaderFactory(device) {
|
|
1290
|
-
const moduleData = device.getModuleData("@luma.gl/engine");
|
|
1291
|
-
moduleData.defaultShaderFactory ||= new _ShaderFactory(device);
|
|
1292
|
-
return moduleData.defaultShaderFactory;
|
|
1293
|
-
}
|
|
1294
|
-
device;
|
|
1295
|
-
_cache = {};
|
|
1296
|
-
get [Symbol.toStringTag]() {
|
|
1297
|
-
return "ShaderFactory";
|
|
1298
|
-
}
|
|
1299
|
-
toString() {
|
|
1300
|
-
return `${this[Symbol.toStringTag]}(${this.device.id})`;
|
|
1301
|
-
}
|
|
1302
|
-
/** @internal */
|
|
1303
|
-
constructor(device) {
|
|
1304
|
-
this.device = device;
|
|
1305
|
-
}
|
|
1306
|
-
/** Requests a {@link Shader} from the cache, creating a new Shader only if necessary. */
|
|
1307
|
-
createShader(props) {
|
|
1308
|
-
if (!this.device.props._cacheShaders) {
|
|
1309
|
-
return this.device.createShader(props);
|
|
1310
|
-
}
|
|
1311
|
-
const key = this._hashShader(props);
|
|
1312
|
-
let cacheEntry = this._cache[key];
|
|
1313
|
-
if (!cacheEntry) {
|
|
1314
|
-
const resource = this.device.createShader({
|
|
1315
|
-
...props,
|
|
1316
|
-
id: props.id ? `${props.id}-cached` : void 0
|
|
1317
|
-
});
|
|
1318
|
-
this._cache[key] = cacheEntry = { resource, useCount: 1 };
|
|
1319
|
-
if (this.device.props.debugFactories) {
|
|
1320
|
-
import_core5.log.log(3, `${this}: Created new shader ${resource.id}`)();
|
|
1321
|
-
}
|
|
1322
|
-
} else {
|
|
1323
|
-
cacheEntry.useCount++;
|
|
1324
|
-
if (this.device.props.debugFactories) {
|
|
1325
|
-
import_core5.log.log(
|
|
1326
|
-
3,
|
|
1327
|
-
`${this}: Reusing shader ${cacheEntry.resource.id} count=${cacheEntry.useCount}`
|
|
1328
|
-
)();
|
|
1329
|
-
}
|
|
1330
|
-
}
|
|
1331
|
-
return cacheEntry.resource;
|
|
1332
|
-
}
|
|
1333
|
-
/** Releases a previously-requested {@link Shader}, destroying it if no users remain. */
|
|
1334
|
-
release(shader) {
|
|
1335
|
-
if (!this.device.props._cacheShaders) {
|
|
1336
|
-
shader.destroy();
|
|
1337
|
-
return;
|
|
1338
|
-
}
|
|
1339
|
-
const key = this._hashShader(shader);
|
|
1340
|
-
const cacheEntry = this._cache[key];
|
|
1341
|
-
if (cacheEntry) {
|
|
1342
|
-
cacheEntry.useCount--;
|
|
1343
|
-
if (cacheEntry.useCount === 0) {
|
|
1344
|
-
if (this.device.props._destroyShaders) {
|
|
1345
|
-
delete this._cache[key];
|
|
1346
|
-
cacheEntry.resource.destroy();
|
|
1347
|
-
if (this.device.props.debugFactories) {
|
|
1348
|
-
import_core5.log.log(3, `${this}: Releasing shader ${shader.id}, destroyed`)();
|
|
1349
|
-
}
|
|
1350
|
-
}
|
|
1351
|
-
} else if (cacheEntry.useCount < 0) {
|
|
1352
|
-
throw new Error(`ShaderFactory: Shader ${shader.id} released too many times`);
|
|
1353
|
-
} else if (this.device.props.debugFactories) {
|
|
1354
|
-
import_core5.log.log(3, `${this}: Releasing shader ${shader.id} count=${cacheEntry.useCount}`)();
|
|
1355
|
-
}
|
|
1356
|
-
}
|
|
1357
|
-
}
|
|
1358
|
-
// PRIVATE
|
|
1359
|
-
_hashShader(value) {
|
|
1360
|
-
return `${value.stage}:${value.source}`;
|
|
1361
|
-
}
|
|
1362
|
-
};
|
|
1363
|
-
var ShaderFactory = _ShaderFactory;
|
|
1364
|
-
__publicField(ShaderFactory, "defaultProps", { ...import_core5.Shader.defaultProps });
|
|
1365
|
-
|
|
1366
1096
|
// src/debug/debug-shader-layout.ts
|
|
1367
1097
|
function getDebugTableForShaderLayout(layout, name) {
|
|
1368
1098
|
const table = {};
|
|
@@ -1469,7 +1199,7 @@ var __exports__ = (() => {
|
|
|
1469
1199
|
}
|
|
1470
1200
|
|
|
1471
1201
|
// src/utils/buffer-layout-helper.ts
|
|
1472
|
-
var
|
|
1202
|
+
var import_core4 = __toESM(require_core(), 1);
|
|
1473
1203
|
var BufferLayoutHelper = class {
|
|
1474
1204
|
bufferLayouts;
|
|
1475
1205
|
constructor(bufferLayouts) {
|
|
@@ -1497,7 +1227,7 @@ var __exports__ = (() => {
|
|
|
1497
1227
|
getBufferIndex(bufferName) {
|
|
1498
1228
|
const bufferIndex = this.bufferLayouts.findIndex((layout) => layout.name === bufferName);
|
|
1499
1229
|
if (bufferIndex === -1) {
|
|
1500
|
-
|
|
1230
|
+
import_core4.log.warn(`BufferLayout: Missing buffer for "${bufferName}".`)();
|
|
1501
1231
|
}
|
|
1502
1232
|
return bufferIndex;
|
|
1503
1233
|
}
|
|
@@ -1529,8 +1259,51 @@ var __exports__ = (() => {
|
|
|
1529
1259
|
return sortedLayout;
|
|
1530
1260
|
}
|
|
1531
1261
|
|
|
1262
|
+
// src/utils/shader-module-utils.ts
|
|
1263
|
+
function mergeShaderModuleBindingsIntoLayout(shaderLayout, modules) {
|
|
1264
|
+
if (!shaderLayout || !modules.some((module) => module.bindingLayout?.length)) {
|
|
1265
|
+
return shaderLayout;
|
|
1266
|
+
}
|
|
1267
|
+
const mergedLayout = {
|
|
1268
|
+
...shaderLayout,
|
|
1269
|
+
bindings: shaderLayout.bindings.map((binding) => ({ ...binding }))
|
|
1270
|
+
};
|
|
1271
|
+
if ("attributes" in (shaderLayout || {})) {
|
|
1272
|
+
mergedLayout.attributes = shaderLayout?.attributes || [];
|
|
1273
|
+
}
|
|
1274
|
+
for (const module of modules) {
|
|
1275
|
+
for (const bindingLayout of module.bindingLayout || []) {
|
|
1276
|
+
for (const relatedBindingName of getRelatedBindingNames(bindingLayout.name)) {
|
|
1277
|
+
const binding = mergedLayout.bindings.find(
|
|
1278
|
+
(candidate) => candidate.name === relatedBindingName
|
|
1279
|
+
);
|
|
1280
|
+
if (binding?.group === 0) {
|
|
1281
|
+
binding.group = bindingLayout.group;
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
return mergedLayout;
|
|
1287
|
+
}
|
|
1288
|
+
function shaderModuleHasUniforms(module) {
|
|
1289
|
+
return Boolean(module.uniformTypes && !isObjectEmpty(module.uniformTypes));
|
|
1290
|
+
}
|
|
1291
|
+
function getRelatedBindingNames(bindingName) {
|
|
1292
|
+
const bindingNames = /* @__PURE__ */ new Set([bindingName, `${bindingName}Uniforms`]);
|
|
1293
|
+
if (!bindingName.endsWith("Uniforms")) {
|
|
1294
|
+
bindingNames.add(`${bindingName}Sampler`);
|
|
1295
|
+
}
|
|
1296
|
+
return [...bindingNames];
|
|
1297
|
+
}
|
|
1298
|
+
function isObjectEmpty(obj) {
|
|
1299
|
+
for (const key in obj) {
|
|
1300
|
+
return false;
|
|
1301
|
+
}
|
|
1302
|
+
return true;
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1532
1305
|
// src/shader-inputs.ts
|
|
1533
|
-
var
|
|
1306
|
+
var import_core5 = __toESM(require_core(), 1);
|
|
1534
1307
|
var import_shadertools = __toESM(require_shadertools(), 1);
|
|
1535
1308
|
|
|
1536
1309
|
// ../../node_modules/@math.gl/types/dist/is-array.js
|
|
@@ -1551,11 +1324,11 @@ var __exports__ = (() => {
|
|
|
1551
1324
|
function isUniformValue(value) {
|
|
1552
1325
|
return isNumericArray(value) || typeof value === "number" || typeof value === "boolean";
|
|
1553
1326
|
}
|
|
1554
|
-
function splitUniformsAndBindings(uniforms) {
|
|
1327
|
+
function splitUniformsAndBindings(uniforms, uniformTypes2 = {}) {
|
|
1555
1328
|
const result = { bindings: {}, uniforms: {} };
|
|
1556
1329
|
Object.keys(uniforms).forEach((name) => {
|
|
1557
1330
|
const uniform = uniforms[name];
|
|
1558
|
-
if (isUniformValue(uniform)) {
|
|
1331
|
+
if (Object.prototype.hasOwnProperty.call(uniformTypes2, name) || isUniformValue(uniform)) {
|
|
1559
1332
|
result.uniforms[name] = uniform;
|
|
1560
1333
|
} else {
|
|
1561
1334
|
result.bindings[name] = uniform;
|
|
@@ -1588,19 +1361,22 @@ var __exports__ = (() => {
|
|
|
1588
1361
|
constructor(modules, options) {
|
|
1589
1362
|
Object.assign(this.options, options);
|
|
1590
1363
|
const resolvedModules = (0, import_shadertools.getShaderModuleDependencies)(
|
|
1591
|
-
Object.values(modules).filter(
|
|
1364
|
+
Object.values(modules).filter(isShaderInputsModuleWithDependencies)
|
|
1592
1365
|
);
|
|
1593
1366
|
for (const resolvedModule of resolvedModules) {
|
|
1594
1367
|
modules[resolvedModule.name] = resolvedModule;
|
|
1595
1368
|
}
|
|
1596
|
-
|
|
1369
|
+
import_core5.log.log(1, "Creating ShaderInputs with modules", Object.keys(modules))();
|
|
1597
1370
|
this.modules = modules;
|
|
1598
1371
|
this.moduleUniforms = {};
|
|
1599
1372
|
this.moduleBindings = {};
|
|
1600
1373
|
for (const [name, module] of Object.entries(modules)) {
|
|
1374
|
+
if (!module) {
|
|
1375
|
+
continue;
|
|
1376
|
+
}
|
|
1601
1377
|
this._addModule(module);
|
|
1602
1378
|
if (module.name && name !== module.name && !this.options.disableWarnings) {
|
|
1603
|
-
|
|
1379
|
+
import_core5.log.warn(`Module name: ${name} vs ${module.name}`)();
|
|
1604
1380
|
}
|
|
1605
1381
|
}
|
|
1606
1382
|
}
|
|
@@ -1617,15 +1393,22 @@ var __exports__ = (() => {
|
|
|
1617
1393
|
const module = this.modules[moduleName];
|
|
1618
1394
|
if (!module) {
|
|
1619
1395
|
if (!this.options.disableWarnings) {
|
|
1620
|
-
|
|
1396
|
+
import_core5.log.warn(`Module ${name} not found`)();
|
|
1621
1397
|
}
|
|
1622
1398
|
continue;
|
|
1623
1399
|
}
|
|
1624
1400
|
const oldUniforms = this.moduleUniforms[moduleName];
|
|
1625
1401
|
const oldBindings = this.moduleBindings[moduleName];
|
|
1626
1402
|
const uniformsAndBindings = module.getUniforms?.(moduleProps, oldUniforms) || moduleProps;
|
|
1627
|
-
const { uniforms, bindings } = splitUniformsAndBindings(
|
|
1628
|
-
|
|
1403
|
+
const { uniforms, bindings } = splitUniformsAndBindings(
|
|
1404
|
+
uniformsAndBindings,
|
|
1405
|
+
module.uniformTypes
|
|
1406
|
+
);
|
|
1407
|
+
this.moduleUniforms[moduleName] = mergeModuleUniforms(
|
|
1408
|
+
oldUniforms,
|
|
1409
|
+
uniforms,
|
|
1410
|
+
module.uniformTypes
|
|
1411
|
+
);
|
|
1629
1412
|
this.moduleBindings[moduleName] = { ...oldBindings, ...bindings };
|
|
1630
1413
|
}
|
|
1631
1414
|
}
|
|
@@ -1664,16 +1447,99 @@ var __exports__ = (() => {
|
|
|
1664
1447
|
}
|
|
1665
1448
|
_addModule(module) {
|
|
1666
1449
|
const moduleName = module.name;
|
|
1667
|
-
this.moduleUniforms[moduleName] =
|
|
1450
|
+
this.moduleUniforms[moduleName] = mergeModuleUniforms(
|
|
1451
|
+
{},
|
|
1452
|
+
module.defaultUniforms || {},
|
|
1453
|
+
module.uniformTypes
|
|
1454
|
+
);
|
|
1668
1455
|
this.moduleBindings[moduleName] = {};
|
|
1669
1456
|
}
|
|
1670
1457
|
};
|
|
1458
|
+
function mergeModuleUniforms(currentUniforms = {}, nextUniforms = {}, uniformTypes2 = {}) {
|
|
1459
|
+
const mergedUniforms = { ...currentUniforms };
|
|
1460
|
+
for (const [key, value] of Object.entries(nextUniforms)) {
|
|
1461
|
+
if (value === void 0) {
|
|
1462
|
+
continue;
|
|
1463
|
+
}
|
|
1464
|
+
mergedUniforms[key] = mergeModuleUniformValue(currentUniforms[key], value, uniformTypes2[key]);
|
|
1465
|
+
}
|
|
1466
|
+
return mergedUniforms;
|
|
1467
|
+
}
|
|
1468
|
+
function mergeModuleUniformValue(currentValue, nextValue, uniformType) {
|
|
1469
|
+
if (!uniformType || typeof uniformType === "string") {
|
|
1470
|
+
return cloneModuleUniformValue(nextValue);
|
|
1471
|
+
}
|
|
1472
|
+
if (Array.isArray(uniformType)) {
|
|
1473
|
+
if (isPackedUniformArrayValue(nextValue) || !Array.isArray(nextValue)) {
|
|
1474
|
+
return cloneModuleUniformValue(nextValue);
|
|
1475
|
+
}
|
|
1476
|
+
const currentArray = Array.isArray(currentValue) && !isPackedUniformArrayValue(currentValue) ? [...currentValue] : [];
|
|
1477
|
+
const mergedArray = currentArray.slice();
|
|
1478
|
+
for (let index = 0; index < nextValue.length; index++) {
|
|
1479
|
+
const elementValue = nextValue[index];
|
|
1480
|
+
if (elementValue === void 0) {
|
|
1481
|
+
continue;
|
|
1482
|
+
}
|
|
1483
|
+
mergedArray[index] = mergeModuleUniformValue(
|
|
1484
|
+
currentArray[index],
|
|
1485
|
+
elementValue,
|
|
1486
|
+
uniformType[0]
|
|
1487
|
+
);
|
|
1488
|
+
}
|
|
1489
|
+
return mergedArray;
|
|
1490
|
+
}
|
|
1491
|
+
if (!isPlainUniformObject(nextValue)) {
|
|
1492
|
+
return cloneModuleUniformValue(nextValue);
|
|
1493
|
+
}
|
|
1494
|
+
const uniformStruct = uniformType;
|
|
1495
|
+
const currentObject = isPlainUniformObject(currentValue) ? currentValue : {};
|
|
1496
|
+
const mergedObject = { ...currentObject };
|
|
1497
|
+
for (const [key, value] of Object.entries(nextValue)) {
|
|
1498
|
+
if (value === void 0) {
|
|
1499
|
+
continue;
|
|
1500
|
+
}
|
|
1501
|
+
mergedObject[key] = mergeModuleUniformValue(currentObject[key], value, uniformStruct[key]);
|
|
1502
|
+
}
|
|
1503
|
+
return mergedObject;
|
|
1504
|
+
}
|
|
1505
|
+
function cloneModuleUniformValue(value) {
|
|
1506
|
+
if (ArrayBuffer.isView(value)) {
|
|
1507
|
+
return Array.prototype.slice.call(value);
|
|
1508
|
+
}
|
|
1509
|
+
if (Array.isArray(value)) {
|
|
1510
|
+
if (isPackedUniformArrayValue(value)) {
|
|
1511
|
+
return value.slice();
|
|
1512
|
+
}
|
|
1513
|
+
const compositeArray = value;
|
|
1514
|
+
return compositeArray.map(
|
|
1515
|
+
(element) => element === void 0 ? void 0 : cloneModuleUniformValue(element)
|
|
1516
|
+
);
|
|
1517
|
+
}
|
|
1518
|
+
if (isPlainUniformObject(value)) {
|
|
1519
|
+
return Object.fromEntries(
|
|
1520
|
+
Object.entries(value).map(([key, nestedValue]) => [
|
|
1521
|
+
key,
|
|
1522
|
+
nestedValue === void 0 ? void 0 : cloneModuleUniformValue(nestedValue)
|
|
1523
|
+
])
|
|
1524
|
+
);
|
|
1525
|
+
}
|
|
1526
|
+
return value;
|
|
1527
|
+
}
|
|
1528
|
+
function isPackedUniformArrayValue(value) {
|
|
1529
|
+
return ArrayBuffer.isView(value) || Array.isArray(value) && (value.length === 0 || typeof value[0] === "number");
|
|
1530
|
+
}
|
|
1531
|
+
function isPlainUniformObject(value) {
|
|
1532
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value) && !ArrayBuffer.isView(value);
|
|
1533
|
+
}
|
|
1534
|
+
function isShaderInputsModuleWithDependencies(module) {
|
|
1535
|
+
return Boolean(module?.dependencies);
|
|
1536
|
+
}
|
|
1671
1537
|
|
|
1672
1538
|
// src/dynamic-texture/dynamic-texture.ts
|
|
1673
|
-
var
|
|
1539
|
+
var import_core7 = __toESM(require_core(), 1);
|
|
1674
1540
|
|
|
1675
1541
|
// src/dynamic-texture/texture-data.ts
|
|
1676
|
-
var
|
|
1542
|
+
var import_core6 = __toESM(require_core(), 1);
|
|
1677
1543
|
var TEXTURE_CUBE_FACE_MAP = { "+X": 0, "-X": 1, "+Y": 2, "-Y": 3, "+Z": 4, "-Z": 5 };
|
|
1678
1544
|
function getFirstMipLevel(layer) {
|
|
1679
1545
|
if (!layer)
|
|
@@ -1727,8 +1593,8 @@ var __exports__ = (() => {
|
|
|
1727
1593
|
}
|
|
1728
1594
|
}
|
|
1729
1595
|
function getTextureMipLevelSize(data) {
|
|
1730
|
-
if ((0,
|
|
1731
|
-
return (0,
|
|
1596
|
+
if ((0, import_core6.isExternalImage)(data)) {
|
|
1597
|
+
return (0, import_core6.getExternalImageSize)(data);
|
|
1732
1598
|
}
|
|
1733
1599
|
if (typeof data === "object" && "width" in data && "height" in data) {
|
|
1734
1600
|
return { width: data.width, height: data.height };
|
|
@@ -1738,6 +1604,9 @@ var __exports__ = (() => {
|
|
|
1738
1604
|
function isTextureImageData(data) {
|
|
1739
1605
|
return typeof data === "object" && data !== null && "data" in data && "width" in data && "height" in data;
|
|
1740
1606
|
}
|
|
1607
|
+
function isTypedArrayMipLevelData(data) {
|
|
1608
|
+
return ArrayBuffer.isView(data);
|
|
1609
|
+
}
|
|
1741
1610
|
function resolveTextureImageFormat(data) {
|
|
1742
1611
|
const { textureFormat, format } = data;
|
|
1743
1612
|
if (textureFormat && format && textureFormat !== format) {
|
|
@@ -1762,13 +1631,13 @@ var __exports__ = (() => {
|
|
|
1762
1631
|
function _normalizeTexture2DData(data) {
|
|
1763
1632
|
return Array.isArray(data) ? data : [data];
|
|
1764
1633
|
}
|
|
1765
|
-
function getTexture2DSubresources(slice, lodData) {
|
|
1634
|
+
function getTexture2DSubresources(slice, lodData, baseLevelSize, textureFormat) {
|
|
1766
1635
|
const lodArray = _normalizeTexture2DData(lodData);
|
|
1767
1636
|
const z = slice;
|
|
1768
1637
|
const subresources = [];
|
|
1769
1638
|
for (let mipLevel = 0; mipLevel < lodArray.length; mipLevel++) {
|
|
1770
1639
|
const imageData = lodArray[mipLevel];
|
|
1771
|
-
if ((0,
|
|
1640
|
+
if ((0, import_core6.isExternalImage)(imageData)) {
|
|
1772
1641
|
subresources.push({
|
|
1773
1642
|
type: "external-image",
|
|
1774
1643
|
image: imageData,
|
|
@@ -1783,6 +1652,19 @@ var __exports__ = (() => {
|
|
|
1783
1652
|
z,
|
|
1784
1653
|
mipLevel
|
|
1785
1654
|
});
|
|
1655
|
+
} else if (isTypedArrayMipLevelData(imageData) && baseLevelSize) {
|
|
1656
|
+
subresources.push({
|
|
1657
|
+
type: "texture-data",
|
|
1658
|
+
data: {
|
|
1659
|
+
data: imageData,
|
|
1660
|
+
width: Math.max(1, baseLevelSize.width >> mipLevel),
|
|
1661
|
+
height: Math.max(1, baseLevelSize.height >> mipLevel),
|
|
1662
|
+
...textureFormat ? { format: textureFormat } : {}
|
|
1663
|
+
},
|
|
1664
|
+
textureFormat,
|
|
1665
|
+
z,
|
|
1666
|
+
mipLevel
|
|
1667
|
+
});
|
|
1786
1668
|
} else {
|
|
1787
1669
|
throw new Error("Unsupported 2D mip-level payload");
|
|
1788
1670
|
}
|
|
@@ -1878,7 +1760,12 @@ var __exports__ = (() => {
|
|
|
1878
1760
|
try {
|
|
1879
1761
|
const propsWithSyncData = await this._loadAllData(originalPropsWithAsyncData);
|
|
1880
1762
|
this._checkNotDestroyed();
|
|
1881
|
-
const subresources = propsWithSyncData.data ? getTextureSubresources(
|
|
1763
|
+
const subresources = propsWithSyncData.data ? getTextureSubresources({
|
|
1764
|
+
...propsWithSyncData,
|
|
1765
|
+
width: originalPropsWithAsyncData.width,
|
|
1766
|
+
height: originalPropsWithAsyncData.height,
|
|
1767
|
+
format: originalPropsWithAsyncData.format
|
|
1768
|
+
}) : [];
|
|
1882
1769
|
const userProvidedFormat = "format" in originalPropsWithAsyncData && originalPropsWithAsyncData.format !== void 0;
|
|
1883
1770
|
const userProvidedUsage = "usage" in originalPropsWithAsyncData && originalPropsWithAsyncData.usage !== void 0;
|
|
1884
1771
|
const deduceSize = () => {
|
|
@@ -1908,11 +1795,11 @@ var __exports__ = (() => {
|
|
|
1908
1795
|
data: void 0
|
|
1909
1796
|
};
|
|
1910
1797
|
if (this.device.isTextureFormatCompressed(resolvedFormat) && !userProvidedUsage) {
|
|
1911
|
-
baseTextureProps.usage =
|
|
1798
|
+
baseTextureProps.usage = import_core7.Texture.SAMPLE | import_core7.Texture.COPY_DST;
|
|
1912
1799
|
}
|
|
1913
1800
|
const shouldGenerateMipmaps = this.props.mipmaps && !textureData.hasExplicitMipChain && !this.device.isTextureFormatCompressed(resolvedFormat);
|
|
1914
1801
|
if (this.device.type === "webgpu" && shouldGenerateMipmaps) {
|
|
1915
|
-
const requiredUsage = this.props.dimension === "3d" ?
|
|
1802
|
+
const requiredUsage = this.props.dimension === "3d" ? import_core7.Texture.SAMPLE | import_core7.Texture.STORAGE | import_core7.Texture.COPY_DST | import_core7.Texture.COPY_SRC : import_core7.Texture.SAMPLE | import_core7.Texture.RENDER | import_core7.Texture.COPY_DST | import_core7.Texture.COPY_SRC;
|
|
1916
1803
|
baseTextureProps.usage |= requiredUsage;
|
|
1917
1804
|
}
|
|
1918
1805
|
const maxMips = this.device.getMipLevelCount(baseTextureProps.width, baseTextureProps.height);
|
|
@@ -1925,18 +1812,17 @@ var __exports__ = (() => {
|
|
|
1925
1812
|
this._setTextureSubresources(textureData.subresources);
|
|
1926
1813
|
}
|
|
1927
1814
|
if (this.props.mipmaps && !textureData.hasExplicitMipChain && !shouldGenerateMipmaps) {
|
|
1928
|
-
|
|
1815
|
+
import_core7.log.warn(`${this} skipping auto-generated mipmaps for compressed texture format`)();
|
|
1929
1816
|
}
|
|
1930
1817
|
if (shouldGenerateMipmaps) {
|
|
1931
1818
|
this.generateMipmaps();
|
|
1932
1819
|
}
|
|
1933
1820
|
this.isReady = true;
|
|
1934
1821
|
this.resolveReady(this.texture);
|
|
1935
|
-
|
|
1822
|
+
import_core7.log.info(0, `${this} created`)();
|
|
1936
1823
|
} catch (e) {
|
|
1937
1824
|
const err = e instanceof Error ? e : new Error(String(e));
|
|
1938
1825
|
this.rejectReady(err);
|
|
1939
|
-
throw err;
|
|
1940
1826
|
}
|
|
1941
1827
|
}
|
|
1942
1828
|
destroy() {
|
|
@@ -1954,16 +1840,60 @@ var __exports__ = (() => {
|
|
|
1954
1840
|
} else if (this.device.type === "webgpu") {
|
|
1955
1841
|
this.device.generateMipmapsWebGPU(this.texture);
|
|
1956
1842
|
} else {
|
|
1957
|
-
|
|
1843
|
+
import_core7.log.warn(`${this} mipmaps not supported on ${this.device.type}`);
|
|
1958
1844
|
}
|
|
1959
1845
|
}
|
|
1960
1846
|
/** Set sampler or create one from props */
|
|
1961
1847
|
setSampler(sampler = {}) {
|
|
1962
1848
|
this._checkReady();
|
|
1963
|
-
const s = sampler instanceof
|
|
1849
|
+
const s = sampler instanceof import_core7.Sampler ? sampler : this.device.createSampler(sampler);
|
|
1964
1850
|
this.texture.setSampler(s);
|
|
1965
1851
|
this._sampler = s;
|
|
1966
1852
|
}
|
|
1853
|
+
/**
|
|
1854
|
+
* Copies texture contents into a GPU buffer and waits until the copy is complete.
|
|
1855
|
+
* The caller owns the returned buffer and must destroy it when finished.
|
|
1856
|
+
*/
|
|
1857
|
+
async readBuffer(options = {}) {
|
|
1858
|
+
if (!this.isReady) {
|
|
1859
|
+
await this.ready;
|
|
1860
|
+
}
|
|
1861
|
+
const width = options.width ?? this.texture.width;
|
|
1862
|
+
const height = options.height ?? this.texture.height;
|
|
1863
|
+
const depthOrArrayLayers = options.depthOrArrayLayers ?? this.texture.depth;
|
|
1864
|
+
const layout = this.texture.computeMemoryLayout({ width, height, depthOrArrayLayers });
|
|
1865
|
+
const buffer = this.device.createBuffer({
|
|
1866
|
+
byteLength: layout.byteLength,
|
|
1867
|
+
usage: import_core7.Buffer.COPY_DST | import_core7.Buffer.MAP_READ
|
|
1868
|
+
});
|
|
1869
|
+
this.texture.readBuffer(
|
|
1870
|
+
{
|
|
1871
|
+
...options,
|
|
1872
|
+
width,
|
|
1873
|
+
height,
|
|
1874
|
+
depthOrArrayLayers
|
|
1875
|
+
},
|
|
1876
|
+
buffer
|
|
1877
|
+
);
|
|
1878
|
+
const fence = this.device.createFence();
|
|
1879
|
+
await fence.signaled;
|
|
1880
|
+
fence.destroy();
|
|
1881
|
+
return buffer;
|
|
1882
|
+
}
|
|
1883
|
+
/** Reads texture contents back to CPU memory. */
|
|
1884
|
+
async readAsync(options = {}) {
|
|
1885
|
+
if (!this.isReady) {
|
|
1886
|
+
await this.ready;
|
|
1887
|
+
}
|
|
1888
|
+
const width = options.width ?? this.texture.width;
|
|
1889
|
+
const height = options.height ?? this.texture.height;
|
|
1890
|
+
const depthOrArrayLayers = options.depthOrArrayLayers ?? this.texture.depth;
|
|
1891
|
+
const layout = this.texture.computeMemoryLayout({ width, height, depthOrArrayLayers });
|
|
1892
|
+
const buffer = await this.readBuffer(options);
|
|
1893
|
+
const data = await buffer.readAsync(0, layout.byteLength);
|
|
1894
|
+
buffer.destroy();
|
|
1895
|
+
return data.buffer;
|
|
1896
|
+
}
|
|
1967
1897
|
/**
|
|
1968
1898
|
* Resize by cloning the underlying immutable texture.
|
|
1969
1899
|
* Does not copy contents; caller may need to re-upload and/or regenerate mips.
|
|
@@ -1978,7 +1908,7 @@ var __exports__ = (() => {
|
|
|
1978
1908
|
this._sampler = this.texture.sampler;
|
|
1979
1909
|
this._view = this.texture.view;
|
|
1980
1910
|
prev.destroy();
|
|
1981
|
-
|
|
1911
|
+
import_core7.log.info(`${this} resized`);
|
|
1982
1912
|
return true;
|
|
1983
1913
|
}
|
|
1984
1914
|
/** Convert cube face label to texture slice index. Index can be used with `setTexture2DData()`. */
|
|
@@ -2082,18 +2012,18 @@ var __exports__ = (() => {
|
|
|
2082
2012
|
}
|
|
2083
2013
|
_checkNotDestroyed() {
|
|
2084
2014
|
if (this.destroyed) {
|
|
2085
|
-
|
|
2015
|
+
import_core7.log.warn(`${this} already destroyed`);
|
|
2086
2016
|
}
|
|
2087
2017
|
}
|
|
2088
2018
|
_checkReady() {
|
|
2089
2019
|
if (!this.isReady) {
|
|
2090
|
-
|
|
2020
|
+
import_core7.log.warn(`${this} Cannot perform this operation before ready`);
|
|
2091
2021
|
}
|
|
2092
2022
|
}
|
|
2093
2023
|
};
|
|
2094
2024
|
var DynamicTexture = _DynamicTexture;
|
|
2095
2025
|
__publicField(DynamicTexture, "defaultProps", {
|
|
2096
|
-
...
|
|
2026
|
+
...import_core7.Texture.defaultProps,
|
|
2097
2027
|
dimension: "2d",
|
|
2098
2028
|
data: null,
|
|
2099
2029
|
mipmaps: false
|
|
@@ -2102,11 +2032,13 @@ var __exports__ = (() => {
|
|
|
2102
2032
|
if (!props.data) {
|
|
2103
2033
|
return [];
|
|
2104
2034
|
}
|
|
2035
|
+
const baseLevelSize = props.width && props.height ? { width: props.width, height: props.height } : void 0;
|
|
2036
|
+
const textureFormat = "format" in props ? props.format : void 0;
|
|
2105
2037
|
switch (props.dimension) {
|
|
2106
2038
|
case "1d":
|
|
2107
2039
|
return getTexture1DSubresources(props.data);
|
|
2108
2040
|
case "2d":
|
|
2109
|
-
return getTexture2DSubresources(0, props.data);
|
|
2041
|
+
return getTexture2DSubresources(0, props.data, baseLevelSize, textureFormat);
|
|
2110
2042
|
case "3d":
|
|
2111
2043
|
return getTexture3DSubresources(props.data);
|
|
2112
2044
|
case "2d-array":
|
|
@@ -2239,7 +2171,7 @@ var __exports__ = (() => {
|
|
|
2239
2171
|
}
|
|
2240
2172
|
if (x && typeof x === "object" && x.constructor === Object) {
|
|
2241
2173
|
const object = x;
|
|
2242
|
-
const values = await Promise.all(Object.values(object));
|
|
2174
|
+
const values = await Promise.all(Object.values(object).map(awaitAllPromises));
|
|
2243
2175
|
const keys = Object.keys(object);
|
|
2244
2176
|
const resolvedObject = {};
|
|
2245
2177
|
for (let i = 0; i < keys.length; i++) {
|
|
@@ -2308,6 +2240,7 @@ var __exports__ = (() => {
|
|
|
2308
2240
|
/** ShaderInputs instance */
|
|
2309
2241
|
// @ts-expect-error Assigned in function called by constructor
|
|
2310
2242
|
shaderInputs;
|
|
2243
|
+
material = null;
|
|
2311
2244
|
// @ts-expect-error Assigned in function called by constructor
|
|
2312
2245
|
_uniformStore;
|
|
2313
2246
|
_attributeInfos = {};
|
|
@@ -2318,6 +2251,7 @@ var __exports__ = (() => {
|
|
|
2318
2251
|
_destroyed = false;
|
|
2319
2252
|
/** "Time" of last draw. Monotonically increasing timestamp */
|
|
2320
2253
|
_lastDrawTimestamp = -1;
|
|
2254
|
+
_bindingTable = [];
|
|
2321
2255
|
get [Symbol.toStringTag]() {
|
|
2322
2256
|
return "Model";
|
|
2323
2257
|
}
|
|
@@ -2330,6 +2264,7 @@ var __exports__ = (() => {
|
|
|
2330
2264
|
this.id = props.id || uid("model");
|
|
2331
2265
|
this.device = device;
|
|
2332
2266
|
Object.assign(this.userData, props.userData);
|
|
2267
|
+
this.material = props.material || null;
|
|
2333
2268
|
const moduleMap = Object.fromEntries(
|
|
2334
2269
|
this.props.modules?.map((module) => [module.name, module]) || []
|
|
2335
2270
|
);
|
|
@@ -2340,16 +2275,22 @@ var __exports__ = (() => {
|
|
|
2340
2275
|
// @ts-ignore shaderInputs is assigned in setShaderInputs above.
|
|
2341
2276
|
(this.props.modules?.length > 0 ? this.props.modules : this.shaderInputs?.getModules()) || []
|
|
2342
2277
|
);
|
|
2278
|
+
this.props.shaderLayout = mergeShaderModuleBindingsIntoLayout(this.props.shaderLayout, modules) || null;
|
|
2343
2279
|
const isWebGPU = this.device.type === "webgpu";
|
|
2344
2280
|
if (isWebGPU && this.props.source) {
|
|
2345
|
-
const { source: source3, getUniforms: getUniforms2 } = this.props.shaderAssembler.assembleWGSLShader({
|
|
2281
|
+
const { source: source3, getUniforms: getUniforms2, bindingTable } = this.props.shaderAssembler.assembleWGSLShader({
|
|
2346
2282
|
platformInfo,
|
|
2347
2283
|
...this.props,
|
|
2348
2284
|
modules
|
|
2349
2285
|
});
|
|
2350
2286
|
this.source = source3;
|
|
2351
2287
|
this._getModuleUniforms = getUniforms2;
|
|
2352
|
-
this.
|
|
2288
|
+
this._bindingTable = bindingTable;
|
|
2289
|
+
const inferredShaderLayout = device.getShaderLayout?.(this.source);
|
|
2290
|
+
this.props.shaderLayout = mergeShaderModuleBindingsIntoLayout(
|
|
2291
|
+
this.props.shaderLayout || inferredShaderLayout || null,
|
|
2292
|
+
modules
|
|
2293
|
+
) || null;
|
|
2353
2294
|
} else {
|
|
2354
2295
|
const { vs: vs3, fs: fs3, getUniforms: getUniforms2 } = this.props.shaderAssembler.assembleGLSLShaderPair({
|
|
2355
2296
|
platformInfo,
|
|
@@ -2359,6 +2300,7 @@ var __exports__ = (() => {
|
|
|
2359
2300
|
this.vs = vs3;
|
|
2360
2301
|
this.fs = fs3;
|
|
2361
2302
|
this._getModuleUniforms = getUniforms2;
|
|
2303
|
+
this._bindingTable = [];
|
|
2362
2304
|
}
|
|
2363
2305
|
this.vertexCount = this.props.vertexCount;
|
|
2364
2306
|
this.instanceCount = this.props.instanceCount;
|
|
@@ -2368,8 +2310,8 @@ var __exports__ = (() => {
|
|
|
2368
2310
|
if (props.geometry) {
|
|
2369
2311
|
this.setGeometry(props.geometry);
|
|
2370
2312
|
}
|
|
2371
|
-
this.pipelineFactory = props.pipelineFactory || PipelineFactory.getDefaultPipelineFactory(this.device);
|
|
2372
|
-
this.shaderFactory = props.shaderFactory || ShaderFactory.getDefaultShaderFactory(this.device);
|
|
2313
|
+
this.pipelineFactory = props.pipelineFactory || import_core8.PipelineFactory.getDefaultPipelineFactory(this.device);
|
|
2314
|
+
this.shaderFactory = props.shaderFactory || import_core8.ShaderFactory.getDefaultShaderFactory(this.device);
|
|
2373
2315
|
this.pipeline = this._updatePipeline();
|
|
2374
2316
|
this.vertexArray = device.createVertexArray({
|
|
2375
2317
|
shaderLayout: this.pipeline.shaderLayout,
|
|
@@ -2429,6 +2371,10 @@ var __exports__ = (() => {
|
|
|
2429
2371
|
setNeedsRedraw(reason) {
|
|
2430
2372
|
this._needsRedraw ||= reason;
|
|
2431
2373
|
}
|
|
2374
|
+
/** Returns WGSL binding debug rows for the assembled shader. Returns an empty array for GLSL models. */
|
|
2375
|
+
getBindingDebugTable() {
|
|
2376
|
+
return this._bindingTable;
|
|
2377
|
+
}
|
|
2432
2378
|
/** Update uniforms and pipeline state prior to drawing. */
|
|
2433
2379
|
predraw() {
|
|
2434
2380
|
this.updateShaderInputs();
|
|
@@ -2442,7 +2388,7 @@ var __exports__ = (() => {
|
|
|
2442
2388
|
draw(renderPass) {
|
|
2443
2389
|
const loadingBinding = this._areBindingsLoading();
|
|
2444
2390
|
if (loadingBinding) {
|
|
2445
|
-
|
|
2391
|
+
import_core8.log.info(LOG_DRAW_PRIORITY, `>>> DRAWING ABORTED ${this.id}: ${loadingBinding} not loaded`)();
|
|
2446
2392
|
return false;
|
|
2447
2393
|
}
|
|
2448
2394
|
try {
|
|
@@ -2457,6 +2403,7 @@ var __exports__ = (() => {
|
|
|
2457
2403
|
this._logDrawCallStart();
|
|
2458
2404
|
this.pipeline = this._updatePipeline();
|
|
2459
2405
|
const syncBindings = this._getBindings();
|
|
2406
|
+
const syncBindGroups = this._getBindGroups();
|
|
2460
2407
|
const { indexBuffer } = this.vertexArray;
|
|
2461
2408
|
const indexCount = indexBuffer ? indexBuffer.byteLength / (indexBuffer.indexType === "uint32" ? 4 : 2) : void 0;
|
|
2462
2409
|
drawSuccess = this.pipeline.draw({
|
|
@@ -2471,6 +2418,8 @@ var __exports__ = (() => {
|
|
|
2471
2418
|
// and WebGL uniforms must be supplied on every draw instead of being stored
|
|
2472
2419
|
// on the pipeline instance.
|
|
2473
2420
|
bindings: syncBindings,
|
|
2421
|
+
bindGroups: syncBindGroups,
|
|
2422
|
+
_bindGroupCacheKeys: this._getBindGroupCacheKeys(),
|
|
2474
2423
|
uniforms: this.props.uniforms,
|
|
2475
2424
|
// WebGL shares underlying cached pipelines even for models that have different parameters and topology,
|
|
2476
2425
|
// so we must provide our unique parameters to each draw
|
|
@@ -2574,19 +2523,23 @@ var __exports__ = (() => {
|
|
|
2574
2523
|
/** Set the shader inputs */
|
|
2575
2524
|
setShaderInputs(shaderInputs) {
|
|
2576
2525
|
this.shaderInputs = shaderInputs;
|
|
2577
|
-
this._uniformStore = new
|
|
2526
|
+
this._uniformStore = new import_core8.UniformStore(this.shaderInputs.modules);
|
|
2578
2527
|
for (const [moduleName, module] of Object.entries(this.shaderInputs.modules)) {
|
|
2579
|
-
if (shaderModuleHasUniforms(module)) {
|
|
2528
|
+
if (shaderModuleHasUniforms(module) && !this.material?.ownsModule(moduleName)) {
|
|
2580
2529
|
const uniformBuffer = this._uniformStore.getManagedUniformBuffer(this.device, moduleName);
|
|
2581
2530
|
this.bindings[`${moduleName}Uniforms`] = uniformBuffer;
|
|
2582
2531
|
}
|
|
2583
2532
|
}
|
|
2584
2533
|
this.setNeedsRedraw("shaderInputs");
|
|
2585
2534
|
}
|
|
2535
|
+
setMaterial(material) {
|
|
2536
|
+
this.material = material;
|
|
2537
|
+
this.setNeedsRedraw("material");
|
|
2538
|
+
}
|
|
2586
2539
|
/** Update uniform buffers from the model's shader inputs */
|
|
2587
2540
|
updateShaderInputs() {
|
|
2588
2541
|
this._uniformStore.setUniforms(this.shaderInputs.getUniformValues());
|
|
2589
|
-
this.setBindings(this.shaderInputs.getBindingValues());
|
|
2542
|
+
this.setBindings(this._getNonMaterialBindings(this.shaderInputs.getBindingValues()));
|
|
2590
2543
|
this.setNeedsRedraw("shaderInputs");
|
|
2591
2544
|
}
|
|
2592
2545
|
/**
|
|
@@ -2618,7 +2571,7 @@ var __exports__ = (() => {
|
|
|
2618
2571
|
setAttributes(buffers, options) {
|
|
2619
2572
|
const disableWarnings = options?.disableWarnings ?? this.props.disableWarnings;
|
|
2620
2573
|
if (buffers["indices"]) {
|
|
2621
|
-
|
|
2574
|
+
import_core8.log.warn(
|
|
2622
2575
|
`Model:${this.id} setAttributes() - indexBuffer should be set using setIndexBuffer()`
|
|
2623
2576
|
)();
|
|
2624
2577
|
}
|
|
@@ -2631,7 +2584,7 @@ var __exports__ = (() => {
|
|
|
2631
2584
|
const bufferLayout = bufferLayoutHelper.getBufferLayout(bufferName);
|
|
2632
2585
|
if (!bufferLayout) {
|
|
2633
2586
|
if (!disableWarnings) {
|
|
2634
|
-
|
|
2587
|
+
import_core8.log.warn(`Model(${this.id}): Missing layout for buffer "${bufferName}".`)();
|
|
2635
2588
|
}
|
|
2636
2589
|
continue;
|
|
2637
2590
|
}
|
|
@@ -2646,7 +2599,7 @@ var __exports__ = (() => {
|
|
|
2646
2599
|
}
|
|
2647
2600
|
}
|
|
2648
2601
|
if (!set && !disableWarnings) {
|
|
2649
|
-
|
|
2602
|
+
import_core8.log.warn(
|
|
2650
2603
|
`Model(${this.id}): Ignoring buffer "${buffer.id}" for unknown attribute "${bufferName}"`
|
|
2651
2604
|
)();
|
|
2652
2605
|
}
|
|
@@ -2667,7 +2620,7 @@ var __exports__ = (() => {
|
|
|
2667
2620
|
if (attributeInfo) {
|
|
2668
2621
|
this.vertexArray.setConstantWebGL(attributeInfo.location, value);
|
|
2669
2622
|
} else if (!(options?.disableWarnings ?? this.props.disableWarnings)) {
|
|
2670
|
-
|
|
2623
|
+
import_core8.log.warn(
|
|
2671
2624
|
`Model "${this.id}: Ignoring constant supplied for unknown attribute "${attributeName}"`
|
|
2672
2625
|
)();
|
|
2673
2626
|
}
|
|
@@ -2682,6 +2635,11 @@ var __exports__ = (() => {
|
|
|
2682
2635
|
return binding.id;
|
|
2683
2636
|
}
|
|
2684
2637
|
}
|
|
2638
|
+
for (const binding of Object.values(this.material?.bindings || {})) {
|
|
2639
|
+
if (binding instanceof DynamicTexture && !binding.isReady) {
|
|
2640
|
+
return binding.id;
|
|
2641
|
+
}
|
|
2642
|
+
}
|
|
2685
2643
|
return false;
|
|
2686
2644
|
}
|
|
2687
2645
|
/** Extracts texture view from loaded async textures. Returns null if any textures have not yet been loaded. */
|
|
@@ -2698,24 +2656,43 @@ var __exports__ = (() => {
|
|
|
2698
2656
|
}
|
|
2699
2657
|
return validBindings;
|
|
2700
2658
|
}
|
|
2659
|
+
_getBindGroups() {
|
|
2660
|
+
const shaderLayout = this.pipeline?.shaderLayout || this.props.shaderLayout || { bindings: [] };
|
|
2661
|
+
const bindGroups = shaderLayout.bindings.length ? (0, import_core8.normalizeBindingsByGroup)(shaderLayout, this._getBindings()) : { 0: this._getBindings() };
|
|
2662
|
+
if (!this.material) {
|
|
2663
|
+
return bindGroups;
|
|
2664
|
+
}
|
|
2665
|
+
for (const [groupKey, groupBindings] of Object.entries(this.material.getBindingsByGroup())) {
|
|
2666
|
+
const group = Number(groupKey);
|
|
2667
|
+
bindGroups[group] = {
|
|
2668
|
+
...bindGroups[group] || {},
|
|
2669
|
+
...groupBindings
|
|
2670
|
+
};
|
|
2671
|
+
}
|
|
2672
|
+
return bindGroups;
|
|
2673
|
+
}
|
|
2674
|
+
_getBindGroupCacheKeys() {
|
|
2675
|
+
const bindGroupCacheKey = this.material?.getBindGroupCacheKey(3);
|
|
2676
|
+
return bindGroupCacheKey ? { 3: bindGroupCacheKey } : {};
|
|
2677
|
+
}
|
|
2701
2678
|
/** Get the timestamp of the latest updated bound GPU memory resource (buffer/texture). */
|
|
2702
2679
|
_getBindingsUpdateTimestamp() {
|
|
2703
2680
|
let timestamp = 0;
|
|
2704
2681
|
for (const binding of Object.values(this.bindings)) {
|
|
2705
|
-
if (binding instanceof
|
|
2682
|
+
if (binding instanceof import_core8.TextureView) {
|
|
2706
2683
|
timestamp = Math.max(timestamp, binding.texture.updateTimestamp);
|
|
2707
|
-
} else if (binding instanceof
|
|
2684
|
+
} else if (binding instanceof import_core8.Buffer || binding instanceof import_core8.Texture) {
|
|
2708
2685
|
timestamp = Math.max(timestamp, binding.updateTimestamp);
|
|
2709
2686
|
} else if (binding instanceof DynamicTexture) {
|
|
2710
2687
|
timestamp = binding.texture ? Math.max(timestamp, binding.texture.updateTimestamp) : (
|
|
2711
2688
|
// The texture will become available in the future
|
|
2712
2689
|
Infinity
|
|
2713
2690
|
);
|
|
2714
|
-
} else if (!(binding instanceof
|
|
2691
|
+
} else if (!(binding instanceof import_core8.Sampler)) {
|
|
2715
2692
|
timestamp = Math.max(timestamp, binding.buffer.updateTimestamp);
|
|
2716
2693
|
}
|
|
2717
2694
|
}
|
|
2718
|
-
return timestamp;
|
|
2695
|
+
return Math.max(timestamp, this.material?.getBindingsUpdateTimestamp() || 0);
|
|
2719
2696
|
}
|
|
2720
2697
|
/**
|
|
2721
2698
|
* Updates the optional geometry attributes
|
|
@@ -2746,7 +2723,7 @@ var __exports__ = (() => {
|
|
|
2746
2723
|
let prevShaderVs = null;
|
|
2747
2724
|
let prevShaderFs = null;
|
|
2748
2725
|
if (this.pipeline) {
|
|
2749
|
-
|
|
2726
|
+
import_core8.log.log(
|
|
2750
2727
|
1,
|
|
2751
2728
|
`Model ${this.id}: Recreating pipeline because "${this._pipelineNeedsUpdate}".`
|
|
2752
2729
|
)();
|
|
@@ -2773,16 +2750,15 @@ var __exports__ = (() => {
|
|
|
2773
2750
|
}
|
|
2774
2751
|
this.pipeline = this.pipelineFactory.createRenderPipeline({
|
|
2775
2752
|
...this.props,
|
|
2753
|
+
bindings: void 0,
|
|
2776
2754
|
bufferLayout: this.bufferLayout,
|
|
2777
2755
|
topology: this.topology,
|
|
2778
2756
|
parameters: this.parameters,
|
|
2779
|
-
|
|
2780
|
-
// Should we expose a BindGroup abstraction?
|
|
2781
|
-
bindings: this._getBindings(),
|
|
2757
|
+
bindGroups: this._getBindGroups(),
|
|
2782
2758
|
vs: vs3,
|
|
2783
2759
|
fs: fs3
|
|
2784
2760
|
});
|
|
2785
|
-
this._attributeInfos = (0,
|
|
2761
|
+
this._attributeInfos = (0, import_core8.getAttributeInfosFromLayouts)(
|
|
2786
2762
|
this.pipeline.shaderLayout,
|
|
2787
2763
|
this.bufferLayout
|
|
2788
2764
|
);
|
|
@@ -2798,24 +2774,24 @@ var __exports__ = (() => {
|
|
|
2798
2774
|
_lastLogTime = 0;
|
|
2799
2775
|
_logOpen = false;
|
|
2800
2776
|
_logDrawCallStart() {
|
|
2801
|
-
const logDrawTimeout =
|
|
2802
|
-
if (
|
|
2777
|
+
const logDrawTimeout = import_core8.log.level > 3 ? 0 : LOG_DRAW_TIMEOUT;
|
|
2778
|
+
if (import_core8.log.level < 2 || Date.now() - this._lastLogTime < logDrawTimeout) {
|
|
2803
2779
|
return;
|
|
2804
2780
|
}
|
|
2805
2781
|
this._lastLogTime = Date.now();
|
|
2806
2782
|
this._logOpen = true;
|
|
2807
|
-
|
|
2783
|
+
import_core8.log.group(LOG_DRAW_PRIORITY, `>>> DRAWING MODEL ${this.id}`, { collapsed: import_core8.log.level <= 2 })();
|
|
2808
2784
|
}
|
|
2809
2785
|
_logDrawCallEnd() {
|
|
2810
2786
|
if (this._logOpen) {
|
|
2811
2787
|
const shaderLayoutTable = getDebugTableForShaderLayout(this.pipeline.shaderLayout, this.id);
|
|
2812
|
-
|
|
2788
|
+
import_core8.log.table(LOG_DRAW_PRIORITY, shaderLayoutTable)();
|
|
2813
2789
|
const uniformTable = this.shaderInputs.getDebugTable();
|
|
2814
|
-
|
|
2790
|
+
import_core8.log.table(LOG_DRAW_PRIORITY, uniformTable)();
|
|
2815
2791
|
const attributeTable = this._getAttributeDebugTable();
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2792
|
+
import_core8.log.table(LOG_DRAW_PRIORITY, this._attributeInfos)();
|
|
2793
|
+
import_core8.log.table(LOG_DRAW_PRIORITY, attributeTable)();
|
|
2794
|
+
import_core8.log.groupEnd(LOG_DRAW_PRIORITY)();
|
|
2819
2795
|
this._logOpen = false;
|
|
2820
2796
|
}
|
|
2821
2797
|
}
|
|
@@ -2854,14 +2830,26 @@ var __exports__ = (() => {
|
|
|
2854
2830
|
}
|
|
2855
2831
|
// TODO - fix typing of luma data types
|
|
2856
2832
|
_getBufferOrConstantValues(attribute, dataType) {
|
|
2857
|
-
const TypedArrayConstructor =
|
|
2858
|
-
const typedArray = attribute instanceof
|
|
2833
|
+
const TypedArrayConstructor = import_core8.dataTypeDecoder.getTypedArrayConstructor(dataType);
|
|
2834
|
+
const typedArray = attribute instanceof import_core8.Buffer ? new TypedArrayConstructor(attribute.debugData) : attribute;
|
|
2859
2835
|
return typedArray.toString();
|
|
2860
2836
|
}
|
|
2837
|
+
_getNonMaterialBindings(bindings) {
|
|
2838
|
+
if (!this.material) {
|
|
2839
|
+
return bindings;
|
|
2840
|
+
}
|
|
2841
|
+
const filteredBindings = {};
|
|
2842
|
+
for (const [name, binding] of Object.entries(bindings)) {
|
|
2843
|
+
if (!this.material.ownsBinding(name)) {
|
|
2844
|
+
filteredBindings[name] = binding;
|
|
2845
|
+
}
|
|
2846
|
+
}
|
|
2847
|
+
return filteredBindings;
|
|
2848
|
+
}
|
|
2861
2849
|
};
|
|
2862
2850
|
var Model = _Model;
|
|
2863
2851
|
__publicField(Model, "defaultProps", {
|
|
2864
|
-
...
|
|
2852
|
+
...import_core8.RenderPipeline.defaultProps,
|
|
2865
2853
|
source: void 0,
|
|
2866
2854
|
vs: null,
|
|
2867
2855
|
fs: null,
|
|
@@ -2881,6 +2869,7 @@ var __exports__ = (() => {
|
|
|
2881
2869
|
instanceCount: 0,
|
|
2882
2870
|
vertexCount: 0,
|
|
2883
2871
|
shaderInputs: void 0,
|
|
2872
|
+
material: void 0,
|
|
2884
2873
|
pipelineFactory: void 0,
|
|
2885
2874
|
shaderFactory: void 0,
|
|
2886
2875
|
transformFeedback: void 0,
|
|
@@ -2888,9 +2877,6 @@ var __exports__ = (() => {
|
|
|
2888
2877
|
debugShaders: void 0,
|
|
2889
2878
|
disableWarnings: void 0
|
|
2890
2879
|
});
|
|
2891
|
-
function shaderModuleHasUniforms(module) {
|
|
2892
|
-
return Boolean(module.uniformTypes && !isObjectEmpty(module.uniformTypes));
|
|
2893
|
-
}
|
|
2894
2880
|
function getPlatformInfo(device) {
|
|
2895
2881
|
return {
|
|
2896
2882
|
type: device.type,
|
|
@@ -2901,85 +2887,310 @@ var __exports__ = (() => {
|
|
|
2901
2887
|
features: device.features
|
|
2902
2888
|
};
|
|
2903
2889
|
}
|
|
2904
|
-
function isObjectEmpty(obj) {
|
|
2905
|
-
for (const key in obj) {
|
|
2906
|
-
return false;
|
|
2907
|
-
}
|
|
2908
|
-
return true;
|
|
2909
|
-
}
|
|
2910
2890
|
|
|
2911
|
-
// src/
|
|
2912
|
-
var
|
|
2913
|
-
|
|
2914
|
-
|
|
2891
|
+
// src/material/material.ts
|
|
2892
|
+
var import_core9 = __toESM(require_core(), 1);
|
|
2893
|
+
|
|
2894
|
+
// src/material/material-factory.ts
|
|
2895
|
+
var MATERIAL_BIND_GROUP = 3;
|
|
2896
|
+
var MaterialFactory = class {
|
|
2897
|
+
/** Device that creates materials for this schema. */
|
|
2915
2898
|
device;
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
}
|
|
2921
|
-
constructor(device, props = _BufferTransform.defaultProps) {
|
|
2922
|
-
if (!_BufferTransform.isSupported(device)) {
|
|
2923
|
-
throw new Error("BufferTransform not yet implemented on WebGPU");
|
|
2924
|
-
}
|
|
2899
|
+
/** Shader modules that define the material schema. */
|
|
2900
|
+
modules;
|
|
2901
|
+
_materialBindingNames;
|
|
2902
|
+
_materialModuleNames;
|
|
2903
|
+
constructor(device, props = {}) {
|
|
2925
2904
|
this.device = device;
|
|
2926
|
-
this.
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
});
|
|
2933
|
-
this.transformFeedback = this.device.createTransformFeedback({
|
|
2934
|
-
layout: this.model.pipeline.shaderLayout,
|
|
2935
|
-
// @ts-expect-error TODO
|
|
2936
|
-
buffers: props.feedbackBuffers
|
|
2937
|
-
});
|
|
2938
|
-
this.model.setTransformFeedback(this.transformFeedback);
|
|
2939
|
-
Object.seal(this);
|
|
2905
|
+
this.modules = props.modules || [];
|
|
2906
|
+
const shaderInputs = new ShaderInputs(
|
|
2907
|
+
Object.fromEntries(this.modules.map((module) => [module.name, module]))
|
|
2908
|
+
);
|
|
2909
|
+
this._materialBindingNames = getMaterialBindingNames(shaderInputs);
|
|
2910
|
+
this._materialModuleNames = getMaterialModuleNames(shaderInputs);
|
|
2940
2911
|
}
|
|
2941
|
-
/**
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2912
|
+
/** Creates one typed material instance for this factory's schema. */
|
|
2913
|
+
createMaterial(props = {}) {
|
|
2914
|
+
return new Material(this.device, {
|
|
2915
|
+
...props,
|
|
2916
|
+
factory: this
|
|
2917
|
+
});
|
|
2946
2918
|
}
|
|
2947
|
-
/**
|
|
2948
|
-
|
|
2949
|
-
this.
|
|
2919
|
+
/** Returns the logical material-owned resource binding names. */
|
|
2920
|
+
getBindingNames() {
|
|
2921
|
+
return Array.from(this._materialBindingNames);
|
|
2950
2922
|
}
|
|
2951
|
-
/**
|
|
2952
|
-
|
|
2953
|
-
if (
|
|
2954
|
-
|
|
2955
|
-
}
|
|
2956
|
-
if (options?.outputBuffers) {
|
|
2957
|
-
this.transformFeedback.setBuffers(options.outputBuffers);
|
|
2923
|
+
/** Returns `true` when the supplied binding belongs to this material schema. */
|
|
2924
|
+
ownsBinding(bindingName) {
|
|
2925
|
+
if (this._materialBindingNames.has(bindingName)) {
|
|
2926
|
+
return true;
|
|
2958
2927
|
}
|
|
2959
|
-
const
|
|
2960
|
-
this.
|
|
2961
|
-
renderPass.end();
|
|
2928
|
+
const aliasedModuleName = getModuleNameFromUniformBinding(bindingName);
|
|
2929
|
+
return aliasedModuleName ? this._materialModuleNames.has(aliasedModuleName) : false;
|
|
2962
2930
|
}
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
return this.transformFeedback.getBuffer(varyingName);
|
|
2931
|
+
/** Returns `true` when the supplied shader module is owned by this material schema. */
|
|
2932
|
+
ownsModule(moduleName) {
|
|
2933
|
+
return this._materialModuleNames.has(moduleName);
|
|
2967
2934
|
}
|
|
2968
|
-
/**
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2935
|
+
/** Packages resolved material bindings into bind group `3`. */
|
|
2936
|
+
getBindingsByGroup(bindings) {
|
|
2937
|
+
return Object.keys(bindings).length > 0 ? { [MATERIAL_BIND_GROUP]: bindings } : {};
|
|
2938
|
+
}
|
|
2939
|
+
};
|
|
2940
|
+
function getModuleNameFromUniformBinding(bindingName) {
|
|
2941
|
+
return bindingName.endsWith("Uniforms") ? bindingName.slice(0, -"Uniforms".length) : null;
|
|
2942
|
+
}
|
|
2943
|
+
function getMaterialBindingNames(shaderInputs) {
|
|
2944
|
+
const bindingNames = /* @__PURE__ */ new Set();
|
|
2945
|
+
for (const module of Object.values(shaderInputs.modules)) {
|
|
2946
|
+
for (const binding of module.bindingLayout || []) {
|
|
2947
|
+
if (binding.group === MATERIAL_BIND_GROUP) {
|
|
2948
|
+
bindingNames.add(binding.name);
|
|
2949
|
+
}
|
|
2973
2950
|
}
|
|
2974
|
-
|
|
2975
|
-
|
|
2951
|
+
}
|
|
2952
|
+
return bindingNames;
|
|
2953
|
+
}
|
|
2954
|
+
function getMaterialModuleNames(shaderInputs) {
|
|
2955
|
+
const moduleNames = /* @__PURE__ */ new Set();
|
|
2956
|
+
for (const module of Object.values(shaderInputs.modules)) {
|
|
2957
|
+
if (module.name && module.bindingLayout?.some(
|
|
2958
|
+
(binding) => binding.group === MATERIAL_BIND_GROUP && binding.name === module.name
|
|
2959
|
+
)) {
|
|
2960
|
+
moduleNames.add(module.name);
|
|
2976
2961
|
}
|
|
2977
|
-
const { buffer, byteOffset = 0, byteLength = buffer.byteLength } = result;
|
|
2978
|
-
return buffer.readAsync(byteOffset, byteLength);
|
|
2979
2962
|
}
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2963
|
+
return moduleNames;
|
|
2964
|
+
}
|
|
2965
|
+
|
|
2966
|
+
// src/material/material.ts
|
|
2967
|
+
var Material = class {
|
|
2968
|
+
/** Application-provided identifier. */
|
|
2969
|
+
id;
|
|
2970
|
+
/** Device that owns the material resources. */
|
|
2971
|
+
device;
|
|
2972
|
+
/** Factory that defines the material schema. */
|
|
2973
|
+
factory;
|
|
2974
|
+
/** Shader inputs for the material-owned modules. */
|
|
2975
|
+
shaderInputs;
|
|
2976
|
+
/** Internal binding store including uniform buffers and resource bindings. */
|
|
2977
|
+
bindings = {};
|
|
2978
|
+
_uniformStore;
|
|
2979
|
+
_bindGroupCacheToken = {};
|
|
2980
|
+
constructor(device, props = {}) {
|
|
2981
|
+
this.id = props.id || uid("material");
|
|
2982
|
+
this.device = device;
|
|
2983
|
+
this.factory = props.factory || new MaterialFactory(device, {
|
|
2984
|
+
modules: props.modules || props.shaderInputs?.getModules() || []
|
|
2985
|
+
});
|
|
2986
|
+
const moduleMap = Object.fromEntries(
|
|
2987
|
+
(props.shaderInputs?.getModules() || this.factory.modules).map((module) => [
|
|
2988
|
+
module.name,
|
|
2989
|
+
module
|
|
2990
|
+
])
|
|
2991
|
+
);
|
|
2992
|
+
this.shaderInputs = props.shaderInputs || new ShaderInputs(moduleMap);
|
|
2993
|
+
this._uniformStore = new import_core9.UniformStore(this.shaderInputs.modules);
|
|
2994
|
+
for (const [moduleName, module] of Object.entries(this.shaderInputs.modules)) {
|
|
2995
|
+
if (this.ownsModule(moduleName) && shaderModuleHasUniforms(module)) {
|
|
2996
|
+
const uniformBuffer = this._uniformStore.getManagedUniformBuffer(this.device, moduleName);
|
|
2997
|
+
this.bindings[`${moduleName}Uniforms`] = uniformBuffer;
|
|
2998
|
+
}
|
|
2999
|
+
}
|
|
3000
|
+
this.updateShaderInputs();
|
|
3001
|
+
if (props.bindings) {
|
|
3002
|
+
this._replaceOwnedBindings(props.bindings);
|
|
3003
|
+
}
|
|
3004
|
+
}
|
|
3005
|
+
/** Destroys managed uniform-buffer resources owned by this material. */
|
|
3006
|
+
destroy() {
|
|
3007
|
+
this._uniformStore.destroy();
|
|
3008
|
+
}
|
|
3009
|
+
/** Creates a new material variant with optional structural and uniform overrides. */
|
|
3010
|
+
clone(props = {}) {
|
|
3011
|
+
const material = this.factory.createMaterial({
|
|
3012
|
+
id: props.id,
|
|
3013
|
+
shaderInputs: props.shaderInputs,
|
|
3014
|
+
bindings: {
|
|
3015
|
+
...this.getResourceBindings(),
|
|
3016
|
+
...props.bindings
|
|
3017
|
+
}
|
|
3018
|
+
});
|
|
3019
|
+
if (!props.shaderInputs) {
|
|
3020
|
+
material.setProps(this.shaderInputs.getUniformValues());
|
|
3021
|
+
}
|
|
3022
|
+
if (props.moduleProps) {
|
|
3023
|
+
material.setProps(props.moduleProps);
|
|
3024
|
+
}
|
|
3025
|
+
return material;
|
|
3026
|
+
}
|
|
3027
|
+
/** Returns `true` if this material owns the supplied binding name. */
|
|
3028
|
+
ownsBinding(bindingName) {
|
|
3029
|
+
return this.factory.ownsBinding(bindingName);
|
|
3030
|
+
}
|
|
3031
|
+
/** Returns `true` if this material owns the supplied shader module. */
|
|
3032
|
+
ownsModule(moduleName) {
|
|
3033
|
+
return this.factory.ownsModule(moduleName);
|
|
3034
|
+
}
|
|
3035
|
+
/** Updates material uniform/module props in place without changing material identity. */
|
|
3036
|
+
setProps(props) {
|
|
3037
|
+
this.shaderInputs.setProps(props);
|
|
3038
|
+
this.updateShaderInputs();
|
|
3039
|
+
}
|
|
3040
|
+
/** Updates managed uniform buffers and shader-input-owned bindings. */
|
|
3041
|
+
updateShaderInputs() {
|
|
3042
|
+
this._uniformStore.setUniforms(this.shaderInputs.getUniformValues());
|
|
3043
|
+
const didChange = this._setOwnedBindings(this.shaderInputs.getBindingValues());
|
|
3044
|
+
if (didChange) {
|
|
3045
|
+
this._bindGroupCacheToken = {};
|
|
3046
|
+
}
|
|
3047
|
+
}
|
|
3048
|
+
/** Returns the material-owned resource bindings without internal uniform buffers. */
|
|
3049
|
+
getResourceBindings() {
|
|
3050
|
+
const resourceBindings = {};
|
|
3051
|
+
for (const [name, binding] of Object.entries(this.bindings)) {
|
|
3052
|
+
if (!getModuleNameFromUniformBinding(name)) {
|
|
3053
|
+
resourceBindings[name] = binding;
|
|
3054
|
+
}
|
|
3055
|
+
}
|
|
3056
|
+
return resourceBindings;
|
|
3057
|
+
}
|
|
3058
|
+
/** Returns the resolved bindings, including internal uniform buffers and ready textures. */
|
|
3059
|
+
getBindings() {
|
|
3060
|
+
const validBindings = {};
|
|
3061
|
+
const validBindingsMap = validBindings;
|
|
3062
|
+
for (const [name, binding] of Object.entries(this.bindings)) {
|
|
3063
|
+
if (binding instanceof DynamicTexture) {
|
|
3064
|
+
if (binding.isReady) {
|
|
3065
|
+
validBindingsMap[name] = binding.texture;
|
|
3066
|
+
}
|
|
3067
|
+
} else {
|
|
3068
|
+
validBindingsMap[name] = binding;
|
|
3069
|
+
}
|
|
3070
|
+
}
|
|
3071
|
+
return validBindings;
|
|
3072
|
+
}
|
|
3073
|
+
/** Packages resolved material bindings into logical bind group `3`. */
|
|
3074
|
+
getBindingsByGroup() {
|
|
3075
|
+
return this.factory.getBindingsByGroup(this.getBindings());
|
|
3076
|
+
}
|
|
3077
|
+
/** Returns the stable bind-group cache token for the requested bind group. */
|
|
3078
|
+
getBindGroupCacheKey(group) {
|
|
3079
|
+
return group === MATERIAL_BIND_GROUP ? this._bindGroupCacheToken : null;
|
|
3080
|
+
}
|
|
3081
|
+
/** Returns the latest update timestamp across material-owned resources. */
|
|
3082
|
+
getBindingsUpdateTimestamp() {
|
|
3083
|
+
let timestamp = 0;
|
|
3084
|
+
for (const binding of Object.values(this.bindings)) {
|
|
3085
|
+
if (binding instanceof import_core9.TextureView) {
|
|
3086
|
+
timestamp = Math.max(timestamp, binding.texture.updateTimestamp);
|
|
3087
|
+
} else if (binding instanceof import_core9.Buffer || binding instanceof import_core9.Texture) {
|
|
3088
|
+
timestamp = Math.max(timestamp, binding.updateTimestamp);
|
|
3089
|
+
} else if (binding instanceof DynamicTexture) {
|
|
3090
|
+
timestamp = binding.texture ? Math.max(timestamp, binding.texture.updateTimestamp) : Infinity;
|
|
3091
|
+
} else if (!(binding instanceof import_core9.Sampler)) {
|
|
3092
|
+
timestamp = Math.max(timestamp, binding.buffer.updateTimestamp);
|
|
3093
|
+
}
|
|
3094
|
+
}
|
|
3095
|
+
return timestamp;
|
|
3096
|
+
}
|
|
3097
|
+
/** Replaces owned resource bindings and invalidates the material cache identity when needed. */
|
|
3098
|
+
_replaceOwnedBindings(bindings) {
|
|
3099
|
+
const didChange = this._setOwnedBindings(bindings);
|
|
3100
|
+
if (didChange) {
|
|
3101
|
+
this._bindGroupCacheToken = {};
|
|
3102
|
+
}
|
|
3103
|
+
}
|
|
3104
|
+
_setOwnedBindings(bindings) {
|
|
3105
|
+
let didChange = false;
|
|
3106
|
+
for (const [name, binding] of Object.entries(bindings)) {
|
|
3107
|
+
if (binding === void 0) {
|
|
3108
|
+
continue;
|
|
3109
|
+
}
|
|
3110
|
+
if (!this.ownsBinding(name)) {
|
|
3111
|
+
continue;
|
|
3112
|
+
}
|
|
3113
|
+
if (this.bindings[name] !== binding) {
|
|
3114
|
+
this.bindings[name] = binding;
|
|
3115
|
+
didChange = true;
|
|
3116
|
+
}
|
|
3117
|
+
}
|
|
3118
|
+
return didChange;
|
|
3119
|
+
}
|
|
3120
|
+
};
|
|
3121
|
+
|
|
3122
|
+
// src/compute/buffer-transform.ts
|
|
3123
|
+
var import_core10 = __toESM(require_core(), 1);
|
|
3124
|
+
var import_shadertools3 = __toESM(require_shadertools(), 1);
|
|
3125
|
+
var _BufferTransform = class {
|
|
3126
|
+
device;
|
|
3127
|
+
model;
|
|
3128
|
+
transformFeedback;
|
|
3129
|
+
static isSupported(device) {
|
|
3130
|
+
return device?.info?.type === "webgl";
|
|
3131
|
+
}
|
|
3132
|
+
constructor(device, props = _BufferTransform.defaultProps) {
|
|
3133
|
+
if (!_BufferTransform.isSupported(device)) {
|
|
3134
|
+
throw new Error("BufferTransform not yet implemented on WebGPU");
|
|
3135
|
+
}
|
|
3136
|
+
this.device = device;
|
|
3137
|
+
this.model = new Model(this.device, {
|
|
3138
|
+
id: props.id || "buffer-transform-model",
|
|
3139
|
+
fs: props.fs || (0, import_shadertools3.getPassthroughFS)(),
|
|
3140
|
+
topology: props.topology || "point-list",
|
|
3141
|
+
varyings: props.outputs || props.varyings,
|
|
3142
|
+
...props
|
|
3143
|
+
});
|
|
3144
|
+
this.transformFeedback = this.device.createTransformFeedback({
|
|
3145
|
+
layout: this.model.pipeline.shaderLayout,
|
|
3146
|
+
// @ts-expect-error TODO
|
|
3147
|
+
buffers: props.feedbackBuffers
|
|
3148
|
+
});
|
|
3149
|
+
this.model.setTransformFeedback(this.transformFeedback);
|
|
3150
|
+
Object.seal(this);
|
|
3151
|
+
}
|
|
3152
|
+
/** Destroy owned resources. */
|
|
3153
|
+
destroy() {
|
|
3154
|
+
if (this.model) {
|
|
3155
|
+
this.model.destroy();
|
|
3156
|
+
}
|
|
3157
|
+
}
|
|
3158
|
+
/** @deprecated Use {@link destroy}. */
|
|
3159
|
+
delete() {
|
|
3160
|
+
this.destroy();
|
|
3161
|
+
}
|
|
3162
|
+
/** Run one transform loop. */
|
|
3163
|
+
run(options) {
|
|
3164
|
+
if (options?.inputBuffers) {
|
|
3165
|
+
this.model.setAttributes(options.inputBuffers);
|
|
3166
|
+
}
|
|
3167
|
+
if (options?.outputBuffers) {
|
|
3168
|
+
this.transformFeedback.setBuffers(options.outputBuffers);
|
|
3169
|
+
}
|
|
3170
|
+
const renderPass = this.device.beginRenderPass(options);
|
|
3171
|
+
this.model.draw(renderPass);
|
|
3172
|
+
renderPass.end();
|
|
3173
|
+
}
|
|
3174
|
+
// DEPRECATED METHODS
|
|
3175
|
+
/** @deprecated App knows what buffers it is passing in - Returns the {@link Buffer} or {@link BufferRange} for given varying name. */
|
|
3176
|
+
getBuffer(varyingName) {
|
|
3177
|
+
return this.transformFeedback.getBuffer(varyingName);
|
|
3178
|
+
}
|
|
3179
|
+
/** @deprecated App knows what buffers it is passing in - Reads the {@link Buffer} or {@link BufferRange} for given varying name. */
|
|
3180
|
+
readAsync(varyingName) {
|
|
3181
|
+
const result = this.getBuffer(varyingName);
|
|
3182
|
+
if (!result) {
|
|
3183
|
+
throw new Error("BufferTransform#getBuffer");
|
|
3184
|
+
}
|
|
3185
|
+
if (result instanceof import_core10.Buffer) {
|
|
3186
|
+
return result.readAsync();
|
|
3187
|
+
}
|
|
3188
|
+
const { buffer, byteOffset = 0, byteLength = buffer.byteLength } = result;
|
|
3189
|
+
return buffer.readAsync(byteOffset, byteLength);
|
|
3190
|
+
}
|
|
3191
|
+
};
|
|
3192
|
+
var BufferTransform = _BufferTransform;
|
|
3193
|
+
__publicField(BufferTransform, "defaultProps", {
|
|
2983
3194
|
...Model.defaultProps,
|
|
2984
3195
|
outputs: void 0,
|
|
2985
3196
|
feedbackBuffers: void 0
|
|
@@ -3371,6 +3582,84 @@ void main(void) {
|
|
|
3371
3582
|
}
|
|
3372
3583
|
};
|
|
3373
3584
|
|
|
3585
|
+
// src/geometries/sphere-geometry.ts
|
|
3586
|
+
var SphereGeometry = class extends Geometry {
|
|
3587
|
+
constructor(props = {}) {
|
|
3588
|
+
const { id = uid("sphere-geometry") } = props;
|
|
3589
|
+
const { indices, attributes } = tesselateSphere(props);
|
|
3590
|
+
super({
|
|
3591
|
+
...props,
|
|
3592
|
+
id,
|
|
3593
|
+
topology: "triangle-list",
|
|
3594
|
+
indices,
|
|
3595
|
+
attributes: { ...attributes, ...props.attributes }
|
|
3596
|
+
});
|
|
3597
|
+
}
|
|
3598
|
+
};
|
|
3599
|
+
function tesselateSphere(props) {
|
|
3600
|
+
const { nlat = 10, nlong = 10 } = props;
|
|
3601
|
+
const startLat = 0;
|
|
3602
|
+
const endLat = Math.PI;
|
|
3603
|
+
const latRange = endLat - startLat;
|
|
3604
|
+
const startLong = 0;
|
|
3605
|
+
const endLong = 2 * Math.PI;
|
|
3606
|
+
const longRange = endLong - startLong;
|
|
3607
|
+
const numVertices = (nlat + 1) * (nlong + 1);
|
|
3608
|
+
const radius = (n1, n2, n3, u, v) => props.radius || 1;
|
|
3609
|
+
const positions = new Float32Array(numVertices * 3);
|
|
3610
|
+
const normals = new Float32Array(numVertices * 3);
|
|
3611
|
+
const texCoords = new Float32Array(numVertices * 2);
|
|
3612
|
+
const IndexType = numVertices > 65535 ? Uint32Array : Uint16Array;
|
|
3613
|
+
const indices = new IndexType(nlat * nlong * 6);
|
|
3614
|
+
for (let y = 0; y <= nlat; y++) {
|
|
3615
|
+
for (let x = 0; x <= nlong; x++) {
|
|
3616
|
+
const u = x / nlong;
|
|
3617
|
+
const v = y / nlat;
|
|
3618
|
+
const index = x + y * (nlong + 1);
|
|
3619
|
+
const i2 = index * 2;
|
|
3620
|
+
const i3 = index * 3;
|
|
3621
|
+
const theta = longRange * u;
|
|
3622
|
+
const phi = latRange * v;
|
|
3623
|
+
const sinTheta = Math.sin(theta);
|
|
3624
|
+
const cosTheta = Math.cos(theta);
|
|
3625
|
+
const sinPhi = Math.sin(phi);
|
|
3626
|
+
const cosPhi = Math.cos(phi);
|
|
3627
|
+
const ux = cosTheta * sinPhi;
|
|
3628
|
+
const uy = cosPhi;
|
|
3629
|
+
const uz = sinTheta * sinPhi;
|
|
3630
|
+
const r = radius(ux, uy, uz, u, v);
|
|
3631
|
+
positions[i3 + 0] = r * ux;
|
|
3632
|
+
positions[i3 + 1] = r * uy;
|
|
3633
|
+
positions[i3 + 2] = r * uz;
|
|
3634
|
+
normals[i3 + 0] = ux;
|
|
3635
|
+
normals[i3 + 1] = uy;
|
|
3636
|
+
normals[i3 + 2] = uz;
|
|
3637
|
+
texCoords[i2 + 0] = u;
|
|
3638
|
+
texCoords[i2 + 1] = 1 - v;
|
|
3639
|
+
}
|
|
3640
|
+
}
|
|
3641
|
+
const numVertsAround = nlong + 1;
|
|
3642
|
+
for (let x = 0; x < nlong; x++) {
|
|
3643
|
+
for (let y = 0; y < nlat; y++) {
|
|
3644
|
+
const index = (x * nlat + y) * 6;
|
|
3645
|
+
indices[index + 0] = y * numVertsAround + x;
|
|
3646
|
+
indices[index + 1] = y * numVertsAround + x + 1;
|
|
3647
|
+
indices[index + 2] = (y + 1) * numVertsAround + x;
|
|
3648
|
+
indices[index + 3] = (y + 1) * numVertsAround + x;
|
|
3649
|
+
indices[index + 4] = y * numVertsAround + x + 1;
|
|
3650
|
+
indices[index + 5] = (y + 1) * numVertsAround + x + 1;
|
|
3651
|
+
}
|
|
3652
|
+
}
|
|
3653
|
+
return {
|
|
3654
|
+
indices: { size: 1, value: indices },
|
|
3655
|
+
attributes: {
|
|
3656
|
+
POSITION: { size: 3, value: positions },
|
|
3657
|
+
NORMAL: { size: 3, value: normals },
|
|
3658
|
+
TEXCOORD_0: { size: 2, value: texCoords }
|
|
3659
|
+
}
|
|
3660
|
+
};
|
|
3661
|
+
}
|
|
3662
|
+
|
|
3374
3663
|
// ../../node_modules/@math.gl/core/dist/lib/common.js
|
|
3375
3664
|
var RADIANS_TO_DEGREES = 1 / Math.PI * 180;
|
|
3376
3665
|
var DEGREES_TO_RADIANS = 1 / 180 * Math.PI;
|
|
@@ -5406,28 +5695,616 @@ void main(void) {
|
|
|
5406
5695
|
return result;
|
|
5407
5696
|
}
|
|
5408
5697
|
|
|
5409
|
-
// src/
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
var
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5698
|
+
// src/models/light-model-utils.ts
|
|
5699
|
+
var DEFAULT_POINT_LIGHT_RADIUS_FACTOR = 0.02;
|
|
5700
|
+
var DEFAULT_SPOT_LIGHT_LENGTH_FACTOR = 0.12;
|
|
5701
|
+
var DEFAULT_DIRECTIONAL_LIGHT_LENGTH_FACTOR = 0.15;
|
|
5702
|
+
var DEFAULT_DIRECTIONAL_LIGHT_RADIUS_FACTOR = 0.2;
|
|
5703
|
+
var DEFAULT_DIRECTION_FALLBACK = [0, 1, 0];
|
|
5704
|
+
var DEFAULT_LIGHT_COLOR = [255, 255, 255];
|
|
5705
|
+
var DEFAULT_MARKER_SCALE = 1;
|
|
5706
|
+
var DIRECTIONAL_ANCHOR_DISTANCE_FACTOR = 0.35;
|
|
5707
|
+
var LIGHT_COLOR_FACTOR = 255;
|
|
5708
|
+
var MIN_SCENE_SCALE = 1;
|
|
5709
|
+
var SPOTLIGHT_OUTER_CONE_EPSILON = 0.01;
|
|
5710
|
+
var LIGHT_MARKER_PARAMETERS = {
|
|
5711
|
+
depthCompare: "less-equal",
|
|
5712
|
+
depthWriteEnabled: false,
|
|
5713
|
+
cullMode: "none"
|
|
5714
|
+
};
|
|
5715
|
+
var INSTANCE_BUFFER_LAYOUT = [
|
|
5716
|
+
{ name: "instancePosition", format: "float32x3", stepMode: "instance" },
|
|
5717
|
+
{ name: "instanceDirection", format: "float32x3", stepMode: "instance" },
|
|
5718
|
+
{ name: "instanceScale", format: "float32x3", stepMode: "instance" },
|
|
5719
|
+
{ name: "instanceColor", format: "float32x4", stepMode: "instance" }
|
|
5720
|
+
];
|
|
5721
|
+
var lightMarker = {
|
|
5722
|
+
name: "lightMarker",
|
|
5723
|
+
props: {},
|
|
5724
|
+
uniforms: {},
|
|
5725
|
+
uniformTypes: {
|
|
5726
|
+
viewProjectionMatrix: "mat4x4<f32>"
|
|
5428
5727
|
}
|
|
5429
|
-
|
|
5430
|
-
|
|
5728
|
+
};
|
|
5729
|
+
var CENTERED_LOCAL_POSITION_WGSL = "inputs.positions * inputs.instanceScale";
|
|
5730
|
+
var APEX_LOCAL_POSITION_WGSL = "vec3<f32>(inputs.positions.x * inputs.instanceScale.x, (inputs.positions.y - 0.5) * inputs.instanceScale.y, inputs.positions.z * inputs.instanceScale.z)";
|
|
5731
|
+
var CENTERED_LOCAL_POSITION_GLSL = "positions * instanceScale";
|
|
5732
|
+
var APEX_LOCAL_POSITION_GLSL = "vec3(positions.x * instanceScale.x, (positions.y - 0.5) * instanceScale.y, positions.z * instanceScale.z)";
|
|
5733
|
+
var BaseLightModel = class extends Model {
|
|
5734
|
+
lightModelProps;
|
|
5735
|
+
_instanceData;
|
|
5736
|
+
_managedBuffers;
|
|
5737
|
+
buildInstanceData;
|
|
5738
|
+
sizePropNames;
|
|
5739
|
+
constructor(device, props, options) {
|
|
5740
|
+
const instanceData = options.buildInstanceData(props);
|
|
5741
|
+
const managedBuffers = createManagedInstanceBuffers(
|
|
5742
|
+
device,
|
|
5743
|
+
props.id || options.idPrefix,
|
|
5744
|
+
instanceData
|
|
5745
|
+
);
|
|
5746
|
+
const shaderInputs = new ShaderInputs({ lightMarker });
|
|
5747
|
+
shaderInputs.setProps({
|
|
5748
|
+
lightMarker: { viewProjectionMatrix: createViewProjectionMatrix(props) }
|
|
5749
|
+
});
|
|
5750
|
+
const { source: source3, vs: vs3, fs: fs3 } = getLightMarkerShaders(options.anchorMode);
|
|
5751
|
+
const modelProps = props;
|
|
5752
|
+
super(device, {
|
|
5753
|
+
...modelProps,
|
|
5754
|
+
id: props.id || options.idPrefix,
|
|
5755
|
+
source: source3,
|
|
5756
|
+
vs: vs3,
|
|
5757
|
+
fs: fs3,
|
|
5758
|
+
geometry: options.geometry,
|
|
5759
|
+
shaderInputs,
|
|
5760
|
+
bufferLayout: [...INSTANCE_BUFFER_LAYOUT],
|
|
5761
|
+
attributes: managedBuffers,
|
|
5762
|
+
instanceCount: instanceData.instanceCount,
|
|
5763
|
+
parameters: mergeLightMarkerParameters(props.parameters)
|
|
5764
|
+
});
|
|
5765
|
+
this.lightModelProps = props;
|
|
5766
|
+
this._instanceData = instanceData;
|
|
5767
|
+
this._managedBuffers = managedBuffers;
|
|
5768
|
+
this.buildInstanceData = options.buildInstanceData;
|
|
5769
|
+
this.sizePropNames = options.sizePropNames;
|
|
5770
|
+
}
|
|
5771
|
+
destroy() {
|
|
5772
|
+
super.destroy();
|
|
5773
|
+
destroyManagedInstanceBuffers(this._managedBuffers);
|
|
5774
|
+
this._managedBuffers = {};
|
|
5775
|
+
}
|
|
5776
|
+
draw(renderPass) {
|
|
5777
|
+
if (this.instanceCount === 0) {
|
|
5778
|
+
return true;
|
|
5779
|
+
}
|
|
5780
|
+
return super.draw(renderPass);
|
|
5781
|
+
}
|
|
5782
|
+
setProps(props) {
|
|
5783
|
+
this.lightModelProps = { ...this.lightModelProps, ...props };
|
|
5784
|
+
if (props.parameters) {
|
|
5785
|
+
this.setParameters(mergeLightMarkerParameters(this.lightModelProps.parameters));
|
|
5786
|
+
}
|
|
5787
|
+
if ("viewMatrix" in props || "projectionMatrix" in props) {
|
|
5788
|
+
this.shaderInputs.setProps({
|
|
5789
|
+
lightMarker: { viewProjectionMatrix: createViewProjectionMatrix(this.lightModelProps) }
|
|
5790
|
+
});
|
|
5791
|
+
this.setNeedsRedraw("lightMarker camera");
|
|
5792
|
+
}
|
|
5793
|
+
if (shouldRebuildInstanceData(props, this.sizePropNames)) {
|
|
5794
|
+
this.rebuildInstanceData();
|
|
5795
|
+
}
|
|
5796
|
+
}
|
|
5797
|
+
rebuildInstanceData() {
|
|
5798
|
+
const nextInstanceData = this.buildInstanceData(this.lightModelProps);
|
|
5799
|
+
const nextManagedBuffers = createManagedInstanceBuffers(this.device, this.id, nextInstanceData);
|
|
5800
|
+
this.setAttributes(nextManagedBuffers);
|
|
5801
|
+
this.setInstanceCount(nextInstanceData.instanceCount);
|
|
5802
|
+
destroyManagedInstanceBuffers(this._managedBuffers);
|
|
5803
|
+
this._managedBuffers = nextManagedBuffers;
|
|
5804
|
+
this._instanceData = nextInstanceData;
|
|
5805
|
+
}
|
|
5806
|
+
};
|
|
5807
|
+
function buildPointLightInstanceData(props) {
|
|
5808
|
+
const pointLights = getPointLights(props.lights);
|
|
5809
|
+
const context = getLightMarkerContext(props);
|
|
5810
|
+
const pointLightRadius = props.pointLightRadius ?? DEFAULT_POINT_LIGHT_RADIUS_FACTOR * context.sceneScale * context.markerScale;
|
|
5811
|
+
return createLightMarkerInstanceData(
|
|
5812
|
+
pointLights.length,
|
|
5813
|
+
(light, _index) => ({
|
|
5814
|
+
color: getDisplayColor(light),
|
|
5815
|
+
direction: DEFAULT_DIRECTION_FALLBACK,
|
|
5816
|
+
position: light.position,
|
|
5817
|
+
scale: [pointLightRadius, pointLightRadius, pointLightRadius]
|
|
5818
|
+
}),
|
|
5819
|
+
pointLights
|
|
5820
|
+
);
|
|
5821
|
+
}
|
|
5822
|
+
function buildSpotLightInstanceData(props) {
|
|
5823
|
+
const spotLights = getSpotLights(props.lights);
|
|
5824
|
+
const context = getLightMarkerContext(props);
|
|
5825
|
+
const spotLightLength = props.spotLightLength ?? DEFAULT_SPOT_LIGHT_LENGTH_FACTOR * context.sceneScale * context.markerScale;
|
|
5826
|
+
return createLightMarkerInstanceData(
|
|
5827
|
+
spotLights.length,
|
|
5828
|
+
(light, _index) => {
|
|
5829
|
+
const outerConeAngle = clamp(
|
|
5830
|
+
light.outerConeAngle ?? Math.PI / 4,
|
|
5831
|
+
0,
|
|
5832
|
+
Math.PI / 2 - SPOTLIGHT_OUTER_CONE_EPSILON
|
|
5833
|
+
);
|
|
5834
|
+
const radius = Math.tan(outerConeAngle) * spotLightLength;
|
|
5835
|
+
return {
|
|
5836
|
+
color: getDisplayColor(light),
|
|
5837
|
+
direction: normalizeDirection(light.direction),
|
|
5838
|
+
position: light.position,
|
|
5839
|
+
scale: [radius, spotLightLength, radius]
|
|
5840
|
+
};
|
|
5841
|
+
},
|
|
5842
|
+
spotLights
|
|
5843
|
+
);
|
|
5844
|
+
}
|
|
5845
|
+
function buildDirectionalLightInstanceData(props) {
|
|
5846
|
+
const directionalLights = getDirectionalLights(props.lights);
|
|
5847
|
+
const context = getLightMarkerContext(props);
|
|
5848
|
+
const directionalLightLength = props.directionalLightLength ?? DEFAULT_DIRECTIONAL_LIGHT_LENGTH_FACTOR * context.sceneScale * context.markerScale;
|
|
5849
|
+
const directionalLightRadius = directionalLightLength * DEFAULT_DIRECTIONAL_LIGHT_RADIUS_FACTOR;
|
|
5850
|
+
return createLightMarkerInstanceData(
|
|
5851
|
+
directionalLights.length,
|
|
5852
|
+
(light, _index) => {
|
|
5853
|
+
const direction = normalizeDirection(light.direction);
|
|
5854
|
+
const position = [
|
|
5855
|
+
context.sceneCenter[0] - direction[0] * context.sceneScale * DIRECTIONAL_ANCHOR_DISTANCE_FACTOR,
|
|
5856
|
+
context.sceneCenter[1] - direction[1] * context.sceneScale * DIRECTIONAL_ANCHOR_DISTANCE_FACTOR,
|
|
5857
|
+
context.sceneCenter[2] - direction[2] * context.sceneScale * DIRECTIONAL_ANCHOR_DISTANCE_FACTOR
|
|
5858
|
+
];
|
|
5859
|
+
return {
|
|
5860
|
+
color: getDisplayColor(light),
|
|
5861
|
+
direction,
|
|
5862
|
+
position,
|
|
5863
|
+
scale: [directionalLightRadius, directionalLightLength, directionalLightRadius]
|
|
5864
|
+
};
|
|
5865
|
+
},
|
|
5866
|
+
directionalLights
|
|
5867
|
+
);
|
|
5868
|
+
}
|
|
5869
|
+
function getPointLights(lights) {
|
|
5870
|
+
return lights.filter((light) => light.type === "point");
|
|
5871
|
+
}
|
|
5872
|
+
function getSpotLights(lights) {
|
|
5873
|
+
return lights.filter((light) => light.type === "spot");
|
|
5874
|
+
}
|
|
5875
|
+
function getDirectionalLights(lights) {
|
|
5876
|
+
return lights.filter((light) => light.type === "directional");
|
|
5877
|
+
}
|
|
5878
|
+
function getLightMarkerContext(props) {
|
|
5879
|
+
const bounds = getSceneBounds(props.lights, props.bounds);
|
|
5880
|
+
const sceneCenter = [
|
|
5881
|
+
(bounds[0][0] + bounds[1][0]) / 2,
|
|
5882
|
+
(bounds[0][1] + bounds[1][1]) / 2,
|
|
5883
|
+
(bounds[0][2] + bounds[1][2]) / 2
|
|
5884
|
+
];
|
|
5885
|
+
const sceneScale = Math.max(
|
|
5886
|
+
Math.hypot(
|
|
5887
|
+
bounds[1][0] - bounds[0][0],
|
|
5888
|
+
bounds[1][1] - bounds[0][1],
|
|
5889
|
+
bounds[1][2] - bounds[0][2]
|
|
5890
|
+
),
|
|
5891
|
+
MIN_SCENE_SCALE
|
|
5892
|
+
);
|
|
5893
|
+
return {
|
|
5894
|
+
bounds,
|
|
5895
|
+
markerScale: Math.max(props.markerScale ?? DEFAULT_MARKER_SCALE, 0),
|
|
5896
|
+
sceneCenter,
|
|
5897
|
+
sceneScale
|
|
5898
|
+
};
|
|
5899
|
+
}
|
|
5900
|
+
function getDisplayColor(light) {
|
|
5901
|
+
const color = light.color || DEFAULT_LIGHT_COLOR;
|
|
5902
|
+
const intensity = Math.max(light.intensity ?? 1, 0);
|
|
5903
|
+
const brightness = clamp(0.35 + 0.3 * Math.log10(intensity + 1), 0.35, 1);
|
|
5904
|
+
return [
|
|
5905
|
+
clamp(color[0] / LIGHT_COLOR_FACTOR, 0, 1) * brightness,
|
|
5906
|
+
clamp(color[1] / LIGHT_COLOR_FACTOR, 0, 1) * brightness,
|
|
5907
|
+
clamp(color[2] / LIGHT_COLOR_FACTOR, 0, 1) * brightness,
|
|
5908
|
+
1
|
|
5909
|
+
];
|
|
5910
|
+
}
|
|
5911
|
+
function normalizeDirection(direction) {
|
|
5912
|
+
const [x, y, z] = direction || DEFAULT_DIRECTION_FALLBACK;
|
|
5913
|
+
const length = Math.hypot(x, y, z);
|
|
5914
|
+
if (length === 0) {
|
|
5915
|
+
return [...DEFAULT_DIRECTION_FALLBACK];
|
|
5916
|
+
}
|
|
5917
|
+
return [x / length, y / length, z / length];
|
|
5918
|
+
}
|
|
5919
|
+
function createLightMarkerInstanceData(instanceCount, getInstance, lights = []) {
|
|
5920
|
+
const instancePositions = new Float32Array(instanceCount * 3);
|
|
5921
|
+
const instanceDirections = new Float32Array(instanceCount * 3);
|
|
5922
|
+
const instanceScales = new Float32Array(instanceCount * 3);
|
|
5923
|
+
const instanceColors = new Float32Array(instanceCount * 4);
|
|
5924
|
+
for (const [index, light] of lights.entries()) {
|
|
5925
|
+
const instance = getInstance(light, index);
|
|
5926
|
+
instancePositions.set(instance.position, index * 3);
|
|
5927
|
+
instanceDirections.set(instance.direction, index * 3);
|
|
5928
|
+
instanceScales.set(instance.scale, index * 3);
|
|
5929
|
+
instanceColors.set(instance.color, index * 4);
|
|
5930
|
+
}
|
|
5931
|
+
return {
|
|
5932
|
+
instanceCount,
|
|
5933
|
+
instancePositions,
|
|
5934
|
+
instanceDirections,
|
|
5935
|
+
instanceScales,
|
|
5936
|
+
instanceColors
|
|
5937
|
+
};
|
|
5938
|
+
}
|
|
5939
|
+
function getSceneBounds(lights, bounds) {
|
|
5940
|
+
if (bounds) {
|
|
5941
|
+
return cloneBounds(bounds);
|
|
5942
|
+
}
|
|
5943
|
+
const positions = [
|
|
5944
|
+
...getPointLights(lights).map((light) => light.position),
|
|
5945
|
+
...getSpotLights(lights).map((light) => light.position)
|
|
5946
|
+
];
|
|
5947
|
+
if (positions.length === 0) {
|
|
5948
|
+
return [
|
|
5949
|
+
[-0.5, -0.5, -0.5],
|
|
5950
|
+
[0.5, 0.5, 0.5]
|
|
5951
|
+
];
|
|
5952
|
+
}
|
|
5953
|
+
const minBounds = [...positions[0]];
|
|
5954
|
+
const maxBounds = [...positions[0]];
|
|
5955
|
+
for (const position of positions.slice(1)) {
|
|
5956
|
+
minBounds[0] = Math.min(minBounds[0], position[0]);
|
|
5957
|
+
minBounds[1] = Math.min(minBounds[1], position[1]);
|
|
5958
|
+
minBounds[2] = Math.min(minBounds[2], position[2]);
|
|
5959
|
+
maxBounds[0] = Math.max(maxBounds[0], position[0]);
|
|
5960
|
+
maxBounds[1] = Math.max(maxBounds[1], position[1]);
|
|
5961
|
+
maxBounds[2] = Math.max(maxBounds[2], position[2]);
|
|
5962
|
+
}
|
|
5963
|
+
return [minBounds, maxBounds];
|
|
5964
|
+
}
|
|
5965
|
+
function cloneBounds(bounds) {
|
|
5966
|
+
return [[...bounds[0]], [...bounds[1]]];
|
|
5967
|
+
}
|
|
5968
|
+
function createManagedInstanceBuffers(device, idPrefix, instanceData) {
|
|
5969
|
+
return {
|
|
5970
|
+
instancePosition: device.createBuffer({
|
|
5971
|
+
id: `${idPrefix}-instance-position`,
|
|
5972
|
+
data: getBufferDataOrPlaceholder(instanceData.instancePositions, 3)
|
|
5973
|
+
}),
|
|
5974
|
+
instanceDirection: device.createBuffer({
|
|
5975
|
+
id: `${idPrefix}-instance-direction`,
|
|
5976
|
+
data: getBufferDataOrPlaceholder(instanceData.instanceDirections, 3)
|
|
5977
|
+
}),
|
|
5978
|
+
instanceScale: device.createBuffer({
|
|
5979
|
+
id: `${idPrefix}-instance-scale`,
|
|
5980
|
+
data: getBufferDataOrPlaceholder(instanceData.instanceScales, 3)
|
|
5981
|
+
}),
|
|
5982
|
+
instanceColor: device.createBuffer({
|
|
5983
|
+
id: `${idPrefix}-instance-color`,
|
|
5984
|
+
data: getBufferDataOrPlaceholder(instanceData.instanceColors, 4)
|
|
5985
|
+
})
|
|
5986
|
+
};
|
|
5987
|
+
}
|
|
5988
|
+
function getBufferDataOrPlaceholder(data, size) {
|
|
5989
|
+
return data.length > 0 ? data : new Float32Array(size);
|
|
5990
|
+
}
|
|
5991
|
+
function destroyManagedInstanceBuffers(managedBuffers) {
|
|
5992
|
+
for (const buffer of Object.values(managedBuffers)) {
|
|
5993
|
+
buffer?.destroy();
|
|
5994
|
+
}
|
|
5995
|
+
}
|
|
5996
|
+
function createViewProjectionMatrix(props) {
|
|
5997
|
+
return new Matrix4(props.projectionMatrix).multiplyRight(props.viewMatrix);
|
|
5998
|
+
}
|
|
5999
|
+
function shouldRebuildInstanceData(props, sizePropNames) {
|
|
6000
|
+
if ("lights" in props || "bounds" in props || "markerScale" in props) {
|
|
6001
|
+
return true;
|
|
6002
|
+
}
|
|
6003
|
+
return sizePropNames.some((sizePropName) => sizePropName in props);
|
|
6004
|
+
}
|
|
6005
|
+
function mergeLightMarkerParameters(parameters) {
|
|
6006
|
+
return {
|
|
6007
|
+
...LIGHT_MARKER_PARAMETERS,
|
|
6008
|
+
...parameters || {}
|
|
6009
|
+
};
|
|
6010
|
+
}
|
|
6011
|
+
function getLightMarkerShaders(anchorMode) {
|
|
6012
|
+
const localPositionWGSL = anchorMode === "apex" ? APEX_LOCAL_POSITION_WGSL : CENTERED_LOCAL_POSITION_WGSL;
|
|
6013
|
+
const localPositionGLSL = anchorMode === "apex" ? APEX_LOCAL_POSITION_GLSL : CENTERED_LOCAL_POSITION_GLSL;
|
|
6014
|
+
return {
|
|
6015
|
+
source: `struct lightMarkerUniforms {
|
|
6016
|
+
viewProjectionMatrix: mat4x4<f32>,
|
|
6017
|
+
};
|
|
6018
|
+
|
|
6019
|
+
@binding(0) @group(0) var<uniform> lightMarker : lightMarkerUniforms;
|
|
6020
|
+
|
|
6021
|
+
struct VertexInputs {
|
|
6022
|
+
@location(0) positions : vec3<f32>,
|
|
6023
|
+
@location(1) instancePosition : vec3<f32>,
|
|
6024
|
+
@location(2) instanceDirection : vec3<f32>,
|
|
6025
|
+
@location(3) instanceScale : vec3<f32>,
|
|
6026
|
+
@location(4) instanceColor : vec4<f32>,
|
|
6027
|
+
};
|
|
6028
|
+
|
|
6029
|
+
struct FragmentInputs {
|
|
6030
|
+
@builtin(position) Position : vec4<f32>,
|
|
6031
|
+
@location(0) color : vec4<f32>,
|
|
6032
|
+
};
|
|
6033
|
+
|
|
6034
|
+
fn lightMarker_rotate(localPosition: vec3<f32>, direction: vec3<f32>) -> vec3<f32> {
|
|
6035
|
+
let forward = normalize(direction);
|
|
6036
|
+
var helperAxis = vec3<f32>(0.0, 1.0, 0.0);
|
|
6037
|
+
if (abs(forward.y) > 0.999) {
|
|
6038
|
+
helperAxis = vec3<f32>(1.0, 0.0, 0.0);
|
|
6039
|
+
}
|
|
6040
|
+
|
|
6041
|
+
let tangent = normalize(cross(helperAxis, forward));
|
|
6042
|
+
let bitangent = cross(forward, tangent);
|
|
6043
|
+
return tangent * localPosition.x + forward * localPosition.y + bitangent * localPosition.z;
|
|
6044
|
+
}
|
|
6045
|
+
|
|
6046
|
+
@vertex
|
|
6047
|
+
fn vertexMain(inputs: VertexInputs) -> FragmentInputs {
|
|
6048
|
+
var outputs : FragmentInputs;
|
|
6049
|
+
let localPosition = ${localPositionWGSL};
|
|
6050
|
+
let worldPosition = inputs.instancePosition + lightMarker_rotate(localPosition, inputs.instanceDirection);
|
|
6051
|
+
outputs.Position = lightMarker.viewProjectionMatrix * vec4<f32>(worldPosition, 1.0);
|
|
6052
|
+
outputs.color = inputs.instanceColor;
|
|
6053
|
+
return outputs;
|
|
6054
|
+
}
|
|
6055
|
+
|
|
6056
|
+
@fragment
|
|
6057
|
+
fn fragmentMain(inputs: FragmentInputs) -> @location(0) vec4<f32> {
|
|
6058
|
+
return inputs.color;
|
|
6059
|
+
}
|
|
6060
|
+
`,
|
|
6061
|
+
vs: `#version 300 es
|
|
6062
|
+
|
|
6063
|
+
in vec3 positions;
|
|
6064
|
+
in vec3 instancePosition;
|
|
6065
|
+
in vec3 instanceDirection;
|
|
6066
|
+
in vec3 instanceScale;
|
|
6067
|
+
in vec4 instanceColor;
|
|
6068
|
+
|
|
6069
|
+
uniform lightMarkerUniforms {
|
|
6070
|
+
mat4 viewProjectionMatrix;
|
|
6071
|
+
} lightMarker;
|
|
6072
|
+
|
|
6073
|
+
out vec4 vColor;
|
|
6074
|
+
|
|
6075
|
+
vec3 lightMarker_rotate(vec3 localPosition, vec3 direction) {
|
|
6076
|
+
vec3 forward = normalize(direction);
|
|
6077
|
+
vec3 helperAxis = abs(forward.y) > 0.999 ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0);
|
|
6078
|
+
vec3 tangent = normalize(cross(helperAxis, forward));
|
|
6079
|
+
vec3 bitangent = cross(forward, tangent);
|
|
6080
|
+
return tangent * localPosition.x + forward * localPosition.y + bitangent * localPosition.z;
|
|
6081
|
+
}
|
|
6082
|
+
|
|
6083
|
+
void main(void) {
|
|
6084
|
+
vec3 localPosition = ${localPositionGLSL};
|
|
6085
|
+
vec3 worldPosition = instancePosition + lightMarker_rotate(localPosition, instanceDirection);
|
|
6086
|
+
gl_Position = lightMarker.viewProjectionMatrix * vec4(worldPosition, 1.0);
|
|
6087
|
+
vColor = instanceColor;
|
|
6088
|
+
}
|
|
6089
|
+
`,
|
|
6090
|
+
fs: `#version 300 es
|
|
6091
|
+
precision highp float;
|
|
6092
|
+
|
|
6093
|
+
in vec4 vColor;
|
|
6094
|
+
out vec4 fragColor;
|
|
6095
|
+
|
|
6096
|
+
void main(void) {
|
|
6097
|
+
fragColor = vColor;
|
|
6098
|
+
}
|
|
6099
|
+
`
|
|
6100
|
+
};
|
|
6101
|
+
}
|
|
6102
|
+
function clamp(value, minValue, maxValue) {
|
|
6103
|
+
return Math.min(maxValue, Math.max(minValue, value));
|
|
6104
|
+
}
|
|
6105
|
+
|
|
6106
|
+
// src/models/point-light-model.ts
|
|
6107
|
+
var POINT_LIGHT_GEOMETRY = new SphereGeometry({
|
|
6108
|
+
nlat: 8,
|
|
6109
|
+
nlong: 12,
|
|
6110
|
+
radius: 1
|
|
6111
|
+
});
|
|
6112
|
+
var PointLightModel = class extends BaseLightModel {
|
|
6113
|
+
constructor(device, props) {
|
|
6114
|
+
super(device, props, {
|
|
6115
|
+
anchorMode: "centered",
|
|
6116
|
+
buildInstanceData: buildPointLightInstanceData,
|
|
6117
|
+
geometry: POINT_LIGHT_GEOMETRY,
|
|
6118
|
+
idPrefix: "point-light-model",
|
|
6119
|
+
sizePropNames: ["pointLightRadius"]
|
|
6120
|
+
});
|
|
6121
|
+
}
|
|
6122
|
+
};
|
|
6123
|
+
|
|
6124
|
+
// src/geometries/truncated-cone-geometry.ts
|
|
6125
|
+
var INDEX_OFFSETS = {
|
|
6126
|
+
x: [2, 0, 1],
|
|
6127
|
+
y: [0, 1, 2],
|
|
6128
|
+
z: [1, 2, 0]
|
|
6129
|
+
};
|
|
6130
|
+
var TruncatedConeGeometry = class extends Geometry {
|
|
6131
|
+
constructor(props = {}) {
|
|
6132
|
+
const { id = uid("truncated-code-geometry") } = props;
|
|
6133
|
+
const { indices, attributes } = tesselateTruncatedCone(props);
|
|
6134
|
+
super({
|
|
6135
|
+
...props,
|
|
6136
|
+
id,
|
|
6137
|
+
topology: "triangle-list",
|
|
6138
|
+
indices,
|
|
6139
|
+
attributes: {
|
|
6140
|
+
POSITION: { size: 3, value: attributes.POSITION },
|
|
6141
|
+
NORMAL: { size: 3, value: attributes.NORMAL },
|
|
6142
|
+
TEXCOORD_0: { size: 2, value: attributes.TEXCOORD_0 },
|
|
6143
|
+
...props.attributes
|
|
6144
|
+
}
|
|
6145
|
+
});
|
|
6146
|
+
}
|
|
6147
|
+
};
|
|
6148
|
+
function tesselateTruncatedCone(props = {}) {
|
|
6149
|
+
const {
|
|
6150
|
+
bottomRadius = 0,
|
|
6151
|
+
topRadius = 0,
|
|
6152
|
+
height = 1,
|
|
6153
|
+
nradial = 10,
|
|
6154
|
+
nvertical = 10,
|
|
6155
|
+
verticalAxis = "y",
|
|
6156
|
+
topCap = false,
|
|
6157
|
+
bottomCap = false
|
|
6158
|
+
} = props;
|
|
6159
|
+
const extra = (topCap ? 2 : 0) + (bottomCap ? 2 : 0);
|
|
6160
|
+
const numVertices = (nradial + 1) * (nvertical + 1 + extra);
|
|
6161
|
+
const slant = Math.atan2(bottomRadius - topRadius, height);
|
|
6162
|
+
const msin = Math.sin;
|
|
6163
|
+
const mcos = Math.cos;
|
|
6164
|
+
const mpi = Math.PI;
|
|
6165
|
+
const cosSlant = mcos(slant);
|
|
6166
|
+
const sinSlant = msin(slant);
|
|
6167
|
+
const start = topCap ? -2 : 0;
|
|
6168
|
+
const end = nvertical + (bottomCap ? 2 : 0);
|
|
6169
|
+
const vertsAroundEdge = nradial + 1;
|
|
6170
|
+
const indices = new Uint16Array(nradial * (nvertical + extra) * 6);
|
|
6171
|
+
const indexOffset = INDEX_OFFSETS[verticalAxis];
|
|
6172
|
+
const positions = new Float32Array(numVertices * 3);
|
|
6173
|
+
const normals = new Float32Array(numVertices * 3);
|
|
6174
|
+
const texCoords = new Float32Array(numVertices * 2);
|
|
6175
|
+
let i3 = 0;
|
|
6176
|
+
let i2 = 0;
|
|
6177
|
+
for (let i = start; i <= end; i++) {
|
|
6178
|
+
let v = i / nvertical;
|
|
6179
|
+
let y = height * v;
|
|
6180
|
+
let ringRadius;
|
|
6181
|
+
if (i < 0) {
|
|
6182
|
+
y = 0;
|
|
6183
|
+
v = 1;
|
|
6184
|
+
ringRadius = bottomRadius;
|
|
6185
|
+
} else if (i > nvertical) {
|
|
6186
|
+
y = height;
|
|
6187
|
+
v = 1;
|
|
6188
|
+
ringRadius = topRadius;
|
|
6189
|
+
} else {
|
|
6190
|
+
ringRadius = bottomRadius + (topRadius - bottomRadius) * (i / nvertical);
|
|
6191
|
+
}
|
|
6192
|
+
if (i === -2 || i === nvertical + 2) {
|
|
6193
|
+
ringRadius = 0;
|
|
6194
|
+
v = 0;
|
|
6195
|
+
}
|
|
6196
|
+
y -= height / 2;
|
|
6197
|
+
for (let j = 0; j < vertsAroundEdge; j++) {
|
|
6198
|
+
const sin = msin(j * mpi * 2 / nradial);
|
|
6199
|
+
const cos = mcos(j * mpi * 2 / nradial);
|
|
6200
|
+
positions[i3 + indexOffset[0]] = sin * ringRadius;
|
|
6201
|
+
positions[i3 + indexOffset[1]] = y;
|
|
6202
|
+
positions[i3 + indexOffset[2]] = cos * ringRadius;
|
|
6203
|
+
normals[i3 + indexOffset[0]] = i < 0 || i > nvertical ? 0 : sin * cosSlant;
|
|
6204
|
+
normals[i3 + indexOffset[1]] = i < 0 ? -1 : i > nvertical ? 1 : sinSlant;
|
|
6205
|
+
normals[i3 + indexOffset[2]] = i < 0 || i > nvertical ? 0 : cos * cosSlant;
|
|
6206
|
+
texCoords[i2 + 0] = j / nradial;
|
|
6207
|
+
texCoords[i2 + 1] = v;
|
|
6208
|
+
i2 += 2;
|
|
6209
|
+
i3 += 3;
|
|
6210
|
+
}
|
|
6211
|
+
}
|
|
6212
|
+
for (let i = 0; i < nvertical + extra; i++) {
|
|
6213
|
+
for (let j = 0; j < nradial; j++) {
|
|
6214
|
+
const index = (i * nradial + j) * 6;
|
|
6215
|
+
indices[index + 0] = vertsAroundEdge * (i + 0) + 0 + j;
|
|
6216
|
+
indices[index + 1] = vertsAroundEdge * (i + 0) + 1 + j;
|
|
6217
|
+
indices[index + 2] = vertsAroundEdge * (i + 1) + 1 + j;
|
|
6218
|
+
indices[index + 3] = vertsAroundEdge * (i + 0) + 0 + j;
|
|
6219
|
+
indices[index + 4] = vertsAroundEdge * (i + 1) + 1 + j;
|
|
6220
|
+
indices[index + 5] = vertsAroundEdge * (i + 1) + 0 + j;
|
|
6221
|
+
}
|
|
6222
|
+
}
|
|
6223
|
+
return {
|
|
6224
|
+
indices,
|
|
6225
|
+
attributes: {
|
|
6226
|
+
POSITION: positions,
|
|
6227
|
+
NORMAL: normals,
|
|
6228
|
+
TEXCOORD_0: texCoords
|
|
6229
|
+
}
|
|
6230
|
+
};
|
|
6231
|
+
}
|
|
6232
|
+
|
|
6233
|
+
// src/geometries/cone-geometry.ts
|
|
6234
|
+
var ConeGeometry = class extends TruncatedConeGeometry {
|
|
6235
|
+
constructor(props = {}) {
|
|
6236
|
+
const { id = uid("cone-geometry"), radius = 1, cap = true } = props;
|
|
6237
|
+
super({
|
|
6238
|
+
...props,
|
|
6239
|
+
id,
|
|
6240
|
+
topRadius: 0,
|
|
6241
|
+
topCap: Boolean(cap),
|
|
6242
|
+
bottomCap: Boolean(cap),
|
|
6243
|
+
bottomRadius: radius
|
|
6244
|
+
});
|
|
6245
|
+
}
|
|
6246
|
+
};
|
|
6247
|
+
|
|
6248
|
+
// src/models/spot-light-model.ts
|
|
6249
|
+
var SPOT_LIGHT_GEOMETRY = new ConeGeometry({
|
|
6250
|
+
cap: true,
|
|
6251
|
+
nradial: 16,
|
|
6252
|
+
nvertical: 1,
|
|
6253
|
+
radius: 1
|
|
6254
|
+
});
|
|
6255
|
+
var SpotLightModel = class extends BaseLightModel {
|
|
6256
|
+
constructor(device, props) {
|
|
6257
|
+
super(device, props, {
|
|
6258
|
+
anchorMode: "apex",
|
|
6259
|
+
buildInstanceData: buildSpotLightInstanceData,
|
|
6260
|
+
geometry: SPOT_LIGHT_GEOMETRY,
|
|
6261
|
+
idPrefix: "spot-light-model",
|
|
6262
|
+
sizePropNames: ["spotLightLength"]
|
|
6263
|
+
});
|
|
6264
|
+
}
|
|
6265
|
+
};
|
|
6266
|
+
|
|
6267
|
+
// src/models/directional-light-model.ts
|
|
6268
|
+
var DIRECTIONAL_LIGHT_GEOMETRY = new ConeGeometry({
|
|
6269
|
+
cap: true,
|
|
6270
|
+
nradial: 12,
|
|
6271
|
+
nvertical: 1,
|
|
6272
|
+
radius: 1
|
|
6273
|
+
});
|
|
6274
|
+
var DirectionalLightModel = class extends BaseLightModel {
|
|
6275
|
+
constructor(device, props) {
|
|
6276
|
+
super(device, props, {
|
|
6277
|
+
anchorMode: "apex",
|
|
6278
|
+
buildInstanceData: buildDirectionalLightInstanceData,
|
|
6279
|
+
geometry: DIRECTIONAL_LIGHT_GEOMETRY,
|
|
6280
|
+
idPrefix: "directional-light-model",
|
|
6281
|
+
sizePropNames: ["directionalLightLength"]
|
|
6282
|
+
});
|
|
6283
|
+
}
|
|
6284
|
+
};
|
|
6285
|
+
|
|
6286
|
+
// src/scenegraph/scenegraph-node.ts
|
|
6287
|
+
function assert2(condition, message) {
|
|
6288
|
+
if (!condition) {
|
|
6289
|
+
throw new Error(message);
|
|
6290
|
+
}
|
|
6291
|
+
}
|
|
6292
|
+
var ScenegraphNode = class {
|
|
6293
|
+
id;
|
|
6294
|
+
matrix = new Matrix4();
|
|
6295
|
+
display = true;
|
|
6296
|
+
position = new Vector3();
|
|
6297
|
+
rotation = new Vector3();
|
|
6298
|
+
scale = new Vector3(1, 1, 1);
|
|
6299
|
+
userData = {};
|
|
6300
|
+
props = {};
|
|
6301
|
+
constructor(props = {}) {
|
|
6302
|
+
const { id } = props;
|
|
6303
|
+
this.id = id || uid(this.constructor.name);
|
|
6304
|
+
this._setScenegraphNodeProps(props);
|
|
6305
|
+
}
|
|
6306
|
+
getBounds() {
|
|
6307
|
+
return null;
|
|
5431
6308
|
}
|
|
5432
6309
|
destroy() {
|
|
5433
6310
|
}
|
|
@@ -5685,130 +6562,6 @@ void main(void) {
|
|
|
5685
6562
|
}
|
|
5686
6563
|
};
|
|
5687
6564
|
|
|
5688
|
-
// src/geometries/truncated-cone-geometry.ts
|
|
5689
|
-
var INDEX_OFFSETS = {
|
|
5690
|
-
x: [2, 0, 1],
|
|
5691
|
-
y: [0, 1, 2],
|
|
5692
|
-
z: [1, 2, 0]
|
|
5693
|
-
};
|
|
5694
|
-
var TruncatedConeGeometry = class extends Geometry {
|
|
5695
|
-
constructor(props = {}) {
|
|
5696
|
-
const { id = uid("truncated-code-geometry") } = props;
|
|
5697
|
-
const { indices, attributes } = tesselateTruncatedCone(props);
|
|
5698
|
-
super({
|
|
5699
|
-
...props,
|
|
5700
|
-
id,
|
|
5701
|
-
topology: "triangle-list",
|
|
5702
|
-
indices,
|
|
5703
|
-
attributes: {
|
|
5704
|
-
POSITION: { size: 3, value: attributes.POSITION },
|
|
5705
|
-
NORMAL: { size: 3, value: attributes.NORMAL },
|
|
5706
|
-
TEXCOORD_0: { size: 2, value: attributes.TEXCOORD_0 },
|
|
5707
|
-
...props.attributes
|
|
5708
|
-
}
|
|
5709
|
-
});
|
|
5710
|
-
}
|
|
5711
|
-
};
|
|
5712
|
-
function tesselateTruncatedCone(props = {}) {
|
|
5713
|
-
const {
|
|
5714
|
-
bottomRadius = 0,
|
|
5715
|
-
topRadius = 0,
|
|
5716
|
-
height = 1,
|
|
5717
|
-
nradial = 10,
|
|
5718
|
-
nvertical = 10,
|
|
5719
|
-
verticalAxis = "y",
|
|
5720
|
-
topCap = false,
|
|
5721
|
-
bottomCap = false
|
|
5722
|
-
} = props;
|
|
5723
|
-
const extra = (topCap ? 2 : 0) + (bottomCap ? 2 : 0);
|
|
5724
|
-
const numVertices = (nradial + 1) * (nvertical + 1 + extra);
|
|
5725
|
-
const slant = Math.atan2(bottomRadius - topRadius, height);
|
|
5726
|
-
const msin = Math.sin;
|
|
5727
|
-
const mcos = Math.cos;
|
|
5728
|
-
const mpi = Math.PI;
|
|
5729
|
-
const cosSlant = mcos(slant);
|
|
5730
|
-
const sinSlant = msin(slant);
|
|
5731
|
-
const start = topCap ? -2 : 0;
|
|
5732
|
-
const end = nvertical + (bottomCap ? 2 : 0);
|
|
5733
|
-
const vertsAroundEdge = nradial + 1;
|
|
5734
|
-
const indices = new Uint16Array(nradial * (nvertical + extra) * 6);
|
|
5735
|
-
const indexOffset = INDEX_OFFSETS[verticalAxis];
|
|
5736
|
-
const positions = new Float32Array(numVertices * 3);
|
|
5737
|
-
const normals = new Float32Array(numVertices * 3);
|
|
5738
|
-
const texCoords = new Float32Array(numVertices * 2);
|
|
5739
|
-
let i3 = 0;
|
|
5740
|
-
let i2 = 0;
|
|
5741
|
-
for (let i = start; i <= end; i++) {
|
|
5742
|
-
let v = i / nvertical;
|
|
5743
|
-
let y = height * v;
|
|
5744
|
-
let ringRadius;
|
|
5745
|
-
if (i < 0) {
|
|
5746
|
-
y = 0;
|
|
5747
|
-
v = 1;
|
|
5748
|
-
ringRadius = bottomRadius;
|
|
5749
|
-
} else if (i > nvertical) {
|
|
5750
|
-
y = height;
|
|
5751
|
-
v = 1;
|
|
5752
|
-
ringRadius = topRadius;
|
|
5753
|
-
} else {
|
|
5754
|
-
ringRadius = bottomRadius + (topRadius - bottomRadius) * (i / nvertical);
|
|
5755
|
-
}
|
|
5756
|
-
if (i === -2 || i === nvertical + 2) {
|
|
5757
|
-
ringRadius = 0;
|
|
5758
|
-
v = 0;
|
|
5759
|
-
}
|
|
5760
|
-
y -= height / 2;
|
|
5761
|
-
for (let j = 0; j < vertsAroundEdge; j++) {
|
|
5762
|
-
const sin = msin(j * mpi * 2 / nradial);
|
|
5763
|
-
const cos = mcos(j * mpi * 2 / nradial);
|
|
5764
|
-
positions[i3 + indexOffset[0]] = sin * ringRadius;
|
|
5765
|
-
positions[i3 + indexOffset[1]] = y;
|
|
5766
|
-
positions[i3 + indexOffset[2]] = cos * ringRadius;
|
|
5767
|
-
normals[i3 + indexOffset[0]] = i < 0 || i > nvertical ? 0 : sin * cosSlant;
|
|
5768
|
-
normals[i3 + indexOffset[1]] = i < 0 ? -1 : i > nvertical ? 1 : sinSlant;
|
|
5769
|
-
normals[i3 + indexOffset[2]] = i < 0 || i > nvertical ? 0 : cos * cosSlant;
|
|
5770
|
-
texCoords[i2 + 0] = j / nradial;
|
|
5771
|
-
texCoords[i2 + 1] = v;
|
|
5772
|
-
i2 += 2;
|
|
5773
|
-
i3 += 3;
|
|
5774
|
-
}
|
|
5775
|
-
}
|
|
5776
|
-
for (let i = 0; i < nvertical + extra; i++) {
|
|
5777
|
-
for (let j = 0; j < nradial; j++) {
|
|
5778
|
-
const index = (i * nradial + j) * 6;
|
|
5779
|
-
indices[index + 0] = vertsAroundEdge * (i + 0) + 0 + j;
|
|
5780
|
-
indices[index + 1] = vertsAroundEdge * (i + 0) + 1 + j;
|
|
5781
|
-
indices[index + 2] = vertsAroundEdge * (i + 1) + 1 + j;
|
|
5782
|
-
indices[index + 3] = vertsAroundEdge * (i + 0) + 0 + j;
|
|
5783
|
-
indices[index + 4] = vertsAroundEdge * (i + 1) + 1 + j;
|
|
5784
|
-
indices[index + 5] = vertsAroundEdge * (i + 1) + 0 + j;
|
|
5785
|
-
}
|
|
5786
|
-
}
|
|
5787
|
-
return {
|
|
5788
|
-
indices,
|
|
5789
|
-
attributes: {
|
|
5790
|
-
POSITION: positions,
|
|
5791
|
-
NORMAL: normals,
|
|
5792
|
-
TEXCOORD_0: texCoords
|
|
5793
|
-
}
|
|
5794
|
-
};
|
|
5795
|
-
}
|
|
5796
|
-
|
|
5797
|
-
// src/geometries/cone-geometry.ts
|
|
5798
|
-
var ConeGeometry = class extends TruncatedConeGeometry {
|
|
5799
|
-
constructor(props = {}) {
|
|
5800
|
-
const { id = uid("cone-geometry"), radius = 1, cap = true } = props;
|
|
5801
|
-
super({
|
|
5802
|
-
...props,
|
|
5803
|
-
id,
|
|
5804
|
-
topRadius: 0,
|
|
5805
|
-
topCap: Boolean(cap),
|
|
5806
|
-
bottomCap: Boolean(cap),
|
|
5807
|
-
bottomRadius: radius
|
|
5808
|
-
});
|
|
5809
|
-
}
|
|
5810
|
-
};
|
|
5811
|
-
|
|
5812
6565
|
// src/geometries/cube-geometry.ts
|
|
5813
6566
|
var CubeGeometry = class extends Geometry {
|
|
5814
6567
|
constructor(props = {}) {
|
|
@@ -6699,84 +7452,6 @@ void main(void) {
|
|
|
6699
7452
|
return unpack ? unpackIndexedGeometry(geometry) : geometry;
|
|
6700
7453
|
}
|
|
6701
7454
|
|
|
6702
|
-
// src/geometries/sphere-geometry.ts
|
|
6703
|
-
var SphereGeometry = class extends Geometry {
|
|
6704
|
-
constructor(props = {}) {
|
|
6705
|
-
const { id = uid("sphere-geometry") } = props;
|
|
6706
|
-
const { indices, attributes } = tesselateSphere(props);
|
|
6707
|
-
super({
|
|
6708
|
-
...props,
|
|
6709
|
-
id,
|
|
6710
|
-
topology: "triangle-list",
|
|
6711
|
-
indices,
|
|
6712
|
-
attributes: { ...attributes, ...props.attributes }
|
|
6713
|
-
});
|
|
6714
|
-
}
|
|
6715
|
-
};
|
|
6716
|
-
function tesselateSphere(props) {
|
|
6717
|
-
const { nlat = 10, nlong = 10 } = props;
|
|
6718
|
-
const startLat = 0;
|
|
6719
|
-
const endLat = Math.PI;
|
|
6720
|
-
const latRange = endLat - startLat;
|
|
6721
|
-
const startLong = 0;
|
|
6722
|
-
const endLong = 2 * Math.PI;
|
|
6723
|
-
const longRange = endLong - startLong;
|
|
6724
|
-
const numVertices = (nlat + 1) * (nlong + 1);
|
|
6725
|
-
const radius = (n1, n2, n3, u, v) => props.radius || 1;
|
|
6726
|
-
const positions = new Float32Array(numVertices * 3);
|
|
6727
|
-
const normals = new Float32Array(numVertices * 3);
|
|
6728
|
-
const texCoords = new Float32Array(numVertices * 2);
|
|
6729
|
-
const IndexType = numVertices > 65535 ? Uint32Array : Uint16Array;
|
|
6730
|
-
const indices = new IndexType(nlat * nlong * 6);
|
|
6731
|
-
for (let y = 0; y <= nlat; y++) {
|
|
6732
|
-
for (let x = 0; x <= nlong; x++) {
|
|
6733
|
-
const u = x / nlong;
|
|
6734
|
-
const v = y / nlat;
|
|
6735
|
-
const index = x + y * (nlong + 1);
|
|
6736
|
-
const i2 = index * 2;
|
|
6737
|
-
const i3 = index * 3;
|
|
6738
|
-
const theta = longRange * u;
|
|
6739
|
-
const phi = latRange * v;
|
|
6740
|
-
const sinTheta = Math.sin(theta);
|
|
6741
|
-
const cosTheta = Math.cos(theta);
|
|
6742
|
-
const sinPhi = Math.sin(phi);
|
|
6743
|
-
const cosPhi = Math.cos(phi);
|
|
6744
|
-
const ux = cosTheta * sinPhi;
|
|
6745
|
-
const uy = cosPhi;
|
|
6746
|
-
const uz = sinTheta * sinPhi;
|
|
6747
|
-
const r = radius(ux, uy, uz, u, v);
|
|
6748
|
-
positions[i3 + 0] = r * ux;
|
|
6749
|
-
positions[i3 + 1] = r * uy;
|
|
6750
|
-
positions[i3 + 2] = r * uz;
|
|
6751
|
-
normals[i3 + 0] = ux;
|
|
6752
|
-
normals[i3 + 1] = uy;
|
|
6753
|
-
normals[i3 + 2] = uz;
|
|
6754
|
-
texCoords[i2 + 0] = u;
|
|
6755
|
-
texCoords[i2 + 1] = 1 - v;
|
|
6756
|
-
}
|
|
6757
|
-
}
|
|
6758
|
-
const numVertsAround = nlong + 1;
|
|
6759
|
-
for (let x = 0; x < nlong; x++) {
|
|
6760
|
-
for (let y = 0; y < nlat; y++) {
|
|
6761
|
-
const index = (x * nlat + y) * 6;
|
|
6762
|
-
indices[index + 0] = y * numVertsAround + x;
|
|
6763
|
-
indices[index + 1] = y * numVertsAround + x + 1;
|
|
6764
|
-
indices[index + 2] = (y + 1) * numVertsAround + x;
|
|
6765
|
-
indices[index + 3] = (y + 1) * numVertsAround + x;
|
|
6766
|
-
indices[index + 4] = y * numVertsAround + x + 1;
|
|
6767
|
-
indices[index + 5] = (y + 1) * numVertsAround + x + 1;
|
|
6768
|
-
}
|
|
6769
|
-
}
|
|
6770
|
-
return {
|
|
6771
|
-
indices: { size: 1, value: indices },
|
|
6772
|
-
attributes: {
|
|
6773
|
-
POSITION: { size: 3, value: positions },
|
|
6774
|
-
NORMAL: { size: 3, value: normals },
|
|
6775
|
-
TEXCOORD_0: { size: 2, value: texCoords }
|
|
6776
|
-
}
|
|
6777
|
-
};
|
|
6778
|
-
}
|
|
6779
|
-
|
|
6780
7455
|
// src/application-utils/random.ts
|
|
6781
7456
|
function makeRandomGenerator() {
|
|
6782
7457
|
let s = 1;
|
|
@@ -7203,11 +7878,11 @@ void main() {
|
|
|
7203
7878
|
);
|
|
7204
7879
|
this.shaderInputs = props.shaderInputs || new ShaderInputs(moduleMap);
|
|
7205
7880
|
this.setShaderInputs(this.shaderInputs);
|
|
7206
|
-
this.props.shaderLayout ||= device.getShaderLayout(this.props.source);
|
|
7207
7881
|
const platformInfo = getPlatformInfo2(device);
|
|
7208
7882
|
const modules = (this.props.modules?.length > 0 ? this.props.modules : this.shaderInputs?.getModules()) || [];
|
|
7209
|
-
this.
|
|
7210
|
-
this.
|
|
7883
|
+
this.props.shaderLayout = mergeShaderModuleBindingsIntoLayout(this.props.shaderLayout, modules) || null;
|
|
7884
|
+
this.pipelineFactory = props.pipelineFactory || import_core17.PipelineFactory.getDefaultPipelineFactory(this.device);
|
|
7885
|
+
this.shaderFactory = props.shaderFactory || import_core17.ShaderFactory.getDefaultShaderFactory(this.device);
|
|
7211
7886
|
const { source: source3, getUniforms: getUniforms2 } = this.props.shaderAssembler.assembleWGSLShader({
|
|
7212
7887
|
platformInfo,
|
|
7213
7888
|
...this.props,
|
|
@@ -7215,6 +7890,11 @@ void main() {
|
|
|
7215
7890
|
});
|
|
7216
7891
|
this.source = source3;
|
|
7217
7892
|
this._getModuleUniforms = getUniforms2;
|
|
7893
|
+
const inferredShaderLayout = device.getShaderLayout?.(this.source);
|
|
7894
|
+
this.props.shaderLayout = mergeShaderModuleBindingsIntoLayout(
|
|
7895
|
+
this.props.shaderLayout || inferredShaderLayout || null,
|
|
7896
|
+
modules
|
|
7897
|
+
) || null;
|
|
7218
7898
|
this.pipeline = this._updatePipeline();
|
|
7219
7899
|
if (props.bindings) {
|
|
7220
7900
|
this.setBindings(props.bindings);
|
|
@@ -7239,7 +7919,7 @@ void main() {
|
|
|
7239
7919
|
this.pipeline = this._updatePipeline();
|
|
7240
7920
|
this.pipeline.setBindings(this.bindings);
|
|
7241
7921
|
computePass.setPipeline(this.pipeline);
|
|
7242
|
-
computePass.setBindings(
|
|
7922
|
+
computePass.setBindings({});
|
|
7243
7923
|
computePass.dispatch(x, y, z);
|
|
7244
7924
|
} finally {
|
|
7245
7925
|
this._logDrawCallEnd();
|
|
@@ -7262,9 +7942,11 @@ void main() {
|
|
|
7262
7942
|
setShaderInputs(shaderInputs) {
|
|
7263
7943
|
this.shaderInputs = shaderInputs;
|
|
7264
7944
|
this._uniformStore = new import_core17.UniformStore(this.shaderInputs.modules);
|
|
7265
|
-
for (const moduleName of Object.
|
|
7266
|
-
|
|
7267
|
-
|
|
7945
|
+
for (const [moduleName, module] of Object.entries(this.shaderInputs.modules)) {
|
|
7946
|
+
if (shaderModuleHasUniforms(module)) {
|
|
7947
|
+
const uniformBuffer = this._uniformStore.getManagedUniformBuffer(this.device, moduleName);
|
|
7948
|
+
this.bindings[`${moduleName}Uniforms`] = uniformBuffer;
|
|
7949
|
+
}
|
|
7268
7950
|
}
|
|
7269
7951
|
}
|
|
7270
7952
|
/**
|
|
@@ -7344,7 +8026,7 @@ void main() {
|
|
|
7344
8026
|
_drawCount = 0;
|
|
7345
8027
|
// TODO - fix typing of luma data types
|
|
7346
8028
|
_getBufferOrConstantValues(attribute, dataType) {
|
|
7347
|
-
const TypedArrayConstructor =
|
|
8029
|
+
const TypedArrayConstructor = import_core17.dataTypeDecoder.getTypedArrayConstructor(dataType);
|
|
7348
8030
|
const typedArray = attribute instanceof import_core17.Buffer ? new TypedArrayConstructor(attribute.debugData) : attribute;
|
|
7349
8031
|
return typedArray.toString();
|
|
7350
8032
|
}
|
|
@@ -7376,6 +8058,9 @@ void main() {
|
|
|
7376
8058
|
};
|
|
7377
8059
|
}
|
|
7378
8060
|
|
|
8061
|
+
// src/modules/picking/picking-manager.ts
|
|
8062
|
+
var import_core18 = __toESM(require_core(), 1);
|
|
8063
|
+
|
|
7379
8064
|
// src/modules/picking/picking-uniforms.ts
|
|
7380
8065
|
var DEFAULT_HIGHLIGHT_COLOR = [0, 1, 1, 1];
|
|
7381
8066
|
var INVALID_INDEX = -1;
|
|
@@ -7408,15 +8093,17 @@ uniform pickingUniforms {
|
|
|
7408
8093
|
var WGSL_UNIFORMS = (
|
|
7409
8094
|
/* wgsl */
|
|
7410
8095
|
`struct pickingUniforms {
|
|
7411
|
-
isActive:
|
|
7412
|
-
indexMode:
|
|
7413
|
-
batchIndex:
|
|
7414
|
-
|
|
7415
|
-
isHighlightActive:
|
|
7416
|
-
highlightedBatchIndex:
|
|
7417
|
-
highlightedObjectIndex:
|
|
7418
|
-
highlightColor: vec4<f32
|
|
7419
|
-
}
|
|
8096
|
+
isActive: i32,
|
|
8097
|
+
indexMode: i32,
|
|
8098
|
+
batchIndex: i32,
|
|
8099
|
+
|
|
8100
|
+
isHighlightActive: i32,
|
|
8101
|
+
highlightedBatchIndex: i32,
|
|
8102
|
+
highlightedObjectIndex: i32,
|
|
8103
|
+
highlightColor: vec4<f32>,
|
|
8104
|
+
};
|
|
8105
|
+
|
|
8106
|
+
@group(0) @binding(auto) var<uniform> picking: pickingUniforms;
|
|
7420
8107
|
`
|
|
7421
8108
|
);
|
|
7422
8109
|
function getUniforms(props = {}, prevUniforms) {
|
|
@@ -7428,25 +8115,36 @@ uniform pickingUniforms {
|
|
|
7428
8115
|
case "instance":
|
|
7429
8116
|
uniforms.indexMode = 0;
|
|
7430
8117
|
break;
|
|
7431
|
-
case "
|
|
8118
|
+
case "attribute":
|
|
7432
8119
|
uniforms.indexMode = 1;
|
|
7433
8120
|
break;
|
|
7434
8121
|
case void 0:
|
|
7435
8122
|
break;
|
|
7436
8123
|
}
|
|
7437
|
-
|
|
8124
|
+
if (typeof props.batchIndex === "number") {
|
|
8125
|
+
uniforms.batchIndex = props.batchIndex;
|
|
8126
|
+
}
|
|
8127
|
+
switch (props.highlightedObjectIndex) {
|
|
8128
|
+
case void 0:
|
|
8129
|
+
break;
|
|
8130
|
+
case null:
|
|
8131
|
+
uniforms.isHighlightActive = false;
|
|
8132
|
+
uniforms.highlightedObjectIndex = INVALID_INDEX;
|
|
8133
|
+
break;
|
|
8134
|
+
default:
|
|
8135
|
+
uniforms.isHighlightActive = true;
|
|
8136
|
+
uniforms.highlightedObjectIndex = props.highlightedObjectIndex;
|
|
8137
|
+
}
|
|
8138
|
+
switch (props.highlightedBatchIndex) {
|
|
7438
8139
|
case void 0:
|
|
7439
8140
|
break;
|
|
7440
8141
|
case null:
|
|
7441
8142
|
uniforms.isHighlightActive = false;
|
|
7442
|
-
uniforms.
|
|
8143
|
+
uniforms.highlightedBatchIndex = INVALID_INDEX;
|
|
7443
8144
|
break;
|
|
7444
8145
|
default:
|
|
7445
8146
|
uniforms.isHighlightActive = true;
|
|
7446
|
-
uniforms.
|
|
7447
|
-
}
|
|
7448
|
-
if (typeof props.highlightedBatchIndex === "number") {
|
|
7449
|
-
uniforms.highlightedBatchIndex = props.highlightedBatchIndex;
|
|
8147
|
+
uniforms.highlightedBatchIndex = props.highlightedBatchIndex;
|
|
7450
8148
|
}
|
|
7451
8149
|
if (props.highlightColor) {
|
|
7452
8150
|
uniforms.highlightColor = props.highlightColor;
|
|
@@ -7462,7 +8160,7 @@ uniform pickingUniforms {
|
|
|
7462
8160
|
isActive: false,
|
|
7463
8161
|
indexMode: 0,
|
|
7464
8162
|
batchIndex: 0,
|
|
7465
|
-
isHighlightActive:
|
|
8163
|
+
isHighlightActive: false,
|
|
7466
8164
|
highlightedBatchIndex: INVALID_INDEX,
|
|
7467
8165
|
highlightedObjectIndex: INVALID_INDEX,
|
|
7468
8166
|
highlightColor: DEFAULT_HIGHLIGHT_COLOR
|
|
@@ -7471,9 +8169,44 @@ uniform pickingUniforms {
|
|
|
7471
8169
|
};
|
|
7472
8170
|
|
|
7473
8171
|
// src/modules/picking/picking-manager.ts
|
|
8172
|
+
var INDEX_PICKING_ATTACHMENT_INDEX = 1;
|
|
8173
|
+
var INDEX_PICKING_CLEAR_COLOR = new Int32Array([INVALID_INDEX, INVALID_INDEX, 0, 0]);
|
|
8174
|
+
function resolvePickingMode(deviceType, mode = "color", indexPickingSupported = deviceType === "webgpu") {
|
|
8175
|
+
if (mode === "auto") {
|
|
8176
|
+
return indexPickingSupported ? "index" : "color";
|
|
8177
|
+
}
|
|
8178
|
+
if (mode === "index" && !indexPickingSupported) {
|
|
8179
|
+
throw new Error(
|
|
8180
|
+
`Picking mode "${mode}" requires WebGPU or a WebGL device that supports renderable rg32sint textures.`
|
|
8181
|
+
);
|
|
8182
|
+
}
|
|
8183
|
+
return mode;
|
|
8184
|
+
}
|
|
8185
|
+
function supportsIndexPicking(device) {
|
|
8186
|
+
return device.type === "webgpu" || device.type === "webgl" && device.isTextureFormatRenderable("rg32sint");
|
|
8187
|
+
}
|
|
8188
|
+
var resolvePickingBackend = resolvePickingMode;
|
|
8189
|
+
function decodeIndexPickInfo(pixelData) {
|
|
8190
|
+
return {
|
|
8191
|
+
objectIndex: pixelData[0] === INVALID_INDEX ? null : pixelData[0],
|
|
8192
|
+
batchIndex: pixelData[1] === INVALID_INDEX ? null : pixelData[1]
|
|
8193
|
+
};
|
|
8194
|
+
}
|
|
8195
|
+
function decodeColorPickInfo(pixelData) {
|
|
8196
|
+
const encodedObjectIndex = pixelData[0] + pixelData[1] * 256 + pixelData[2] * 65536;
|
|
8197
|
+
if (encodedObjectIndex === 0) {
|
|
8198
|
+
return { objectIndex: null, batchIndex: null };
|
|
8199
|
+
}
|
|
8200
|
+
const batchIndex = pixelData[3] > 0 ? pixelData[3] - 1 : 0;
|
|
8201
|
+
return {
|
|
8202
|
+
objectIndex: encodedObjectIndex - 1,
|
|
8203
|
+
batchIndex
|
|
8204
|
+
};
|
|
8205
|
+
}
|
|
7474
8206
|
var _PickingManager = class {
|
|
7475
8207
|
device;
|
|
7476
8208
|
props;
|
|
8209
|
+
mode;
|
|
7477
8210
|
/** Info from latest pick operation */
|
|
7478
8211
|
pickInfo = { batchIndex: null, objectIndex: null };
|
|
7479
8212
|
/** Framebuffer used for picking */
|
|
@@ -7481,6 +8214,14 @@ uniform pickingUniforms {
|
|
|
7481
8214
|
constructor(device, props) {
|
|
7482
8215
|
this.device = device;
|
|
7483
8216
|
this.props = { ..._PickingManager.defaultProps, ...props };
|
|
8217
|
+
const requestedMode = props.mode ?? props.backend ?? _PickingManager.defaultProps.mode;
|
|
8218
|
+
this.props.mode = requestedMode;
|
|
8219
|
+
this.props.backend = requestedMode;
|
|
8220
|
+
this.mode = resolvePickingMode(
|
|
8221
|
+
this.device.type,
|
|
8222
|
+
requestedMode,
|
|
8223
|
+
supportsIndexPicking(this.device)
|
|
8224
|
+
);
|
|
7484
8225
|
}
|
|
7485
8226
|
destroy() {
|
|
7486
8227
|
this.framebuffer?.destroy();
|
|
@@ -7488,56 +8229,44 @@ uniform pickingUniforms {
|
|
|
7488
8229
|
// TODO - Ask for a cached framebuffer? a Framebuffer factory?
|
|
7489
8230
|
getFramebuffer() {
|
|
7490
8231
|
if (!this.framebuffer) {
|
|
7491
|
-
this.framebuffer = this.
|
|
7492
|
-
colorAttachments: ["rgba8unorm", "rg32sint"],
|
|
7493
|
-
depthStencilAttachment: "depth24plus"
|
|
7494
|
-
});
|
|
8232
|
+
this.framebuffer = this.mode === "index" ? this.createIndexFramebuffer() : this.createColorFramebuffer();
|
|
7495
8233
|
}
|
|
7496
8234
|
return this.framebuffer;
|
|
7497
8235
|
}
|
|
7498
8236
|
/** Clear highlighted / picked object */
|
|
7499
8237
|
clearPickState() {
|
|
7500
|
-
this.
|
|
8238
|
+
this.setPickingProps({ highlightedBatchIndex: null, highlightedObjectIndex: null });
|
|
7501
8239
|
}
|
|
7502
8240
|
/** Prepare for rendering picking colors */
|
|
7503
8241
|
beginRenderPass() {
|
|
7504
8242
|
const framebuffer = this.getFramebuffer();
|
|
7505
8243
|
framebuffer.resize(this.device.getDefaultCanvasContext().getDevicePixelSize());
|
|
7506
|
-
this.
|
|
7507
|
-
|
|
8244
|
+
this.setPickingProps({ isActive: true });
|
|
8245
|
+
return this.mode === "index" ? this.device.beginRenderPass({
|
|
8246
|
+
framebuffer,
|
|
8247
|
+
clearColors: [new Float32Array([0, 0, 0, 0]), INDEX_PICKING_CLEAR_COLOR],
|
|
8248
|
+
clearDepth: 1
|
|
8249
|
+
}) : this.device.beginRenderPass({
|
|
7508
8250
|
framebuffer,
|
|
7509
|
-
|
|
8251
|
+
clearColor: [0, 0, 0, 0],
|
|
7510
8252
|
clearDepth: 1
|
|
7511
8253
|
});
|
|
7512
|
-
return pickingPass;
|
|
7513
8254
|
}
|
|
7514
8255
|
async updatePickInfo(mousePosition) {
|
|
7515
8256
|
const framebuffer = this.getFramebuffer();
|
|
7516
|
-
const
|
|
7517
|
-
const
|
|
7518
|
-
|
|
7519
|
-
sourceY: pickY,
|
|
7520
|
-
sourceWidth: 1,
|
|
7521
|
-
sourceHeight: 1,
|
|
7522
|
-
sourceAttachment: 1
|
|
7523
|
-
});
|
|
7524
|
-
if (!pixelData) {
|
|
8257
|
+
const pickPosition = this.getPickPosition(mousePosition);
|
|
8258
|
+
const pickInfo = await this.readPickInfo(framebuffer, pickPosition);
|
|
8259
|
+
if (!pickInfo) {
|
|
7525
8260
|
return null;
|
|
7526
8261
|
}
|
|
7527
|
-
|
|
7528
|
-
objectIndex: pixelData[0] === INVALID_INDEX ? null : pixelData[0],
|
|
7529
|
-
batchIndex: pixelData[1] === INVALID_INDEX ? null : pixelData[1]
|
|
7530
|
-
};
|
|
7531
|
-
if (pickInfo.objectIndex !== this.pickInfo.objectIndex || pickInfo.batchIndex !== this.pickInfo.batchIndex) {
|
|
8262
|
+
if (this.hasPickInfoChanged(pickInfo)) {
|
|
7532
8263
|
this.pickInfo = pickInfo;
|
|
7533
8264
|
this.props.onObjectPicked(pickInfo);
|
|
7534
8265
|
}
|
|
7535
|
-
this.
|
|
7536
|
-
|
|
7537
|
-
|
|
7538
|
-
|
|
7539
|
-
highlightedObjectIndex: pickInfo.objectIndex
|
|
7540
|
-
}
|
|
8266
|
+
this.setPickingProps({
|
|
8267
|
+
isActive: false,
|
|
8268
|
+
highlightedBatchIndex: pickInfo.batchIndex,
|
|
8269
|
+
highlightedObjectIndex: pickInfo.objectIndex
|
|
7541
8270
|
});
|
|
7542
8271
|
return this.pickInfo;
|
|
7543
8272
|
}
|
|
@@ -7546,43 +8275,207 @@ uniform pickingUniforms {
|
|
|
7546
8275
|
* use the center pixel location in device pixel range
|
|
7547
8276
|
*/
|
|
7548
8277
|
getPickPosition(mousePosition) {
|
|
7549
|
-
const
|
|
8278
|
+
const yInvert = this.device.type !== "webgpu";
|
|
8279
|
+
const devicePixels = this.device.getDefaultCanvasContext().cssToDevicePixels(mousePosition, yInvert);
|
|
7550
8280
|
const pickX = devicePixels.x + Math.floor(devicePixels.width / 2);
|
|
7551
8281
|
const pickY = devicePixels.y + Math.floor(devicePixels.height / 2);
|
|
7552
8282
|
return [pickX, pickY];
|
|
7553
8283
|
}
|
|
8284
|
+
createIndexFramebuffer() {
|
|
8285
|
+
const colorTexture = this.device.createTexture({
|
|
8286
|
+
format: "rgba8unorm",
|
|
8287
|
+
width: 1,
|
|
8288
|
+
height: 1,
|
|
8289
|
+
usage: import_core18.Texture.RENDER_ATTACHMENT
|
|
8290
|
+
});
|
|
8291
|
+
const pickingTexture = this.device.createTexture({
|
|
8292
|
+
format: "rg32sint",
|
|
8293
|
+
width: 1,
|
|
8294
|
+
height: 1,
|
|
8295
|
+
usage: import_core18.Texture.RENDER_ATTACHMENT | import_core18.Texture.COPY_SRC
|
|
8296
|
+
});
|
|
8297
|
+
return this.device.createFramebuffer({
|
|
8298
|
+
colorAttachments: [colorTexture, pickingTexture],
|
|
8299
|
+
depthStencilAttachment: "depth24plus"
|
|
8300
|
+
});
|
|
8301
|
+
}
|
|
8302
|
+
createColorFramebuffer() {
|
|
8303
|
+
const pickingTexture = this.device.createTexture({
|
|
8304
|
+
format: "rgba8unorm",
|
|
8305
|
+
width: 1,
|
|
8306
|
+
height: 1,
|
|
8307
|
+
usage: import_core18.Texture.RENDER_ATTACHMENT | import_core18.Texture.COPY_SRC
|
|
8308
|
+
});
|
|
8309
|
+
return this.device.createFramebuffer({
|
|
8310
|
+
colorAttachments: [pickingTexture],
|
|
8311
|
+
depthStencilAttachment: "depth24plus"
|
|
8312
|
+
});
|
|
8313
|
+
}
|
|
8314
|
+
setPickingProps(props) {
|
|
8315
|
+
this.props.shaderInputs?.setProps({ picking: props });
|
|
8316
|
+
}
|
|
8317
|
+
async readPickInfo(framebuffer, pickPosition) {
|
|
8318
|
+
return this.mode === "index" ? this.readIndexPickInfo(framebuffer, pickPosition) : this.readColorPickInfo(framebuffer, pickPosition);
|
|
8319
|
+
}
|
|
8320
|
+
async readIndexPickInfo(framebuffer, [pickX, pickY]) {
|
|
8321
|
+
if (this.device.type === "webgpu") {
|
|
8322
|
+
const pickTexture = framebuffer.colorAttachments[INDEX_PICKING_ATTACHMENT_INDEX]?.texture;
|
|
8323
|
+
if (!pickTexture) {
|
|
8324
|
+
return null;
|
|
8325
|
+
}
|
|
8326
|
+
const layout = pickTexture.computeMemoryLayout({ width: 1, height: 1 });
|
|
8327
|
+
const readBuffer = this.device.createBuffer({
|
|
8328
|
+
byteLength: layout.byteLength,
|
|
8329
|
+
usage: import_core18.Buffer.COPY_DST | import_core18.Buffer.MAP_READ
|
|
8330
|
+
});
|
|
8331
|
+
try {
|
|
8332
|
+
pickTexture.readBuffer(
|
|
8333
|
+
{
|
|
8334
|
+
x: pickX,
|
|
8335
|
+
y: pickY,
|
|
8336
|
+
width: 1,
|
|
8337
|
+
height: 1
|
|
8338
|
+
},
|
|
8339
|
+
readBuffer
|
|
8340
|
+
);
|
|
8341
|
+
const pickDataView = await readBuffer.readAsync(0, layout.byteLength);
|
|
8342
|
+
return decodeIndexPickInfo(new Int32Array(pickDataView.buffer, pickDataView.byteOffset, 2));
|
|
8343
|
+
} finally {
|
|
8344
|
+
readBuffer.destroy();
|
|
8345
|
+
}
|
|
8346
|
+
}
|
|
8347
|
+
const pixelData = this.device.readPixelsToArrayWebGL(framebuffer, {
|
|
8348
|
+
sourceX: pickX,
|
|
8349
|
+
sourceY: pickY,
|
|
8350
|
+
sourceWidth: 1,
|
|
8351
|
+
sourceHeight: 1,
|
|
8352
|
+
sourceAttachment: INDEX_PICKING_ATTACHMENT_INDEX
|
|
8353
|
+
});
|
|
8354
|
+
return pixelData ? decodeIndexPickInfo(new Int32Array(pixelData.buffer, pixelData.byteOffset, 2)) : null;
|
|
8355
|
+
}
|
|
8356
|
+
async readColorPickInfo(framebuffer, [pickX, pickY]) {
|
|
8357
|
+
if (this.device.type === "webgpu") {
|
|
8358
|
+
const pickTexture = framebuffer.colorAttachments[0]?.texture;
|
|
8359
|
+
if (!pickTexture) {
|
|
8360
|
+
return null;
|
|
8361
|
+
}
|
|
8362
|
+
const layout = pickTexture.computeMemoryLayout({ width: 1, height: 1 });
|
|
8363
|
+
const readBuffer = this.device.createBuffer({
|
|
8364
|
+
byteLength: layout.byteLength,
|
|
8365
|
+
usage: import_core18.Buffer.COPY_DST | import_core18.Buffer.MAP_READ
|
|
8366
|
+
});
|
|
8367
|
+
try {
|
|
8368
|
+
pickTexture.readBuffer(
|
|
8369
|
+
{
|
|
8370
|
+
x: pickX,
|
|
8371
|
+
y: pickY,
|
|
8372
|
+
width: 1,
|
|
8373
|
+
height: 1
|
|
8374
|
+
},
|
|
8375
|
+
readBuffer
|
|
8376
|
+
);
|
|
8377
|
+
const pickDataView = await readBuffer.readAsync(0, layout.byteLength);
|
|
8378
|
+
return decodeColorPickInfo(new Uint8Array(pickDataView.buffer, pickDataView.byteOffset, 4));
|
|
8379
|
+
} finally {
|
|
8380
|
+
readBuffer.destroy();
|
|
8381
|
+
}
|
|
8382
|
+
}
|
|
8383
|
+
const pixelData = this.device.readPixelsToArrayWebGL(framebuffer, {
|
|
8384
|
+
sourceX: pickX,
|
|
8385
|
+
sourceY: pickY,
|
|
8386
|
+
sourceWidth: 1,
|
|
8387
|
+
sourceHeight: 1,
|
|
8388
|
+
sourceAttachment: 0
|
|
8389
|
+
});
|
|
8390
|
+
return pixelData ? decodeColorPickInfo(new Uint8Array(pixelData.buffer, pixelData.byteOffset, 4)) : null;
|
|
8391
|
+
}
|
|
8392
|
+
hasPickInfoChanged(pickInfo) {
|
|
8393
|
+
return pickInfo.objectIndex !== this.pickInfo.objectIndex || pickInfo.batchIndex !== this.pickInfo.batchIndex;
|
|
8394
|
+
}
|
|
7554
8395
|
};
|
|
7555
8396
|
var PickingManager = _PickingManager;
|
|
7556
8397
|
__publicField(PickingManager, "defaultProps", {
|
|
7557
8398
|
shaderInputs: void 0,
|
|
7558
8399
|
onObjectPicked: () => {
|
|
7559
|
-
}
|
|
8400
|
+
},
|
|
8401
|
+
mode: "color",
|
|
8402
|
+
backend: "color"
|
|
7560
8403
|
});
|
|
7561
8404
|
|
|
7562
|
-
// src/modules/picking/
|
|
8405
|
+
// src/modules/picking/color-picking.ts
|
|
7563
8406
|
var source = (
|
|
7564
8407
|
/* wgsl */
|
|
7565
8408
|
`${WGSL_UNIFORMS}
|
|
7566
8409
|
|
|
7567
|
-
const
|
|
7568
|
-
const
|
|
7569
|
-
const
|
|
8410
|
+
const COLOR_PICKING_INVALID_INDEX = ${INVALID_INDEX};
|
|
8411
|
+
const COLOR_PICKING_MAX_OBJECT_INDEX = 16777214;
|
|
8412
|
+
const COLOR_PICKING_MAX_BATCH_INDEX = 254;
|
|
7570
8413
|
|
|
7571
|
-
|
|
7572
|
-
|
|
7573
|
-
|
|
7574
|
-
|
|
7575
|
-
fn
|
|
7576
|
-
|
|
7577
|
-
|
|
7578
|
-
|
|
7579
|
-
|
|
7580
|
-
|
|
7581
|
-
|
|
7582
|
-
|
|
8414
|
+
fn picking_setObjectIndex(objectIndex: i32) -> i32 {
|
|
8415
|
+
return objectIndex;
|
|
8416
|
+
}
|
|
8417
|
+
|
|
8418
|
+
fn picking_isObjectHighlighted(objectIndex: i32) -> bool {
|
|
8419
|
+
return
|
|
8420
|
+
picking.isHighlightActive != 0 &&
|
|
8421
|
+
picking.highlightedBatchIndex == picking.batchIndex &&
|
|
8422
|
+
picking.highlightedObjectIndex == objectIndex;
|
|
8423
|
+
}
|
|
8424
|
+
|
|
8425
|
+
fn picking_filterHighlightColor(color: vec4<f32>, objectIndex: i32) -> vec4<f32> {
|
|
8426
|
+
if (picking.isActive != 0 || !picking_isObjectHighlighted(objectIndex)) {
|
|
8427
|
+
return color;
|
|
8428
|
+
}
|
|
8429
|
+
|
|
8430
|
+
let highLightAlpha = picking.highlightColor.a;
|
|
8431
|
+
let blendedAlpha = highLightAlpha + color.a * (1.0 - highLightAlpha);
|
|
8432
|
+
if (blendedAlpha == 0.0) {
|
|
8433
|
+
return vec4<f32>(color.rgb, 0.0);
|
|
7583
8434
|
}
|
|
8435
|
+
|
|
8436
|
+
let highLightRatio = highLightAlpha / blendedAlpha;
|
|
8437
|
+
let blendedRGB = mix(color.rgb, picking.highlightColor.rgb, highLightRatio);
|
|
8438
|
+
return vec4<f32>(blendedRGB, blendedAlpha);
|
|
8439
|
+
}
|
|
8440
|
+
|
|
8441
|
+
fn picking_canEncodePickInfo(objectIndex: i32) -> bool {
|
|
8442
|
+
return
|
|
8443
|
+
objectIndex != COLOR_PICKING_INVALID_INDEX &&
|
|
8444
|
+
objectIndex >= 0 &&
|
|
8445
|
+
objectIndex <= COLOR_PICKING_MAX_OBJECT_INDEX &&
|
|
8446
|
+
picking.batchIndex >= 0 &&
|
|
8447
|
+
picking.batchIndex <= COLOR_PICKING_MAX_BATCH_INDEX;
|
|
8448
|
+
}
|
|
8449
|
+
|
|
8450
|
+
fn picking_getPickingColor(objectIndex: i32) -> vec4<f32> {
|
|
8451
|
+
if (!picking_canEncodePickInfo(objectIndex)) {
|
|
8452
|
+
return vec4<f32>(0.0, 0.0, 0.0, 0.0);
|
|
8453
|
+
}
|
|
8454
|
+
|
|
8455
|
+
let encodedObjectIndex = objectIndex + 1;
|
|
8456
|
+
let red = encodedObjectIndex % 256;
|
|
8457
|
+
let green = (encodedObjectIndex / 256) % 256;
|
|
8458
|
+
let blue = (encodedObjectIndex / 65536) % 256;
|
|
8459
|
+
let alpha = picking.batchIndex + 1;
|
|
8460
|
+
|
|
8461
|
+
return vec4<f32>(
|
|
8462
|
+
f32(red) / 255.0,
|
|
8463
|
+
f32(green) / 255.0,
|
|
8464
|
+
f32(blue) / 255.0,
|
|
8465
|
+
f32(alpha) / 255.0
|
|
8466
|
+
);
|
|
7584
8467
|
}
|
|
7585
8468
|
|
|
8469
|
+
fn picking_filterPickingColor(color: vec4<f32>, objectIndex: i32) -> vec4<f32> {
|
|
8470
|
+
if (picking.isActive != 0) {
|
|
8471
|
+
if (!picking_canEncodePickInfo(objectIndex)) {
|
|
8472
|
+
discard;
|
|
8473
|
+
}
|
|
8474
|
+
return picking_getPickingColor(objectIndex);
|
|
8475
|
+
}
|
|
8476
|
+
|
|
8477
|
+
return color;
|
|
8478
|
+
}
|
|
7586
8479
|
`
|
|
7587
8480
|
);
|
|
7588
8481
|
var vs = (
|
|
@@ -7592,14 +8485,10 @@ fn picking_setObjectIndex(objectIndex: int32) {
|
|
|
7592
8485
|
const int INDEX_PICKING_MODE_INSTANCE = 0;
|
|
7593
8486
|
const int INDEX_PICKING_MODE_CUSTOM = 1;
|
|
7594
8487
|
|
|
7595
|
-
const int
|
|
8488
|
+
const int COLOR_PICKING_INVALID_INDEX = ${INVALID_INDEX};
|
|
7596
8489
|
|
|
7597
8490
|
flat out int picking_objectIndex;
|
|
7598
8491
|
|
|
7599
|
-
/**
|
|
7600
|
-
* Vertex shaders should call this function to set the object index.
|
|
7601
|
-
* If using instance or vertex mode, argument will be ignored, 0 can be supplied.
|
|
7602
|
-
*/
|
|
7603
8492
|
void picking_setObjectIndex(int objectIndex) {
|
|
7604
8493
|
switch (picking.indexMode) {
|
|
7605
8494
|
case INDEX_PICKING_MODE_INSTANCE:
|
|
@@ -7616,36 +8505,29 @@ void picking_setObjectIndex(int objectIndex) {
|
|
|
7616
8505
|
/* glsl */
|
|
7617
8506
|
`${GLSL_UNIFORMS}
|
|
7618
8507
|
|
|
7619
|
-
const int
|
|
8508
|
+
const int COLOR_PICKING_INVALID_INDEX = ${INVALID_INDEX};
|
|
8509
|
+
const int COLOR_PICKING_MAX_OBJECT_INDEX = 16777214;
|
|
8510
|
+
const int COLOR_PICKING_MAX_BATCH_INDEX = 254;
|
|
7620
8511
|
|
|
7621
8512
|
flat in int picking_objectIndex;
|
|
7622
8513
|
|
|
7623
|
-
/**
|
|
7624
|
-
* Check if this vertex is highlighted (part of the selected batch and object)
|
|
7625
|
-
*/
|
|
7626
8514
|
bool picking_isFragmentHighlighted() {
|
|
7627
|
-
return
|
|
8515
|
+
return
|
|
7628
8516
|
bool(picking.isHighlightActive) &&
|
|
7629
8517
|
picking.highlightedBatchIndex == picking.batchIndex &&
|
|
7630
8518
|
picking.highlightedObjectIndex == picking_objectIndex
|
|
7631
8519
|
;
|
|
7632
8520
|
}
|
|
7633
8521
|
|
|
7634
|
-
/**
|
|
7635
|
-
* Returns highlight color if this item is selected.
|
|
7636
|
-
*/
|
|
7637
8522
|
vec4 picking_filterHighlightColor(vec4 color) {
|
|
7638
|
-
// If we are still picking, we don't highlight
|
|
7639
8523
|
if (bool(picking.isActive)) {
|
|
7640
8524
|
return color;
|
|
7641
8525
|
}
|
|
7642
8526
|
|
|
7643
|
-
// If we are not highlighted, return color as is
|
|
7644
8527
|
if (!picking_isFragmentHighlighted()) {
|
|
7645
8528
|
return color;
|
|
7646
8529
|
}
|
|
7647
|
-
|
|
7648
|
-
// Blend in highlight color based on its alpha value
|
|
8530
|
+
|
|
7649
8531
|
float highLightAlpha = picking.highlightColor.a;
|
|
7650
8532
|
float blendedAlpha = highLightAlpha + color.a * (1.0 - highLightAlpha);
|
|
7651
8533
|
float highLightRatio = highLightAlpha / blendedAlpha;
|
|
@@ -7654,28 +8536,40 @@ vec4 picking_filterHighlightColor(vec4 color) {
|
|
|
7654
8536
|
return vec4(blendedRGB, blendedAlpha);
|
|
7655
8537
|
}
|
|
7656
8538
|
|
|
7657
|
-
|
|
7658
|
-
|
|
7659
|
-
|
|
7660
|
-
|
|
7661
|
-
|
|
7662
|
-
|
|
7663
|
-
|
|
8539
|
+
bool picking_canEncodePickInfo(int objectIndex) {
|
|
8540
|
+
return
|
|
8541
|
+
objectIndex != COLOR_PICKING_INVALID_INDEX &&
|
|
8542
|
+
objectIndex >= 0 &&
|
|
8543
|
+
objectIndex <= COLOR_PICKING_MAX_OBJECT_INDEX &&
|
|
8544
|
+
picking.batchIndex >= 0 &&
|
|
8545
|
+
picking.batchIndex <= COLOR_PICKING_MAX_BATCH_INDEX;
|
|
8546
|
+
}
|
|
8547
|
+
|
|
8548
|
+
vec4 picking_getPickingColor() {
|
|
8549
|
+
if (!picking_canEncodePickInfo(picking_objectIndex)) {
|
|
8550
|
+
return vec4(0.0);
|
|
8551
|
+
}
|
|
8552
|
+
|
|
8553
|
+
int encodedObjectIndex = picking_objectIndex + 1;
|
|
8554
|
+
int red = encodedObjectIndex % 256;
|
|
8555
|
+
int green = (encodedObjectIndex / 256) % 256;
|
|
8556
|
+
int blue = (encodedObjectIndex / 65536) % 256;
|
|
8557
|
+
int alpha = picking.batchIndex + 1;
|
|
8558
|
+
|
|
8559
|
+
return vec4(float(red), float(green), float(blue), float(alpha)) / 255.0;
|
|
7664
8560
|
}
|
|
7665
8561
|
|
|
7666
8562
|
vec4 picking_filterPickingColor(vec4 color) {
|
|
7667
8563
|
if (bool(picking.isActive)) {
|
|
7668
|
-
if (picking_objectIndex
|
|
8564
|
+
if (!picking_canEncodePickInfo(picking_objectIndex)) {
|
|
7669
8565
|
discard;
|
|
7670
8566
|
}
|
|
8567
|
+
return picking_getPickingColor();
|
|
7671
8568
|
}
|
|
8569
|
+
|
|
7672
8570
|
return color;
|
|
7673
8571
|
}
|
|
7674
8572
|
|
|
7675
|
-
/*
|
|
7676
|
-
* Returns picking color if picking is enabled if not
|
|
7677
|
-
* highlight color if this item is selected, otherwise unmodified argument.
|
|
7678
|
-
*/
|
|
7679
8573
|
vec4 picking_filterColor(vec4 color) {
|
|
7680
8574
|
vec4 outColor = color;
|
|
7681
8575
|
outColor = picking_filterHighlightColor(outColor);
|
|
@@ -7692,87 +8586,81 @@ vec4 picking_filterColor(vec4 color) {
|
|
|
7692
8586
|
fs
|
|
7693
8587
|
};
|
|
7694
8588
|
|
|
7695
|
-
// src/modules/picking/
|
|
8589
|
+
// src/modules/picking/index-picking.ts
|
|
7696
8590
|
var source2 = (
|
|
7697
8591
|
/* wgsl */
|
|
7698
8592
|
`${WGSL_UNIFORMS}
|
|
7699
|
-
`
|
|
7700
|
-
);
|
|
7701
|
-
var vs2 = (
|
|
7702
|
-
/* glsl */
|
|
7703
|
-
`${GLSL_UNIFORMS}
|
|
7704
|
-
out vec4 picking_vRGBcolor_Avalid;
|
|
7705
|
-
|
|
7706
|
-
// Normalize unsigned byte color to 0-1 range
|
|
7707
|
-
vec3 picking_normalizeColor(vec3 color) {
|
|
7708
|
-
return picking.useFloatColors > 0.5 ? color : color / 255.0;
|
|
7709
|
-
}
|
|
7710
|
-
|
|
7711
|
-
// Normalize unsigned byte color to 0-1 range
|
|
7712
|
-
vec4 picking_normalizeColor(vec4 color) {
|
|
7713
|
-
return picking.useFloatColors > 0.5 ? color : color / 255.0;
|
|
7714
|
-
}
|
|
7715
8593
|
|
|
7716
|
-
|
|
7717
|
-
|
|
7718
|
-
}
|
|
8594
|
+
const INDEX_PICKING_MODE_INSTANCE = 0;
|
|
8595
|
+
const INDEX_PICKING_MODE_CUSTOM = 1;
|
|
8596
|
+
const INDEX_PICKING_INVALID_INDEX = ${INVALID_INDEX}; // 2^32 - 1
|
|
7719
8597
|
|
|
7720
|
-
|
|
7721
|
-
|
|
8598
|
+
/**
|
|
8599
|
+
* WGSL shaders need to carry the returned object index through their own stage outputs.
|
|
8600
|
+
*/
|
|
8601
|
+
fn picking_setObjectIndex(objectIndex: i32) -> i32 {
|
|
8602
|
+
return objectIndex;
|
|
7722
8603
|
}
|
|
7723
8604
|
|
|
7724
|
-
|
|
7725
|
-
bool isVertexHighlighted(vec3 vertexColor) {
|
|
7726
|
-
vec3 highlightedObjectColor = picking_normalizeColor(picking.highlightedObjectColor);
|
|
8605
|
+
fn picking_isObjectHighlighted(objectIndex: i32) -> bool {
|
|
7727
8606
|
return
|
|
7728
|
-
|
|
8607
|
+
picking.isHighlightActive != 0 &&
|
|
8608
|
+
picking.highlightedBatchIndex == picking.batchIndex &&
|
|
8609
|
+
picking.highlightedObjectIndex == objectIndex;
|
|
7729
8610
|
}
|
|
7730
8611
|
|
|
7731
|
-
|
|
7732
|
-
|
|
7733
|
-
|
|
7734
|
-
|
|
7735
|
-
if (bool(picking.isActive)) {
|
|
7736
|
-
// Use alpha as the validity flag. If pickingColor is [0, 0, 0] fragment is non-pickable
|
|
7737
|
-
picking_vRGBcolor_Avalid.a = float(picking_isColorValid(pickingColor));
|
|
7738
|
-
|
|
7739
|
-
if (!bool(picking.isAttribute)) {
|
|
7740
|
-
// Stores the picking color so that the fragment shader can render it during picking
|
|
7741
|
-
picking_vRGBcolor_Avalid.rgb = pickingColor;
|
|
7742
|
-
}
|
|
7743
|
-
} else {
|
|
7744
|
-
// Do the comparison with selected item color in vertex shader as it should mean fewer compares
|
|
7745
|
-
picking_vRGBcolor_Avalid.a = float(isVertexHighlighted(pickingColor));
|
|
8612
|
+
fn picking_filterHighlightColor(color: vec4<f32>, objectIndex: i32) -> vec4<f32> {
|
|
8613
|
+
if (picking.isActive != 0 || !picking_isObjectHighlighted(objectIndex)) {
|
|
8614
|
+
return color;
|
|
7746
8615
|
}
|
|
7747
|
-
}
|
|
7748
8616
|
|
|
7749
|
-
|
|
7750
|
-
|
|
7751
|
-
|
|
7752
|
-
|
|
7753
|
-
index = uint(gl_InstanceID);
|
|
7754
|
-
}
|
|
7755
|
-
picking_vRGBcolor_Avalid.r = float(index % 255) / 255.0;
|
|
7756
|
-
picking_vRGBcolor_Avalid.g = float((index / 255) % 255) / 255.0;
|
|
7757
|
-
picking_vRGBcolor_Avalid.b = float((index / 255 / 255) %255) / 255.0;
|
|
8617
|
+
let highLightAlpha = picking.highlightColor.a;
|
|
8618
|
+
let blendedAlpha = highLightAlpha + color.a * (1.0 - highLightAlpha);
|
|
8619
|
+
if (blendedAlpha == 0.0) {
|
|
8620
|
+
return vec4<f32>(color.rgb, 0.0);
|
|
7758
8621
|
}
|
|
8622
|
+
|
|
8623
|
+
let highLightRatio = highLightAlpha / blendedAlpha;
|
|
8624
|
+
let blendedRGB = mix(color.rgb, picking.highlightColor.rgb, highLightRatio);
|
|
8625
|
+
return vec4<f32>(blendedRGB, blendedAlpha);
|
|
7759
8626
|
}
|
|
7760
8627
|
|
|
7761
|
-
|
|
7762
|
-
if (
|
|
7763
|
-
|
|
8628
|
+
fn picking_filterPickingColor(color: vec4<f32>, objectIndex: i32) -> vec4<f32> {
|
|
8629
|
+
if (picking.isActive != 0 && objectIndex == INDEX_PICKING_INVALID_INDEX) {
|
|
8630
|
+
discard;
|
|
7764
8631
|
}
|
|
8632
|
+
return color;
|
|
7765
8633
|
}
|
|
7766
8634
|
|
|
7767
|
-
|
|
7768
|
-
|
|
7769
|
-
picking_vRGBcolor_Avalid.rg = value;
|
|
7770
|
-
}
|
|
8635
|
+
fn picking_getPickingColor(objectIndex: i32) -> vec2<i32> {
|
|
8636
|
+
return vec2<i32>(objectIndex, picking.batchIndex);
|
|
7771
8637
|
}
|
|
7772
8638
|
|
|
7773
|
-
|
|
7774
|
-
|
|
7775
|
-
|
|
8639
|
+
`
|
|
8640
|
+
);
|
|
8641
|
+
var vs2 = (
|
|
8642
|
+
/* glsl */
|
|
8643
|
+
`${GLSL_UNIFORMS}
|
|
8644
|
+
|
|
8645
|
+
const int INDEX_PICKING_MODE_INSTANCE = 0;
|
|
8646
|
+
const int INDEX_PICKING_MODE_CUSTOM = 1;
|
|
8647
|
+
|
|
8648
|
+
const int INDEX_PICKING_INVALID_INDEX = ${INVALID_INDEX}; // 2^32 - 1
|
|
8649
|
+
|
|
8650
|
+
flat out int picking_objectIndex;
|
|
8651
|
+
|
|
8652
|
+
/**
|
|
8653
|
+
* Vertex shaders should call this function to set the object index.
|
|
8654
|
+
* If using instance or vertex mode, argument will be ignored, 0 can be supplied.
|
|
8655
|
+
*/
|
|
8656
|
+
void picking_setObjectIndex(int objectIndex) {
|
|
8657
|
+
switch (picking.indexMode) {
|
|
8658
|
+
case INDEX_PICKING_MODE_INSTANCE:
|
|
8659
|
+
picking_objectIndex = gl_InstanceID;
|
|
8660
|
+
break;
|
|
8661
|
+
case INDEX_PICKING_MODE_CUSTOM:
|
|
8662
|
+
picking_objectIndex = objectIndex;
|
|
8663
|
+
break;
|
|
7776
8664
|
}
|
|
7777
8665
|
}
|
|
7778
8666
|
`
|
|
@@ -7781,41 +8669,58 @@ void picking_setPickingAttribute(vec3 value) {
|
|
|
7781
8669
|
/* glsl */
|
|
7782
8670
|
`${GLSL_UNIFORMS}
|
|
7783
8671
|
|
|
7784
|
-
|
|
8672
|
+
const int INDEX_PICKING_INVALID_INDEX = ${INVALID_INDEX}; // 2^32 - 1
|
|
8673
|
+
|
|
8674
|
+
flat in int picking_objectIndex;
|
|
7785
8675
|
|
|
7786
|
-
|
|
8676
|
+
/**
|
|
8677
|
+
* Check if this vertex is highlighted (part of the selected batch and object)
|
|
8678
|
+
*/
|
|
8679
|
+
bool picking_isFragmentHighlighted() {
|
|
8680
|
+
return
|
|
8681
|
+
bool(picking.isHighlightActive) &&
|
|
8682
|
+
picking.highlightedBatchIndex == picking.batchIndex &&
|
|
8683
|
+
picking.highlightedObjectIndex == picking_objectIndex
|
|
8684
|
+
;
|
|
8685
|
+
}
|
|
8686
|
+
|
|
8687
|
+
/**
|
|
7787
8688
|
* Returns highlight color if this item is selected.
|
|
7788
8689
|
*/
|
|
7789
8690
|
vec4 picking_filterHighlightColor(vec4 color) {
|
|
7790
8691
|
// If we are still picking, we don't highlight
|
|
7791
|
-
if (picking.isActive
|
|
8692
|
+
if (bool(picking.isActive)) {
|
|
7792
8693
|
return color;
|
|
7793
8694
|
}
|
|
7794
8695
|
|
|
7795
|
-
|
|
7796
|
-
|
|
7797
|
-
if (selected) {
|
|
7798
|
-
// Blend in highlight color based on its alpha value
|
|
7799
|
-
float highLightAlpha = picking.highlightColor.a;
|
|
7800
|
-
float blendedAlpha = highLightAlpha + color.a * (1.0 - highLightAlpha);
|
|
7801
|
-
float highLightRatio = highLightAlpha / blendedAlpha;
|
|
7802
|
-
|
|
7803
|
-
vec3 blendedRGB = mix(color.rgb, picking.highlightColor.rgb, highLightRatio);
|
|
7804
|
-
return vec4(blendedRGB, blendedAlpha);
|
|
7805
|
-
} else {
|
|
8696
|
+
// If we are not highlighted, return color as is
|
|
8697
|
+
if (!picking_isFragmentHighlighted()) {
|
|
7806
8698
|
return color;
|
|
7807
8699
|
}
|
|
8700
|
+
|
|
8701
|
+
// Blend in highlight color based on its alpha value
|
|
8702
|
+
float highLightAlpha = picking.highlightColor.a;
|
|
8703
|
+
float blendedAlpha = highLightAlpha + color.a * (1.0 - highLightAlpha);
|
|
8704
|
+
float highLightRatio = highLightAlpha / blendedAlpha;
|
|
8705
|
+
|
|
8706
|
+
vec3 blendedRGB = mix(color.rgb, picking.highlightColor.rgb, highLightRatio);
|
|
8707
|
+
return vec4(blendedRGB, blendedAlpha);
|
|
7808
8708
|
}
|
|
7809
8709
|
|
|
7810
8710
|
/*
|
|
7811
8711
|
* Returns picking color if picking enabled else unmodified argument.
|
|
7812
8712
|
*/
|
|
8713
|
+
ivec4 picking_getPickingColor() {
|
|
8714
|
+
// Assumes that colorAttachment0 is rg32int
|
|
8715
|
+
// TODO? - we could render indices into a second color attachment and not mess with fragColor
|
|
8716
|
+
return ivec4(picking_objectIndex, picking.batchIndex, 0u, 0u);
|
|
8717
|
+
}
|
|
8718
|
+
|
|
7813
8719
|
vec4 picking_filterPickingColor(vec4 color) {
|
|
7814
8720
|
if (bool(picking.isActive)) {
|
|
7815
|
-
if (
|
|
8721
|
+
if (picking_objectIndex == INDEX_PICKING_INVALID_INDEX) {
|
|
7816
8722
|
discard;
|
|
7817
8723
|
}
|
|
7818
|
-
return picking_vRGBcolor_Avalid;
|
|
7819
8724
|
}
|
|
7820
8725
|
return color;
|
|
7821
8726
|
}
|
|
@@ -7825,8 +8730,10 @@ vec4 picking_filterPickingColor(vec4 color) {
|
|
|
7825
8730
|
* highlight color if this item is selected, otherwise unmodified argument.
|
|
7826
8731
|
*/
|
|
7827
8732
|
vec4 picking_filterColor(vec4 color) {
|
|
7828
|
-
vec4
|
|
7829
|
-
|
|
8733
|
+
vec4 outColor = color;
|
|
8734
|
+
outColor = picking_filterHighlightColor(outColor);
|
|
8735
|
+
outColor = picking_filterPickingColor(outColor);
|
|
8736
|
+
return outColor;
|
|
7830
8737
|
}
|
|
7831
8738
|
`
|
|
7832
8739
|
);
|
|
@@ -7838,6 +8745,15 @@ vec4 picking_filterColor(vec4 color) {
|
|
|
7838
8745
|
fs: fs2
|
|
7839
8746
|
};
|
|
7840
8747
|
|
|
8748
|
+
// src/modules/picking/picking.ts
|
|
8749
|
+
var picking3 = {
|
|
8750
|
+
...pickingUniforms,
|
|
8751
|
+
name: "picking",
|
|
8752
|
+
source: picking2.source,
|
|
8753
|
+
vs: picking.vs,
|
|
8754
|
+
fs: picking.fs
|
|
8755
|
+
};
|
|
8756
|
+
|
|
7841
8757
|
// src/modules/picking/legacy-picking-manager.ts
|
|
7842
8758
|
var LegacyPickingManager = class {
|
|
7843
8759
|
device;
|
|
@@ -7907,6 +8823,10 @@ vec4 picking_filterColor(vec4 color) {
|
|
|
7907
8823
|
}
|
|
7908
8824
|
};
|
|
7909
8825
|
|
|
8826
|
+
// src/modules/picking/legacy-color-picking.ts
|
|
8827
|
+
var import_shadertools7 = __toESM(require_shadertools(), 1);
|
|
8828
|
+
var legacyColorPicking = import_shadertools7.picking;
|
|
8829
|
+
|
|
7910
8830
|
// src/index.ts
|
|
7911
8831
|
var AsyncTexture = DynamicTexture;
|
|
7912
8832
|
return __toCommonJS(bundle_exports);
|