@rings-webgpu/core 1.0.26 → 1.0.28
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/rings.es.js +344 -215
- package/dist/rings.es.js.map +3 -3
- package/dist/rings.es.max.js +1854 -98
- package/dist/rings.umd.js +344 -215
- package/dist/rings.umd.js.map +3 -3
- package/dist/rings.umd.max.js +1863 -97
- package/dist/types/assets/shader/pointcloud/PointCloudShader.d.ts +2 -0
- package/dist/types/components/renderer/PointCloudRenderer.d.ts +89 -0
- package/dist/types/gfx/graphics/webGpu/shader/RenderShaderPass.d.ts +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/loader/parser/ply/PlyLoader.d.ts +10 -2
- package/dist/types/loader/parser/ply/PlyParser.d.ts +7 -0
- package/dist/types/loader/parser/ply/PlyTypes.d.ts +33 -0
- package/dist/types/loader/parser/prefab/mats/shader/PointCloudShader.d.ts +9 -0
- package/dist/types/materials/PointCloudMaterial.d.ts +44 -0
- package/dist/types/shape/GSplatGeometry.d.ts +1 -3
- package/dist/types/shape/PointCloudGeometry.d.ts +5 -0
- package/dist/types/textures/Float32ArrayTexture.d.ts +1 -1
- package/dist/types/util/BoundUtil.d.ts +1 -0
- package/package.json +1 -1
package/dist/rings.umd.max.js
CHANGED
|
@@ -2120,7 +2120,7 @@
|
|
|
2120
2120
|
}
|
|
2121
2121
|
|
|
2122
2122
|
var __defProp$2 = Object.defineProperty;
|
|
2123
|
-
var __decorateClass$
|
|
2123
|
+
var __decorateClass$o = (decorators, target, key, kind) => {
|
|
2124
2124
|
var result = void 0 ;
|
|
2125
2125
|
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
2126
2126
|
if (decorator = decorators[i])
|
|
@@ -2223,10 +2223,10 @@
|
|
|
2223
2223
|
return struct.__size;
|
|
2224
2224
|
}
|
|
2225
2225
|
};
|
|
2226
|
-
__decorateClass$
|
|
2226
|
+
__decorateClass$o([
|
|
2227
2227
|
NonSerialize
|
|
2228
2228
|
], _Struct.prototype, "__refection");
|
|
2229
|
-
__decorateClass$
|
|
2229
|
+
__decorateClass$o([
|
|
2230
2230
|
NonSerialize
|
|
2231
2231
|
], _Struct.prototype, "__size");
|
|
2232
2232
|
let Struct = _Struct;
|
|
@@ -20496,6 +20496,10 @@ struct InstanceData {
|
|
|
20496
20496
|
this.vsEntryPoint = vsEntryPoint;
|
|
20497
20497
|
this.fsEntryPoint = fsEntryPoint;
|
|
20498
20498
|
}
|
|
20499
|
+
setUniformArray(name, value) {
|
|
20500
|
+
super.setUniformArray(name, value);
|
|
20501
|
+
this.materialDataUniformBuffer.onChange();
|
|
20502
|
+
}
|
|
20499
20503
|
setUniform(name, value) {
|
|
20500
20504
|
super.setUniform(name, value);
|
|
20501
20505
|
this.materialDataUniformBuffer.onChange();
|
|
@@ -20764,16 +20768,21 @@ struct InstanceData {
|
|
|
20764
20768
|
if (buffer) {
|
|
20765
20769
|
if (buffer.bufferType == GPUBufferType.MaterialDataUniformGPUBuffer) {
|
|
20766
20770
|
let uniforms = [];
|
|
20767
|
-
|
|
20768
|
-
|
|
20769
|
-
|
|
20770
|
-
|
|
20771
|
-
|
|
20772
|
-
|
|
20771
|
+
if (refs.dataFields) {
|
|
20772
|
+
for (let i = 0; i < refs.dataFields.length; i++) {
|
|
20773
|
+
const field = refs.dataFields[i];
|
|
20774
|
+
if (!this.uniforms[field.name]) {
|
|
20775
|
+
console.error(
|
|
20776
|
+
`shader-${this.vsName}:${this.fsName} ${field.name}is empty`
|
|
20777
|
+
);
|
|
20778
|
+
} else {
|
|
20779
|
+
uniforms.push(this.uniforms[field.name]);
|
|
20780
|
+
}
|
|
20773
20781
|
}
|
|
20774
|
-
uniforms.push(this.uniforms[field.name]);
|
|
20775
20782
|
}
|
|
20776
|
-
|
|
20783
|
+
if (uniforms.length > 0) {
|
|
20784
|
+
this.materialDataUniformBuffer.initDataUniform(uniforms);
|
|
20785
|
+
}
|
|
20777
20786
|
}
|
|
20778
20787
|
let entry = {
|
|
20779
20788
|
binding: refs.binding,
|
|
@@ -21963,9 +21972,9 @@ struct InstanceData {
|
|
|
21963
21972
|
}
|
|
21964
21973
|
|
|
21965
21974
|
var __defProp$1 = Object.defineProperty;
|
|
21966
|
-
var __getOwnPropDesc$
|
|
21967
|
-
var __decorateClass$
|
|
21968
|
-
var result = __getOwnPropDesc$
|
|
21975
|
+
var __getOwnPropDesc$n = Object.getOwnPropertyDescriptor;
|
|
21976
|
+
var __decorateClass$n = (decorators, target, key, kind) => {
|
|
21977
|
+
var result = __getOwnPropDesc$n(target, key) ;
|
|
21969
21978
|
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
21970
21979
|
if (decorator = decorators[i])
|
|
21971
21980
|
result = (decorator(target, key, result) ) || result;
|
|
@@ -22563,13 +22572,13 @@ struct InstanceData {
|
|
|
22563
22572
|
this._combineShaderRefection = void 0;
|
|
22564
22573
|
}
|
|
22565
22574
|
}
|
|
22566
|
-
__decorateClass$
|
|
22575
|
+
__decorateClass$n([
|
|
22567
22576
|
EditorInspector
|
|
22568
22577
|
], RenderNode.prototype, "materials");
|
|
22569
|
-
__decorateClass$
|
|
22578
|
+
__decorateClass$n([
|
|
22570
22579
|
EditorInspector
|
|
22571
22580
|
], RenderNode.prototype, "castShadow");
|
|
22572
|
-
__decorateClass$
|
|
22581
|
+
__decorateClass$n([
|
|
22573
22582
|
EditorInspector
|
|
22574
22583
|
], RenderNode.prototype, "castGI");
|
|
22575
22584
|
|
|
@@ -22790,7 +22799,7 @@ struct InstanceData {
|
|
|
22790
22799
|
@location(1) vTexCoord: vec2<f32>,
|
|
22791
22800
|
};
|
|
22792
22801
|
|
|
22793
|
-
// Textures
|
|
22802
|
+
// Textures
|
|
22794
22803
|
@group(1) @binding(1) var splatColor: texture_2d<f32>;
|
|
22795
22804
|
@group(1) @binding(2) var transformA: texture_2d<u32>;
|
|
22796
22805
|
@group(1) @binding(3) var transformB: texture_2d<f32>;
|
|
@@ -22887,7 +22896,7 @@ struct InstanceData {
|
|
|
22887
22896
|
return vec4f(v1.x, -v1.y, v2.x, -v2.y);
|
|
22888
22897
|
}
|
|
22889
22898
|
|
|
22890
|
-
// ===== SPLAT MAIN VS
|
|
22899
|
+
// ===== SPLAT MAIN VS =====
|
|
22891
22900
|
|
|
22892
22901
|
@vertex
|
|
22893
22902
|
fn VertMain(
|
|
@@ -23236,9 +23245,9 @@ struct InstanceData {
|
|
|
23236
23245
|
}
|
|
23237
23246
|
}
|
|
23238
23247
|
|
|
23239
|
-
var __getOwnPropDesc$
|
|
23240
|
-
var __decorateClass$
|
|
23241
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$
|
|
23248
|
+
var __getOwnPropDesc$m = Object.getOwnPropertyDescriptor;
|
|
23249
|
+
var __decorateClass$m = (decorators, target, key, kind) => {
|
|
23250
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$m(target, key) : target;
|
|
23242
23251
|
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
23243
23252
|
if (decorator = decorators[i])
|
|
23244
23253
|
result = (decorator(result)) || result;
|
|
@@ -23270,7 +23279,7 @@ struct InstanceData {
|
|
|
23270
23279
|
pass.setUniform("pixelCull", new Float32Array([2, 0, 0, 0]));
|
|
23271
23280
|
}
|
|
23272
23281
|
};
|
|
23273
|
-
exports.GSplatShader = __decorateClass$
|
|
23282
|
+
exports.GSplatShader = __decorateClass$m([
|
|
23274
23283
|
RegisterShader(exports.GSplatShader, "GSplatShader")
|
|
23275
23284
|
], exports.GSplatShader);
|
|
23276
23285
|
|
|
@@ -24053,7 +24062,7 @@ struct InstanceData {
|
|
|
24053
24062
|
size: data.byteLength,
|
|
24054
24063
|
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC
|
|
24055
24064
|
});
|
|
24056
|
-
device.queue.writeBuffer(textureDataBuffer, 0, data);
|
|
24065
|
+
device.queue.writeBuffer(textureDataBuffer, 0, data.buffer);
|
|
24057
24066
|
const commandEncoder = GPUContext.beginCommandEncoder();
|
|
24058
24067
|
commandEncoder.copyBufferToTexture(
|
|
24059
24068
|
{
|
|
@@ -24085,7 +24094,7 @@ struct InstanceData {
|
|
|
24085
24094
|
size: data.byteLength,
|
|
24086
24095
|
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC
|
|
24087
24096
|
});
|
|
24088
|
-
device.queue.writeBuffer(textureDataBuffer, 0, data);
|
|
24097
|
+
device.queue.writeBuffer(textureDataBuffer, 0, data.buffer);
|
|
24089
24098
|
const commandEncoder = GPUContext.beginCommandEncoder();
|
|
24090
24099
|
commandEncoder.copyBufferToTexture(
|
|
24091
24100
|
{
|
|
@@ -24287,9 +24296,9 @@ struct InstanceData {
|
|
|
24287
24296
|
}
|
|
24288
24297
|
}
|
|
24289
24298
|
|
|
24290
|
-
var __getOwnPropDesc$
|
|
24291
|
-
var __decorateClass$
|
|
24292
|
-
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$
|
|
24299
|
+
var __getOwnPropDesc$l = Object.getOwnPropertyDescriptor;
|
|
24300
|
+
var __decorateClass$l = (decorators, target, key, kind) => {
|
|
24301
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$l(target, key) : target;
|
|
24293
24302
|
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
24294
24303
|
if (decorator = decorators[i])
|
|
24295
24304
|
result = (decorator(result)) || result;
|
|
@@ -25088,10 +25097,689 @@ struct InstanceData {
|
|
|
25088
25097
|
super.destroy(force);
|
|
25089
25098
|
}
|
|
25090
25099
|
};
|
|
25091
|
-
exports.GSplatRenderer = __decorateClass$
|
|
25100
|
+
exports.GSplatRenderer = __decorateClass$l([
|
|
25092
25101
|
RegisterComponent(exports.GSplatRenderer, "GSplatRenderer")
|
|
25093
25102
|
], exports.GSplatRenderer);
|
|
25094
25103
|
|
|
25104
|
+
const PointCloud_VS = (
|
|
25105
|
+
/* wgsl */
|
|
25106
|
+
`
|
|
25107
|
+
#include "GlobalUniform"
|
|
25108
|
+
|
|
25109
|
+
const ALPHA_THRESHOLD: f32 = 0.00392156863;
|
|
25110
|
+
|
|
25111
|
+
struct MaterialUniform {
|
|
25112
|
+
modelMatrix: mat4x4<f32>,
|
|
25113
|
+
tex_params: vec4<f32>,
|
|
25114
|
+
pointParams: vec4<f32>,
|
|
25115
|
+
};
|
|
25116
|
+
@group(1) @binding(0) var<uniform> materialUniform: MaterialUniform;
|
|
25117
|
+
|
|
25118
|
+
struct VSOut {
|
|
25119
|
+
@builtin(position) member: vec4<f32>,
|
|
25120
|
+
@location(0) vColor: vec4<f32>,
|
|
25121
|
+
@location(1) vTexCoord: vec2<f32>,
|
|
25122
|
+
};
|
|
25123
|
+
|
|
25124
|
+
@group(1) @binding(1) var pointColor: texture_2d<f32>;
|
|
25125
|
+
@group(1) @binding(2) var pointPosition: texture_2d<f32>;
|
|
25126
|
+
@group(1) @binding(3) var pointOrder: texture_2d<u32>;
|
|
25127
|
+
|
|
25128
|
+
fn discardPoint() -> VSOut {
|
|
25129
|
+
var o: VSOut;
|
|
25130
|
+
o.member = vec4f(0.0, 0.0, 2.0, 1.0);
|
|
25131
|
+
o.vColor = vec4f(0.0);
|
|
25132
|
+
o.vTexCoord = vec2f(0.0);
|
|
25133
|
+
return o;
|
|
25134
|
+
}
|
|
25135
|
+
|
|
25136
|
+
fn calcPointUV(orderId: u32, textureWidth: u32, numPoints: u32) -> vec2<i32> {
|
|
25137
|
+
let pointId = orderId;
|
|
25138
|
+
return vec2<i32>(
|
|
25139
|
+
i32(pointId % textureWidth),
|
|
25140
|
+
i32(pointId / textureWidth)
|
|
25141
|
+
);
|
|
25142
|
+
}
|
|
25143
|
+
|
|
25144
|
+
@vertex
|
|
25145
|
+
fn VertMain(
|
|
25146
|
+
@builtin(vertex_index) vid: u32,
|
|
25147
|
+
@builtin(instance_index) iid: u32,
|
|
25148
|
+
@location(0) position: vec3<f32>
|
|
25149
|
+
) -> VSOut {
|
|
25150
|
+
let batchSize = max(1u, u32(materialUniform.pointParams.w));
|
|
25151
|
+
let orderId = iid * batchSize + u32(position.z);
|
|
25152
|
+
|
|
25153
|
+
let textureWidth = max(1u, u32(materialUniform.tex_params.y));
|
|
25154
|
+
let numPoints = max(1u, u32(materialUniform.tex_params.x));
|
|
25155
|
+
let safeOrderId = min(orderId, numPoints - 1u);
|
|
25156
|
+
|
|
25157
|
+
let pointUV = calcPointUV(safeOrderId, textureWidth, numPoints);
|
|
25158
|
+
let color = textureLoad(pointColor, pointUV, 0);
|
|
25159
|
+
|
|
25160
|
+
let posData = textureLoad(pointPosition, pointUV, 0);
|
|
25161
|
+
let pointPos = vec3f(
|
|
25162
|
+
posData.x,
|
|
25163
|
+
posData.y,
|
|
25164
|
+
posData.z
|
|
25165
|
+
);
|
|
25166
|
+
|
|
25167
|
+
let matrix_model = materialUniform.modelMatrix;
|
|
25168
|
+
let matrix_view = globalUniform.viewMat;
|
|
25169
|
+
let matrix_projection = globalUniform.projMat;
|
|
25170
|
+
let model_view = matrix_view * matrix_model;
|
|
25171
|
+
|
|
25172
|
+
let centerClip = matrix_projection * (model_view * vec4f(pointPos, 1.0));
|
|
25173
|
+
|
|
25174
|
+
let inv_w = 1.0 / centerClip.w;
|
|
25175
|
+
let ndc = centerClip.xyz * inv_w;
|
|
25176
|
+
if (ndc.x < -1.0 || ndc.x > 1.0 ||
|
|
25177
|
+
ndc.y < -1.0 || ndc.y > 1.0 ||
|
|
25178
|
+
ndc.z < 0.0 || ndc.z > 1.0) {
|
|
25179
|
+
return discardPoint();
|
|
25180
|
+
}
|
|
25181
|
+
|
|
25182
|
+
let viewPos = model_view * vec4f(pointPos, 1.0);
|
|
25183
|
+
if (viewPos.z <= 0.0) {
|
|
25184
|
+
return discardPoint();
|
|
25185
|
+
}
|
|
25186
|
+
|
|
25187
|
+
let pointSize = materialUniform.tex_params.w;
|
|
25188
|
+
let viewport = vec2f(globalUniform.windowWidth, globalUniform.windowHeight);
|
|
25189
|
+
let safeViewport = max(viewport, vec2f(1.0, 1.0));
|
|
25190
|
+
let inv_viewport = 2.0 / safeViewport;
|
|
25191
|
+
let offsetNDC = position.xy * pointSize * 0.5 * inv_viewport;
|
|
25192
|
+
let offsetClip = vec4f(offsetNDC * centerClip.w, 0.0, 0.0);
|
|
25193
|
+
|
|
25194
|
+
var o: VSOut;
|
|
25195
|
+
o.member = centerClip + offsetClip;
|
|
25196
|
+
o.vColor = color;
|
|
25197
|
+
o.vTexCoord = position.xy;
|
|
25198
|
+
return o;
|
|
25199
|
+
}
|
|
25200
|
+
`
|
|
25201
|
+
);
|
|
25202
|
+
const PointCloud_FS = (
|
|
25203
|
+
/* wgsl */
|
|
25204
|
+
`
|
|
25205
|
+
#include "FragmentOutput"
|
|
25206
|
+
|
|
25207
|
+
const ALPHA_THRESHOLD: f32 = 0.00392156863;
|
|
25208
|
+
|
|
25209
|
+
struct MaterialUniform {
|
|
25210
|
+
modelMatrix: mat4x4<f32>,
|
|
25211
|
+
tex_params: vec4<f32>,
|
|
25212
|
+
pointParams: vec4<f32>,
|
|
25213
|
+
};
|
|
25214
|
+
@group(1) @binding(0) var<uniform> materialUniform: MaterialUniform;
|
|
25215
|
+
|
|
25216
|
+
@fragment
|
|
25217
|
+
fn FragMain(
|
|
25218
|
+
@location(0) vColor: vec4<f32>,
|
|
25219
|
+
@location(1) vTexCoord: vec2<f32>
|
|
25220
|
+
) -> FragmentOutput {
|
|
25221
|
+
var o: FragmentOutput;
|
|
25222
|
+
|
|
25223
|
+
let pointShape = materialUniform.pointParams.x;
|
|
25224
|
+
let distSq = dot(vTexCoord, vTexCoord);
|
|
25225
|
+
let isCircle = pointShape > 0.5;
|
|
25226
|
+
let discardPixel = isCircle && distSq > 1.0;
|
|
25227
|
+
|
|
25228
|
+
if (discardPixel) {
|
|
25229
|
+
discard;
|
|
25230
|
+
}
|
|
25231
|
+
|
|
25232
|
+
o.color = vColor;
|
|
25233
|
+
o.gBuffer = vec4f(0.0);
|
|
25234
|
+
return o;
|
|
25235
|
+
}
|
|
25236
|
+
`
|
|
25237
|
+
);
|
|
25238
|
+
|
|
25239
|
+
var __getOwnPropDesc$k = Object.getOwnPropertyDescriptor;
|
|
25240
|
+
var __decorateClass$k = (decorators, target, key, kind) => {
|
|
25241
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$k(target, key) : target;
|
|
25242
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
25243
|
+
if (decorator = decorators[i])
|
|
25244
|
+
result = (decorator(result)) || result;
|
|
25245
|
+
return result;
|
|
25246
|
+
};
|
|
25247
|
+
exports.PointCloudShader = class PointCloudShader extends Shader {
|
|
25248
|
+
constructor() {
|
|
25249
|
+
super();
|
|
25250
|
+
ShaderLib.register("pointcloud_vs_dc", PointCloud_VS);
|
|
25251
|
+
ShaderLib.register("pointcloud_fs_dc", PointCloud_FS);
|
|
25252
|
+
const pass = new RenderShaderPass("pointcloud_vs_dc", "pointcloud_fs_dc");
|
|
25253
|
+
pass.passType = PassType.COLOR;
|
|
25254
|
+
pass.setShaderEntry("VertMain", "FragMain");
|
|
25255
|
+
pass.topology = GPUPrimitiveTopology.triangle_list;
|
|
25256
|
+
pass.depthWriteEnabled = false;
|
|
25257
|
+
pass.cullMode = GPUCullMode.none;
|
|
25258
|
+
pass.shaderState.transparent = true;
|
|
25259
|
+
pass.shaderState.blendMode = BlendMode.NORMAL;
|
|
25260
|
+
pass.shaderState.writeMasks = [15, 15];
|
|
25261
|
+
pass.shaderState.castReflection = false;
|
|
25262
|
+
this.addRenderPass(pass);
|
|
25263
|
+
this.setDefault();
|
|
25264
|
+
}
|
|
25265
|
+
setDefault() {
|
|
25266
|
+
const pass = this.getDefaultColorShader();
|
|
25267
|
+
const identityMatrix = new Matrix4();
|
|
25268
|
+
pass.setUniform("modelMatrix", identityMatrix.rawData);
|
|
25269
|
+
pass.setUniformArray("tex_params", new Float32Array([0, 0, 0, 4]));
|
|
25270
|
+
pass.setUniformArray("pointParams", new Float32Array([0, 0, 0, 128]));
|
|
25271
|
+
}
|
|
25272
|
+
};
|
|
25273
|
+
exports.PointCloudShader = __decorateClass$k([
|
|
25274
|
+
RegisterShader(exports.PointCloudShader, "PointCloudShader")
|
|
25275
|
+
], exports.PointCloudShader);
|
|
25276
|
+
|
|
25277
|
+
class PointCloudMaterial extends Material {
|
|
25278
|
+
_texParams = new Float32Array([0, 0, 0, 4]);
|
|
25279
|
+
_pointParamsArray = new Float32Array([0, 0, 0, 128]);
|
|
25280
|
+
constructor() {
|
|
25281
|
+
super();
|
|
25282
|
+
this.shader = new exports.PointCloudShader();
|
|
25283
|
+
}
|
|
25284
|
+
/**
|
|
25285
|
+
* Set point cloud textures
|
|
25286
|
+
* @param pointPosition Position texture (RGB = xyz)
|
|
25287
|
+
* @param pointColor Color texture (RGBA)
|
|
25288
|
+
* @param texParams Texture parameters [numPoints, texWidth, validCount, pointSize]
|
|
25289
|
+
* @param pointOrder Optional sorting texture (R32U format)
|
|
25290
|
+
*/
|
|
25291
|
+
setPointTextures(pointPosition, pointColor, texParams, pointOrder) {
|
|
25292
|
+
const pass = this.shader.getDefaultColorShader();
|
|
25293
|
+
if (!pass.getUniform("modelMatrix")) {
|
|
25294
|
+
const identityMatrix = new Matrix4();
|
|
25295
|
+
pass.setUniform("modelMatrix", identityMatrix.rawData);
|
|
25296
|
+
}
|
|
25297
|
+
pass.setTexture("pointColor", pointColor);
|
|
25298
|
+
pass.setTexture("pointPosition", pointPosition);
|
|
25299
|
+
this._texParams[0] = texParams[0];
|
|
25300
|
+
this._texParams[1] = texParams[1];
|
|
25301
|
+
this._texParams[2] = texParams[2];
|
|
25302
|
+
this._texParams[3] = texParams[3];
|
|
25303
|
+
pass.setUniformArray("tex_params", this._texParams);
|
|
25304
|
+
pass.setUniformArray("pointParams", this._pointParamsArray);
|
|
25305
|
+
if (pointOrder) {
|
|
25306
|
+
pass.setTexture("pointOrder", pointOrder);
|
|
25307
|
+
}
|
|
25308
|
+
pass.shaderState.depthCompare = GPUCompareFunction.less;
|
|
25309
|
+
}
|
|
25310
|
+
/**
|
|
25311
|
+
* Set the model matrix for transforming points to world space
|
|
25312
|
+
* @param matrix Model transformation matrix
|
|
25313
|
+
*/
|
|
25314
|
+
setTransformMatrix(matrix) {
|
|
25315
|
+
const pass = this.shader.getDefaultColorShader();
|
|
25316
|
+
pass.setUniform("modelMatrix", matrix.rawData);
|
|
25317
|
+
}
|
|
25318
|
+
/**
|
|
25319
|
+
* Set point size in pixels
|
|
25320
|
+
* @param size Point size in pixels (default: 4.0)
|
|
25321
|
+
*/
|
|
25322
|
+
setPointSize(size) {
|
|
25323
|
+
this._texParams[3] = Math.max(0.1, size);
|
|
25324
|
+
const pass = this.shader.getDefaultColorShader();
|
|
25325
|
+
pass.setUniformArray("tex_params", this._texParams);
|
|
25326
|
+
}
|
|
25327
|
+
/**
|
|
25328
|
+
* Set point shape
|
|
25329
|
+
* @param shape Point shape: 'square' or 'circle'
|
|
25330
|
+
*/
|
|
25331
|
+
setPointShape(shape) {
|
|
25332
|
+
this._pointParamsArray[0] = shape === "circle" ? 1 : 0;
|
|
25333
|
+
const pass = this.shader.getDefaultColorShader();
|
|
25334
|
+
pass.setUniformArray("pointParams", this._pointParamsArray);
|
|
25335
|
+
}
|
|
25336
|
+
enableDebugFullScreen(enabled) {
|
|
25337
|
+
this._pointParamsArray[1] = enabled ? 1 : 0;
|
|
25338
|
+
const pass = this.shader.getDefaultColorShader();
|
|
25339
|
+
pass.setUniformArray("pointParams", this._pointParamsArray);
|
|
25340
|
+
}
|
|
25341
|
+
/**
|
|
25342
|
+
* Set batch size for instanced rendering
|
|
25343
|
+
* @param batchSize Number of points per draw call (default: 128)
|
|
25344
|
+
*/
|
|
25345
|
+
setBatchSize(batchSize) {
|
|
25346
|
+
this._pointParamsArray[3] = Math.max(1, batchSize | 0);
|
|
25347
|
+
const pass = this.shader.getDefaultColorShader();
|
|
25348
|
+
pass.setUniformArray("pointParams", this._pointParamsArray);
|
|
25349
|
+
}
|
|
25350
|
+
}
|
|
25351
|
+
|
|
25352
|
+
class PointCloudGeometry extends GeometryBase {
|
|
25353
|
+
batchSize;
|
|
25354
|
+
constructor(batchSize = 128) {
|
|
25355
|
+
super();
|
|
25356
|
+
this.batchSize = batchSize;
|
|
25357
|
+
const meshPositions = new Float32Array(12 * batchSize);
|
|
25358
|
+
for (let i = 0; i < batchSize; ++i) {
|
|
25359
|
+
const baseIdx = i * 12;
|
|
25360
|
+
meshPositions.set([
|
|
25361
|
+
-1,
|
|
25362
|
+
-1,
|
|
25363
|
+
i,
|
|
25364
|
+
1,
|
|
25365
|
+
-1,
|
|
25366
|
+
i,
|
|
25367
|
+
1,
|
|
25368
|
+
1,
|
|
25369
|
+
i,
|
|
25370
|
+
-1,
|
|
25371
|
+
1,
|
|
25372
|
+
i
|
|
25373
|
+
], baseIdx);
|
|
25374
|
+
}
|
|
25375
|
+
const meshIndices = new Uint32Array(6 * batchSize);
|
|
25376
|
+
for (let i = 0; i < batchSize; ++i) {
|
|
25377
|
+
const baseVertex = i * 4;
|
|
25378
|
+
const baseIdx = i * 6;
|
|
25379
|
+
meshIndices.set([
|
|
25380
|
+
0 + baseVertex,
|
|
25381
|
+
1 + baseVertex,
|
|
25382
|
+
2 + baseVertex,
|
|
25383
|
+
0 + baseVertex,
|
|
25384
|
+
2 + baseVertex,
|
|
25385
|
+
3 + baseVertex
|
|
25386
|
+
], baseIdx);
|
|
25387
|
+
}
|
|
25388
|
+
this.setAttribute(VertexAttributeName.position, meshPositions);
|
|
25389
|
+
this.setIndices(meshIndices);
|
|
25390
|
+
this.addSubGeometry({
|
|
25391
|
+
indexStart: 0,
|
|
25392
|
+
indexCount: meshIndices.length,
|
|
25393
|
+
vertexStart: 0,
|
|
25394
|
+
vertexCount: meshPositions.length / 3,
|
|
25395
|
+
firstStart: 0,
|
|
25396
|
+
index: 0,
|
|
25397
|
+
topology: 0
|
|
25398
|
+
});
|
|
25399
|
+
}
|
|
25400
|
+
}
|
|
25401
|
+
|
|
25402
|
+
class Float32ArrayTexture extends Texture {
|
|
25403
|
+
create(width, height, data, filtering = true) {
|
|
25404
|
+
let device = webGPUContext.device;
|
|
25405
|
+
const bytesPerRow = width * 4 * 4;
|
|
25406
|
+
this.format = GPUTextureFormat.rgba32float;
|
|
25407
|
+
let mipmapCount = 1;
|
|
25408
|
+
this.createTextureDescriptor(width, height, mipmapCount, this.format);
|
|
25409
|
+
const textureDataBuffer = device.createBuffer({
|
|
25410
|
+
size: data.byteLength,
|
|
25411
|
+
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC
|
|
25412
|
+
});
|
|
25413
|
+
device.queue.writeBuffer(textureDataBuffer, 0, data.buffer);
|
|
25414
|
+
const commandEncoder = GPUContext.beginCommandEncoder();
|
|
25415
|
+
commandEncoder.copyBufferToTexture(
|
|
25416
|
+
{
|
|
25417
|
+
buffer: textureDataBuffer,
|
|
25418
|
+
bytesPerRow
|
|
25419
|
+
},
|
|
25420
|
+
{
|
|
25421
|
+
texture: this.getGPUTexture()
|
|
25422
|
+
},
|
|
25423
|
+
{
|
|
25424
|
+
width,
|
|
25425
|
+
height,
|
|
25426
|
+
depthOrArrayLayers: 1
|
|
25427
|
+
}
|
|
25428
|
+
);
|
|
25429
|
+
GPUContext.endCommandEncoder(commandEncoder);
|
|
25430
|
+
if (filtering) {
|
|
25431
|
+
this.samplerBindingLayout.type = `non-filtering`;
|
|
25432
|
+
this.textureBindingLayout.sampleType = `unfilterable-float`;
|
|
25433
|
+
}
|
|
25434
|
+
this.gpuSampler = device.createSampler({});
|
|
25435
|
+
return this;
|
|
25436
|
+
}
|
|
25437
|
+
fromBuffer(width, height, textureDataBuffer) {
|
|
25438
|
+
let device = webGPUContext.device;
|
|
25439
|
+
const bytesPerRow = width * 4 * 4;
|
|
25440
|
+
this.format = GPUTextureFormat.rgba32float;
|
|
25441
|
+
this.mipmapCount = 1;
|
|
25442
|
+
this.createTextureDescriptor(width, height, this.mipmapCount, this.format);
|
|
25443
|
+
const commandEncoder = GPUContext.beginCommandEncoder();
|
|
25444
|
+
commandEncoder.copyBufferToTexture(
|
|
25445
|
+
{
|
|
25446
|
+
buffer: textureDataBuffer,
|
|
25447
|
+
bytesPerRow
|
|
25448
|
+
},
|
|
25449
|
+
{
|
|
25450
|
+
texture: this.getGPUTexture()
|
|
25451
|
+
},
|
|
25452
|
+
{
|
|
25453
|
+
width,
|
|
25454
|
+
height,
|
|
25455
|
+
depthOrArrayLayers: 1
|
|
25456
|
+
}
|
|
25457
|
+
);
|
|
25458
|
+
GPUContext.endCommandEncoder(commandEncoder);
|
|
25459
|
+
this.samplerBindingLayout.type = `non-filtering`;
|
|
25460
|
+
this.textureBindingLayout.sampleType = `unfilterable-float`;
|
|
25461
|
+
this.gpuSampler = device.createSampler({});
|
|
25462
|
+
return this;
|
|
25463
|
+
}
|
|
25464
|
+
}
|
|
25465
|
+
|
|
25466
|
+
var __getOwnPropDesc$j = Object.getOwnPropertyDescriptor;
|
|
25467
|
+
var __decorateClass$j = (decorators, target, key, kind) => {
|
|
25468
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc$j(target, key) : target;
|
|
25469
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
25470
|
+
if (decorator = decorators[i])
|
|
25471
|
+
result = (decorator(result)) || result;
|
|
25472
|
+
return result;
|
|
25473
|
+
};
|
|
25474
|
+
exports.PointCloudRenderer = class PointCloudRenderer extends RenderNode {
|
|
25475
|
+
count = 0;
|
|
25476
|
+
size = new Vector2();
|
|
25477
|
+
pointColor;
|
|
25478
|
+
pointPosition;
|
|
25479
|
+
pointOrder;
|
|
25480
|
+
texParams;
|
|
25481
|
+
// [numPoints, texWidth, validCount, pointSize]
|
|
25482
|
+
pointCloudMaterial;
|
|
25483
|
+
_positions;
|
|
25484
|
+
get positions() {
|
|
25485
|
+
return this._positions;
|
|
25486
|
+
}
|
|
25487
|
+
_colors;
|
|
25488
|
+
_orderData;
|
|
25489
|
+
_fullCount = 0;
|
|
25490
|
+
get fullCount() {
|
|
25491
|
+
return this._fullCount;
|
|
25492
|
+
}
|
|
25493
|
+
_batchSize = 128;
|
|
25494
|
+
instanceCount = 0;
|
|
25495
|
+
_texturesInitialized = false;
|
|
25496
|
+
_debugFullScreen = false;
|
|
25497
|
+
_centerOffset = new Vector3();
|
|
25498
|
+
get centerOffset() {
|
|
25499
|
+
return this._centerOffset;
|
|
25500
|
+
}
|
|
25501
|
+
constructor() {
|
|
25502
|
+
super();
|
|
25503
|
+
}
|
|
25504
|
+
/**
|
|
25505
|
+
* Initialize point cloud from raw data
|
|
25506
|
+
* @param positions Point positions (xyz per point, Float32Array)
|
|
25507
|
+
* @param colors Point colors (rgba per point, Uint8Array)
|
|
25508
|
+
* @param count Number of points
|
|
25509
|
+
*/
|
|
25510
|
+
initFromData(positions, colors, count) {
|
|
25511
|
+
if (!positions || !colors || count <= 0) {
|
|
25512
|
+
console.error("PointCloudRenderer: Invalid input data");
|
|
25513
|
+
return;
|
|
25514
|
+
}
|
|
25515
|
+
if (positions.length < count * 3) {
|
|
25516
|
+
console.error("PointCloudRenderer: Positions array too small");
|
|
25517
|
+
return;
|
|
25518
|
+
}
|
|
25519
|
+
if (colors.length < count * 4) {
|
|
25520
|
+
console.error("PointCloudRenderer: Colors array too small");
|
|
25521
|
+
return;
|
|
25522
|
+
}
|
|
25523
|
+
this.count = count;
|
|
25524
|
+
this._fullCount = count;
|
|
25525
|
+
this.size = this.evalTextureSize(count);
|
|
25526
|
+
this._positions = positions;
|
|
25527
|
+
this._colors = colors;
|
|
25528
|
+
this.centerizePositions();
|
|
25529
|
+
this.buildPositionTexture();
|
|
25530
|
+
this.buildColorTexture();
|
|
25531
|
+
this.texParams = new Float32Array([
|
|
25532
|
+
this.count,
|
|
25533
|
+
this.size.x,
|
|
25534
|
+
this.count,
|
|
25535
|
+
4
|
|
25536
|
+
]);
|
|
25537
|
+
this.buildOrderTexture();
|
|
25538
|
+
this.pointCloudMaterial = new PointCloudMaterial();
|
|
25539
|
+
this.geometry = new PointCloudGeometry(this._batchSize);
|
|
25540
|
+
this.materials = [this.pointCloudMaterial];
|
|
25541
|
+
this.instanceCount = Math.ceil(this.count / this._batchSize);
|
|
25542
|
+
}
|
|
25543
|
+
/**
|
|
25544
|
+
* Calculate texture size for given point count
|
|
25545
|
+
* @param count Number of points
|
|
25546
|
+
* @returns Texture dimensions (width, height)
|
|
25547
|
+
*/
|
|
25548
|
+
evalTextureSize(count) {
|
|
25549
|
+
let w = Math.ceil(Math.sqrt(count));
|
|
25550
|
+
const align = 64;
|
|
25551
|
+
w = Math.ceil(w / align) * align;
|
|
25552
|
+
const h = Math.ceil(count / w);
|
|
25553
|
+
return new Vector2(w, h);
|
|
25554
|
+
}
|
|
25555
|
+
/**
|
|
25556
|
+
* Centerize positions to improve precision for large values
|
|
25557
|
+
* Subtracts the center point from all positions to keep values near zero
|
|
25558
|
+
*/
|
|
25559
|
+
centerizePositions() {
|
|
25560
|
+
if (this.count === 0) return;
|
|
25561
|
+
let sumX = 0, sumY = 0, sumZ = 0;
|
|
25562
|
+
for (let i = 0; i < this.count; i++) {
|
|
25563
|
+
const idx = i * 3;
|
|
25564
|
+
sumX += this._positions[idx + 0];
|
|
25565
|
+
sumY += this._positions[idx + 1];
|
|
25566
|
+
sumZ += this._positions[idx + 2];
|
|
25567
|
+
}
|
|
25568
|
+
const centerX = sumX / this.count;
|
|
25569
|
+
const centerY = sumY / this.count;
|
|
25570
|
+
const centerZ = sumZ / this.count;
|
|
25571
|
+
this._centerOffset.set(centerX, centerY, centerZ);
|
|
25572
|
+
for (let i = 0; i < this.count; i++) {
|
|
25573
|
+
const idx = i * 3;
|
|
25574
|
+
this._positions[idx + 0] -= centerX;
|
|
25575
|
+
this._positions[idx + 1] -= centerY;
|
|
25576
|
+
this._positions[idx + 2] -= centerZ;
|
|
25577
|
+
}
|
|
25578
|
+
this.object3D.localPosition = this._centerOffset;
|
|
25579
|
+
}
|
|
25580
|
+
buildPositionTexture() {
|
|
25581
|
+
const w = this.size.x | 0;
|
|
25582
|
+
const h = this.size.y | 0;
|
|
25583
|
+
const count = this.count;
|
|
25584
|
+
const data = new Float32Array(w * h * 4);
|
|
25585
|
+
for (let i = 0; i < count; i++) {
|
|
25586
|
+
const idx = i * 4;
|
|
25587
|
+
const posIdx = i * 3;
|
|
25588
|
+
data[idx + 0] = this._positions[posIdx + 0];
|
|
25589
|
+
data[idx + 1] = this._positions[posIdx + 1];
|
|
25590
|
+
data[idx + 2] = this._positions[posIdx + 2];
|
|
25591
|
+
data[idx + 3] = 0;
|
|
25592
|
+
}
|
|
25593
|
+
if (count < w * h) {
|
|
25594
|
+
const lastIdx = (count - 1) * 4;
|
|
25595
|
+
for (let i = count; i < w * h; i++) {
|
|
25596
|
+
const idx = i * 4;
|
|
25597
|
+
data[idx + 0] = data[lastIdx + 0];
|
|
25598
|
+
data[idx + 1] = data[lastIdx + 1];
|
|
25599
|
+
data[idx + 2] = data[lastIdx + 2];
|
|
25600
|
+
data[idx + 3] = 0;
|
|
25601
|
+
}
|
|
25602
|
+
}
|
|
25603
|
+
this.pointPosition = new Float32ArrayTexture().create(w, h, data);
|
|
25604
|
+
this.pointPosition.name = "pointPosition";
|
|
25605
|
+
this.pointPosition.minFilter = "nearest";
|
|
25606
|
+
this.pointPosition.magFilter = "nearest";
|
|
25607
|
+
this.pointPosition.addressModeU = "clamp-to-edge";
|
|
25608
|
+
this.pointPosition.addressModeV = "clamp-to-edge";
|
|
25609
|
+
}
|
|
25610
|
+
buildColorTexture() {
|
|
25611
|
+
const w = this.size.x | 0;
|
|
25612
|
+
const h = this.size.y | 0;
|
|
25613
|
+
const count = this.count;
|
|
25614
|
+
const data = new Uint8Array(w * h * 4);
|
|
25615
|
+
for (let i = 0; i < count; i++) {
|
|
25616
|
+
const idx = i * 4;
|
|
25617
|
+
const colorIdx = i * 4;
|
|
25618
|
+
data[idx + 0] = this._colors[colorIdx + 0];
|
|
25619
|
+
data[idx + 1] = this._colors[colorIdx + 1];
|
|
25620
|
+
data[idx + 2] = this._colors[colorIdx + 2];
|
|
25621
|
+
data[idx + 3] = this._colors[colorIdx + 3];
|
|
25622
|
+
}
|
|
25623
|
+
if (count < w * h) {
|
|
25624
|
+
const lastIdx = (count - 1) * 4;
|
|
25625
|
+
for (let i = count; i < w * h; i++) {
|
|
25626
|
+
const idx = i * 4;
|
|
25627
|
+
data[idx + 0] = data[lastIdx + 0];
|
|
25628
|
+
data[idx + 1] = data[lastIdx + 1];
|
|
25629
|
+
data[idx + 2] = data[lastIdx + 2];
|
|
25630
|
+
data[idx + 3] = data[lastIdx + 3];
|
|
25631
|
+
}
|
|
25632
|
+
}
|
|
25633
|
+
this.pointColor = new Uint8ArrayTexture().create(w, h, data, false);
|
|
25634
|
+
this.pointColor.name = "pointColor";
|
|
25635
|
+
this.pointColor.minFilter = "nearest";
|
|
25636
|
+
this.pointColor.magFilter = "nearest";
|
|
25637
|
+
this.pointColor.mipmapFilter = "nearest";
|
|
25638
|
+
this.pointColor.addressModeU = "clamp-to-edge";
|
|
25639
|
+
this.pointColor.addressModeV = "clamp-to-edge";
|
|
25640
|
+
}
|
|
25641
|
+
buildOrderTexture() {
|
|
25642
|
+
const total = this.size.x * this.size.y;
|
|
25643
|
+
this._orderData = new Uint32Array(total);
|
|
25644
|
+
for (let i = 0; i < total; i++) {
|
|
25645
|
+
this._orderData[i] = i < this.count ? i : this.count > 0 ? this.count - 1 : 0;
|
|
25646
|
+
}
|
|
25647
|
+
this.pointOrder = new R32UintTexture().create(this.size.x, this.size.y, this._orderData);
|
|
25648
|
+
this.pointOrder.name = "pointOrder";
|
|
25649
|
+
this.pointOrder.minFilter = "nearest";
|
|
25650
|
+
this.pointOrder.magFilter = "nearest";
|
|
25651
|
+
this.pointOrder.addressModeU = "clamp-to-edge";
|
|
25652
|
+
this.pointOrder.addressModeV = "clamp-to-edge";
|
|
25653
|
+
}
|
|
25654
|
+
/**
|
|
25655
|
+
* Update node before rendering
|
|
25656
|
+
*/
|
|
25657
|
+
nodeUpdate(view, passType, renderPassState, clusterLightingBuffer) {
|
|
25658
|
+
const worldMatrix = this.object3D.transform.worldMatrix;
|
|
25659
|
+
this.pointCloudMaterial.setTransformMatrix(worldMatrix);
|
|
25660
|
+
if (!this._texturesInitialized) {
|
|
25661
|
+
this.pointCloudMaterial.setPointTextures(
|
|
25662
|
+
this.pointPosition,
|
|
25663
|
+
this.pointColor,
|
|
25664
|
+
this.texParams,
|
|
25665
|
+
this.pointOrder
|
|
25666
|
+
);
|
|
25667
|
+
this.pointCloudMaterial.setBatchSize(this._batchSize);
|
|
25668
|
+
this.pointCloudMaterial.setPointSize(this.texParams[3]);
|
|
25669
|
+
this.pointCloudMaterial.enableDebugFullScreen(this._debugFullScreen);
|
|
25670
|
+
this._texturesInitialized = true;
|
|
25671
|
+
}
|
|
25672
|
+
super.nodeUpdate(view, passType, renderPassState, clusterLightingBuffer);
|
|
25673
|
+
}
|
|
25674
|
+
/**
|
|
25675
|
+
* Render pass
|
|
25676
|
+
*/
|
|
25677
|
+
renderPass(view, passType, renderContext) {
|
|
25678
|
+
const encoder = renderContext.encoder;
|
|
25679
|
+
for (let mat of this.materials) {
|
|
25680
|
+
const passes = mat.getPass(passType);
|
|
25681
|
+
if (!passes || passes.length === 0) continue;
|
|
25682
|
+
for (const pass of passes) {
|
|
25683
|
+
if (!pass.pipeline) continue;
|
|
25684
|
+
pass.apply(this.geometry, renderContext.rendererPassState || renderContext);
|
|
25685
|
+
GPUContext.bindPipeline(encoder, pass);
|
|
25686
|
+
GPUContext.bindGeometryBuffer(encoder, this.geometry);
|
|
25687
|
+
const subGeometry = this.geometry.subGeometries[0];
|
|
25688
|
+
const lodInfo = subGeometry.lodLevels[0];
|
|
25689
|
+
if (this.instanceCount > 0) {
|
|
25690
|
+
GPUContext.drawIndexed(
|
|
25691
|
+
encoder,
|
|
25692
|
+
lodInfo.indexCount,
|
|
25693
|
+
this.instanceCount,
|
|
25694
|
+
lodInfo.indexStart,
|
|
25695
|
+
0,
|
|
25696
|
+
0
|
|
25697
|
+
);
|
|
25698
|
+
} else {
|
|
25699
|
+
GPUContext.drawIndexed(
|
|
25700
|
+
encoder,
|
|
25701
|
+
lodInfo.indexCount,
|
|
25702
|
+
1,
|
|
25703
|
+
lodInfo.indexStart,
|
|
25704
|
+
0,
|
|
25705
|
+
0
|
|
25706
|
+
);
|
|
25707
|
+
}
|
|
25708
|
+
}
|
|
25709
|
+
}
|
|
25710
|
+
}
|
|
25711
|
+
/**
|
|
25712
|
+
* Set point size in pixels
|
|
25713
|
+
* @param size Point size in pixels
|
|
25714
|
+
*/
|
|
25715
|
+
setPointSize(size) {
|
|
25716
|
+
this.texParams[3] = Math.max(0.1, size);
|
|
25717
|
+
if (this.pointCloudMaterial) {
|
|
25718
|
+
this.pointCloudMaterial.setPointSize(size);
|
|
25719
|
+
}
|
|
25720
|
+
}
|
|
25721
|
+
/**
|
|
25722
|
+
* Set point shape
|
|
25723
|
+
* @param shape 'square' or 'circle'
|
|
25724
|
+
*/
|
|
25725
|
+
setPointShape(shape) {
|
|
25726
|
+
if (this.pointCloudMaterial) {
|
|
25727
|
+
this.pointCloudMaterial.setPointShape(shape);
|
|
25728
|
+
}
|
|
25729
|
+
}
|
|
25730
|
+
/**
|
|
25731
|
+
* Enable a fullscreen debug quad to validate the render pipeline.
|
|
25732
|
+
*/
|
|
25733
|
+
enableDebugFullScreen(enabled) {
|
|
25734
|
+
this._debugFullScreen = enabled;
|
|
25735
|
+
if (this.pointCloudMaterial) {
|
|
25736
|
+
this.pointCloudMaterial.enableDebugFullScreen(enabled);
|
|
25737
|
+
}
|
|
25738
|
+
}
|
|
25739
|
+
/**
|
|
25740
|
+
* Set batch size for instanced rendering
|
|
25741
|
+
* @param batchSize Number of points per draw call
|
|
25742
|
+
*/
|
|
25743
|
+
setBatchSize(batchSize) {
|
|
25744
|
+
this._batchSize = Math.max(1, batchSize | 0);
|
|
25745
|
+
if (this.geometry) {
|
|
25746
|
+
const oldGeometry = this.geometry;
|
|
25747
|
+
Reference.getInstance().detached(oldGeometry, this);
|
|
25748
|
+
if (!Reference.getInstance().hasReference(oldGeometry)) {
|
|
25749
|
+
oldGeometry.destroy();
|
|
25750
|
+
}
|
|
25751
|
+
this.geometry = new PointCloudGeometry(this._batchSize);
|
|
25752
|
+
}
|
|
25753
|
+
if (this.pointCloudMaterial) {
|
|
25754
|
+
this.pointCloudMaterial.setBatchSize(this._batchSize);
|
|
25755
|
+
this.pointCloudMaterial.enableDebugFullScreen(this._debugFullScreen);
|
|
25756
|
+
}
|
|
25757
|
+
this.instanceCount = Math.ceil(this.count / this._batchSize);
|
|
25758
|
+
}
|
|
25759
|
+
destroy(force) {
|
|
25760
|
+
if (this.pointColor) {
|
|
25761
|
+
this.pointColor.destroy(force);
|
|
25762
|
+
this.pointColor = null;
|
|
25763
|
+
}
|
|
25764
|
+
if (this.pointPosition) {
|
|
25765
|
+
this.pointPosition.destroy(force);
|
|
25766
|
+
this.pointPosition = null;
|
|
25767
|
+
}
|
|
25768
|
+
if (this.pointOrder) {
|
|
25769
|
+
this.pointOrder.destroy(force);
|
|
25770
|
+
this.pointOrder = null;
|
|
25771
|
+
}
|
|
25772
|
+
this._positions = null;
|
|
25773
|
+
this._colors = null;
|
|
25774
|
+
this._orderData = null;
|
|
25775
|
+
this.texParams = null;
|
|
25776
|
+
super.destroy(force);
|
|
25777
|
+
}
|
|
25778
|
+
};
|
|
25779
|
+
exports.PointCloudRenderer = __decorateClass$j([
|
|
25780
|
+
RegisterComponent(exports.PointCloudRenderer, "PointCloudRenderer")
|
|
25781
|
+
], exports.PointCloudRenderer);
|
|
25782
|
+
|
|
25095
25783
|
class BoundUtil {
|
|
25096
25784
|
static maxVector = new Vector3(
|
|
25097
25785
|
Number.MAX_VALUE * 0.1,
|
|
@@ -25111,6 +25799,36 @@ struct InstanceData {
|
|
|
25111
25799
|
new Vector3(),
|
|
25112
25800
|
new Vector3()
|
|
25113
25801
|
];
|
|
25802
|
+
static genPointCloudBounds(obj, bound) {
|
|
25803
|
+
bound ||= new BoundingBox(Vector3.ZERO, Vector3.ZERO);
|
|
25804
|
+
bound.setFromMinMax(this.maxVector, this.minVector);
|
|
25805
|
+
let pointCloudRenderers = obj.getComponents(exports.PointCloudRenderer);
|
|
25806
|
+
if (!pointCloudRenderers) {
|
|
25807
|
+
console.warn("genPointCloudBounds: No PointCloudRenderer found on object");
|
|
25808
|
+
return bound;
|
|
25809
|
+
}
|
|
25810
|
+
for (const pointCloudRenderer of pointCloudRenderers) {
|
|
25811
|
+
const positions = pointCloudRenderer.positions;
|
|
25812
|
+
const count = pointCloudRenderer.fullCount;
|
|
25813
|
+
if (!positions || count === 0) {
|
|
25814
|
+
console.warn("genPointCloudBounds: No position data available");
|
|
25815
|
+
continue;
|
|
25816
|
+
}
|
|
25817
|
+
const matrix = pointCloudRenderer.object3D.transform.worldMatrix;
|
|
25818
|
+
const point = new Vector3();
|
|
25819
|
+
for (let i = 0; i < count; i++) {
|
|
25820
|
+
const idx = i * 3;
|
|
25821
|
+
point.set(
|
|
25822
|
+
positions[idx + 0],
|
|
25823
|
+
positions[idx + 1],
|
|
25824
|
+
positions[idx + 2]
|
|
25825
|
+
);
|
|
25826
|
+
matrix.transformPoint(point, point);
|
|
25827
|
+
bound.expandByPoint(point);
|
|
25828
|
+
}
|
|
25829
|
+
}
|
|
25830
|
+
return bound;
|
|
25831
|
+
}
|
|
25114
25832
|
static genGSplatBounds(obj, bound) {
|
|
25115
25833
|
bound ||= new BoundingBox(Vector3.ZERO, Vector3.ZERO);
|
|
25116
25834
|
bound.setFromMinMax(this.maxVector, this.minVector);
|
|
@@ -41432,7 +42150,7 @@ else if (typeof exports === 'object')
|
|
|
41432
42150
|
}
|
|
41433
42151
|
}
|
|
41434
42152
|
|
|
41435
|
-
const version = "1.0.
|
|
42153
|
+
const version = "1.0.27";
|
|
41436
42154
|
|
|
41437
42155
|
class Engine3D {
|
|
41438
42156
|
/**
|
|
@@ -59144,6 +59862,15 @@ fn frag(){
|
|
|
59144
59862
|
return "unknown" /* UNKNOWN */;
|
|
59145
59863
|
}
|
|
59146
59864
|
|
|
59865
|
+
var PlyMode = /* @__PURE__ */ ((PlyMode2) => {
|
|
59866
|
+
PlyMode2[PlyMode2["Splat"] = 0] = "Splat";
|
|
59867
|
+
PlyMode2[PlyMode2["PointCloud"] = 1] = "PointCloud";
|
|
59868
|
+
PlyMode2[PlyMode2["Mesh"] = 2] = "Mesh";
|
|
59869
|
+
return PlyMode2;
|
|
59870
|
+
})(PlyMode || {});
|
|
59871
|
+
const splatProperties = ["x", "y", "z", "scale_0", "scale_1", "scale_2", "opacity", "rot_0", "rot_1", "rot_2", "rot_3"];
|
|
59872
|
+
const splatColorProperties = ["red", "green", "blue", "f_dc_0", "f_dc_1", "f_dc_2"];
|
|
59873
|
+
|
|
59147
59874
|
function byteSizeOfType(t) {
|
|
59148
59875
|
switch (t) {
|
|
59149
59876
|
case "char":
|
|
@@ -59219,34 +59946,85 @@ fn frag(){
|
|
|
59219
59946
|
const lines = headerText.split(/\r?\n/);
|
|
59220
59947
|
let format = "";
|
|
59221
59948
|
let vertexCount = 0;
|
|
59949
|
+
let faceCount = 0;
|
|
59222
59950
|
const properties = [];
|
|
59951
|
+
const faceProperties = [];
|
|
59952
|
+
const textureFiles = [];
|
|
59223
59953
|
let inVertexElement = false;
|
|
59954
|
+
let inFaceElement = false;
|
|
59224
59955
|
for (const line of lines) {
|
|
59225
59956
|
if (line.startsWith("format ")) {
|
|
59226
59957
|
format = line.split(/\s+/)[1];
|
|
59958
|
+
} else if (line.startsWith("comment TextureFile ")) {
|
|
59959
|
+
const texturePath = line.substring("comment TextureFile ".length).trim();
|
|
59960
|
+
if (texturePath) {
|
|
59961
|
+
textureFiles.push(texturePath);
|
|
59962
|
+
}
|
|
59227
59963
|
} else if (line.startsWith("element ")) {
|
|
59228
59964
|
const toks = line.split(/\s+/);
|
|
59229
59965
|
inVertexElement = toks[1] === "vertex";
|
|
59230
|
-
|
|
59966
|
+
inFaceElement = toks[1] === "face";
|
|
59967
|
+
if (inVertexElement) {
|
|
59968
|
+
vertexCount = parseInt(toks[2]);
|
|
59969
|
+
inFaceElement = false;
|
|
59970
|
+
}
|
|
59971
|
+
if (inFaceElement) {
|
|
59972
|
+
faceCount = parseInt(toks[2]);
|
|
59973
|
+
inVertexElement = false;
|
|
59974
|
+
}
|
|
59231
59975
|
} else if (inVertexElement && line.startsWith("property ")) {
|
|
59232
59976
|
const toks = line.split(/\s+/);
|
|
59233
59977
|
const type = toks[1];
|
|
59234
59978
|
const name = toks[2];
|
|
59235
59979
|
properties.push({ name, type });
|
|
59980
|
+
} else if (inFaceElement && line.startsWith("property ")) {
|
|
59981
|
+
const toks = line.split(/\s+/);
|
|
59982
|
+
if (toks[1] === "list") {
|
|
59983
|
+
const countType = toks[2];
|
|
59984
|
+
const itemType = toks[3];
|
|
59985
|
+
const name = toks[4];
|
|
59986
|
+
faceProperties.push({ name, type: `list ${countType} ${itemType}` });
|
|
59987
|
+
} else {
|
|
59988
|
+
const type = toks[1];
|
|
59989
|
+
const name = toks[2];
|
|
59990
|
+
faceProperties.push({ name, type });
|
|
59991
|
+
}
|
|
59236
59992
|
}
|
|
59237
59993
|
}
|
|
59238
|
-
if (format !== "binary_little_endian") {
|
|
59239
|
-
throw new Error(
|
|
59994
|
+
if (format !== "binary_little_endian" && format !== "ascii") {
|
|
59995
|
+
throw new Error(`PLY: Unsupported format: ${format}. Only binary_little_endian and ascii are supported.`);
|
|
59996
|
+
}
|
|
59997
|
+
let splatPropertyCount = 0;
|
|
59998
|
+
let splatPropertyColorCount = 0;
|
|
59999
|
+
for (const property of properties) {
|
|
60000
|
+
if (splatProperties.includes(property.name)) {
|
|
60001
|
+
splatPropertyCount++;
|
|
60002
|
+
}
|
|
60003
|
+
if (splatColorProperties.includes(property.name)) {
|
|
60004
|
+
splatPropertyColorCount++;
|
|
60005
|
+
}
|
|
59240
60006
|
}
|
|
59241
60007
|
return {
|
|
59242
60008
|
format,
|
|
59243
60009
|
vertexCount,
|
|
60010
|
+
faceCount,
|
|
59244
60011
|
properties,
|
|
59245
|
-
|
|
60012
|
+
faceProperties: faceProperties.length > 0 ? faceProperties : void 0,
|
|
60013
|
+
textureFiles,
|
|
60014
|
+
headerByteLength: headerText.length,
|
|
60015
|
+
mode: faceCount ? PlyMode.Mesh : splatPropertyCount === splatProperties.length && splatPropertyColorCount === 3 ? PlyMode.Splat : PlyMode.PointCloud
|
|
59246
60016
|
};
|
|
59247
60017
|
}
|
|
59248
60018
|
function parsePlyGaussianSplat(buffer) {
|
|
59249
60019
|
const header = parsePlyHeader(buffer);
|
|
60020
|
+
const { format } = header;
|
|
60021
|
+
if (format === "ascii") {
|
|
60022
|
+
return parsePlyGaussianSplatASCII(buffer, header);
|
|
60023
|
+
} else {
|
|
60024
|
+
return parsePlyGaussianSplatBinary(buffer, header);
|
|
60025
|
+
}
|
|
60026
|
+
}
|
|
60027
|
+
function parsePlyGaussianSplatBinary(buffer, header) {
|
|
59250
60028
|
const { vertexCount, properties, headerByteLength } = header;
|
|
59251
60029
|
const payload = new DataView(buffer, headerByteLength);
|
|
59252
60030
|
const has = (n) => properties.find((p) => p.name === n) != null;
|
|
@@ -59368,6 +60146,903 @@ fn frag(){
|
|
|
59368
60146
|
sh: hasSH && shCoeffs ? { order: shOrder, coeffs: shCoeffs } : void 0
|
|
59369
60147
|
};
|
|
59370
60148
|
}
|
|
60149
|
+
function parsePlyGaussianSplatASCII(buffer, header) {
|
|
60150
|
+
const { vertexCount, properties } = header;
|
|
60151
|
+
const text = new TextDecoder("utf-8").decode(buffer);
|
|
60152
|
+
const headerEnd = text.indexOf("end_header");
|
|
60153
|
+
if (headerEnd < 0) {
|
|
60154
|
+
throw new Error("PLY: Invalid PLY header");
|
|
60155
|
+
}
|
|
60156
|
+
let bodyStart = headerEnd + "end_header".length;
|
|
60157
|
+
while (bodyStart < text.length && (text[bodyStart] === " " || text[bodyStart] === "\n" || text[bodyStart] === "\r")) {
|
|
60158
|
+
bodyStart++;
|
|
60159
|
+
}
|
|
60160
|
+
const bodyText = text.substring(bodyStart);
|
|
60161
|
+
const tokens = bodyText.split(/\s+/).filter((token) => token.length > 0);
|
|
60162
|
+
let tokenIndex = 0;
|
|
60163
|
+
const has = (n) => properties.find((p) => p.name === n) != null;
|
|
60164
|
+
const propIndex = (n) => properties.findIndex((p) => p.name === n);
|
|
60165
|
+
const parseASCIINumber = (type) => {
|
|
60166
|
+
if (tokenIndex >= tokens.length) {
|
|
60167
|
+
throw new Error("PLY: Unexpected end of file");
|
|
60168
|
+
}
|
|
60169
|
+
const value = tokens[tokenIndex++];
|
|
60170
|
+
switch (type) {
|
|
60171
|
+
case "char":
|
|
60172
|
+
case "uchar":
|
|
60173
|
+
case "short":
|
|
60174
|
+
case "ushort":
|
|
60175
|
+
case "int":
|
|
60176
|
+
case "uint":
|
|
60177
|
+
case "int8":
|
|
60178
|
+
case "uint8":
|
|
60179
|
+
case "int16":
|
|
60180
|
+
case "uint16":
|
|
60181
|
+
case "int32":
|
|
60182
|
+
case "uint32":
|
|
60183
|
+
return parseInt(value);
|
|
60184
|
+
case "float":
|
|
60185
|
+
case "double":
|
|
60186
|
+
case "float32":
|
|
60187
|
+
case "float64":
|
|
60188
|
+
return parseFloat(value);
|
|
60189
|
+
default:
|
|
60190
|
+
return parseFloat(value);
|
|
60191
|
+
}
|
|
60192
|
+
};
|
|
60193
|
+
const position = new Float32Array(vertexCount * 3);
|
|
60194
|
+
const scale = has("scale_0") ? new Float32Array(vertexCount * 3) : void 0;
|
|
60195
|
+
const rotation = has("rot_0") ? new Float32Array(vertexCount * 4) : void 0;
|
|
60196
|
+
const opacity = has("opacity") ? new Float32Array(vertexCount) : void 0;
|
|
60197
|
+
const dcIdx = [propIndex("f_dc_0"), propIndex("f_dc_1"), propIndex("f_dc_2")];
|
|
60198
|
+
const restIndices = [];
|
|
60199
|
+
for (let i = 0; i < properties.length; i++) {
|
|
60200
|
+
if (properties[i].name.startsWith("f_rest_")) restIndices.push(i);
|
|
60201
|
+
}
|
|
60202
|
+
const hasSH = dcIdx[0] >= 0 && dcIdx[1] >= 0 && dcIdx[2] >= 0;
|
|
60203
|
+
let shCoeffs = void 0;
|
|
60204
|
+
let shOrder = 0;
|
|
60205
|
+
if (hasSH) {
|
|
60206
|
+
const coeffsPerColor = 1 + restIndices.length / 3;
|
|
60207
|
+
shOrder = inferSHOrder(coeffsPerColor);
|
|
60208
|
+
shCoeffs = new Float32Array(vertexCount * coeffsPerColor * 3);
|
|
60209
|
+
}
|
|
60210
|
+
const ix = propIndex("x");
|
|
60211
|
+
const iy = propIndex("y");
|
|
60212
|
+
const iz = propIndex("z");
|
|
60213
|
+
if (ix < 0 || iy < 0 || iz < 0) {
|
|
60214
|
+
throw new Error("PLY: Missing x/y/z for vertex");
|
|
60215
|
+
}
|
|
60216
|
+
const s0 = scale ? propIndex("scale_0") : -1;
|
|
60217
|
+
const s1 = scale ? propIndex("scale_1") : -1;
|
|
60218
|
+
const s2 = scale ? propIndex("scale_2") : -1;
|
|
60219
|
+
const r0 = rotation ? propIndex("rot_0") : -1;
|
|
60220
|
+
const r1 = rotation ? propIndex("rot_1") : -1;
|
|
60221
|
+
const r2 = rotation ? propIndex("rot_2") : -1;
|
|
60222
|
+
const r3 = rotation ? propIndex("rot_3") : -1;
|
|
60223
|
+
const oi = opacity ? propIndex("opacity") : -1;
|
|
60224
|
+
for (let v = 0; v < vertexCount; v++) {
|
|
60225
|
+
for (let pIdx = 0; pIdx < properties.length; pIdx++) {
|
|
60226
|
+
const prop = properties[pIdx];
|
|
60227
|
+
const value = parseASCIINumber(prop.type);
|
|
60228
|
+
if (pIdx === ix) {
|
|
60229
|
+
position[v * 3 + 0] = value;
|
|
60230
|
+
} else if (pIdx === iy) {
|
|
60231
|
+
position[v * 3 + 1] = value;
|
|
60232
|
+
} else if (pIdx === iz) {
|
|
60233
|
+
position[v * 3 + 2] = value;
|
|
60234
|
+
}
|
|
60235
|
+
if (scale && pIdx === s0) {
|
|
60236
|
+
scale[v * 3 + 0] = value;
|
|
60237
|
+
} else if (scale && pIdx === s1) {
|
|
60238
|
+
scale[v * 3 + 1] = value;
|
|
60239
|
+
} else if (scale && pIdx === s2) {
|
|
60240
|
+
scale[v * 3 + 2] = value;
|
|
60241
|
+
}
|
|
60242
|
+
if (rotation && pIdx === r0) {
|
|
60243
|
+
rotation[v * 4 + 3] = value;
|
|
60244
|
+
} else if (rotation && pIdx === r1) {
|
|
60245
|
+
rotation[v * 4 + 0] = value;
|
|
60246
|
+
} else if (rotation && pIdx === r2) {
|
|
60247
|
+
rotation[v * 4 + 1] = value;
|
|
60248
|
+
} else if (rotation && pIdx === r3) {
|
|
60249
|
+
rotation[v * 4 + 2] = value;
|
|
60250
|
+
}
|
|
60251
|
+
if (opacity && pIdx === oi) {
|
|
60252
|
+
opacity[v] = value;
|
|
60253
|
+
}
|
|
60254
|
+
if (hasSH && shCoeffs) {
|
|
60255
|
+
const coeffsPerColor = 1 + restIndices.length / 3;
|
|
60256
|
+
const baseIndex = v * coeffsPerColor * 3;
|
|
60257
|
+
if (pIdx === dcIdx[0]) {
|
|
60258
|
+
shCoeffs[baseIndex + 0] = value;
|
|
60259
|
+
} else if (pIdx === dcIdx[1]) {
|
|
60260
|
+
shCoeffs[baseIndex + coeffsPerColor + 0] = value;
|
|
60261
|
+
} else if (pIdx === dcIdx[2]) {
|
|
60262
|
+
shCoeffs[baseIndex + 2 * coeffsPerColor + 0] = value;
|
|
60263
|
+
}
|
|
60264
|
+
for (let i = 0; i < restIndices.length; i += 3) {
|
|
60265
|
+
const ri = restIndices[i + 0];
|
|
60266
|
+
const gi = restIndices[i + 1];
|
|
60267
|
+
const bi = restIndices[i + 2];
|
|
60268
|
+
if (pIdx === ri) {
|
|
60269
|
+
shCoeffs[baseIndex + (i / 3 + 1)] = value;
|
|
60270
|
+
} else if (pIdx === gi) {
|
|
60271
|
+
shCoeffs[baseIndex + coeffsPerColor + (i / 3 + 1)] = value;
|
|
60272
|
+
} else if (pIdx === bi) {
|
|
60273
|
+
shCoeffs[baseIndex + 2 * coeffsPerColor + (i / 3 + 1)] = value;
|
|
60274
|
+
}
|
|
60275
|
+
}
|
|
60276
|
+
}
|
|
60277
|
+
}
|
|
60278
|
+
}
|
|
60279
|
+
return {
|
|
60280
|
+
vertexCount,
|
|
60281
|
+
position,
|
|
60282
|
+
scale,
|
|
60283
|
+
rotation,
|
|
60284
|
+
opacity,
|
|
60285
|
+
sh: hasSH && shCoeffs ? { order: shOrder, coeffs: shCoeffs } : void 0
|
|
60286
|
+
};
|
|
60287
|
+
}
|
|
60288
|
+
function parsePlyMesh(buffer) {
|
|
60289
|
+
const header = parsePlyHeader(buffer);
|
|
60290
|
+
const { format, vertexCount, faceCount, properties, faceProperties, textureFiles, headerByteLength } = header;
|
|
60291
|
+
if (format === "ascii") {
|
|
60292
|
+
return parsePlyMeshASCII(buffer, header);
|
|
60293
|
+
} else {
|
|
60294
|
+
return parsePlyMeshBinary(buffer, header);
|
|
60295
|
+
}
|
|
60296
|
+
}
|
|
60297
|
+
function parsePlyMeshBinary(buffer, header) {
|
|
60298
|
+
const { vertexCount, faceCount, properties, faceProperties, textureFiles, headerByteLength } = header;
|
|
60299
|
+
const payload = new DataView(buffer, headerByteLength);
|
|
60300
|
+
const has = (n) => properties.find((p) => p.name === n) != null;
|
|
60301
|
+
const propIndex = (n) => properties.findIndex((p) => p.name === n);
|
|
60302
|
+
const hasTexcoord = faceProperties?.some((p) => p.name === "texcoord") || false;
|
|
60303
|
+
const hasTexnumber = faceProperties?.some((p) => p.name === "texnumber") || false;
|
|
60304
|
+
faceProperties?.find((p) => p.name === "texcoord");
|
|
60305
|
+
faceProperties?.find((p) => p.name === "texnumber");
|
|
60306
|
+
const position = new Float32Array(vertexCount * 3);
|
|
60307
|
+
const hasNormalData = has("nx") && has("ny") && has("nz");
|
|
60308
|
+
const normal = hasNormalData ? new Float32Array(vertexCount * 3) : new Float32Array(vertexCount * 3);
|
|
60309
|
+
const color = (has("red") || has("r")) && (has("green") || has("g")) && (has("blue") || has("b")) ? new Float32Array(vertexCount * 3) : void 0;
|
|
60310
|
+
const hasVertexUV = (has("u") || has("s")) && (has("v") || has("t"));
|
|
60311
|
+
const uv = hasVertexUV || hasTexcoord ? new Float32Array(vertexCount * 2) : void 0;
|
|
60312
|
+
const faceTexcoords = /* @__PURE__ */ new Map();
|
|
60313
|
+
const faceTexnumbers = hasTexnumber ? new Array(faceCount) : [];
|
|
60314
|
+
const propOffsets = [];
|
|
60315
|
+
let stride = 0;
|
|
60316
|
+
for (const p of properties) {
|
|
60317
|
+
propOffsets.push(stride);
|
|
60318
|
+
stride += byteSizeOfType(p.type);
|
|
60319
|
+
}
|
|
60320
|
+
let base = 0;
|
|
60321
|
+
for (let v = 0; v < vertexCount; v++) {
|
|
60322
|
+
const vOffset = base;
|
|
60323
|
+
const ix = propIndex("x");
|
|
60324
|
+
const iy = propIndex("y");
|
|
60325
|
+
const iz = propIndex("z");
|
|
60326
|
+
if (ix < 0 || iy < 0 || iz < 0) {
|
|
60327
|
+
throw new Error("PLY: Missing x/y/z for vertex");
|
|
60328
|
+
}
|
|
60329
|
+
position[v * 3 + 0] = readByType(payload, vOffset + propOffsets[ix], properties[ix].type);
|
|
60330
|
+
position[v * 3 + 1] = readByType(payload, vOffset + propOffsets[iy], properties[iy].type);
|
|
60331
|
+
position[v * 3 + 2] = readByType(payload, vOffset + propOffsets[iz], properties[iz].type);
|
|
60332
|
+
if (hasNormalData) {
|
|
60333
|
+
const nx = propIndex("nx");
|
|
60334
|
+
const ny = propIndex("ny");
|
|
60335
|
+
const nz = propIndex("nz");
|
|
60336
|
+
normal[v * 3 + 0] = readByType(payload, vOffset + propOffsets[nx], properties[nx].type);
|
|
60337
|
+
normal[v * 3 + 1] = readByType(payload, vOffset + propOffsets[ny], properties[ny].type);
|
|
60338
|
+
normal[v * 3 + 2] = readByType(payload, vOffset + propOffsets[nz], properties[nz].type);
|
|
60339
|
+
}
|
|
60340
|
+
if (color) {
|
|
60341
|
+
const rIdx = propIndex("red") >= 0 ? propIndex("red") : propIndex("r");
|
|
60342
|
+
const gIdx = propIndex("green") >= 0 ? propIndex("green") : propIndex("g");
|
|
60343
|
+
const bIdx = propIndex("blue") >= 0 ? propIndex("blue") : propIndex("b");
|
|
60344
|
+
if (rIdx >= 0 && gIdx >= 0 && bIdx >= 0) {
|
|
60345
|
+
let r = readByType(payload, vOffset + propOffsets[rIdx], properties[rIdx].type);
|
|
60346
|
+
let g = readByType(payload, vOffset + propOffsets[gIdx], properties[gIdx].type);
|
|
60347
|
+
let b = readByType(payload, vOffset + propOffsets[bIdx], properties[bIdx].type);
|
|
60348
|
+
if (properties[rIdx].type === "uchar" || properties[rIdx].type === "uint8") {
|
|
60349
|
+
r /= 255;
|
|
60350
|
+
g /= 255;
|
|
60351
|
+
b /= 255;
|
|
60352
|
+
}
|
|
60353
|
+
color[v * 3 + 0] = r;
|
|
60354
|
+
color[v * 3 + 1] = g;
|
|
60355
|
+
color[v * 3 + 2] = b;
|
|
60356
|
+
}
|
|
60357
|
+
}
|
|
60358
|
+
if (uv) {
|
|
60359
|
+
const uIdx = propIndex("u") >= 0 ? propIndex("u") : propIndex("s");
|
|
60360
|
+
const vIdx = propIndex("v") >= 0 ? propIndex("v") : propIndex("t");
|
|
60361
|
+
if (uIdx >= 0 && vIdx >= 0) {
|
|
60362
|
+
uv[v * 2 + 0] = readByType(payload, vOffset + propOffsets[uIdx], properties[uIdx].type);
|
|
60363
|
+
uv[v * 2 + 1] = readByType(payload, vOffset + propOffsets[vIdx], properties[vIdx].type);
|
|
60364
|
+
}
|
|
60365
|
+
}
|
|
60366
|
+
base += stride;
|
|
60367
|
+
}
|
|
60368
|
+
const indices = [];
|
|
60369
|
+
const triangleTexnumbers = [];
|
|
60370
|
+
const faceVertexUvs = [];
|
|
60371
|
+
let faceBase = base;
|
|
60372
|
+
uv && !hasVertexUV && !hasTexcoord ? new Array(vertexCount).fill(false) : null;
|
|
60373
|
+
for (let f = 0; f < faceCount; f++) {
|
|
60374
|
+
let currentOffset = faceBase;
|
|
60375
|
+
let faceIndices = [];
|
|
60376
|
+
let faceTexcoordArray = void 0;
|
|
60377
|
+
let faceTexnum = 0;
|
|
60378
|
+
let vertexCountInFace = 0;
|
|
60379
|
+
if (!faceProperties || faceProperties.length === 0) {
|
|
60380
|
+
throw new Error("PLY: Face element must have properties");
|
|
60381
|
+
}
|
|
60382
|
+
for (const prop of faceProperties) {
|
|
60383
|
+
if (prop.name === "vertex_indices") {
|
|
60384
|
+
const parts = prop.type.split(" ");
|
|
60385
|
+
if (parts.length !== 3 || parts[0] !== "list") {
|
|
60386
|
+
throw new Error(`PLY: Invalid vertex_indices property type: ${prop.type}`);
|
|
60387
|
+
}
|
|
60388
|
+
const countType = parts[1];
|
|
60389
|
+
const itemType = parts[2];
|
|
60390
|
+
vertexCountInFace = readByType(payload, currentOffset, countType);
|
|
60391
|
+
currentOffset += byteSizeOfType(countType);
|
|
60392
|
+
if (vertexCountInFace < 3) {
|
|
60393
|
+
throw new Error(`PLY: Face ${f} has less than 3 vertices`);
|
|
60394
|
+
}
|
|
60395
|
+
const indexSize = byteSizeOfType(itemType);
|
|
60396
|
+
faceIndices = [];
|
|
60397
|
+
for (let i = 0; i < vertexCountInFace; i++) {
|
|
60398
|
+
const idx = readByType(payload, currentOffset, itemType);
|
|
60399
|
+
faceIndices.push(idx);
|
|
60400
|
+
currentOffset += indexSize;
|
|
60401
|
+
}
|
|
60402
|
+
} else if (prop.name === "texcoord") {
|
|
60403
|
+
const parts = prop.type.split(" ");
|
|
60404
|
+
if (parts.length !== 3 || parts[0] !== "list") {
|
|
60405
|
+
throw new Error(`PLY: Invalid texcoord property type: ${prop.type}`);
|
|
60406
|
+
}
|
|
60407
|
+
const countType = parts[1];
|
|
60408
|
+
const itemType = parts[2];
|
|
60409
|
+
const texcoordCount = readByType(payload, currentOffset, countType);
|
|
60410
|
+
currentOffset += byteSizeOfType(countType);
|
|
60411
|
+
const itemSize = byteSizeOfType(itemType);
|
|
60412
|
+
faceTexcoordArray = new Float32Array(texcoordCount);
|
|
60413
|
+
for (let i = 0; i < texcoordCount; i++) {
|
|
60414
|
+
faceTexcoordArray[i] = readByType(payload, currentOffset, itemType);
|
|
60415
|
+
currentOffset += itemSize;
|
|
60416
|
+
}
|
|
60417
|
+
faceTexcoords.set(f, faceTexcoordArray);
|
|
60418
|
+
} else if (prop.name === "texnumber") {
|
|
60419
|
+
faceTexnum = readByType(payload, currentOffset, prop.type);
|
|
60420
|
+
currentOffset += byteSizeOfType(prop.type);
|
|
60421
|
+
faceTexnumbers[f] = faceTexnum;
|
|
60422
|
+
} else {
|
|
60423
|
+
if (prop.type.startsWith("list ")) {
|
|
60424
|
+
const parts = prop.type.split(" ");
|
|
60425
|
+
if (parts.length === 3) {
|
|
60426
|
+
const countType = parts[1];
|
|
60427
|
+
const itemType = parts[2];
|
|
60428
|
+
const count = readByType(payload, currentOffset, countType);
|
|
60429
|
+
currentOffset += byteSizeOfType(countType);
|
|
60430
|
+
const itemSize = byteSizeOfType(itemType);
|
|
60431
|
+
currentOffset += count * itemSize;
|
|
60432
|
+
}
|
|
60433
|
+
} else {
|
|
60434
|
+
currentOffset += byteSizeOfType(prop.type);
|
|
60435
|
+
}
|
|
60436
|
+
}
|
|
60437
|
+
}
|
|
60438
|
+
faceBase = currentOffset;
|
|
60439
|
+
const texnum = hasTexnumber ? faceTexnumbers[f] ?? 0 : 0;
|
|
60440
|
+
if (vertexCountInFace === 3) {
|
|
60441
|
+
indices.push(faceIndices[0], faceIndices[1], faceIndices[2]);
|
|
60442
|
+
if (hasTexnumber) {
|
|
60443
|
+
triangleTexnumbers.push(texnum);
|
|
60444
|
+
}
|
|
60445
|
+
if (hasTexcoord && faceTexcoordArray && faceTexcoordArray.length >= 6) {
|
|
60446
|
+
faceVertexUvs.push(
|
|
60447
|
+
faceTexcoordArray[0],
|
|
60448
|
+
1 - faceTexcoordArray[1],
|
|
60449
|
+
// vertex 0
|
|
60450
|
+
faceTexcoordArray[2],
|
|
60451
|
+
1 - faceTexcoordArray[3],
|
|
60452
|
+
// vertex 1
|
|
60453
|
+
faceTexcoordArray[4],
|
|
60454
|
+
1 - faceTexcoordArray[5]
|
|
60455
|
+
// vertex 2
|
|
60456
|
+
);
|
|
60457
|
+
}
|
|
60458
|
+
} else {
|
|
60459
|
+
for (let i = 1; i < vertexCountInFace - 1; i++) {
|
|
60460
|
+
indices.push(faceIndices[0], faceIndices[i], faceIndices[i + 1]);
|
|
60461
|
+
if (hasTexnumber) {
|
|
60462
|
+
triangleTexnumbers.push(texnum);
|
|
60463
|
+
}
|
|
60464
|
+
if (hasTexcoord && faceTexcoordArray && faceTexcoordArray.length >= vertexCountInFace * 2) {
|
|
60465
|
+
faceVertexUvs.push(
|
|
60466
|
+
faceTexcoordArray[0],
|
|
60467
|
+
1 - faceTexcoordArray[1],
|
|
60468
|
+
// vertex 0 (center of fan)
|
|
60469
|
+
faceTexcoordArray[i * 2 + 0],
|
|
60470
|
+
1 - faceTexcoordArray[i * 2 + 1],
|
|
60471
|
+
// vertex i
|
|
60472
|
+
faceTexcoordArray[(i + 1) * 2 + 0],
|
|
60473
|
+
1 - faceTexcoordArray[(i + 1) * 2 + 1]
|
|
60474
|
+
// vertex i+1
|
|
60475
|
+
);
|
|
60476
|
+
}
|
|
60477
|
+
}
|
|
60478
|
+
}
|
|
60479
|
+
}
|
|
60480
|
+
if (!hasNormalData) {
|
|
60481
|
+
for (let i = 0; i < vertexCount * 3; i++) {
|
|
60482
|
+
normal[i] = 0;
|
|
60483
|
+
}
|
|
60484
|
+
for (let i = 0; i < indices.length; i += 3) {
|
|
60485
|
+
const i0 = indices[i];
|
|
60486
|
+
const i1 = indices[i + 1];
|
|
60487
|
+
const i2 = indices[i + 2];
|
|
60488
|
+
const v0x = position[i0 * 3 + 0];
|
|
60489
|
+
const v0y = position[i0 * 3 + 1];
|
|
60490
|
+
const v0z = position[i0 * 3 + 2];
|
|
60491
|
+
const v1x = position[i1 * 3 + 0];
|
|
60492
|
+
const v1y = position[i1 * 3 + 1];
|
|
60493
|
+
const v1z = position[i1 * 3 + 2];
|
|
60494
|
+
const v2x = position[i2 * 3 + 0];
|
|
60495
|
+
const v2y = position[i2 * 3 + 1];
|
|
60496
|
+
const v2z = position[i2 * 3 + 2];
|
|
60497
|
+
const edge1x = v1x - v0x;
|
|
60498
|
+
const edge1y = v1y - v0y;
|
|
60499
|
+
const edge1z = v1z - v0z;
|
|
60500
|
+
const edge2x = v2x - v0x;
|
|
60501
|
+
const edge2y = v2y - v0y;
|
|
60502
|
+
const edge2z = v2z - v0z;
|
|
60503
|
+
const nx = edge1y * edge2z - edge1z * edge2y;
|
|
60504
|
+
const ny = edge1z * edge2x - edge1x * edge2z;
|
|
60505
|
+
const nz = edge1x * edge2y - edge1y * edge2x;
|
|
60506
|
+
normal[i0 * 3 + 0] += nx;
|
|
60507
|
+
normal[i0 * 3 + 1] += ny;
|
|
60508
|
+
normal[i0 * 3 + 2] += nz;
|
|
60509
|
+
normal[i1 * 3 + 0] += nx;
|
|
60510
|
+
normal[i1 * 3 + 1] += ny;
|
|
60511
|
+
normal[i1 * 3 + 2] += nz;
|
|
60512
|
+
normal[i2 * 3 + 0] += nx;
|
|
60513
|
+
normal[i2 * 3 + 1] += ny;
|
|
60514
|
+
normal[i2 * 3 + 2] += nz;
|
|
60515
|
+
}
|
|
60516
|
+
for (let v = 0; v < vertexCount; v++) {
|
|
60517
|
+
const nx = normal[v * 3 + 0];
|
|
60518
|
+
const ny = normal[v * 3 + 1];
|
|
60519
|
+
const nz = normal[v * 3 + 2];
|
|
60520
|
+
const length = Math.sqrt(nx * nx + ny * ny + nz * nz);
|
|
60521
|
+
if (length > 1e-5) {
|
|
60522
|
+
normal[v * 3 + 0] = nx / length;
|
|
60523
|
+
normal[v * 3 + 1] = ny / length;
|
|
60524
|
+
normal[v * 3 + 2] = nz / length;
|
|
60525
|
+
} else {
|
|
60526
|
+
normal[v * 3 + 0] = 0;
|
|
60527
|
+
normal[v * 3 + 1] = 1;
|
|
60528
|
+
normal[v * 3 + 2] = 0;
|
|
60529
|
+
}
|
|
60530
|
+
}
|
|
60531
|
+
}
|
|
60532
|
+
let finalPosition = position;
|
|
60533
|
+
let finalNormal = normal;
|
|
60534
|
+
let finalColor = color;
|
|
60535
|
+
let finalUv = void 0;
|
|
60536
|
+
let finalIndices = void 0;
|
|
60537
|
+
if (hasTexcoord && faceVertexUvs.length > 0) {
|
|
60538
|
+
const triangleCount = indices.length / 3;
|
|
60539
|
+
const expandedPosition = new Float32Array(triangleCount * 3 * 3);
|
|
60540
|
+
const expandedNormal = new Float32Array(triangleCount * 3 * 3);
|
|
60541
|
+
const expandedColor = color ? new Float32Array(triangleCount * 3 * 3) : void 0;
|
|
60542
|
+
finalUv = new Float32Array(faceVertexUvs);
|
|
60543
|
+
for (let i = 0; i < triangleCount; i++) {
|
|
60544
|
+
const baseIdx = i * 3;
|
|
60545
|
+
const i0 = indices[baseIdx + 0];
|
|
60546
|
+
const i1 = indices[baseIdx + 1];
|
|
60547
|
+
const i2 = indices[baseIdx + 2];
|
|
60548
|
+
expandedPosition[i * 9 + 0] = position[i0 * 3 + 0];
|
|
60549
|
+
expandedPosition[i * 9 + 1] = position[i0 * 3 + 1];
|
|
60550
|
+
expandedPosition[i * 9 + 2] = position[i0 * 3 + 2];
|
|
60551
|
+
expandedPosition[i * 9 + 3] = position[i1 * 3 + 0];
|
|
60552
|
+
expandedPosition[i * 9 + 4] = position[i1 * 3 + 1];
|
|
60553
|
+
expandedPosition[i * 9 + 5] = position[i1 * 3 + 2];
|
|
60554
|
+
expandedPosition[i * 9 + 6] = position[i2 * 3 + 0];
|
|
60555
|
+
expandedPosition[i * 9 + 7] = position[i2 * 3 + 1];
|
|
60556
|
+
expandedPosition[i * 9 + 8] = position[i2 * 3 + 2];
|
|
60557
|
+
expandedNormal[i * 9 + 0] = normal[i0 * 3 + 0];
|
|
60558
|
+
expandedNormal[i * 9 + 1] = normal[i0 * 3 + 1];
|
|
60559
|
+
expandedNormal[i * 9 + 2] = normal[i0 * 3 + 2];
|
|
60560
|
+
expandedNormal[i * 9 + 3] = normal[i1 * 3 + 0];
|
|
60561
|
+
expandedNormal[i * 9 + 4] = normal[i1 * 3 + 1];
|
|
60562
|
+
expandedNormal[i * 9 + 5] = normal[i1 * 3 + 2];
|
|
60563
|
+
expandedNormal[i * 9 + 6] = normal[i2 * 3 + 0];
|
|
60564
|
+
expandedNormal[i * 9 + 7] = normal[i2 * 3 + 1];
|
|
60565
|
+
expandedNormal[i * 9 + 8] = normal[i2 * 3 + 2];
|
|
60566
|
+
if (expandedColor && color) {
|
|
60567
|
+
expandedColor[i * 9 + 0] = color[i0 * 3 + 0];
|
|
60568
|
+
expandedColor[i * 9 + 1] = color[i0 * 3 + 1];
|
|
60569
|
+
expandedColor[i * 9 + 2] = color[i0 * 3 + 2];
|
|
60570
|
+
expandedColor[i * 9 + 3] = color[i1 * 3 + 0];
|
|
60571
|
+
expandedColor[i * 9 + 4] = color[i1 * 3 + 1];
|
|
60572
|
+
expandedColor[i * 9 + 5] = color[i1 * 3 + 2];
|
|
60573
|
+
expandedColor[i * 9 + 6] = color[i2 * 3 + 0];
|
|
60574
|
+
expandedColor[i * 9 + 7] = color[i2 * 3 + 1];
|
|
60575
|
+
expandedColor[i * 9 + 8] = color[i2 * 3 + 2];
|
|
60576
|
+
}
|
|
60577
|
+
}
|
|
60578
|
+
finalPosition = expandedPosition;
|
|
60579
|
+
finalNormal = expandedNormal;
|
|
60580
|
+
finalColor = expandedColor;
|
|
60581
|
+
const sequentialIndices = new Uint32Array(triangleCount * 3);
|
|
60582
|
+
for (let i = 0; i < triangleCount * 3; i++) {
|
|
60583
|
+
sequentialIndices[i] = i;
|
|
60584
|
+
}
|
|
60585
|
+
finalIndices = sequentialIndices;
|
|
60586
|
+
} else {
|
|
60587
|
+
finalIndices = new Uint32Array(indices);
|
|
60588
|
+
finalUv = uv;
|
|
60589
|
+
}
|
|
60590
|
+
return {
|
|
60591
|
+
vertexCount: hasTexcoord && faceVertexUvs.length > 0 ? finalPosition.length / 3 : vertexCount,
|
|
60592
|
+
faceCount,
|
|
60593
|
+
position: finalPosition,
|
|
60594
|
+
normal: finalNormal,
|
|
60595
|
+
color: finalColor,
|
|
60596
|
+
uv: finalUv,
|
|
60597
|
+
indices: finalIndices,
|
|
60598
|
+
textureFiles: textureFiles.length > 0 ? textureFiles : void 0,
|
|
60599
|
+
triangleTexnumbers: triangleTexnumbers.length > 0 ? triangleTexnumbers : void 0
|
|
60600
|
+
};
|
|
60601
|
+
}
|
|
60602
|
+
function parsePlyMeshASCII(buffer, header) {
|
|
60603
|
+
const { vertexCount, faceCount, properties, faceProperties, textureFiles, headerByteLength } = header;
|
|
60604
|
+
const text = new TextDecoder("utf-8").decode(buffer);
|
|
60605
|
+
const headerEnd = text.indexOf("end_header");
|
|
60606
|
+
if (headerEnd < 0) {
|
|
60607
|
+
throw new Error("PLY: Invalid PLY header");
|
|
60608
|
+
}
|
|
60609
|
+
let bodyStart = headerEnd + "end_header".length;
|
|
60610
|
+
while (bodyStart < text.length && (text[bodyStart] === " " || text[bodyStart] === "\n" || text[bodyStart] === "\r")) {
|
|
60611
|
+
bodyStart++;
|
|
60612
|
+
}
|
|
60613
|
+
const bodyText = text.substring(bodyStart);
|
|
60614
|
+
const tokens = bodyText.split(/\s+/).filter((token) => token.length > 0);
|
|
60615
|
+
let tokenIndex = 0;
|
|
60616
|
+
const has = (n) => properties.find((p) => p.name === n) != null;
|
|
60617
|
+
const parseASCIINumber = (type) => {
|
|
60618
|
+
if (tokenIndex >= tokens.length) {
|
|
60619
|
+
throw new Error("PLY: Unexpected end of file");
|
|
60620
|
+
}
|
|
60621
|
+
const value = tokens[tokenIndex++];
|
|
60622
|
+
switch (type) {
|
|
60623
|
+
case "char":
|
|
60624
|
+
case "uchar":
|
|
60625
|
+
case "short":
|
|
60626
|
+
case "ushort":
|
|
60627
|
+
case "int":
|
|
60628
|
+
case "uint":
|
|
60629
|
+
case "int8":
|
|
60630
|
+
case "uint8":
|
|
60631
|
+
case "int16":
|
|
60632
|
+
case "uint16":
|
|
60633
|
+
case "int32":
|
|
60634
|
+
case "uint32":
|
|
60635
|
+
return parseInt(value);
|
|
60636
|
+
case "float":
|
|
60637
|
+
case "double":
|
|
60638
|
+
case "float32":
|
|
60639
|
+
case "float64":
|
|
60640
|
+
return parseFloat(value);
|
|
60641
|
+
default:
|
|
60642
|
+
return parseFloat(value);
|
|
60643
|
+
}
|
|
60644
|
+
};
|
|
60645
|
+
const position = new Float32Array(vertexCount * 3);
|
|
60646
|
+
const hasNormalData = has("nx") && has("ny") && has("nz");
|
|
60647
|
+
const normal = hasNormalData ? new Float32Array(vertexCount * 3) : new Float32Array(vertexCount * 3);
|
|
60648
|
+
const color = (has("red") || has("r")) && (has("green") || has("g")) && (has("blue") || has("b")) ? new Float32Array(vertexCount * 3) : void 0;
|
|
60649
|
+
const hasVertexUV = (has("u") || has("s")) && (has("v") || has("t"));
|
|
60650
|
+
const hasTexcoord = faceProperties?.some((p) => p.name === "texcoord") || false;
|
|
60651
|
+
const uv = hasVertexUV || hasTexcoord ? new Float32Array(vertexCount * 2) : void 0;
|
|
60652
|
+
const faceTexcoords = /* @__PURE__ */ new Map();
|
|
60653
|
+
const hasTexnumber = faceProperties?.some((p) => p.name === "texnumber") || false;
|
|
60654
|
+
const faceTexnumbers = hasTexnumber ? new Array(faceCount) : [];
|
|
60655
|
+
const indices = [];
|
|
60656
|
+
const triangleTexnumbers = [];
|
|
60657
|
+
const faceVertexUvs = [];
|
|
60658
|
+
const propIndex = (n) => properties.findIndex((p) => p.name === n);
|
|
60659
|
+
const xIdx = propIndex("x");
|
|
60660
|
+
const yIdx = propIndex("y");
|
|
60661
|
+
const zIdx = propIndex("z");
|
|
60662
|
+
const nxIdx = hasNormalData ? propIndex("nx") : -1;
|
|
60663
|
+
const nyIdx = hasNormalData ? propIndex("ny") : -1;
|
|
60664
|
+
const nzIdx = hasNormalData ? propIndex("nz") : -1;
|
|
60665
|
+
const rIdx = color ? propIndex("red") >= 0 ? propIndex("red") : propIndex("r") : -1;
|
|
60666
|
+
const gIdx = color ? propIndex("green") >= 0 ? propIndex("green") : propIndex("g") : -1;
|
|
60667
|
+
const bIdx = color ? propIndex("blue") >= 0 ? propIndex("blue") : propIndex("b") : -1;
|
|
60668
|
+
const uIdx = uv && hasVertexUV ? propIndex("u") >= 0 ? propIndex("u") : propIndex("s") : -1;
|
|
60669
|
+
const vIdx = uv && hasVertexUV ? propIndex("v") >= 0 ? propIndex("v") : propIndex("t") : -1;
|
|
60670
|
+
for (let v = 0; v < vertexCount; v++) {
|
|
60671
|
+
for (let pIdx = 0; pIdx < properties.length; pIdx++) {
|
|
60672
|
+
const prop = properties[pIdx];
|
|
60673
|
+
const value = parseASCIINumber(prop.type);
|
|
60674
|
+
if (pIdx === xIdx) {
|
|
60675
|
+
position[v * 3 + 0] = value;
|
|
60676
|
+
} else if (pIdx === yIdx) {
|
|
60677
|
+
position[v * 3 + 1] = value;
|
|
60678
|
+
} else if (pIdx === zIdx) {
|
|
60679
|
+
position[v * 3 + 2] = value;
|
|
60680
|
+
} else if (pIdx === nxIdx) {
|
|
60681
|
+
normal[v * 3 + 0] = value;
|
|
60682
|
+
} else if (pIdx === nyIdx) {
|
|
60683
|
+
normal[v * 3 + 1] = value;
|
|
60684
|
+
} else if (pIdx === nzIdx) {
|
|
60685
|
+
normal[v * 3 + 2] = value;
|
|
60686
|
+
} else if (pIdx === rIdx && color) {
|
|
60687
|
+
color[v * 3 + 0] = prop.type === "uchar" || prop.type === "uint8" ? value / 255 : value;
|
|
60688
|
+
} else if (pIdx === gIdx && color) {
|
|
60689
|
+
color[v * 3 + 1] = prop.type === "uchar" || prop.type === "uint8" ? value / 255 : value;
|
|
60690
|
+
} else if (pIdx === bIdx && color) {
|
|
60691
|
+
color[v * 3 + 2] = prop.type === "uchar" || prop.type === "uint8" ? value / 255 : value;
|
|
60692
|
+
} else if (pIdx === uIdx && uv) {
|
|
60693
|
+
uv[v * 2 + 0] = value;
|
|
60694
|
+
} else if (pIdx === vIdx && uv) {
|
|
60695
|
+
uv[v * 2 + 1] = value;
|
|
60696
|
+
}
|
|
60697
|
+
}
|
|
60698
|
+
}
|
|
60699
|
+
for (let f = 0; f < faceCount; f++) {
|
|
60700
|
+
let faceIndices = [];
|
|
60701
|
+
let faceTexcoordArray = void 0;
|
|
60702
|
+
let faceTexnum = 0;
|
|
60703
|
+
for (const prop of faceProperties || []) {
|
|
60704
|
+
if (prop.name === "vertex_indices") {
|
|
60705
|
+
const parts = prop.type.split(" ");
|
|
60706
|
+
const countType = parts[1];
|
|
60707
|
+
const itemType = parts[2];
|
|
60708
|
+
const vertexCountInFace2 = parseASCIINumber(countType);
|
|
60709
|
+
faceIndices = [];
|
|
60710
|
+
for (let i = 0; i < vertexCountInFace2; i++) {
|
|
60711
|
+
faceIndices.push(parseASCIINumber(itemType));
|
|
60712
|
+
}
|
|
60713
|
+
} else if (prop.name === "texcoord") {
|
|
60714
|
+
const parts = prop.type.split(" ");
|
|
60715
|
+
const countType = parts[1];
|
|
60716
|
+
const itemType = parts[2];
|
|
60717
|
+
const texcoordCount = parseASCIINumber(countType);
|
|
60718
|
+
faceTexcoordArray = new Float32Array(texcoordCount);
|
|
60719
|
+
for (let i = 0; i < texcoordCount; i++) {
|
|
60720
|
+
faceTexcoordArray[i] = parseASCIINumber(itemType);
|
|
60721
|
+
}
|
|
60722
|
+
faceTexcoords.set(f, faceTexcoordArray);
|
|
60723
|
+
} else if (prop.name === "texnumber") {
|
|
60724
|
+
faceTexnum = parseASCIINumber(prop.type);
|
|
60725
|
+
faceTexnumbers[f] = faceTexnum;
|
|
60726
|
+
}
|
|
60727
|
+
}
|
|
60728
|
+
const vertexCountInFace = faceIndices.length;
|
|
60729
|
+
const texnum = hasTexnumber ? faceTexnumbers[f] ?? 0 : 0;
|
|
60730
|
+
if (vertexCountInFace === 3) {
|
|
60731
|
+
indices.push(faceIndices[0], faceIndices[1], faceIndices[2]);
|
|
60732
|
+
if (hasTexnumber) {
|
|
60733
|
+
triangleTexnumbers.push(texnum);
|
|
60734
|
+
}
|
|
60735
|
+
if (hasTexcoord && faceTexcoordArray && faceTexcoordArray.length >= 6) {
|
|
60736
|
+
faceVertexUvs.push(
|
|
60737
|
+
faceTexcoordArray[0],
|
|
60738
|
+
1 - faceTexcoordArray[1],
|
|
60739
|
+
faceTexcoordArray[2],
|
|
60740
|
+
1 - faceTexcoordArray[3],
|
|
60741
|
+
faceTexcoordArray[4],
|
|
60742
|
+
1 - faceTexcoordArray[5]
|
|
60743
|
+
);
|
|
60744
|
+
}
|
|
60745
|
+
} else {
|
|
60746
|
+
for (let i = 1; i < vertexCountInFace - 1; i++) {
|
|
60747
|
+
indices.push(faceIndices[0], faceIndices[i], faceIndices[i + 1]);
|
|
60748
|
+
if (hasTexnumber) {
|
|
60749
|
+
triangleTexnumbers.push(texnum);
|
|
60750
|
+
}
|
|
60751
|
+
if (hasTexcoord && faceTexcoordArray && faceTexcoordArray.length >= vertexCountInFace * 2) {
|
|
60752
|
+
faceVertexUvs.push(
|
|
60753
|
+
faceTexcoordArray[0],
|
|
60754
|
+
1 - faceTexcoordArray[1],
|
|
60755
|
+
faceTexcoordArray[i * 2 + 0],
|
|
60756
|
+
1 - faceTexcoordArray[i * 2 + 1],
|
|
60757
|
+
faceTexcoordArray[(i + 1) * 2 + 0],
|
|
60758
|
+
1 - faceTexcoordArray[(i + 1) * 2 + 1]
|
|
60759
|
+
);
|
|
60760
|
+
}
|
|
60761
|
+
}
|
|
60762
|
+
}
|
|
60763
|
+
}
|
|
60764
|
+
if (!hasNormalData) {
|
|
60765
|
+
for (let i = 0; i < vertexCount * 3; i++) {
|
|
60766
|
+
normal[i] = 0;
|
|
60767
|
+
}
|
|
60768
|
+
for (let i = 0; i < indices.length; i += 3) {
|
|
60769
|
+
const i0 = indices[i];
|
|
60770
|
+
const i1 = indices[i + 1];
|
|
60771
|
+
const i2 = indices[i + 2];
|
|
60772
|
+
const v0x = position[i0 * 3 + 0];
|
|
60773
|
+
const v0y = position[i0 * 3 + 1];
|
|
60774
|
+
const v0z = position[i0 * 3 + 2];
|
|
60775
|
+
const v1x = position[i1 * 3 + 0];
|
|
60776
|
+
const v1y = position[i1 * 3 + 1];
|
|
60777
|
+
const v1z = position[i1 * 3 + 2];
|
|
60778
|
+
const v2x = position[i2 * 3 + 0];
|
|
60779
|
+
const v2y = position[i2 * 3 + 1];
|
|
60780
|
+
const v2z = position[i2 * 3 + 2];
|
|
60781
|
+
const edge1x = v1x - v0x;
|
|
60782
|
+
const edge1y = v1y - v0y;
|
|
60783
|
+
const edge1z = v1z - v0z;
|
|
60784
|
+
const edge2x = v2x - v0x;
|
|
60785
|
+
const edge2y = v2y - v0y;
|
|
60786
|
+
const edge2z = v2z - v0z;
|
|
60787
|
+
const nx = edge1y * edge2z - edge1z * edge2y;
|
|
60788
|
+
const ny = edge1z * edge2x - edge1x * edge2z;
|
|
60789
|
+
const nz = edge1x * edge2y - edge1y * edge2x;
|
|
60790
|
+
normal[i0 * 3 + 0] += nx;
|
|
60791
|
+
normal[i0 * 3 + 1] += ny;
|
|
60792
|
+
normal[i0 * 3 + 2] += nz;
|
|
60793
|
+
normal[i1 * 3 + 0] += nx;
|
|
60794
|
+
normal[i1 * 3 + 1] += ny;
|
|
60795
|
+
normal[i1 * 3 + 2] += nz;
|
|
60796
|
+
normal[i2 * 3 + 0] += nx;
|
|
60797
|
+
normal[i2 * 3 + 1] += ny;
|
|
60798
|
+
normal[i2 * 3 + 2] += nz;
|
|
60799
|
+
}
|
|
60800
|
+
for (let v = 0; v < vertexCount; v++) {
|
|
60801
|
+
const nx = normal[v * 3 + 0];
|
|
60802
|
+
const ny = normal[v * 3 + 1];
|
|
60803
|
+
const nz = normal[v * 3 + 2];
|
|
60804
|
+
const length = Math.sqrt(nx * nx + ny * ny + nz * nz);
|
|
60805
|
+
if (length > 1e-5) {
|
|
60806
|
+
normal[v * 3 + 0] = nx / length;
|
|
60807
|
+
normal[v * 3 + 1] = ny / length;
|
|
60808
|
+
normal[v * 3 + 2] = nz / length;
|
|
60809
|
+
} else {
|
|
60810
|
+
normal[v * 3 + 0] = 0;
|
|
60811
|
+
normal[v * 3 + 1] = 1;
|
|
60812
|
+
normal[v * 3 + 2] = 0;
|
|
60813
|
+
}
|
|
60814
|
+
}
|
|
60815
|
+
}
|
|
60816
|
+
let finalPosition = position;
|
|
60817
|
+
let finalNormal = normal;
|
|
60818
|
+
let finalColor = color;
|
|
60819
|
+
let finalUv = void 0;
|
|
60820
|
+
let finalIndices = void 0;
|
|
60821
|
+
if (hasTexcoord && faceVertexUvs.length > 0) {
|
|
60822
|
+
const triangleCount = indices.length / 3;
|
|
60823
|
+
const expandedPosition = new Float32Array(triangleCount * 3 * 3);
|
|
60824
|
+
const expandedNormal = new Float32Array(triangleCount * 3 * 3);
|
|
60825
|
+
const expandedColor = color ? new Float32Array(triangleCount * 3 * 3) : void 0;
|
|
60826
|
+
finalUv = new Float32Array(faceVertexUvs);
|
|
60827
|
+
for (let i = 0; i < triangleCount; i++) {
|
|
60828
|
+
const baseIdx = i * 3;
|
|
60829
|
+
const i0 = indices[baseIdx + 0];
|
|
60830
|
+
const i1 = indices[baseIdx + 1];
|
|
60831
|
+
const i2 = indices[baseIdx + 2];
|
|
60832
|
+
expandedPosition[i * 9 + 0] = position[i0 * 3 + 0];
|
|
60833
|
+
expandedPosition[i * 9 + 1] = position[i0 * 3 + 1];
|
|
60834
|
+
expandedPosition[i * 9 + 2] = position[i0 * 3 + 2];
|
|
60835
|
+
expandedPosition[i * 9 + 3] = position[i1 * 3 + 0];
|
|
60836
|
+
expandedPosition[i * 9 + 4] = position[i1 * 3 + 1];
|
|
60837
|
+
expandedPosition[i * 9 + 5] = position[i1 * 3 + 2];
|
|
60838
|
+
expandedPosition[i * 9 + 6] = position[i2 * 3 + 0];
|
|
60839
|
+
expandedPosition[i * 9 + 7] = position[i2 * 3 + 1];
|
|
60840
|
+
expandedPosition[i * 9 + 8] = position[i2 * 3 + 2];
|
|
60841
|
+
expandedNormal[i * 9 + 0] = normal[i0 * 3 + 0];
|
|
60842
|
+
expandedNormal[i * 9 + 1] = normal[i0 * 3 + 1];
|
|
60843
|
+
expandedNormal[i * 9 + 2] = normal[i0 * 3 + 2];
|
|
60844
|
+
expandedNormal[i * 9 + 3] = normal[i1 * 3 + 0];
|
|
60845
|
+
expandedNormal[i * 9 + 4] = normal[i1 * 3 + 1];
|
|
60846
|
+
expandedNormal[i * 9 + 5] = normal[i1 * 3 + 2];
|
|
60847
|
+
expandedNormal[i * 9 + 6] = normal[i2 * 3 + 0];
|
|
60848
|
+
expandedNormal[i * 9 + 7] = normal[i2 * 3 + 1];
|
|
60849
|
+
expandedNormal[i * 9 + 8] = normal[i2 * 3 + 2];
|
|
60850
|
+
if (expandedColor && color) {
|
|
60851
|
+
expandedColor[i * 9 + 0] = color[i0 * 3 + 0];
|
|
60852
|
+
expandedColor[i * 9 + 1] = color[i0 * 3 + 1];
|
|
60853
|
+
expandedColor[i * 9 + 2] = color[i0 * 3 + 2];
|
|
60854
|
+
expandedColor[i * 9 + 3] = color[i1 * 3 + 0];
|
|
60855
|
+
expandedColor[i * 9 + 4] = color[i1 * 3 + 1];
|
|
60856
|
+
expandedColor[i * 9 + 5] = color[i1 * 3 + 2];
|
|
60857
|
+
expandedColor[i * 9 + 6] = color[i2 * 3 + 0];
|
|
60858
|
+
expandedColor[i * 9 + 7] = color[i2 * 3 + 1];
|
|
60859
|
+
expandedColor[i * 9 + 8] = color[i2 * 3 + 2];
|
|
60860
|
+
}
|
|
60861
|
+
}
|
|
60862
|
+
finalPosition = expandedPosition;
|
|
60863
|
+
finalNormal = expandedNormal;
|
|
60864
|
+
finalColor = expandedColor;
|
|
60865
|
+
const sequentialIndices = new Uint32Array(triangleCount * 3);
|
|
60866
|
+
for (let i = 0; i < triangleCount * 3; i++) {
|
|
60867
|
+
sequentialIndices[i] = i;
|
|
60868
|
+
}
|
|
60869
|
+
finalIndices = sequentialIndices;
|
|
60870
|
+
} else {
|
|
60871
|
+
finalIndices = new Uint32Array(indices);
|
|
60872
|
+
finalUv = uv;
|
|
60873
|
+
}
|
|
60874
|
+
return {
|
|
60875
|
+
vertexCount: hasTexcoord && faceVertexUvs.length > 0 ? finalPosition.length / 3 : vertexCount,
|
|
60876
|
+
faceCount,
|
|
60877
|
+
position: finalPosition,
|
|
60878
|
+
normal: finalNormal,
|
|
60879
|
+
color: finalColor,
|
|
60880
|
+
uv: finalUv,
|
|
60881
|
+
indices: finalIndices,
|
|
60882
|
+
textureFiles: textureFiles.length > 0 ? textureFiles : void 0,
|
|
60883
|
+
triangleTexnumbers: triangleTexnumbers.length > 0 ? triangleTexnumbers : void 0
|
|
60884
|
+
};
|
|
60885
|
+
}
|
|
60886
|
+
function parsePlyPointCloud(buffer) {
|
|
60887
|
+
const header = parsePlyHeader(buffer);
|
|
60888
|
+
const { format } = header;
|
|
60889
|
+
if (format === "ascii") {
|
|
60890
|
+
return parsePlyPointCloudASCII(buffer, header);
|
|
60891
|
+
} else {
|
|
60892
|
+
return parsePlyPointCloudBinary(buffer, header);
|
|
60893
|
+
}
|
|
60894
|
+
}
|
|
60895
|
+
function parsePlyPointCloudBinary(buffer, header) {
|
|
60896
|
+
const { vertexCount, properties, headerByteLength } = header;
|
|
60897
|
+
const payload = new DataView(buffer, headerByteLength);
|
|
60898
|
+
const has = (n) => properties.find((p) => p.name === n) != null;
|
|
60899
|
+
const propIndex = (n) => properties.findIndex((p) => p.name === n);
|
|
60900
|
+
const position = new Float32Array(vertexCount * 3);
|
|
60901
|
+
const hasColor = (has("red") || has("r")) && (has("green") || has("g")) && (has("blue") || has("b"));
|
|
60902
|
+
const hasAlpha = has("alpha") || has("a");
|
|
60903
|
+
const color = hasColor ? new Uint8Array(vertexCount * 4) : void 0;
|
|
60904
|
+
const propOffsets = [];
|
|
60905
|
+
let stride = 0;
|
|
60906
|
+
for (const p of properties) {
|
|
60907
|
+
propOffsets.push(stride);
|
|
60908
|
+
stride += byteSizeOfType(p.type);
|
|
60909
|
+
}
|
|
60910
|
+
let base = 0;
|
|
60911
|
+
for (let v = 0; v < vertexCount; v++) {
|
|
60912
|
+
const vOffset = base;
|
|
60913
|
+
const ix = propIndex("x");
|
|
60914
|
+
const iy = propIndex("y");
|
|
60915
|
+
const iz = propIndex("z");
|
|
60916
|
+
if (ix < 0 || iy < 0 || iz < 0) {
|
|
60917
|
+
throw new Error("PLY: Missing x/y/z for vertex");
|
|
60918
|
+
}
|
|
60919
|
+
position[v * 3 + 0] = readByType(payload, vOffset + propOffsets[ix], properties[ix].type);
|
|
60920
|
+
position[v * 3 + 1] = readByType(payload, vOffset + propOffsets[iy], properties[iy].type);
|
|
60921
|
+
position[v * 3 + 2] = readByType(payload, vOffset + propOffsets[iz], properties[iz].type);
|
|
60922
|
+
if (color) {
|
|
60923
|
+
const rIdx = propIndex("red") >= 0 ? propIndex("red") : propIndex("r");
|
|
60924
|
+
const gIdx = propIndex("green") >= 0 ? propIndex("green") : propIndex("g");
|
|
60925
|
+
const bIdx = propIndex("blue") >= 0 ? propIndex("blue") : propIndex("b");
|
|
60926
|
+
const aIdx = hasAlpha ? propIndex("alpha") >= 0 ? propIndex("alpha") : propIndex("a") : -1;
|
|
60927
|
+
if (rIdx >= 0 && gIdx >= 0 && bIdx >= 0) {
|
|
60928
|
+
let r = readByType(payload, vOffset + propOffsets[rIdx], properties[rIdx].type);
|
|
60929
|
+
let g = readByType(payload, vOffset + propOffsets[gIdx], properties[gIdx].type);
|
|
60930
|
+
let b = readByType(payload, vOffset + propOffsets[bIdx], properties[bIdx].type);
|
|
60931
|
+
let a = 255;
|
|
60932
|
+
if (properties[rIdx].type === "float" || properties[rIdx].type === "float32" || properties[rIdx].type === "double" || properties[rIdx].type === "float64") {
|
|
60933
|
+
r = Math.round(r * 255);
|
|
60934
|
+
g = Math.round(g * 255);
|
|
60935
|
+
b = Math.round(b * 255);
|
|
60936
|
+
}
|
|
60937
|
+
if (aIdx >= 0) {
|
|
60938
|
+
a = readByType(payload, vOffset + propOffsets[aIdx], properties[aIdx].type);
|
|
60939
|
+
if (properties[aIdx].type === "float" || properties[aIdx].type === "float32" || properties[aIdx].type === "double" || properties[aIdx].type === "float64") {
|
|
60940
|
+
a = Math.round(a * 255);
|
|
60941
|
+
}
|
|
60942
|
+
}
|
|
60943
|
+
color[v * 4 + 0] = Math.max(0, Math.min(255, r));
|
|
60944
|
+
color[v * 4 + 1] = Math.max(0, Math.min(255, g));
|
|
60945
|
+
color[v * 4 + 2] = Math.max(0, Math.min(255, b));
|
|
60946
|
+
color[v * 4 + 3] = Math.max(0, Math.min(255, a));
|
|
60947
|
+
}
|
|
60948
|
+
}
|
|
60949
|
+
base += stride;
|
|
60950
|
+
}
|
|
60951
|
+
return {
|
|
60952
|
+
vertexCount,
|
|
60953
|
+
position,
|
|
60954
|
+
color
|
|
60955
|
+
};
|
|
60956
|
+
}
|
|
60957
|
+
function parsePlyPointCloudASCII(buffer, header) {
|
|
60958
|
+
const { vertexCount, properties } = header;
|
|
60959
|
+
const text = new TextDecoder("utf-8").decode(buffer);
|
|
60960
|
+
const headerEnd = text.indexOf("end_header");
|
|
60961
|
+
if (headerEnd < 0) {
|
|
60962
|
+
throw new Error("PLY: Invalid PLY header");
|
|
60963
|
+
}
|
|
60964
|
+
let bodyStart = headerEnd + "end_header".length;
|
|
60965
|
+
while (bodyStart < text.length && (text[bodyStart] === " " || text[bodyStart] === "\n" || text[bodyStart] === "\r")) {
|
|
60966
|
+
bodyStart++;
|
|
60967
|
+
}
|
|
60968
|
+
const bodyText = text.substring(bodyStart);
|
|
60969
|
+
const tokens = bodyText.split(/\s+/).filter((token) => token.length > 0);
|
|
60970
|
+
let tokenIndex = 0;
|
|
60971
|
+
const has = (n) => properties.find((p) => p.name === n) != null;
|
|
60972
|
+
const parseASCIINumber = (type) => {
|
|
60973
|
+
if (tokenIndex >= tokens.length) {
|
|
60974
|
+
throw new Error("PLY: Unexpected end of file");
|
|
60975
|
+
}
|
|
60976
|
+
const value = tokens[tokenIndex++];
|
|
60977
|
+
switch (type) {
|
|
60978
|
+
case "char":
|
|
60979
|
+
case "uchar":
|
|
60980
|
+
case "short":
|
|
60981
|
+
case "ushort":
|
|
60982
|
+
case "int":
|
|
60983
|
+
case "uint":
|
|
60984
|
+
case "int8":
|
|
60985
|
+
case "uint8":
|
|
60986
|
+
case "int16":
|
|
60987
|
+
case "uint16":
|
|
60988
|
+
case "int32":
|
|
60989
|
+
case "uint32":
|
|
60990
|
+
return parseInt(value);
|
|
60991
|
+
case "float":
|
|
60992
|
+
case "double":
|
|
60993
|
+
case "float32":
|
|
60994
|
+
case "float64":
|
|
60995
|
+
return parseFloat(value);
|
|
60996
|
+
default:
|
|
60997
|
+
return parseFloat(value);
|
|
60998
|
+
}
|
|
60999
|
+
};
|
|
61000
|
+
const position = new Float32Array(vertexCount * 3);
|
|
61001
|
+
const hasColor = (has("red") || has("r")) && (has("green") || has("g")) && (has("blue") || has("b"));
|
|
61002
|
+
const hasAlpha = has("alpha") || has("a");
|
|
61003
|
+
const color = hasColor ? new Uint8Array(vertexCount * 4) : void 0;
|
|
61004
|
+
const propIndex = (n) => properties.findIndex((p) => p.name === n);
|
|
61005
|
+
const xIdx = propIndex("x");
|
|
61006
|
+
const yIdx = propIndex("y");
|
|
61007
|
+
const zIdx = propIndex("z");
|
|
61008
|
+
const rIdx = hasColor ? propIndex("red") >= 0 ? propIndex("red") : propIndex("r") : -1;
|
|
61009
|
+
const gIdx = hasColor ? propIndex("green") >= 0 ? propIndex("green") : propIndex("g") : -1;
|
|
61010
|
+
const bIdx = hasColor ? propIndex("blue") >= 0 ? propIndex("blue") : propIndex("b") : -1;
|
|
61011
|
+
const aIdx = hasAlpha ? propIndex("alpha") >= 0 ? propIndex("alpha") : propIndex("a") : -1;
|
|
61012
|
+
for (let v = 0; v < vertexCount; v++) {
|
|
61013
|
+
for (let pIdx = 0; pIdx < properties.length; pIdx++) {
|
|
61014
|
+
const prop = properties[pIdx];
|
|
61015
|
+
const value = parseASCIINumber(prop.type);
|
|
61016
|
+
if (pIdx === xIdx) {
|
|
61017
|
+
position[v * 3 + 0] = value;
|
|
61018
|
+
} else if (pIdx === yIdx) {
|
|
61019
|
+
position[v * 3 + 1] = value;
|
|
61020
|
+
} else if (pIdx === zIdx) {
|
|
61021
|
+
position[v * 3 + 2] = value;
|
|
61022
|
+
} else if (pIdx === rIdx && color) {
|
|
61023
|
+
const r = prop.type === "uchar" || prop.type === "uint8" ? value : Math.round(value * 255);
|
|
61024
|
+
color[v * 4 + 0] = Math.max(0, Math.min(255, r));
|
|
61025
|
+
} else if (pIdx === gIdx && color) {
|
|
61026
|
+
const g = prop.type === "uchar" || prop.type === "uint8" ? value : Math.round(value * 255);
|
|
61027
|
+
color[v * 4 + 1] = Math.max(0, Math.min(255, g));
|
|
61028
|
+
} else if (pIdx === bIdx && color) {
|
|
61029
|
+
const b = prop.type === "uchar" || prop.type === "uint8" ? value : Math.round(value * 255);
|
|
61030
|
+
color[v * 4 + 2] = Math.max(0, Math.min(255, b));
|
|
61031
|
+
} else if (pIdx === aIdx && color) {
|
|
61032
|
+
const a = prop.type === "uchar" || prop.type === "uint8" ? value : Math.round(value * 255);
|
|
61033
|
+
color[v * 4 + 3] = Math.max(0, Math.min(255, a));
|
|
61034
|
+
}
|
|
61035
|
+
}
|
|
61036
|
+
if (color && aIdx < 0) {
|
|
61037
|
+
color[v * 4 + 3] = 255;
|
|
61038
|
+
}
|
|
61039
|
+
}
|
|
61040
|
+
return {
|
|
61041
|
+
vertexCount,
|
|
61042
|
+
position,
|
|
61043
|
+
color
|
|
61044
|
+
};
|
|
61045
|
+
}
|
|
59371
61046
|
|
|
59372
61047
|
class GaussianSplatParser extends ParserBase {
|
|
59373
61048
|
static format = ParserFormat.BIN;
|
|
@@ -59476,6 +61151,150 @@ fn frag(){
|
|
|
59476
61151
|
class KHR_materials_ior {
|
|
59477
61152
|
}
|
|
59478
61153
|
|
|
61154
|
+
class PlyParser extends ParserBase {
|
|
61155
|
+
static format = ParserFormat.BIN;
|
|
61156
|
+
async parseBuffer(buffer) {
|
|
61157
|
+
const header = parsePlyHeader(buffer);
|
|
61158
|
+
switch (header.mode) {
|
|
61159
|
+
case PlyMode.Splat: {
|
|
61160
|
+
const plyData = parsePlyGaussianSplat(buffer);
|
|
61161
|
+
const asset = {
|
|
61162
|
+
count: plyData.vertexCount,
|
|
61163
|
+
position: plyData.position,
|
|
61164
|
+
rotation: plyData.rotation,
|
|
61165
|
+
scale: plyData.scale,
|
|
61166
|
+
opacity: plyData.opacity,
|
|
61167
|
+
sh: plyData.sh
|
|
61168
|
+
};
|
|
61169
|
+
asset.bbox = computeAABBFromPositions(plyData.position);
|
|
61170
|
+
const gsplatObj = new exports.Object3D();
|
|
61171
|
+
gsplatObj.name = "GaussianSplat";
|
|
61172
|
+
const renderer = gsplatObj.addComponent(exports.GSplatRenderer);
|
|
61173
|
+
renderer.initAsset(asset);
|
|
61174
|
+
this.data = gsplatObj;
|
|
61175
|
+
break;
|
|
61176
|
+
}
|
|
61177
|
+
case PlyMode.PointCloud: {
|
|
61178
|
+
const plyData = parsePlyPointCloud(buffer);
|
|
61179
|
+
const pointCloudObj = new exports.Object3D();
|
|
61180
|
+
pointCloudObj.name = "PLYPointCloud";
|
|
61181
|
+
const pointCloudObjRoot = new exports.Object3D();
|
|
61182
|
+
pointCloudObjRoot.name = "PLYPointCloudRoot";
|
|
61183
|
+
pointCloudObj.addChild(pointCloudObjRoot);
|
|
61184
|
+
const renderer = pointCloudObjRoot.addComponent(exports.PointCloudRenderer);
|
|
61185
|
+
if (plyData.color) {
|
|
61186
|
+
renderer.initFromData(plyData.position, plyData.color, plyData.vertexCount);
|
|
61187
|
+
} else {
|
|
61188
|
+
const defaultColors = new Uint8Array(plyData.vertexCount * 4);
|
|
61189
|
+
defaultColors.fill(255);
|
|
61190
|
+
renderer.initFromData(plyData.position, defaultColors, plyData.vertexCount);
|
|
61191
|
+
}
|
|
61192
|
+
renderer.setPointShape("circle");
|
|
61193
|
+
renderer.setPointSize(4);
|
|
61194
|
+
this.data = pointCloudObj;
|
|
61195
|
+
break;
|
|
61196
|
+
}
|
|
61197
|
+
case PlyMode.Mesh: {
|
|
61198
|
+
const plyData = parsePlyMesh(buffer);
|
|
61199
|
+
const rootObj = new exports.Object3D();
|
|
61200
|
+
rootObj.name = "PLYMesh";
|
|
61201
|
+
const textureGroups = /* @__PURE__ */ new Map();
|
|
61202
|
+
if (plyData.triangleTexnumbers && plyData.triangleTexnumbers.length > 0) {
|
|
61203
|
+
for (let i = 0; i < plyData.triangleTexnumbers.length; i++) {
|
|
61204
|
+
const texnum = plyData.triangleTexnumbers[i];
|
|
61205
|
+
if (!textureGroups.has(texnum)) {
|
|
61206
|
+
textureGroups.set(texnum, []);
|
|
61207
|
+
}
|
|
61208
|
+
textureGroups.get(texnum).push(i);
|
|
61209
|
+
}
|
|
61210
|
+
} else {
|
|
61211
|
+
const triangleCount = plyData.indices.length / 3;
|
|
61212
|
+
const allTriangles = [];
|
|
61213
|
+
for (let i = 0; i < triangleCount; i++) {
|
|
61214
|
+
allTriangles.push(i);
|
|
61215
|
+
}
|
|
61216
|
+
textureGroups.set(0, allTriangles);
|
|
61217
|
+
}
|
|
61218
|
+
const materials = /* @__PURE__ */ new Map();
|
|
61219
|
+
if (plyData.textureFiles && plyData.textureFiles.length > 0) {
|
|
61220
|
+
const promiseList = [];
|
|
61221
|
+
for (let texnum = 0; texnum < plyData.textureFiles.length; texnum++) {
|
|
61222
|
+
const material = new LitMaterial();
|
|
61223
|
+
const texturePath = StringUtil.normalizePath(
|
|
61224
|
+
this.baseUrl + plyData.textureFiles[texnum]
|
|
61225
|
+
);
|
|
61226
|
+
promiseList.push(Engine3D.res.loadTexture(texturePath).then((texture) => {
|
|
61227
|
+
material.baseMap = texture;
|
|
61228
|
+
materials.set(texnum, material);
|
|
61229
|
+
}));
|
|
61230
|
+
}
|
|
61231
|
+
await Promise.all(promiseList);
|
|
61232
|
+
}
|
|
61233
|
+
if (materials.size === 0) {
|
|
61234
|
+
materials.set(0, new LitMaterial());
|
|
61235
|
+
}
|
|
61236
|
+
for (const [texnum, triangleIndices] of textureGroups) {
|
|
61237
|
+
const groupIndices = [];
|
|
61238
|
+
for (const triIdx of triangleIndices) {
|
|
61239
|
+
const baseIdx = triIdx * 3;
|
|
61240
|
+
groupIndices.push(
|
|
61241
|
+
plyData.indices[baseIdx + 0],
|
|
61242
|
+
plyData.indices[baseIdx + 1],
|
|
61243
|
+
plyData.indices[baseIdx + 2]
|
|
61244
|
+
);
|
|
61245
|
+
}
|
|
61246
|
+
const geometry = new GeometryBase();
|
|
61247
|
+
geometry.setAttribute(
|
|
61248
|
+
VertexAttributeName.position,
|
|
61249
|
+
plyData.position
|
|
61250
|
+
);
|
|
61251
|
+
geometry.setAttribute(
|
|
61252
|
+
VertexAttributeName.normal,
|
|
61253
|
+
plyData.normal
|
|
61254
|
+
);
|
|
61255
|
+
if (plyData.uv) {
|
|
61256
|
+
geometry.setAttribute(
|
|
61257
|
+
VertexAttributeName.uv,
|
|
61258
|
+
plyData.uv
|
|
61259
|
+
);
|
|
61260
|
+
}
|
|
61261
|
+
if (plyData.color) {
|
|
61262
|
+
geometry.setAttribute(
|
|
61263
|
+
VertexAttributeName.color,
|
|
61264
|
+
plyData.color
|
|
61265
|
+
);
|
|
61266
|
+
}
|
|
61267
|
+
geometry.setIndices(new Uint32Array(groupIndices));
|
|
61268
|
+
geometry.addSubGeometry({
|
|
61269
|
+
indexStart: 0,
|
|
61270
|
+
indexCount: groupIndices.length,
|
|
61271
|
+
vertexStart: 0,
|
|
61272
|
+
vertexCount: 0,
|
|
61273
|
+
firstStart: 0,
|
|
61274
|
+
index: 0,
|
|
61275
|
+
topology: 0
|
|
61276
|
+
});
|
|
61277
|
+
let material = materials.get(texnum);
|
|
61278
|
+
if (!material) {
|
|
61279
|
+
material = materials.values().next().value || new LitMaterial();
|
|
61280
|
+
}
|
|
61281
|
+
const meshObj = new exports.Object3D();
|
|
61282
|
+
meshObj.name = `PLYMesh_Texture_${texnum}`;
|
|
61283
|
+
const renderer = meshObj.addComponent(exports.MeshRenderer);
|
|
61284
|
+
renderer.geometry = geometry;
|
|
61285
|
+
renderer.material = material;
|
|
61286
|
+
rootObj.addChild(meshObj);
|
|
61287
|
+
}
|
|
61288
|
+
this.data = rootObj;
|
|
61289
|
+
break;
|
|
61290
|
+
}
|
|
61291
|
+
}
|
|
61292
|
+
}
|
|
61293
|
+
verification() {
|
|
61294
|
+
return !!this.data;
|
|
61295
|
+
}
|
|
61296
|
+
}
|
|
61297
|
+
|
|
59479
61298
|
class PrefabBoneData {
|
|
59480
61299
|
boneName;
|
|
59481
61300
|
bonePath;
|
|
@@ -67612,69 +69431,6 @@ fn frag(){
|
|
|
67612
69431
|
}
|
|
67613
69432
|
}
|
|
67614
69433
|
|
|
67615
|
-
class Float32ArrayTexture extends Texture {
|
|
67616
|
-
create(width, height, data, filtering = true) {
|
|
67617
|
-
let device = webGPUContext.device;
|
|
67618
|
-
const bytesPerRow = width * 4 * 4;
|
|
67619
|
-
this.format = GPUTextureFormat.rgba32float;
|
|
67620
|
-
let mipmapCount = 1;
|
|
67621
|
-
this.createTextureDescriptor(width, height, mipmapCount, this.format);
|
|
67622
|
-
const textureDataBuffer = device.createBuffer({
|
|
67623
|
-
size: data.byteLength,
|
|
67624
|
-
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC
|
|
67625
|
-
});
|
|
67626
|
-
device.queue.writeBuffer(textureDataBuffer, 0, data);
|
|
67627
|
-
const commandEncoder = GPUContext.beginCommandEncoder();
|
|
67628
|
-
commandEncoder.copyBufferToTexture(
|
|
67629
|
-
{
|
|
67630
|
-
buffer: textureDataBuffer,
|
|
67631
|
-
bytesPerRow
|
|
67632
|
-
},
|
|
67633
|
-
{
|
|
67634
|
-
texture: this.getGPUTexture()
|
|
67635
|
-
},
|
|
67636
|
-
{
|
|
67637
|
-
width,
|
|
67638
|
-
height,
|
|
67639
|
-
depthOrArrayLayers: 1
|
|
67640
|
-
}
|
|
67641
|
-
);
|
|
67642
|
-
GPUContext.endCommandEncoder(commandEncoder);
|
|
67643
|
-
if (filtering) {
|
|
67644
|
-
this.samplerBindingLayout.type = `non-filtering`;
|
|
67645
|
-
this.textureBindingLayout.sampleType = `unfilterable-float`;
|
|
67646
|
-
}
|
|
67647
|
-
this.gpuSampler = device.createSampler({});
|
|
67648
|
-
}
|
|
67649
|
-
fromBuffer(width, height, textureDataBuffer) {
|
|
67650
|
-
let device = webGPUContext.device;
|
|
67651
|
-
const bytesPerRow = width * 4 * 4;
|
|
67652
|
-
this.format = GPUTextureFormat.rgba32float;
|
|
67653
|
-
this.mipmapCount = 1;
|
|
67654
|
-
this.createTextureDescriptor(width, height, this.mipmapCount, this.format);
|
|
67655
|
-
const commandEncoder = GPUContext.beginCommandEncoder();
|
|
67656
|
-
commandEncoder.copyBufferToTexture(
|
|
67657
|
-
{
|
|
67658
|
-
buffer: textureDataBuffer,
|
|
67659
|
-
bytesPerRow
|
|
67660
|
-
},
|
|
67661
|
-
{
|
|
67662
|
-
texture: this.getGPUTexture()
|
|
67663
|
-
},
|
|
67664
|
-
{
|
|
67665
|
-
width,
|
|
67666
|
-
height,
|
|
67667
|
-
depthOrArrayLayers: 1
|
|
67668
|
-
}
|
|
67669
|
-
);
|
|
67670
|
-
GPUContext.endCommandEncoder(commandEncoder);
|
|
67671
|
-
this.samplerBindingLayout.type = `non-filtering`;
|
|
67672
|
-
this.textureBindingLayout.sampleType = `unfilterable-float`;
|
|
67673
|
-
this.gpuSampler = device.createSampler({});
|
|
67674
|
-
return this;
|
|
67675
|
-
}
|
|
67676
|
-
}
|
|
67677
|
-
|
|
67678
69434
|
class SolidColorSky extends LDRTextureCube {
|
|
67679
69435
|
_internalTexture;
|
|
67680
69436
|
_minSize = 32;
|
|
@@ -69459,7 +71215,13 @@ fn frag(){
|
|
|
69459
71215
|
exports.Plane3D = Plane3D;
|
|
69460
71216
|
exports.PlaneClassification = PlaneClassification;
|
|
69461
71217
|
exports.PlaneGeometry = PlaneGeometry;
|
|
71218
|
+
exports.PlyMode = PlyMode;
|
|
71219
|
+
exports.PlyParser = PlyParser;
|
|
69462
71220
|
exports.PointClassification = PointClassification;
|
|
71221
|
+
exports.PointCloudGeometry = PointCloudGeometry;
|
|
71222
|
+
exports.PointCloudMaterial = PointCloudMaterial;
|
|
71223
|
+
exports.PointCloud_FS = PointCloud_FS;
|
|
71224
|
+
exports.PointCloud_VS = PointCloud_VS;
|
|
69463
71225
|
exports.PointLightShadowRenderer = PointLightShadowRenderer;
|
|
69464
71226
|
exports.PointShadowCubeCamera = PointShadowCubeCamera;
|
|
69465
71227
|
exports.PointerEvent3D = PointerEvent3D;
|
|
@@ -69799,6 +71561,8 @@ fn frag(){
|
|
|
69799
71561
|
exports.outlinePostManager = outlinePostManager;
|
|
69800
71562
|
exports.parsePlyGaussianSplat = parsePlyGaussianSplat;
|
|
69801
71563
|
exports.parsePlyHeader = parsePlyHeader;
|
|
71564
|
+
exports.parsePlyMesh = parsePlyMesh;
|
|
71565
|
+
exports.parsePlyPointCloud = parsePlyPointCloud;
|
|
69802
71566
|
exports.perm = perm;
|
|
69803
71567
|
exports.post = post;
|
|
69804
71568
|
exports.priorityCallback = priorityCallback;
|
|
@@ -69834,6 +71598,8 @@ fn frag(){
|
|
|
69834
71598
|
exports.snoise2 = snoise2;
|
|
69835
71599
|
exports.snoise3 = snoise3;
|
|
69836
71600
|
exports.snoise4 = snoise4;
|
|
71601
|
+
exports.splatColorProperties = splatColorProperties;
|
|
71602
|
+
exports.splatProperties = splatProperties;
|
|
69837
71603
|
exports.sqrMagnitude = sqrMagnitude;
|
|
69838
71604
|
exports.sqrtImpl = sqrtImpl;
|
|
69839
71605
|
exports.stencilStateFace = stencilStateFace;
|