rm-webgpu-compute-tasks 0.0.2 → 0.0.4
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/package.json +1 -1
- package/src/index.d.ts +107 -48
- package/src/index.js +1272 -270
package/src/index.js
CHANGED
|
@@ -478,6 +478,37 @@ const getAdapter = () => {
|
|
|
478
478
|
if (!adapter) throw new Error("未初始化webgpu");
|
|
479
479
|
return adapter;
|
|
480
480
|
};
|
|
481
|
+
let __nullBG = null;
|
|
482
|
+
let __nullBGLayout = null;
|
|
483
|
+
function getNullBG() {
|
|
484
|
+
if (!__nullBG) {
|
|
485
|
+
const device2 = getDevice();
|
|
486
|
+
const dummyBuffer = device2.createBuffer({
|
|
487
|
+
size: 16,
|
|
488
|
+
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
|
|
489
|
+
});
|
|
490
|
+
__nullBGLayout = device2.createBindGroupLayout({
|
|
491
|
+
entries: [{
|
|
492
|
+
binding: 0,
|
|
493
|
+
visibility: GPUShaderStage.COMPUTE,
|
|
494
|
+
buffer: {}
|
|
495
|
+
}]
|
|
496
|
+
});
|
|
497
|
+
__nullBG = device2.createBindGroup({
|
|
498
|
+
layout: __nullBGLayout,
|
|
499
|
+
entries: [{
|
|
500
|
+
binding: 0,
|
|
501
|
+
resource: {
|
|
502
|
+
buffer: dummyBuffer
|
|
503
|
+
}
|
|
504
|
+
}]
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
return {
|
|
508
|
+
bindGroup: __nullBG,
|
|
509
|
+
bindGroupLayout: __nullBGLayout
|
|
510
|
+
};
|
|
511
|
+
}
|
|
481
512
|
function createBuffer(device2, options) {
|
|
482
513
|
const { data, size, usage, mappedAtCreation = false, label } = options;
|
|
483
514
|
let bufferSize = size ?? 0;
|
|
@@ -693,6 +724,36 @@ async function readCubeTexture(texture, face = 0, mipLevel = 0, device2 = getDev
|
|
|
693
724
|
bytesPerPixel: result.bytesPerPixel
|
|
694
725
|
};
|
|
695
726
|
}
|
|
727
|
+
function autoWorkgroup(maxSize = [1]) {
|
|
728
|
+
const x = maxSize[0] ?? 1;
|
|
729
|
+
const y = maxSize[1] ?? 1;
|
|
730
|
+
const z = maxSize[2] ?? 1;
|
|
731
|
+
let workgroupSize = [1, 1, 1];
|
|
732
|
+
if (y === 1 && z === 1) {
|
|
733
|
+
const size = x;
|
|
734
|
+
let wg = 64;
|
|
735
|
+
if (size < 64) wg = 32;
|
|
736
|
+
if (size < 32) wg = 16;
|
|
737
|
+
workgroupSize = [wg, 1, 1];
|
|
738
|
+
} else if (z === 1) {
|
|
739
|
+
if (x >= 256 && y >= 256) {
|
|
740
|
+
workgroupSize = [16, 16, 1];
|
|
741
|
+
} else {
|
|
742
|
+
workgroupSize = [8, 8, 1];
|
|
743
|
+
}
|
|
744
|
+
} else {
|
|
745
|
+
workgroupSize = [4, 4, 4];
|
|
746
|
+
}
|
|
747
|
+
const workgroupCount = [
|
|
748
|
+
Math.ceil(x / workgroupSize[0]),
|
|
749
|
+
Math.ceil(y / workgroupSize[1]),
|
|
750
|
+
Math.ceil(z / workgroupSize[2])
|
|
751
|
+
];
|
|
752
|
+
return {
|
|
753
|
+
workgroupSize,
|
|
754
|
+
workgroupCount
|
|
755
|
+
};
|
|
756
|
+
}
|
|
696
757
|
const shaderLocationMap = /* @__PURE__ */ new Map();
|
|
697
758
|
shaderLocationMap.set("position", 0).set("normal ", 1).set("uv", 2).set("color", 3);
|
|
698
759
|
class BufferGeometry extends THREE.BufferGeometry {
|
|
@@ -750,6 +811,9 @@ class BufferGeometry extends THREE.BufferGeometry {
|
|
|
750
811
|
const layoutCache$2 = /* @__PURE__ */ new WeakMap();
|
|
751
812
|
const OBJECT_UNIFORM_SIZE = 128;
|
|
752
813
|
class Object3D extends THREE.Object3D {
|
|
814
|
+
static get GROU_INDEX() {
|
|
815
|
+
return 1;
|
|
816
|
+
}
|
|
753
817
|
static get bindGroupLayout() {
|
|
754
818
|
const device2 = getDevice();
|
|
755
819
|
let layout = layoutCache$2.get(device2);
|
|
@@ -967,7 +1031,7 @@ class Texture {
|
|
|
967
1031
|
viewDimension;
|
|
968
1032
|
constructor(width, height = width, des) {
|
|
969
1033
|
const {
|
|
970
|
-
format =
|
|
1034
|
+
format = "rgba8unorm",
|
|
971
1035
|
sampler,
|
|
972
1036
|
depthOrArrayLayers = 1,
|
|
973
1037
|
dimension = "2d",
|
|
@@ -1203,6 +1267,9 @@ var<uniform> object : Object;
|
|
|
1203
1267
|
`
|
|
1204
1268
|
);
|
|
1205
1269
|
class ShaderMaterial {
|
|
1270
|
+
static get GROU_INDEX() {
|
|
1271
|
+
return 2;
|
|
1272
|
+
}
|
|
1206
1273
|
vertex;
|
|
1207
1274
|
fragment;
|
|
1208
1275
|
pipeline;
|
|
@@ -1218,7 +1285,7 @@ class ShaderMaterial {
|
|
|
1218
1285
|
blend;
|
|
1219
1286
|
writeMask;
|
|
1220
1287
|
depthStencil;
|
|
1221
|
-
|
|
1288
|
+
define;
|
|
1222
1289
|
_needsUniformUpdate = true;
|
|
1223
1290
|
get needsUniformUpdate() {
|
|
1224
1291
|
return this._needsUniformUpdate;
|
|
@@ -1235,14 +1302,14 @@ class ShaderMaterial {
|
|
|
1235
1302
|
}
|
|
1236
1303
|
constructor(options) {
|
|
1237
1304
|
const device2 = getDevice();
|
|
1238
|
-
this.vertex =
|
|
1305
|
+
this.vertex = options.vertex;
|
|
1239
1306
|
this.fragment = options.fragment;
|
|
1240
1307
|
this.topology = options.topology;
|
|
1241
1308
|
this.side = options.side ?? "front";
|
|
1242
1309
|
this.blend = options.blend;
|
|
1243
1310
|
this.writeMask = options.writeMask;
|
|
1244
1311
|
this.depthStencil = options.depthStencil;
|
|
1245
|
-
this.
|
|
1312
|
+
this.define = options.define;
|
|
1246
1313
|
this.buffer = device2.createBuffer({
|
|
1247
1314
|
size: MATERIAL_UNIFORM_SIZE,
|
|
1248
1315
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
|
|
@@ -1258,13 +1325,16 @@ class ShaderMaterial {
|
|
|
1258
1325
|
this.uniforms = {};
|
|
1259
1326
|
let binding = 1;
|
|
1260
1327
|
const createObjectListener = (key, value, type, set) => {
|
|
1328
|
+
let value_ = value;
|
|
1261
1329
|
const uniform = {
|
|
1262
1330
|
get value() {
|
|
1263
|
-
return
|
|
1331
|
+
return value_;
|
|
1264
1332
|
},
|
|
1265
1333
|
set value(v) {
|
|
1266
|
-
if (getUniformType(v) !== type) return;
|
|
1267
|
-
|
|
1334
|
+
if (getUniformType(v, uniforms[key]?.atomic) !== type) return;
|
|
1335
|
+
v = set(v, value_);
|
|
1336
|
+
if ("copy" in value_ && typeof value_.copy === "function") value_.copy(v);
|
|
1337
|
+
else value_ = v;
|
|
1268
1338
|
}
|
|
1269
1339
|
};
|
|
1270
1340
|
this.uniforms[key] = uniform;
|
|
@@ -1319,8 +1389,10 @@ class ShaderMaterial {
|
|
|
1319
1389
|
if (Array.isArray(value) || value instanceof Float32Array || value instanceof Uint32Array || value instanceof Uint8Array) {
|
|
1320
1390
|
arrayListener(key, value, type);
|
|
1321
1391
|
this._storageUniforms[key].write = uniforms[key].write ?? false;
|
|
1322
|
-
} else if (type === "texture_cube" || type === "texture_2d")
|
|
1323
|
-
|
|
1392
|
+
} else if (type === "texture_cube" || type === "texture_2d") {
|
|
1393
|
+
textureListener(key, value, type);
|
|
1394
|
+
this._textureUniforms[key].write = uniforms[key].write ?? false;
|
|
1395
|
+
} else defaultListener(key, value, type);
|
|
1324
1396
|
}
|
|
1325
1397
|
this.needsBindGroupUpdate = true;
|
|
1326
1398
|
this.needsUniformUpdate = true;
|
|
@@ -1345,21 +1417,29 @@ class ShaderMaterial {
|
|
|
1345
1417
|
if (layoutCache.has(key)) return layoutCache.get(key);
|
|
1346
1418
|
const entries = [{
|
|
1347
1419
|
binding: 0,
|
|
1348
|
-
visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
|
|
1420
|
+
visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE,
|
|
1349
1421
|
buffer: {}
|
|
1350
1422
|
}];
|
|
1351
1423
|
textureKeys.forEach((key2) => {
|
|
1352
1424
|
const item = this._textureUniforms[key2];
|
|
1353
|
-
|
|
1425
|
+
const format = item.value?.texture?.format ?? "rgba8unorm";
|
|
1426
|
+
const opt = {
|
|
1354
1427
|
binding: item.binding,
|
|
1355
|
-
visibility: GPUShaderStage.FRAGMENT,
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1428
|
+
visibility: GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE,
|
|
1429
|
+
[item.write ? "storageTexture" : "texture"]: {
|
|
1430
|
+
access: "write",
|
|
1431
|
+
format,
|
|
1432
|
+
...item.type === "texture_cube" ? {
|
|
1433
|
+
viewDimension: "cube"
|
|
1434
|
+
} : {
|
|
1435
|
+
viewDimension: "2d"
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
};
|
|
1439
|
+
entries.push(opt);
|
|
1360
1440
|
entries.push({
|
|
1361
1441
|
binding: item.binding + 1,
|
|
1362
|
-
visibility: GPUShaderStage.FRAGMENT,
|
|
1442
|
+
visibility: GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE,
|
|
1363
1443
|
sampler: {}
|
|
1364
1444
|
});
|
|
1365
1445
|
});
|
|
@@ -1367,7 +1447,7 @@ class ShaderMaterial {
|
|
|
1367
1447
|
const item = this._storageUniforms[key2];
|
|
1368
1448
|
entries.push({
|
|
1369
1449
|
binding: item.binding,
|
|
1370
|
-
visibility: item.write ? GPUShaderStage.FRAGMENT : GPUShaderStage.FRAGMENT | GPUShaderStage.VERTEX,
|
|
1450
|
+
visibility: (item.write ? GPUShaderStage.FRAGMENT : GPUShaderStage.FRAGMENT | GPUShaderStage.VERTEX) | GPUShaderStage.COMPUTE,
|
|
1371
1451
|
buffer: {
|
|
1372
1452
|
type: item.write ? "storage" : "read-only-storage"
|
|
1373
1453
|
}
|
|
@@ -1412,56 +1492,52 @@ class ShaderMaterial {
|
|
|
1412
1492
|
this.needsBindGroupUpdate = false;
|
|
1413
1493
|
}
|
|
1414
1494
|
/** 生成uniform 代码
|
|
1415
|
-
* @param
|
|
1495
|
+
* @param mtype
|
|
1416
1496
|
* @returns
|
|
1417
1497
|
*/
|
|
1418
|
-
_generateUniformWGSL(
|
|
1498
|
+
_generateUniformWGSL(mtype) {
|
|
1419
1499
|
let code = "";
|
|
1420
1500
|
if (Object.keys(this._bufferUniforms).length) {
|
|
1421
1501
|
code += "struct MaterialUniforms {\n";
|
|
1422
1502
|
for (const key in this._bufferUniforms) {
|
|
1423
|
-
const
|
|
1424
|
-
if (
|
|
1503
|
+
const type = this._bufferUniforms[key].type;
|
|
1504
|
+
if (type === "mat4")
|
|
1425
1505
|
code += ` ${key} : mat4x4<f32>,
|
|
1426
1506
|
`;
|
|
1427
|
-
else if (
|
|
1507
|
+
else if (type === "mat3")
|
|
1428
1508
|
code += ` ${key} : mat3x3<f32>,
|
|
1429
1509
|
`;
|
|
1430
|
-
else if (
|
|
1510
|
+
else if (type === "vec2")
|
|
1431
1511
|
code += ` ${key} : vec2<f32>,
|
|
1432
1512
|
`;
|
|
1433
|
-
else if (
|
|
1513
|
+
else if (type === "vec3")
|
|
1434
1514
|
code += ` ${key} : vec3<f32>,
|
|
1435
1515
|
`;
|
|
1436
|
-
else if (
|
|
1516
|
+
else if (type === "vec4")
|
|
1437
1517
|
code += ` ${key} : vec4<f32>,
|
|
1438
1518
|
`;
|
|
1439
|
-
else if (
|
|
1519
|
+
else if (type === "f32")
|
|
1440
1520
|
code += ` ${key} : f32,
|
|
1441
1521
|
`;
|
|
1442
1522
|
}
|
|
1443
1523
|
code += "};\n";
|
|
1444
|
-
code += ` @group(2) @binding(0) var<uniform> uniforms : MaterialUniforms;
|
|
1524
|
+
code += ` @group(2) @binding(0) var<uniform> uniforms : MaterialUniforms;
|
|
1525
|
+
`;
|
|
1445
1526
|
}
|
|
1446
|
-
if (
|
|
1527
|
+
if (mtype === "fragment" || mtype === "compute") {
|
|
1447
1528
|
for (const key in this._textureUniforms) {
|
|
1448
1529
|
const meta = this._textureUniforms[key];
|
|
1449
1530
|
const b = meta.binding;
|
|
1531
|
+
const format = meta.value?.texture?.format ?? "rgba8unorm";
|
|
1450
1532
|
if (meta.type === "texture_2d") {
|
|
1451
|
-
code += `
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
@group(2) @binding(${b + 1})
|
|
1455
|
-
var ${key}Sampler : sampler;
|
|
1456
|
-
`;
|
|
1533
|
+
code += `@group(2) @binding(${b})var ${key} : ${meta.write ? `texture_storage_2d<${format}, read_write>` : `texture_2d<f32>`};
|
|
1534
|
+
@group(2) @binding(${b + 1})var ${key}Sampler : sampler;
|
|
1535
|
+
`;
|
|
1457
1536
|
}
|
|
1458
1537
|
if (meta.type === "texture_cube") {
|
|
1459
|
-
code +=
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
@group(2) @binding(${b + 1})
|
|
1463
|
-
var ${key}Sampler : sampler;
|
|
1464
|
-
`;
|
|
1538
|
+
code += `@group(2) @binding(${b})var ${key} : texture_cube<f32>;
|
|
1539
|
+
@group(2) @binding(${b + 1})var ${key}Sampler : sampler;
|
|
1540
|
+
`;
|
|
1465
1541
|
}
|
|
1466
1542
|
}
|
|
1467
1543
|
}
|
|
@@ -1473,7 +1549,7 @@ class ShaderMaterial {
|
|
|
1473
1549
|
*/
|
|
1474
1550
|
_generateVertexInputWGSL(attrMap) {
|
|
1475
1551
|
if (!attrMap.size) return "";
|
|
1476
|
-
let code = `struct VertexInput {
|
|
1552
|
+
let code = `struct VertexInput { @builtin(vertex_index) vertexId: u32,`;
|
|
1477
1553
|
attrMap.forEach((v, name) => code += `@location(${v.shaderLocation}) ${name}: ${vertexFormatToWGSL[v.format]}, `);
|
|
1478
1554
|
code += `};`;
|
|
1479
1555
|
return code;
|
|
@@ -1514,13 +1590,13 @@ class ShaderMaterial {
|
|
|
1514
1590
|
this.pipeline = pipelineCache.get(key);
|
|
1515
1591
|
return this.pipeline;
|
|
1516
1592
|
}
|
|
1517
|
-
const
|
|
1518
|
-
for (const key2 of attrMap.keys())
|
|
1593
|
+
const define = { ...this.define };
|
|
1594
|
+
for (const key2 of attrMap.keys()) define[key2] = true;
|
|
1519
1595
|
const moduleVertex = device2.createShaderModule({
|
|
1520
|
-
code: `${this._generateUniformWGSL("vertex")} ${this._generateStorageWGSL("vertex")} ${this._generateVertexInputWGSL(attrMap)} ${preprocessShaderFSM(this.vertex,
|
|
1596
|
+
code: `${vertexCommon} ${this._generateUniformWGSL("vertex")} ${this._generateStorageWGSL("vertex")} ${this._generateVertexInputWGSL(attrMap)} ${preprocessShaderFSM(this.vertex, define)}`
|
|
1521
1597
|
});
|
|
1522
1598
|
const moduleFragment = device2.createShaderModule({
|
|
1523
|
-
code: `${this._generateUniformWGSL("fragment")} ${this._generateStorageWGSL("fragment")} ${preprocessShaderFSM(this.fragment,
|
|
1599
|
+
code: `${this._generateUniformWGSL("fragment")} ${this._generateStorageWGSL("fragment")} ${preprocessShaderFSM(this.fragment, define)}`
|
|
1524
1600
|
});
|
|
1525
1601
|
const pipeline = device2.createRenderPipeline({
|
|
1526
1602
|
layout: device2.createPipelineLayout({
|
|
@@ -1538,11 +1614,13 @@ class ShaderMaterial {
|
|
|
1538
1614
|
fragment: {
|
|
1539
1615
|
module: moduleFragment,
|
|
1540
1616
|
entryPoint: "main",
|
|
1541
|
-
targets: [
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1617
|
+
targets: [
|
|
1618
|
+
{
|
|
1619
|
+
format: colorFormat,
|
|
1620
|
+
blend: this.blend,
|
|
1621
|
+
writeMask: this.writeMask
|
|
1622
|
+
}
|
|
1623
|
+
]
|
|
1546
1624
|
},
|
|
1547
1625
|
primitive: {
|
|
1548
1626
|
topology: this.topology,
|
|
@@ -1564,53 +1642,55 @@ class ShaderMaterial {
|
|
|
1564
1642
|
*/
|
|
1565
1643
|
_updateUniform() {
|
|
1566
1644
|
const device2 = getDevice();
|
|
1645
|
+
const align = (offset2, alignmentBytes) => {
|
|
1646
|
+
const alignment = alignmentBytes / 4;
|
|
1647
|
+
return offset2 + alignment - 1 & ~(alignment - 1);
|
|
1648
|
+
};
|
|
1567
1649
|
let offset = 0;
|
|
1568
|
-
const align4 = (n) => n + 3 & -4;
|
|
1569
1650
|
for (const key in this._bufferUniforms) {
|
|
1570
1651
|
const value = this._bufferUniforms[key].value;
|
|
1571
|
-
offset = align4(offset);
|
|
1572
1652
|
if (typeof value === "number") {
|
|
1653
|
+
offset = align(offset, 4);
|
|
1573
1654
|
this.uniformArray[offset++] = value;
|
|
1574
1655
|
continue;
|
|
1575
1656
|
}
|
|
1576
1657
|
if (value instanceof Vector2) {
|
|
1658
|
+
offset = align(offset, 8);
|
|
1577
1659
|
this.uniformArray.set([value.x, value.y], offset);
|
|
1578
1660
|
offset += 2;
|
|
1579
1661
|
continue;
|
|
1580
1662
|
}
|
|
1581
1663
|
if (value instanceof Vector3) {
|
|
1582
|
-
|
|
1583
|
-
|
|
1664
|
+
offset = align(offset, 16);
|
|
1665
|
+
this.uniformArray.set([value.x, value.y, value.z, 0], offset);
|
|
1666
|
+
offset += 4;
|
|
1584
1667
|
continue;
|
|
1585
1668
|
}
|
|
1586
1669
|
if (value instanceof Vector4) {
|
|
1670
|
+
offset = align(offset, 16);
|
|
1587
1671
|
this.uniformArray.set([value.x, value.y, value.z, value.w], offset);
|
|
1588
1672
|
offset += 4;
|
|
1589
1673
|
continue;
|
|
1590
1674
|
}
|
|
1591
1675
|
if (value.isColor) {
|
|
1676
|
+
offset = align(offset, 16);
|
|
1592
1677
|
const c = value;
|
|
1593
|
-
this.uniformArray[
|
|
1594
|
-
|
|
1595
|
-
this.uniformArray[offset++] = c.b;
|
|
1678
|
+
this.uniformArray.set([c.r, c.g, c.b, 0], offset);
|
|
1679
|
+
offset += 4;
|
|
1596
1680
|
continue;
|
|
1597
1681
|
}
|
|
1598
1682
|
if (value.isMatrix4) {
|
|
1683
|
+
offset = align(offset, 16);
|
|
1599
1684
|
this.uniformArray.set(value.elements, offset);
|
|
1600
1685
|
offset += 16;
|
|
1601
1686
|
continue;
|
|
1602
1687
|
}
|
|
1603
1688
|
if (value.isMatrix3) {
|
|
1689
|
+
offset = align(offset, 16);
|
|
1604
1690
|
const m = value.elements;
|
|
1605
|
-
this.uniformArray[
|
|
1606
|
-
this.uniformArray[
|
|
1607
|
-
this.uniformArray[
|
|
1608
|
-
this.uniformArray[offset + 4] = m[3];
|
|
1609
|
-
this.uniformArray[offset + 5] = m[4];
|
|
1610
|
-
this.uniformArray[offset + 6] = m[5];
|
|
1611
|
-
this.uniformArray[offset + 8] = m[6];
|
|
1612
|
-
this.uniformArray[offset + 9] = m[7];
|
|
1613
|
-
this.uniformArray[offset + 10] = m[8];
|
|
1691
|
+
this.uniformArray.set([m[0], m[1], m[2], 0], offset + 0);
|
|
1692
|
+
this.uniformArray.set([m[3], m[4], m[5], 0], offset + 4);
|
|
1693
|
+
this.uniformArray.set([m[6], m[7], m[8], 0], offset + 8);
|
|
1614
1694
|
offset += 12;
|
|
1615
1695
|
continue;
|
|
1616
1696
|
}
|
|
@@ -1629,6 +1709,16 @@ class ShaderMaterial {
|
|
|
1629
1709
|
getStorageBuffer(name) {
|
|
1630
1710
|
return this._storageUniforms[name]?.buffer;
|
|
1631
1711
|
}
|
|
1712
|
+
/** 主动设置GPUBuffer, 可共享其他材质已经创建的 GPUBuffer
|
|
1713
|
+
* @param name
|
|
1714
|
+
* @param buff
|
|
1715
|
+
*/
|
|
1716
|
+
setStorageBuffer(name, buff) {
|
|
1717
|
+
if (this._storageUniforms[name]) {
|
|
1718
|
+
this._storageUniforms[name].buffer = buff;
|
|
1719
|
+
this.needsBindGroupUpdate = true;
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1632
1722
|
}
|
|
1633
1723
|
const transparentOption = {
|
|
1634
1724
|
blend: {
|
|
@@ -1708,167 +1798,53 @@ class BaseMaterial extends ShaderMaterial {
|
|
|
1708
1798
|
});
|
|
1709
1799
|
}
|
|
1710
1800
|
}
|
|
1711
|
-
class
|
|
1712
|
-
|
|
1801
|
+
class ComputeMaterial extends ShaderMaterial {
|
|
1802
|
+
workgroupCount;
|
|
1803
|
+
workgroupSize;
|
|
1804
|
+
constructor(opt) {
|
|
1713
1805
|
super({
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
struct VertexOutput {
|
|
1718
|
-
@builtin(position) Position : vec4<f32>,
|
|
1719
|
-
@location(0) worldDir: vec3<f32>,
|
|
1720
|
-
@location(1) near: f32,
|
|
1721
|
-
@location(2) far: f32,
|
|
1722
|
-
};
|
|
1723
|
-
|
|
1724
|
-
@vertex
|
|
1725
|
-
fn main(input: VertexInput) -> VertexOutput {
|
|
1726
|
-
var out: VertexOutput;
|
|
1727
|
-
let worldPos = object.modelMatrix * vec4<f32>(input.position, 1.0);
|
|
1728
|
-
|
|
1729
|
-
out.Position = camera.viewProjection * worldPos;
|
|
1730
|
-
out.worldDir = worldPos.xyz - camera.position;
|
|
1731
|
-
out.near = camera.near;
|
|
1732
|
-
out.far = camera.far;
|
|
1733
|
-
|
|
1734
|
-
return out;
|
|
1735
|
-
}
|
|
1736
|
-
`
|
|
1737
|
-
),
|
|
1738
|
-
fragment: (
|
|
1739
|
-
/* wgsl */
|
|
1740
|
-
`
|
|
1741
|
-
fn packDepth(v: f32) -> vec4<f32> {
|
|
1742
|
-
var bitShift: vec4<f32> = vec4<f32>( 256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0 );
|
|
1743
|
-
var bitMask: vec4<f32> = vec4<f32>( 0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0 );
|
|
1744
|
-
var res: vec4<f32> = fract(v * bitShift);
|
|
1745
|
-
res -= res.xxyz * bitMask;
|
|
1746
|
-
return res;
|
|
1747
|
-
}
|
|
1748
|
-
|
|
1749
|
-
@fragment
|
|
1750
|
-
fn main(
|
|
1751
|
-
@location(0) worldDir: vec3<f32>,
|
|
1752
|
-
@location(1) near: f32,
|
|
1753
|
-
@location(2) far: f32
|
|
1754
|
-
) -> @location(0) vec4<f32> {
|
|
1755
|
-
var depth = length(worldDir);
|
|
1756
|
-
depth = (depth - near) / (far - near);
|
|
1757
|
-
depth = clamp(depth, 0.0, 1.0);
|
|
1758
|
-
return packDepth(depth);
|
|
1759
|
-
}
|
|
1760
|
-
`
|
|
1761
|
-
),
|
|
1762
|
-
side: opt.side ?? "none",
|
|
1763
|
-
topology: opt.topology ?? "triangle-list",
|
|
1764
|
-
depthStencil: {
|
|
1765
|
-
depthWriteEnabled: true,
|
|
1766
|
-
depthCompare: "greater"
|
|
1767
|
-
}
|
|
1806
|
+
...opt,
|
|
1807
|
+
vertex: opt.mainCode,
|
|
1808
|
+
fragment: opt.beforeCcde ?? ""
|
|
1768
1809
|
});
|
|
1810
|
+
this.workgroupCount = opt.workgroupCount ?? [256];
|
|
1811
|
+
this.workgroupSize = opt.workgroupSize ?? [1, 1, 1];
|
|
1812
|
+
if (opt.maxSize) {
|
|
1813
|
+
const { workgroupCount, workgroupSize } = autoWorkgroup(opt.maxSize);
|
|
1814
|
+
this.workgroupCount = workgroupCount;
|
|
1815
|
+
this.workgroupSize = workgroupSize;
|
|
1816
|
+
}
|
|
1769
1817
|
}
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
@location(2) far: f32,
|
|
1782
|
-
@location(3) @interpolate(flat) vId: vec4<f32>,
|
|
1783
|
-
@location(4) @interpolate(flat) id: u32,
|
|
1784
|
-
};
|
|
1785
|
-
|
|
1786
|
-
fn packUint(v: u32) -> vec4<f32>{
|
|
1787
|
-
return vec4<f32>(
|
|
1788
|
-
f32(v & 255u),
|
|
1789
|
-
f32((v >> 8) & 255u),
|
|
1790
|
-
f32((v >> 16) & 255u),
|
|
1791
|
-
f32((v >> 24) & 255u)
|
|
1792
|
-
) / 255.0;
|
|
1793
|
-
}
|
|
1794
|
-
|
|
1795
|
-
@vertex
|
|
1796
|
-
fn main(input: VertexInput) -> VertexOutput {
|
|
1797
|
-
var out: VertexOutput;
|
|
1798
|
-
let worldPos = object.modelMatrix * vec4<f32>(input.position, 1.0);
|
|
1799
|
-
|
|
1800
|
-
out.Position = camera.viewProjection * worldPos;
|
|
1801
|
-
out.worldDir = worldPos.xyz - camera.position;
|
|
1802
|
-
out.near = camera.near;
|
|
1803
|
-
out.far = camera.far;
|
|
1804
|
-
out.vId = packUint( input.id );
|
|
1805
|
-
out.id = input.id;
|
|
1806
|
-
|
|
1807
|
-
return out;
|
|
1808
|
-
}
|
|
1809
|
-
`
|
|
1810
|
-
),
|
|
1811
|
-
fragment: (
|
|
1812
|
-
/* wgsl */
|
|
1813
|
-
`
|
|
1814
|
-
fn unpackDepth(v: vec4<f32>) -> f32 {
|
|
1815
|
-
var bitShift: vec4<f32> = vec4<f32>( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );
|
|
1816
|
-
return dot(v, 1.0 / bitShift);
|
|
1817
|
-
}
|
|
1818
|
-
|
|
1819
|
-
@fragment
|
|
1820
|
-
fn main(
|
|
1821
|
-
@location(0) worldDir: vec3<f32>,
|
|
1822
|
-
@location(1) near: f32,
|
|
1823
|
-
@location(2) far: f32,
|
|
1824
|
-
@location(3) @interpolate(flat) vId: vec4<f32>,
|
|
1825
|
-
@location(4) @interpolate(flat) id: u32
|
|
1826
|
-
) -> @location(0) vec4<f32> {
|
|
1827
|
-
var dist = length(worldDir);
|
|
1828
|
-
|
|
1829
|
-
// 偏移
|
|
1830
|
-
var diff = 0.1;
|
|
1831
|
-
|
|
1832
|
-
var dir = normalize(worldDir);
|
|
1833
|
-
dir.x = -dir.x;
|
|
1834
|
-
|
|
1835
|
-
var depthColor = textureSample(cubeTexture, cubeTextureSampler, dir);
|
|
1836
|
-
var maxDepth = unpackDepth( depthColor );
|
|
1837
|
-
var maxDist = maxDepth * (far - near) + near;
|
|
1838
|
-
|
|
1839
|
-
if(depthColor.a != 1.0 && maxDist - dist > diff) {
|
|
1840
|
-
atomicOr(&results[id], 1);
|
|
1841
|
-
return vId;
|
|
1842
|
-
}
|
|
1843
|
-
return vec4<f32>(0);
|
|
1818
|
+
setWorkgroupCount(workgroupCount) {
|
|
1819
|
+
this.workgroupCount = workgroupCount;
|
|
1820
|
+
}
|
|
1821
|
+
needsPipelineUpdate = true;
|
|
1822
|
+
createPipeline() {
|
|
1823
|
+
if (!this.needsPipelineUpdate) return;
|
|
1824
|
+
const device2 = getDevice(), uniformCode = this._generateUniformWGSL("compute"), storageCode = this._generateStorageWGSL("compute"), code = ` ${uniformCode} ${storageCode}
|
|
1825
|
+
${this.fragment}
|
|
1826
|
+
@compute @workgroup_size(${this.workgroupSize.join(",")})
|
|
1827
|
+
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
|
|
1828
|
+
${this.vertex}
|
|
1844
1829
|
}
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1830
|
+
`, shaderModule = device2.createShaderModule({ code });
|
|
1831
|
+
const { bindGroupLayout } = getNullBG();
|
|
1832
|
+
const groupLayout = this._getBindGroupLayout();
|
|
1833
|
+
this.pipeline = device2.createComputePipeline({
|
|
1834
|
+
layout: device2.createPipelineLayout({
|
|
1835
|
+
bindGroupLayouts: [bindGroupLayout, bindGroupLayout, groupLayout]
|
|
1836
|
+
}),
|
|
1837
|
+
compute: {
|
|
1838
|
+
module: shaderModule,
|
|
1839
|
+
entryPoint: "main"
|
|
1852
1840
|
}
|
|
1853
1841
|
});
|
|
1842
|
+
this.needsPipelineUpdate = false;
|
|
1843
|
+
return this.pipeline;
|
|
1854
1844
|
}
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
v & 255,
|
|
1859
|
-
v >> 8 & 255,
|
|
1860
|
-
v >> 16 & 255,
|
|
1861
|
-
v >> 24 & 255
|
|
1862
|
-
);
|
|
1863
|
-
return vec4.divideScalar(255);
|
|
1864
|
-
}
|
|
1865
|
-
static unpackUint(r, g, b, a) {
|
|
1866
|
-
return (r | g << 8 | b << 16 | a << 24) >>> 0;
|
|
1867
|
-
}
|
|
1868
|
-
static unpackUintByUint8(buff, i) {
|
|
1869
|
-
const r = buff[i * 4], g = buff[i * 4 + 1], b = buff[i * 4 + 2], a = buff[i * 4 + 3];
|
|
1870
|
-
if ((r | g | b) === 0 && a === 255) return null;
|
|
1871
|
-
return this.unpackUint(r, g, b, a);
|
|
1845
|
+
update() {
|
|
1846
|
+
super.update();
|
|
1847
|
+
if (this.needsPipelineUpdate) this.createPipeline();
|
|
1872
1848
|
}
|
|
1873
1849
|
}
|
|
1874
1850
|
const directions = [
|
|
@@ -1955,6 +1931,11 @@ class Renderer {
|
|
|
1955
1931
|
format;
|
|
1956
1932
|
renderTarget = null;
|
|
1957
1933
|
depthTarget = null;
|
|
1934
|
+
/**
|
|
1935
|
+
* @param width
|
|
1936
|
+
* @param height
|
|
1937
|
+
* @param format
|
|
1938
|
+
*/
|
|
1958
1939
|
constructor(width = 800, height = 800, format = navigator.gpu.getPreferredCanvasFormat()) {
|
|
1959
1940
|
const device2 = getDevice();
|
|
1960
1941
|
this.format = format;
|
|
@@ -1977,6 +1958,12 @@ class Renderer {
|
|
|
1977
1958
|
});
|
|
1978
1959
|
this.depthTextureView = this.depthTexture.createView();
|
|
1979
1960
|
}
|
|
1961
|
+
/** 渲染
|
|
1962
|
+
* @param meshList
|
|
1963
|
+
* @param camera
|
|
1964
|
+
* @param depthClearValue
|
|
1965
|
+
* @returns
|
|
1966
|
+
*/
|
|
1980
1967
|
render(meshList, camera, depthClearValue = 1) {
|
|
1981
1968
|
const device2 = getDevice();
|
|
1982
1969
|
camera.update();
|
|
@@ -2001,8 +1988,8 @@ class Renderer {
|
|
|
2001
1988
|
meshList.forEach((mesh) => {
|
|
2002
1989
|
mesh.update(this.format);
|
|
2003
1990
|
pass.setPipeline(mesh.pipeline);
|
|
2004
|
-
pass.setBindGroup(
|
|
2005
|
-
pass.setBindGroup(
|
|
1991
|
+
pass.setBindGroup(Object3D.GROU_INDEX, mesh.bindGroup);
|
|
1992
|
+
pass.setBindGroup(ShaderMaterial.GROU_INDEX, mesh.material.bindGroup);
|
|
2006
1993
|
let index = 0;
|
|
2007
1994
|
mesh.geometry.gpuAttributes.forEach((v) => {
|
|
2008
1995
|
pass.setVertexBuffer(index, v.buffer);
|
|
@@ -2018,6 +2005,24 @@ class Renderer {
|
|
|
2018
2005
|
pass.end();
|
|
2019
2006
|
device2.queue.submit([encoder.finish()]);
|
|
2020
2007
|
}
|
|
2008
|
+
compute(materials) {
|
|
2009
|
+
if (materials instanceof ComputeMaterial) materials = [materials];
|
|
2010
|
+
const device2 = getDevice();
|
|
2011
|
+
const encoder = device2.createCommandEncoder();
|
|
2012
|
+
const pass = encoder.beginComputePass();
|
|
2013
|
+
const { bindGroup } = getNullBG();
|
|
2014
|
+
pass.setBindGroup(0, bindGroup);
|
|
2015
|
+
pass.setBindGroup(1, bindGroup);
|
|
2016
|
+
materials.forEach((material) => {
|
|
2017
|
+
material.update();
|
|
2018
|
+
pass.setPipeline(material.pipeline);
|
|
2019
|
+
pass.setBindGroup(ShaderMaterial.GROU_INDEX, material.bindGroup);
|
|
2020
|
+
const workgroupCount = material.workgroupCount;
|
|
2021
|
+
pass.dispatchWorkgroups(workgroupCount[0], workgroupCount[1], workgroupCount[2]);
|
|
2022
|
+
});
|
|
2023
|
+
pass.end();
|
|
2024
|
+
device2.queue.submit([encoder.finish()]);
|
|
2025
|
+
}
|
|
2021
2026
|
}
|
|
2022
2027
|
class PCD {
|
|
2023
2028
|
header;
|
|
@@ -2206,52 +2211,231 @@ async function trajectoryHandle(baseUrl, trajectoryData) {
|
|
|
2206
2211
|
pointCloudArray
|
|
2207
2212
|
};
|
|
2208
2213
|
}
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
rectArray,
|
|
2219
|
-
indexArray,
|
|
2220
|
-
linesJson
|
|
2221
|
-
};
|
|
2214
|
+
function getPointsCenter(arr) {
|
|
2215
|
+
let x = 0, y = 0, z = 0;
|
|
2216
|
+
for (let i = 0; i < arr.length; i += 3) {
|
|
2217
|
+
x += arr[i];
|
|
2218
|
+
y += arr[i + 1];
|
|
2219
|
+
z += arr[i + 2];
|
|
2220
|
+
}
|
|
2221
|
+
const count = arr.length / 3;
|
|
2222
|
+
return { x: x / count, y: y / count, z: z / count };
|
|
2222
2223
|
}
|
|
2223
|
-
|
|
2224
|
-
const
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2224
|
+
function getPointDistance(p1, p2) {
|
|
2225
|
+
const dx = p2.x - p1.x;
|
|
2226
|
+
const dy = p2.y - p1.y;
|
|
2227
|
+
const dz = p2.z - p1.z;
|
|
2228
|
+
return Math.sqrt(dx * dx + dy * dy + dz * dz);
|
|
2229
|
+
}
|
|
2230
|
+
class OcclusionMaterial extends ShaderMaterial {
|
|
2231
|
+
constructor(opt) {
|
|
2232
|
+
super({
|
|
2233
|
+
vertex: (
|
|
2234
|
+
/* wgsl */
|
|
2235
|
+
`
|
|
2236
|
+
struct VertexOutput {
|
|
2237
|
+
@builtin(position) Position : vec4<f32>,
|
|
2238
|
+
@location(0) worldDir: vec3<f32>,
|
|
2239
|
+
@location(1) near: f32,
|
|
2240
|
+
@location(2) far: f32,
|
|
2241
|
+
@location(3) @interpolate(flat) vId: vec4<f32>,
|
|
2242
|
+
@location(4) @interpolate(flat) id: u32,
|
|
2243
|
+
};
|
|
2244
|
+
|
|
2245
|
+
fn packUint(v: u32) -> vec4<f32>{
|
|
2246
|
+
return vec4<f32>(
|
|
2247
|
+
f32(v & 255u),
|
|
2248
|
+
f32((v >> 8) & 255u),
|
|
2249
|
+
f32((v >> 16) & 255u),
|
|
2250
|
+
f32((v >> 24) & 255u)
|
|
2251
|
+
) / 255.0;
|
|
2252
|
+
}
|
|
2253
|
+
|
|
2254
|
+
@vertex
|
|
2255
|
+
fn main(input: VertexInput) -> VertexOutput {
|
|
2256
|
+
var out: VertexOutput;
|
|
2257
|
+
let worldPos = object.modelMatrix * vec4<f32>(input.position, 1.0);
|
|
2258
|
+
|
|
2259
|
+
out.Position = camera.viewProjection * worldPos;
|
|
2260
|
+
out.worldDir = worldPos.xyz - camera.position;
|
|
2261
|
+
out.near = camera.near;
|
|
2262
|
+
out.far = camera.far;
|
|
2263
|
+
out.vId = packUint( input.id );
|
|
2264
|
+
out.id = input.id;
|
|
2265
|
+
|
|
2266
|
+
return out;
|
|
2267
|
+
}
|
|
2268
|
+
`
|
|
2269
|
+
),
|
|
2270
|
+
fragment: (
|
|
2271
|
+
/* wgsl */
|
|
2272
|
+
`
|
|
2273
|
+
fn unpackDepth(v: vec4<f32>) -> f32 {
|
|
2274
|
+
var bitShift: vec4<f32> = vec4<f32>( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );
|
|
2275
|
+
return dot(v, 1.0 / bitShift);
|
|
2276
|
+
}
|
|
2277
|
+
|
|
2278
|
+
@fragment
|
|
2279
|
+
fn main(
|
|
2280
|
+
@location(0) worldDir: vec3<f32>,
|
|
2281
|
+
@location(1) near: f32,
|
|
2282
|
+
@location(2) far: f32,
|
|
2283
|
+
@location(3) @interpolate(flat) vId: vec4<f32>,
|
|
2284
|
+
@location(4) @interpolate(flat) id: u32
|
|
2285
|
+
) -> @location(0) vec4<f32> {
|
|
2286
|
+
var dist = length(worldDir);
|
|
2287
|
+
|
|
2288
|
+
// 偏移
|
|
2289
|
+
var diff = 0.1;
|
|
2290
|
+
|
|
2291
|
+
var dir = normalize(worldDir);
|
|
2292
|
+
dir.x = -dir.x;
|
|
2293
|
+
|
|
2294
|
+
var depthColor = textureSample(cubeTexture, cubeTextureSampler, dir);
|
|
2295
|
+
var maxDepth = unpackDepth( depthColor );
|
|
2296
|
+
var maxDist = maxDepth * (far - near) + near;
|
|
2297
|
+
|
|
2298
|
+
if(depthColor.a != 1.0 && maxDist - dist > diff) {
|
|
2299
|
+
atomicOr(&results[id], 1);
|
|
2300
|
+
return vId;
|
|
2301
|
+
}
|
|
2302
|
+
return vec4<f32>(0);
|
|
2303
|
+
}
|
|
2304
|
+
`
|
|
2305
|
+
),
|
|
2306
|
+
side: opt.side ?? "none",
|
|
2307
|
+
topology: opt.topology ?? "triangle-list",
|
|
2308
|
+
uniforms: {
|
|
2309
|
+
cubeTexture: { value: opt.cubeTexture },
|
|
2310
|
+
results: { value: opt.results ?? new Uint32Array([0, 0, 0]), write: true, atomic: true }
|
|
2311
|
+
}
|
|
2312
|
+
});
|
|
2313
|
+
}
|
|
2314
|
+
static packUint(v) {
|
|
2315
|
+
const vec4 = new Vector4();
|
|
2316
|
+
vec4.set(
|
|
2317
|
+
v & 255,
|
|
2318
|
+
v >> 8 & 255,
|
|
2319
|
+
v >> 16 & 255,
|
|
2320
|
+
v >> 24 & 255
|
|
2321
|
+
);
|
|
2322
|
+
return vec4.divideScalar(255);
|
|
2323
|
+
}
|
|
2324
|
+
static unpackUint(r, g, b, a) {
|
|
2325
|
+
return (r | g << 8 | b << 16 | a << 24) >>> 0;
|
|
2326
|
+
}
|
|
2327
|
+
static unpackUintByUint8(buff, i) {
|
|
2328
|
+
const r = buff[i * 4], g = buff[i * 4 + 1], b = buff[i * 4 + 2], a = buff[i * 4 + 3];
|
|
2329
|
+
if ((r | g | b) === 0 && a === 255) return null;
|
|
2330
|
+
return this.unpackUint(r, g, b, a);
|
|
2331
|
+
}
|
|
2332
|
+
}
|
|
2333
|
+
class DepthMaterial extends ShaderMaterial {
|
|
2334
|
+
constructor(opt = {}) {
|
|
2335
|
+
super({
|
|
2336
|
+
vertex: (
|
|
2337
|
+
/* wgsl */
|
|
2338
|
+
`
|
|
2339
|
+
struct VertexOutput {
|
|
2340
|
+
@builtin(position) Position : vec4<f32>,
|
|
2341
|
+
@location(0) worldDir: vec3<f32>,
|
|
2342
|
+
@location(1) near: f32,
|
|
2343
|
+
@location(2) far: f32,
|
|
2344
|
+
};
|
|
2345
|
+
|
|
2346
|
+
@vertex
|
|
2347
|
+
fn main(input: VertexInput) -> VertexOutput {
|
|
2348
|
+
var out: VertexOutput;
|
|
2349
|
+
let worldPos = object.modelMatrix * vec4<f32>(input.position, 1.0);
|
|
2350
|
+
|
|
2351
|
+
out.Position = camera.viewProjection * worldPos;
|
|
2352
|
+
out.worldDir = worldPos.xyz - camera.position;
|
|
2353
|
+
out.near = camera.near;
|
|
2354
|
+
out.far = camera.far;
|
|
2355
|
+
|
|
2356
|
+
return out;
|
|
2357
|
+
}
|
|
2358
|
+
`
|
|
2359
|
+
),
|
|
2360
|
+
fragment: (
|
|
2361
|
+
/* wgsl */
|
|
2362
|
+
`
|
|
2363
|
+
fn packDepth(v: f32) -> vec4<f32> {
|
|
2364
|
+
var bitShift: vec4<f32> = vec4<f32>( 256.0*256.0*256.0, 256.0*256.0, 256.0, 1.0 );
|
|
2365
|
+
var bitMask: vec4<f32> = vec4<f32>( 0.0, 1.0/256.0, 1.0/256.0, 1.0/256.0 );
|
|
2366
|
+
var res: vec4<f32> = fract(v * bitShift);
|
|
2367
|
+
res -= res.xxyz * bitMask;
|
|
2368
|
+
return res;
|
|
2369
|
+
}
|
|
2370
|
+
|
|
2371
|
+
@fragment
|
|
2372
|
+
fn main(
|
|
2373
|
+
@location(0) worldDir: vec3<f32>,
|
|
2374
|
+
@location(1) near: f32,
|
|
2375
|
+
@location(2) far: f32
|
|
2376
|
+
) -> @location(0) vec4<f32> {
|
|
2377
|
+
var depth = length(worldDir);
|
|
2378
|
+
depth = (depth - near) / (far - near);
|
|
2379
|
+
depth = clamp(depth, 0.0, 1.0);
|
|
2380
|
+
return packDepth(depth);
|
|
2381
|
+
}
|
|
2382
|
+
`
|
|
2383
|
+
),
|
|
2384
|
+
side: opt.side ?? "none",
|
|
2385
|
+
topology: opt.topology ?? "triangle-list",
|
|
2386
|
+
depthStencil: {
|
|
2387
|
+
depthWriteEnabled: true,
|
|
2388
|
+
depthCompare: "greater"
|
|
2389
|
+
}
|
|
2390
|
+
});
|
|
2391
|
+
}
|
|
2392
|
+
}
|
|
2393
|
+
async function loadData(base, linesJson_) {
|
|
2394
|
+
const t = performance.now();
|
|
2395
|
+
const trajectory = await loadTrajectory(base), { pointClouds, pointCloudArray, trajectoryList } = await trajectoryHandle(base, trajectory), linesJson = linesJson_ ?? await loadLines(base), { map, rectArray, indexArray } = linesToBuffer(linesJson);
|
|
2396
|
+
console.log("加载耗时", performance.now() - t);
|
|
2397
|
+
return {
|
|
2398
|
+
pointClouds,
|
|
2399
|
+
pointCloudArray,
|
|
2400
|
+
trajectoryList,
|
|
2401
|
+
map,
|
|
2402
|
+
rectArray,
|
|
2403
|
+
indexArray,
|
|
2404
|
+
linesJson
|
|
2405
|
+
};
|
|
2406
|
+
}
|
|
2407
|
+
async function obstacleDetection_(opt) {
|
|
2408
|
+
const {
|
|
2409
|
+
base,
|
|
2410
|
+
size = 512,
|
|
2411
|
+
near = 0.01,
|
|
2412
|
+
far = 100,
|
|
2413
|
+
canvasWidth = 1400,
|
|
2414
|
+
canvasHeight = 800,
|
|
2415
|
+
fov = 75,
|
|
2416
|
+
linesJson
|
|
2417
|
+
} = opt;
|
|
2418
|
+
let t = performance.now();
|
|
2419
|
+
const data = await loadData(base, linesJson), { indexArray, rectArray, trajectoryList, pointClouds, map } = data, renderer = new Renderer(canvasWidth, canvasHeight, "rgba8unorm"), camera = new PerspectiveCamera(fov, canvasWidth / canvasHeight, 1e-3, 100);
|
|
2420
|
+
console.log("数据加载耗时", performance.now() - t);
|
|
2421
|
+
t = performance.now();
|
|
2422
|
+
camera.up = new THREE.Vector3(0, 0, 1);
|
|
2423
|
+
camera.position.set(0, 0, 5);
|
|
2424
|
+
camera.lookAt(new THREE.Vector3(0, 0, 0));
|
|
2425
|
+
const depthCubeTexture = new CubeTexture(size, size, { needDepthTexture: true, format: "rgba8unorm", sampler: { minFilter: "nearest", magFilter: "nearest", mipmapFilter: "nearest" } }), resultCubeTexture = new CubeTexture(size, size, { needDepthTexture: true, format: "rgba8unorm", sampler: { minFilter: "nearest", magFilter: "nearest", mipmapFilter: "nearest" } }), cubeCamera = new CubeCamera(near, far), indexCount = indexArray.length / 6, quadObject3D = new Object3D(
|
|
2426
|
+
new BufferGeometry().setAttribute("position", new THREE.BufferAttribute(new Float32Array(rectArray), 3)).setAttribute("id", new THREE.Uint32BufferAttribute(new Uint32Array(indexArray), 1)),
|
|
2427
|
+
new OcclusionMaterial({
|
|
2428
|
+
cubeTexture: depthCubeTexture,
|
|
2429
|
+
results: new Uint32Array(indexCount)
|
|
2430
|
+
// indexCount 个 uint8
|
|
2431
|
+
})
|
|
2432
|
+
), pointsObject3D = new Object3D(
|
|
2433
|
+
new BufferGeometry().setAttribute("position", new THREE.BufferAttribute(new Float32Array(), 3)),
|
|
2434
|
+
new DepthMaterial({ topology: "point-list" })
|
|
2435
|
+
);
|
|
2436
|
+
for (let i = 0; i < trajectoryList.length; i++) {
|
|
2437
|
+
const trajectory = trajectoryList[i];
|
|
2438
|
+
pointsObject3D.geometry.setAttribute("position", new THREE.BufferAttribute(new Float32Array(pointClouds[i]), 3));
|
|
2255
2439
|
cubeCamera.setPosition(trajectory.x, trajectory.y, trajectory.z);
|
|
2256
2440
|
cubeCamera.depthClearValue = 0;
|
|
2257
2441
|
cubeCamera.render([pointsObject3D], renderer, depthCubeTexture);
|
|
@@ -2291,20 +2475,836 @@ const obstacleDetection = Object.assign(obstacleDetection_, {
|
|
|
2291
2475
|
return result;
|
|
2292
2476
|
}
|
|
2293
2477
|
});
|
|
2478
|
+
const vertexShader$1 = (
|
|
2479
|
+
/* wgsl*/
|
|
2480
|
+
`
|
|
2481
|
+
struct VertexOutput {
|
|
2482
|
+
@builtin(position) Position : vec4<f32>,
|
|
2483
|
+
@location(0) vId: vec4<f32>,
|
|
2484
|
+
@location(1) z: f32
|
|
2485
|
+
};
|
|
2486
|
+
|
|
2487
|
+
fn packUint(v: u32) -> vec4<f32> {
|
|
2488
|
+
return vec4(
|
|
2489
|
+
f32(v & 255u),
|
|
2490
|
+
f32((v >> 8) & 255u),
|
|
2491
|
+
f32((v >> 16) & 255u),
|
|
2492
|
+
f32((v >> 24) & 255u)
|
|
2493
|
+
) / 255.0;
|
|
2494
|
+
}
|
|
2495
|
+
|
|
2496
|
+
@vertex
|
|
2497
|
+
fn main(input: VertexInput) -> VertexOutput {
|
|
2498
|
+
var out: VertexOutput;
|
|
2499
|
+
|
|
2500
|
+
if(uniforms.groundZ > input.position.z) {
|
|
2501
|
+
out.Position = vec4(2.0, 2.0, 2.0, 1.0);
|
|
2502
|
+
return out;
|
|
2503
|
+
}
|
|
2504
|
+
|
|
2505
|
+
var worldPos = object.modelMatrix * vec4(input.position, 1.0);
|
|
2506
|
+
|
|
2507
|
+
// world -> camera
|
|
2508
|
+
var camPos = (uniforms.T_cw * worldPos).xyz;
|
|
2509
|
+
|
|
2510
|
+
if (camPos.z <= 0.1) {
|
|
2511
|
+
out.Position = vec4(2.0, 2.0, 2.0, 1.0);
|
|
2512
|
+
return out;
|
|
2513
|
+
}
|
|
2514
|
+
|
|
2515
|
+
// 投影
|
|
2516
|
+
var uvw = uniforms.cameraMat * camPos;
|
|
2517
|
+
|
|
2518
|
+
var uv = uvw.xy / uvw.z;
|
|
2519
|
+
|
|
2520
|
+
// 像素 -> NDC
|
|
2521
|
+
var x = (uv.x / uniforms.imageSize.x) * 2.0 - 1.0;
|
|
2522
|
+
var y = 1.0 - (uv.y / uniforms.imageSize.y) * 2.0;
|
|
2523
|
+
|
|
2524
|
+
out.Position = vec4(x, y, camPos.z * 0.000001, 1.0);
|
|
2525
|
+
|
|
2526
|
+
out.vId = packUint( input.vertexId );
|
|
2527
|
+
out.z = camPos.z;
|
|
2528
|
+
|
|
2529
|
+
return out;
|
|
2530
|
+
}
|
|
2531
|
+
`
|
|
2532
|
+
);
|
|
2533
|
+
const fragmentShader$1 = (
|
|
2534
|
+
/* wgsl*/
|
|
2535
|
+
`
|
|
2536
|
+
fn floatToOrderedUint(v: f32) -> u32 {
|
|
2537
|
+
let u = bitcast<u32>(v);
|
|
2538
|
+
return select( u ^ 0xffffffffu, u, (u & 0x80000000u) == 0u );
|
|
2539
|
+
}
|
|
2540
|
+
|
|
2541
|
+
@fragment
|
|
2542
|
+
fn main(
|
|
2543
|
+
@builtin(position) fragCoord: vec4<f32>,
|
|
2544
|
+
@location(0) vId: vec4<f32>,
|
|
2545
|
+
@location(1) z: f32
|
|
2546
|
+
) -> @location(0) vec4<f32> {
|
|
2547
|
+
let x: u32 = u32(fragCoord.x);
|
|
2548
|
+
let y: u32 = u32(fragCoord.y);
|
|
2549
|
+
let width: u32 = u32(uniforms.imageSize.x);
|
|
2550
|
+
let offset = y * width + x;
|
|
2551
|
+
|
|
2552
|
+
let currz = floatToOrderedUint(z);
|
|
2553
|
+
|
|
2554
|
+
atomicMin(&depth[offset], currz);
|
|
2555
|
+
return vId;
|
|
2556
|
+
}
|
|
2557
|
+
`
|
|
2558
|
+
);
|
|
2559
|
+
class PointCloudsIndexMaterial extends ShaderMaterial {
|
|
2560
|
+
resultTexture;
|
|
2561
|
+
_depthU32;
|
|
2562
|
+
constructor(width, height) {
|
|
2563
|
+
const resultTexture = new Texture(width, height, { needDepthTexture: true, format: "rgba8unorm" });
|
|
2564
|
+
const depthU32 = new Uint32Array(width * height).fill(4294967295);
|
|
2565
|
+
super({
|
|
2566
|
+
vertex: vertexShader$1,
|
|
2567
|
+
fragment: fragmentShader$1,
|
|
2568
|
+
side: "none",
|
|
2569
|
+
uniforms: {
|
|
2570
|
+
cameraMat: { value: new Matrix3() },
|
|
2571
|
+
T_cw: { value: new Matrix4() },
|
|
2572
|
+
imageSize: { value: new Vector2(width, height) },
|
|
2573
|
+
groundZ: { value: -0.911335763281652 + 0.1 },
|
|
2574
|
+
depth: { value: depthU32, write: true, atomic: true }
|
|
2575
|
+
},
|
|
2576
|
+
topology: "point-list"
|
|
2577
|
+
});
|
|
2578
|
+
this.resultTexture = resultTexture;
|
|
2579
|
+
this._depthU32 = depthU32;
|
|
2580
|
+
}
|
|
2581
|
+
clearDepth() {
|
|
2582
|
+
this.uniforms.depth.value = this._depthU32;
|
|
2583
|
+
}
|
|
2584
|
+
get cameraMat() {
|
|
2585
|
+
return this.uniforms.cameraMat.value;
|
|
2586
|
+
}
|
|
2587
|
+
set cameraMat(value) {
|
|
2588
|
+
this.uniforms.cameraMat.value = value;
|
|
2589
|
+
}
|
|
2590
|
+
get T_cw() {
|
|
2591
|
+
return this.uniforms.T_cw.value;
|
|
2592
|
+
}
|
|
2593
|
+
set T_cw(value) {
|
|
2594
|
+
this.uniforms.T_cw.value = value;
|
|
2595
|
+
}
|
|
2596
|
+
get imageSize() {
|
|
2597
|
+
return this.uniforms.imageSize.value;
|
|
2598
|
+
}
|
|
2599
|
+
set imageSize(value) {
|
|
2600
|
+
this.uniforms.imageSize.value = value;
|
|
2601
|
+
this.uniforms.depth.value = new Float32Array(value.x * value.y);
|
|
2602
|
+
}
|
|
2603
|
+
get groundZ() {
|
|
2604
|
+
return this.uniforms.groundZ.value;
|
|
2605
|
+
}
|
|
2606
|
+
set groundZ(value) {
|
|
2607
|
+
this.uniforms.groundZ.value = value;
|
|
2608
|
+
}
|
|
2609
|
+
}
|
|
2610
|
+
const vertexShader = (
|
|
2611
|
+
/* wgsl*/
|
|
2612
|
+
`
|
|
2613
|
+
struct VertexOutput {
|
|
2614
|
+
@builtin(position) Position : vec4<f32>,
|
|
2615
|
+
@location(0) vId: vec4<f32>
|
|
2616
|
+
};
|
|
2617
|
+
|
|
2618
|
+
fn packUint(v: u32) -> vec4<f32>{
|
|
2619
|
+
return vec4(
|
|
2620
|
+
f32(v & 255u),
|
|
2621
|
+
f32((v >> 8) & 255u),
|
|
2622
|
+
f32((v >> 16) & 255u),
|
|
2623
|
+
f32((v >> 24) & 255u)
|
|
2624
|
+
) / 255.0;
|
|
2625
|
+
}
|
|
2626
|
+
|
|
2627
|
+
@vertex
|
|
2628
|
+
fn main(input: VertexInput) -> VertexOutput {
|
|
2629
|
+
var out: VertexOutput;
|
|
2630
|
+
|
|
2631
|
+
// 像素 -> NDC
|
|
2632
|
+
var x = (input.position.x / uniforms.imageSize.x) * 2.0 - 1.0;
|
|
2633
|
+
var y = 1.0 - (input.position.y / uniforms.imageSize.y) * 2.0;
|
|
2634
|
+
|
|
2635
|
+
out.Position = vec4(x, y, 0, 1);
|
|
2636
|
+
out.vId = packUint(u32(input.position.z));
|
|
2637
|
+
|
|
2638
|
+
return out;
|
|
2639
|
+
}
|
|
2640
|
+
`
|
|
2641
|
+
);
|
|
2642
|
+
const fragmentShader = (
|
|
2643
|
+
/* wgsl*/
|
|
2644
|
+
`
|
|
2645
|
+
@fragment
|
|
2646
|
+
fn main(
|
|
2647
|
+
@location(0) vId: vec4<f32>,
|
|
2648
|
+
) -> @location(0) vec4<f32> {
|
|
2649
|
+
return vId;
|
|
2650
|
+
}
|
|
2651
|
+
`
|
|
2652
|
+
);
|
|
2653
|
+
class PolyAreaIndexMaterial extends ShaderMaterial {
|
|
2654
|
+
resultTexture;
|
|
2655
|
+
constructor(width = 1920, height = 1200) {
|
|
2656
|
+
const resultTexture = new Texture(width, height, { needDepthTexture: true, format: "rgba8unorm" });
|
|
2657
|
+
super({
|
|
2658
|
+
vertex: vertexShader,
|
|
2659
|
+
fragment: fragmentShader,
|
|
2660
|
+
side: "none",
|
|
2661
|
+
uniforms: {
|
|
2662
|
+
imageSize: { value: new Vector2(width, height) }
|
|
2663
|
+
}
|
|
2664
|
+
});
|
|
2665
|
+
this.resultTexture = resultTexture;
|
|
2666
|
+
}
|
|
2667
|
+
get imageSize() {
|
|
2668
|
+
return this.uniforms.imageSize.value;
|
|
2669
|
+
}
|
|
2670
|
+
set imageSize(value) {
|
|
2671
|
+
this.uniforms.imageSize.value = value;
|
|
2672
|
+
}
|
|
2673
|
+
}
|
|
2674
|
+
class MapEnhance extends Map {
|
|
2675
|
+
get valueArray() {
|
|
2676
|
+
return [...this.values()];
|
|
2677
|
+
}
|
|
2678
|
+
map(callbackfn) {
|
|
2679
|
+
const result = [];
|
|
2680
|
+
for (const [k, v] of this) {
|
|
2681
|
+
result.push(callbackfn(v, k));
|
|
2682
|
+
}
|
|
2683
|
+
return result;
|
|
2684
|
+
}
|
|
2685
|
+
filter(callbackfn) {
|
|
2686
|
+
const result = [];
|
|
2687
|
+
for (const [k, v] of this) {
|
|
2688
|
+
callbackfn(v, k) && result.push(v);
|
|
2689
|
+
}
|
|
2690
|
+
return result;
|
|
2691
|
+
}
|
|
2692
|
+
filterKey(callbackfn) {
|
|
2693
|
+
const result = [];
|
|
2694
|
+
for (const [k, v] of this) {
|
|
2695
|
+
callbackfn(v, k) && result.push(k);
|
|
2696
|
+
}
|
|
2697
|
+
return result;
|
|
2698
|
+
}
|
|
2699
|
+
reduce(callbackfn, result) {
|
|
2700
|
+
for (const [k, v] of this) {
|
|
2701
|
+
result = callbackfn(result, v, k);
|
|
2702
|
+
}
|
|
2703
|
+
return result;
|
|
2704
|
+
}
|
|
2705
|
+
some(callbackfn) {
|
|
2706
|
+
for (const [k, v] of this) {
|
|
2707
|
+
if (callbackfn(v, k)) return true;
|
|
2708
|
+
}
|
|
2709
|
+
return false;
|
|
2710
|
+
}
|
|
2711
|
+
every(callbackfn) {
|
|
2712
|
+
for (const [k, v] of this) {
|
|
2713
|
+
if (!callbackfn(v, k)) return false;
|
|
2714
|
+
}
|
|
2715
|
+
return true;
|
|
2716
|
+
}
|
|
2717
|
+
find(callbackfn) {
|
|
2718
|
+
for (const [k, v] of this) {
|
|
2719
|
+
if (callbackfn(v, k)) return v;
|
|
2720
|
+
}
|
|
2721
|
+
}
|
|
2722
|
+
findKey(callbackfn) {
|
|
2723
|
+
for (const [k, v] of this) {
|
|
2724
|
+
if (callbackfn(v, k)) return k;
|
|
2725
|
+
}
|
|
2726
|
+
}
|
|
2727
|
+
someKeys(keys) {
|
|
2728
|
+
return keys.some((key) => this.has(key));
|
|
2729
|
+
}
|
|
2730
|
+
everyKeys(keys) {
|
|
2731
|
+
return keys.every((key) => this.has(key));
|
|
2732
|
+
}
|
|
2733
|
+
group(callbackfn) {
|
|
2734
|
+
const map = new ArrayMap();
|
|
2735
|
+
for (const [k, v] of this) {
|
|
2736
|
+
const groupKey = callbackfn(v, k);
|
|
2737
|
+
map.append(groupKey, v);
|
|
2738
|
+
}
|
|
2739
|
+
return map;
|
|
2740
|
+
}
|
|
2741
|
+
toObject() {
|
|
2742
|
+
return this.reduce((obj, v, k) => (obj[`${k}`] = v, obj), {});
|
|
2743
|
+
}
|
|
2744
|
+
// 在 MapEnhance 裡面補充
|
|
2745
|
+
first() {
|
|
2746
|
+
return this.values().next().value;
|
|
2747
|
+
}
|
|
2748
|
+
firstKey() {
|
|
2749
|
+
return this.keys().next().value;
|
|
2750
|
+
}
|
|
2751
|
+
last() {
|
|
2752
|
+
let last;
|
|
2753
|
+
for (const v of this.values()) last = v;
|
|
2754
|
+
return last;
|
|
2755
|
+
}
|
|
2756
|
+
sortBy(callback) {
|
|
2757
|
+
return [...this.entries()].sort((a, b) => {
|
|
2758
|
+
const va = callback(a[1], a[0]);
|
|
2759
|
+
const vb = callback(b[1], b[0]);
|
|
2760
|
+
return va < vb ? -1 : va > vb ? 1 : 0;
|
|
2761
|
+
});
|
|
2762
|
+
}
|
|
2763
|
+
// 很常見的 collect / pluck 模式
|
|
2764
|
+
pluck(keyPath) {
|
|
2765
|
+
return this.map((v) => v[keyPath]);
|
|
2766
|
+
}
|
|
2767
|
+
}
|
|
2768
|
+
class ArrayMap extends MapEnhance {
|
|
2769
|
+
maxLength = Infinity;
|
|
2770
|
+
append(k, ...arr) {
|
|
2771
|
+
arr.forEach((v) => {
|
|
2772
|
+
if (!this.has(k)) this.set(k, []);
|
|
2773
|
+
const list = this.get(k);
|
|
2774
|
+
list.push(v);
|
|
2775
|
+
if (list.length > this.maxLength) {
|
|
2776
|
+
list.splice(0, list.length - this.maxLength);
|
|
2777
|
+
}
|
|
2778
|
+
});
|
|
2779
|
+
return this;
|
|
2780
|
+
}
|
|
2781
|
+
setLength(key, len) {
|
|
2782
|
+
const list = this.get(key);
|
|
2783
|
+
if (list) list.length = Math.max(0, len);
|
|
2784
|
+
}
|
|
2785
|
+
remove(k, ...arr) {
|
|
2786
|
+
const set = this.get(k);
|
|
2787
|
+
if (set) {
|
|
2788
|
+
arr.forEach((v) => set.splice(set.indexOf(v), 1));
|
|
2789
|
+
}
|
|
2790
|
+
return this;
|
|
2791
|
+
}
|
|
2792
|
+
// 在 ArrayMap 補充
|
|
2793
|
+
getOrCreate(key) {
|
|
2794
|
+
if (!this.has(key)) {
|
|
2795
|
+
this.set(key, []);
|
|
2796
|
+
}
|
|
2797
|
+
return this.get(key);
|
|
2798
|
+
}
|
|
2799
|
+
}
|
|
2800
|
+
class UnionFindSet {
|
|
2801
|
+
parent;
|
|
2802
|
+
rank;
|
|
2803
|
+
constructor(size) {
|
|
2804
|
+
this.parent = Array(size).fill(0).map((_, index) => index);
|
|
2805
|
+
this.rank = Array(size).fill(1);
|
|
2806
|
+
}
|
|
2807
|
+
// 查找操作,使用路径压缩优化
|
|
2808
|
+
find(x) {
|
|
2809
|
+
if (this.parent[x] !== x) {
|
|
2810
|
+
this.parent[x] = this.find(this.parent[x]);
|
|
2811
|
+
}
|
|
2812
|
+
return this.parent[x];
|
|
2813
|
+
}
|
|
2814
|
+
// 合并操作,使用按秩合并优化
|
|
2815
|
+
union(x, y) {
|
|
2816
|
+
let rootX = this.find(x);
|
|
2817
|
+
let rootY = this.find(y);
|
|
2818
|
+
if (rootX !== rootY) {
|
|
2819
|
+
if (this.rank[rootX] > this.rank[rootY]) {
|
|
2820
|
+
this.parent[rootY] = rootX;
|
|
2821
|
+
} else if (this.rank[rootX] < this.rank[rootY]) {
|
|
2822
|
+
this.parent[rootX] = rootY;
|
|
2823
|
+
} else {
|
|
2824
|
+
this.parent[rootY] = rootX;
|
|
2825
|
+
this.rank[rootX] += 1;
|
|
2826
|
+
}
|
|
2827
|
+
}
|
|
2828
|
+
}
|
|
2829
|
+
/** 获取所有集合
|
|
2830
|
+
* @returns
|
|
2831
|
+
*/
|
|
2832
|
+
getAllSets() {
|
|
2833
|
+
const sets = new ArrayMap();
|
|
2834
|
+
for (const el of this.parent.keys()) {
|
|
2835
|
+
const root = this.find(el);
|
|
2836
|
+
sets.append(root, el);
|
|
2837
|
+
}
|
|
2838
|
+
return sets;
|
|
2839
|
+
}
|
|
2840
|
+
}
|
|
2841
|
+
function hash(ix, iy, iz) {
|
|
2842
|
+
return ix * 73856093 ^ iy * 19349663 ^ iz * 83492791;
|
|
2843
|
+
}
|
|
2844
|
+
function voxelization(pointsArray, size = 0.05) {
|
|
2845
|
+
const inv = 1 / size, keySet = /* @__PURE__ */ new Set(), result = [], points = [];
|
|
2846
|
+
for (let i = 0; i < pointsArray.length; i += 3) {
|
|
2847
|
+
const xi = Math.floor(pointsArray[i] * inv), yi = Math.floor(pointsArray[i + 1] * inv), zi = Math.floor(pointsArray[i + 2] * inv), key = hash(xi, yi, zi);
|
|
2848
|
+
if (keySet.has(key)) continue;
|
|
2849
|
+
keySet.add(key);
|
|
2850
|
+
result.push(xi, yi, zi);
|
|
2851
|
+
points.push(pointsArray[i], pointsArray[i + 1], pointsArray[i + 2]);
|
|
2852
|
+
}
|
|
2853
|
+
return { result, keySet, points };
|
|
2854
|
+
}
|
|
2855
|
+
function gridClustering(pointsArray, size = 0.05, threshold = 2) {
|
|
2856
|
+
const { result, points, keySet } = voxelization(new Float32Array(pointsArray), size), unionFindSet = new UnionFindSet(keySet.size), keys = [...keySet.values()];
|
|
2857
|
+
const indexMap = /* @__PURE__ */ new Map();
|
|
2858
|
+
keys.forEach((v, i) => indexMap.set(v, i));
|
|
2859
|
+
keys.forEach((key, i) => {
|
|
2860
|
+
const x = result[i * 3];
|
|
2861
|
+
const y = result[i * 3 + 1];
|
|
2862
|
+
const z = result[i * 3 + 2];
|
|
2863
|
+
for (let i2 = -threshold; i2 <= threshold; i2++) {
|
|
2864
|
+
for (let j = -threshold; j <= threshold; j++) {
|
|
2865
|
+
for (let k = -threshold; k <= threshold; k++) {
|
|
2866
|
+
const xx = x + i2, yy = y + j, zz = z + k;
|
|
2867
|
+
if (xx === x && yy === y && zz === z) continue;
|
|
2868
|
+
const id = hash(xx, yy, zz);
|
|
2869
|
+
if (!keySet.has(id)) continue;
|
|
2870
|
+
unionFindSet.union(indexMap.get(key), indexMap.get(id));
|
|
2871
|
+
}
|
|
2872
|
+
}
|
|
2873
|
+
}
|
|
2874
|
+
});
|
|
2875
|
+
return unionFindSet.getAllSets().map(
|
|
2876
|
+
(list) => list.flatMap((i) => {
|
|
2877
|
+
const x = points[i * 3];
|
|
2878
|
+
const y = points[i * 3 + 1];
|
|
2879
|
+
const z = points[i * 3 + 2];
|
|
2880
|
+
return [x, y, z];
|
|
2881
|
+
})
|
|
2882
|
+
);
|
|
2883
|
+
}
|
|
2884
|
+
const beforeCcde$1 = (
|
|
2885
|
+
/* wgsl*/
|
|
2886
|
+
`
|
|
2887
|
+
fn packUint(v: u32) -> vec4<f32>{
|
|
2888
|
+
return vec4(
|
|
2889
|
+
f32(v & 255u),
|
|
2890
|
+
f32((v >> 8) & 255u),
|
|
2891
|
+
f32((v >> 16) & 255u),
|
|
2892
|
+
f32((v >> 24) & 255u)
|
|
2893
|
+
) / 255.0;
|
|
2894
|
+
}
|
|
2895
|
+
|
|
2896
|
+
fn unPackUint(color: vec4<f32>) -> u32 {
|
|
2897
|
+
let r = u32(color.r * 255.0);
|
|
2898
|
+
let g = u32(color.g * 255.0);
|
|
2899
|
+
let b = u32(color.b * 255.0);
|
|
2900
|
+
let a = u32(color.a * 255.0);
|
|
2901
|
+
return (a << 24u) | (b << 16u) | (g << 8u) | r;
|
|
2902
|
+
}
|
|
2903
|
+
|
|
2904
|
+
fn isEmpty(value: u32) -> bool {
|
|
2905
|
+
return value == 0xff000000 || value == 0x0 ;
|
|
2906
|
+
}
|
|
2907
|
+
`
|
|
2908
|
+
);
|
|
2909
|
+
const mainCode$1 = (
|
|
2910
|
+
/* wgsl*/
|
|
2911
|
+
`
|
|
2912
|
+
let width = i32(uniforms.size.x);
|
|
2913
|
+
let height = i32(uniforms.size.y);
|
|
2914
|
+
let half = i32(uniforms.kernelSize / 2);
|
|
2915
|
+
|
|
2916
|
+
let x = i32(id.x);
|
|
2917
|
+
let y = i32(id.y);
|
|
2918
|
+
|
|
2919
|
+
let idx = u32(y) * u32(width) + u32(x);
|
|
2920
|
+
|
|
2921
|
+
// 当前像素
|
|
2922
|
+
let center = unPackUint(textureLoad(map, vec2<i32>(x, y), 0));
|
|
2923
|
+
|
|
2924
|
+
// 如果当前就是空,直接空
|
|
2925
|
+
if ( isEmpty(center) ) {
|
|
2926
|
+
result[idx] = 0xff000000;
|
|
2927
|
+
return;
|
|
2928
|
+
}
|
|
2929
|
+
|
|
2930
|
+
// 是否被腐蚀
|
|
2931
|
+
var eroded = false;
|
|
2932
|
+
|
|
2933
|
+
// 遍历邻域
|
|
2934
|
+
for (var ky = -half; ky <= half; ky = ky + 1) {
|
|
2935
|
+
let ny = y + ky;
|
|
2936
|
+
|
|
2937
|
+
if (ny < 0 || ny >= height) {
|
|
2938
|
+
continue;
|
|
2939
|
+
}
|
|
2940
|
+
|
|
2941
|
+
for (var kx = -half; kx <= half; kx = kx + 1) {
|
|
2942
|
+
let nx = x + kx;
|
|
2943
|
+
|
|
2944
|
+
if (nx < 0 || nx >= width) {
|
|
2945
|
+
continue;
|
|
2946
|
+
}
|
|
2947
|
+
|
|
2948
|
+
let neighbor = unPackUint(textureLoad(map, vec2<i32>(nx, ny), 0));
|
|
2949
|
+
|
|
2950
|
+
// 只要有一个是空 → 腐蚀
|
|
2951
|
+
if (isEmpty(neighbor) || neighbor != center) {
|
|
2952
|
+
eroded = true;
|
|
2953
|
+
break;
|
|
2954
|
+
}
|
|
2955
|
+
}
|
|
2956
|
+
|
|
2957
|
+
if (eroded) {
|
|
2958
|
+
break;
|
|
2959
|
+
}
|
|
2960
|
+
}
|
|
2961
|
+
|
|
2962
|
+
// 写结果
|
|
2963
|
+
if (eroded) {
|
|
2964
|
+
result[idx] = 0xff000000;
|
|
2965
|
+
} else {
|
|
2966
|
+
result[idx] = center;
|
|
2967
|
+
}
|
|
2968
|
+
`
|
|
2969
|
+
);
|
|
2970
|
+
class ErodeMaskComputeMaterial extends ComputeMaterial {
|
|
2971
|
+
constructor(width = 1920, height = 1200, texture, kernelSize = 3) {
|
|
2972
|
+
super({
|
|
2973
|
+
maxSize: [width, height],
|
|
2974
|
+
mainCode: mainCode$1,
|
|
2975
|
+
beforeCcde: beforeCcde$1,
|
|
2976
|
+
uniforms: {
|
|
2977
|
+
map: { value: texture },
|
|
2978
|
+
size: { value: new Vector2(width, height) },
|
|
2979
|
+
kernelSize: { value: kernelSize },
|
|
2980
|
+
// 建议从3开始
|
|
2981
|
+
result: {
|
|
2982
|
+
value: new Uint32Array(width * height),
|
|
2983
|
+
write: true
|
|
2984
|
+
}
|
|
2985
|
+
}
|
|
2986
|
+
});
|
|
2987
|
+
}
|
|
2988
|
+
}
|
|
2989
|
+
const beforeCcde = (
|
|
2990
|
+
/* wgsl*/
|
|
2991
|
+
`
|
|
2992
|
+
// fn orderedUintToFloat(u: u32) -> f32 {
|
|
2993
|
+
// let mask = select(0x80000000u, 0xffffffffu, (u & 0x80000000u) != 0u);
|
|
2994
|
+
// return bitcast<f32>(u ^ mask);
|
|
2995
|
+
// }
|
|
2996
|
+
|
|
2997
|
+
fn orderedUintToFloat(u: u32) -> f32 {
|
|
2998
|
+
let restored = select(u ^ 0xffffffffu, u, (u & 0x80000000u) != 0u);
|
|
2999
|
+
return bitcast<f32>(restored);
|
|
3000
|
+
}
|
|
3001
|
+
|
|
3002
|
+
fn packUint(v: u32) -> vec4<f32>{
|
|
3003
|
+
return vec4(
|
|
3004
|
+
f32(v & 255u),
|
|
3005
|
+
f32((v >> 8) & 255u),
|
|
3006
|
+
f32((v >> 16) & 255u),
|
|
3007
|
+
f32((v >> 24) & 255u)
|
|
3008
|
+
) / 255.0;
|
|
3009
|
+
}
|
|
3010
|
+
|
|
3011
|
+
fn unPackUint(color: vec4<f32>) -> u32 {
|
|
3012
|
+
let r = u32(color.r * 255.0);
|
|
3013
|
+
let g = u32(color.g * 255.0);
|
|
3014
|
+
let b = u32(color.b * 255.0);
|
|
3015
|
+
let a = u32(color.a * 255.0);
|
|
3016
|
+
return (a << 24u) | (b << 16u) | (g << 8u) | r;
|
|
3017
|
+
}
|
|
3018
|
+
|
|
3019
|
+
fn isPolyEmpty(value: u32) -> bool {
|
|
3020
|
+
return value == 0xff000000 || value == 0x0 ;
|
|
3021
|
+
}
|
|
3022
|
+
|
|
3023
|
+
fn isEmpty(value: u32) -> bool {
|
|
3024
|
+
return value == 0xff000000;
|
|
3025
|
+
}
|
|
3026
|
+
|
|
3027
|
+
fn isDepthEmpty(value: u32) -> bool {
|
|
3028
|
+
return value == 0xffffffff;
|
|
3029
|
+
}
|
|
3030
|
+
`
|
|
3031
|
+
);
|
|
3032
|
+
const mainCode = (
|
|
3033
|
+
/* wgsl*/
|
|
3034
|
+
`
|
|
3035
|
+
let width = i32(uniforms.size.x);
|
|
3036
|
+
let height = i32(uniforms.size.y);
|
|
3037
|
+
let half = i32(uniforms.kernelSize / 2);
|
|
3038
|
+
let depthTol = uniforms.depthTol;
|
|
3039
|
+
|
|
3040
|
+
let x = i32(id.x);
|
|
3041
|
+
let y = i32(id.y);
|
|
3042
|
+
|
|
3043
|
+
let idx = u32(y) * u32(width) + u32(x);
|
|
3044
|
+
|
|
3045
|
+
// 判断是不是多边形区域
|
|
3046
|
+
let polyPackedIndex = polyAreaIndex[idx];
|
|
3047
|
+
if(isPolyEmpty(polyPackedIndex)) {
|
|
3048
|
+
return;
|
|
3049
|
+
}
|
|
3050
|
+
|
|
3051
|
+
// 获取多边形当前坐标有没有点云(获取深度值判断也是一样的, 深度值和点云索引图一一对应)
|
|
3052
|
+
let packedIndex = textureLoad(pcIndexMap, vec2<i32>(x, y), 0);
|
|
3053
|
+
let pointIndex = unPackUint(packedIndex);
|
|
3054
|
+
if(isEmpty(pointIndex)) {
|
|
3055
|
+
return;
|
|
3056
|
+
}
|
|
3057
|
+
|
|
3058
|
+
// 获取当前点云深度值
|
|
3059
|
+
let depthU32 = pcDepth[idx];
|
|
3060
|
+
let depthF32 = orderedUintToFloat(depthU32);
|
|
3061
|
+
|
|
3062
|
+
// 获取范围内最小深度值和对应点云索引
|
|
3063
|
+
let maxDepth = 10000.0;
|
|
3064
|
+
var minDepth = maxDepth;
|
|
3065
|
+
var minPcUv = vec2<i32>(0, 0);
|
|
3066
|
+
|
|
3067
|
+
for (var ky = -half; ky <= half; ky = ky + 1) {
|
|
3068
|
+
let ny = y + ky;
|
|
3069
|
+
for (var kx = -half; kx <= half; kx = kx + 1) {
|
|
3070
|
+
let nx = x + kx;
|
|
3071
|
+
|
|
3072
|
+
if (nx < 0 || ny < 0 || nx >= width || ny >= height ) {
|
|
3073
|
+
continue;
|
|
3074
|
+
}
|
|
3075
|
+
|
|
3076
|
+
let idx = u32(ny) * u32(width) + u32(nx);
|
|
3077
|
+
|
|
3078
|
+
let depthU32 = pcDepth[idx];
|
|
3079
|
+
let depthF32 = orderedUintToFloat( depthU32 );
|
|
3080
|
+
|
|
3081
|
+
if(depthF32 < minDepth) {
|
|
3082
|
+
minDepth = depthF32;
|
|
3083
|
+
minPcUv.x = nx;
|
|
3084
|
+
minPcUv.y = ny;
|
|
3085
|
+
}
|
|
3086
|
+
}
|
|
3087
|
+
}
|
|
3088
|
+
|
|
3089
|
+
// 是否找到最小值, 当前判断条件为未找到
|
|
3090
|
+
if(minDepth >= maxDepth) {
|
|
3091
|
+
return;
|
|
3092
|
+
}
|
|
3093
|
+
|
|
3094
|
+
// 判断当前点深度和最小深度的差值是否小于阈值
|
|
3095
|
+
if(abs(depthF32 - minDepth) > depthTol) {
|
|
3096
|
+
return;
|
|
3097
|
+
}
|
|
3098
|
+
|
|
3099
|
+
let finalPackedIndex = textureLoad(pcIndexMap, minPcUv, 0);
|
|
3100
|
+
let finalPointIndex = unPackUint(packedIndex);
|
|
3101
|
+
result[finalPointIndex] = polyPackedIndex;
|
|
3102
|
+
`
|
|
3103
|
+
);
|
|
3104
|
+
class SOPCComputeMaterial extends ComputeMaterial {
|
|
3105
|
+
result;
|
|
3106
|
+
constructor(width, height, count, pcIndexTexture, kernelSize = 15) {
|
|
3107
|
+
const result = new Uint32Array(count).fill(4294967295);
|
|
3108
|
+
super({
|
|
3109
|
+
maxSize: [width, height],
|
|
3110
|
+
mainCode,
|
|
3111
|
+
beforeCcde,
|
|
3112
|
+
uniforms: {
|
|
3113
|
+
pcIndexMap: { value: pcIndexTexture },
|
|
3114
|
+
// 空白填充 0xff_00_00_00
|
|
3115
|
+
pcDepth: { value: new Uint32Array() },
|
|
3116
|
+
// 默认填充 0xff_ff_ff_ff
|
|
3117
|
+
polyAreaIndex: { value: new Uint32Array() },
|
|
3118
|
+
// 空白填充 0xff_00_00_00
|
|
3119
|
+
size: { value: new Vector2(width, height) },
|
|
3120
|
+
kernelSize: { value: kernelSize },
|
|
3121
|
+
depthTol: { value: 0.05 },
|
|
3122
|
+
result: {
|
|
3123
|
+
value: result,
|
|
3124
|
+
write: true
|
|
3125
|
+
}
|
|
3126
|
+
}
|
|
3127
|
+
});
|
|
3128
|
+
this.result = result;
|
|
3129
|
+
}
|
|
3130
|
+
clearResult() {
|
|
3131
|
+
this.uniforms.result.value = this.result;
|
|
3132
|
+
}
|
|
3133
|
+
}
|
|
3134
|
+
async function load(base, urls) {
|
|
3135
|
+
let points = await loadPCDCustom(base + "/data/rgb_global_map.pcd");
|
|
3136
|
+
const itemsFiles = await Promise.all(urls.map((path) => loadJson(path)));
|
|
3137
|
+
const width = itemsFiles[0].imageSize[0];
|
|
3138
|
+
const height = itemsFiles[0].imageSize[1];
|
|
3139
|
+
return { points, itemsFiles, width, height };
|
|
3140
|
+
}
|
|
3141
|
+
function getInfo(itemsFile, cindex) {
|
|
3142
|
+
const width = itemsFile.imageSize[0];
|
|
3143
|
+
const height = itemsFile.imageSize[1];
|
|
3144
|
+
const T_wi = new THREE.Matrix4();
|
|
3145
|
+
T_wi.compose(
|
|
3146
|
+
new THREE.Vector3().copy(itemsFile.position),
|
|
3147
|
+
new THREE.Quaternion().copy(itemsFile.quaternion),
|
|
3148
|
+
new THREE.Vector3(1, 1, 1)
|
|
3149
|
+
);
|
|
3150
|
+
const T_il = new THREE.Matrix4().makeTranslation(-0.011, -0.02329, 0.04412);
|
|
3151
|
+
const T_lc = new THREE.Matrix4().fromArray(itemsFile.extrinsicMat).transpose();
|
|
3152
|
+
const T_wc = new THREE.Matrix4();
|
|
3153
|
+
T_wc.copy(T_wi).multiply(T_il).multiply(T_lc);
|
|
3154
|
+
const T_cw = T_wc.clone().invert();
|
|
3155
|
+
const cameraMat = new THREE.Matrix3();
|
|
3156
|
+
cameraMat.fromArray(itemsFile.cameraMat);
|
|
3157
|
+
cameraMat.transpose();
|
|
3158
|
+
let count = 0;
|
|
3159
|
+
itemsFile.sam3Objects.forEach((item) => count += item.coordinates.length);
|
|
3160
|
+
const itemPosition = [];
|
|
3161
|
+
for (let i = 0; i < itemsFile.sam3Objects.length; i++) {
|
|
3162
|
+
const item = itemsFile.sam3Objects[i], path = item.coordinates.map((coordinate) => new THREE.Vector2(coordinate[0], coordinate[1])), triangles = THREE.ShapeUtils.triangulateShape(path, []);
|
|
3163
|
+
triangles.forEach(
|
|
3164
|
+
(list) => list.forEach(
|
|
3165
|
+
(index) => itemPosition.push(
|
|
3166
|
+
path[index].x,
|
|
3167
|
+
path[index].y,
|
|
3168
|
+
cindex * 200 + i
|
|
3169
|
+
)
|
|
3170
|
+
)
|
|
3171
|
+
);
|
|
3172
|
+
}
|
|
3173
|
+
return {
|
|
3174
|
+
cameraMat,
|
|
3175
|
+
T_cw,
|
|
3176
|
+
width,
|
|
3177
|
+
height,
|
|
3178
|
+
itemPosition: new Float32Array(itemPosition)
|
|
3179
|
+
};
|
|
3180
|
+
}
|
|
3181
|
+
async function sopc_(opt) {
|
|
3182
|
+
const {
|
|
3183
|
+
base,
|
|
3184
|
+
urls,
|
|
3185
|
+
erodeMaskSize = 3,
|
|
3186
|
+
kernelSize = 15,
|
|
3187
|
+
gridSize = 0.05,
|
|
3188
|
+
gridAmount = 2
|
|
3189
|
+
} = opt;
|
|
3190
|
+
console.log("开始计算");
|
|
3191
|
+
let t = performance.now();
|
|
3192
|
+
await initWebgpu();
|
|
3193
|
+
const canvasWidth = window?.innerWidth ?? 256, canvasHeight = window?.innerHeight ?? 256, renderer = new Renderer(canvasWidth, canvasHeight, "rgba8unorm"), camera = new PerspectiveCamera(75, canvasWidth / canvasHeight, 1e-3, 100), { points: pointsArray, itemsFiles, width, height } = await load(base, urls), pointCount = pointsArray.length / 3, pcIndexMaterial = new PointCloudsIndexMaterial(width, height), polyAreaIndexMaterial = new PolyAreaIndexMaterial(width, height), erodeMaskComputeMaterial = new ErodeMaskComputeMaterial(width, height, polyAreaIndexMaterial.resultTexture, erodeMaskSize), sopcComputeMaterial = new SOPCComputeMaterial(width, height, pointCount, pcIndexMaterial.resultTexture, kernelSize), points = new Object3D(
|
|
3194
|
+
new BufferGeometry().setAttribute("position", new THREE.BufferAttribute(pointsArray, 3)),
|
|
3195
|
+
pcIndexMaterial
|
|
3196
|
+
), mesh = new Object3D(
|
|
3197
|
+
new BufferGeometry().setAttribute("position", new THREE.BufferAttribute(new Float32Array(), 3)),
|
|
3198
|
+
polyAreaIndexMaterial
|
|
3199
|
+
);
|
|
3200
|
+
camera.position.set(1, 1, 1);
|
|
3201
|
+
console.log("文件加载耗时:", performance.now() - t);
|
|
3202
|
+
t = performance.now();
|
|
3203
|
+
for (let i = 0; i < itemsFiles.length; i++) {
|
|
3204
|
+
const itemsFile = itemsFiles[i];
|
|
3205
|
+
if (itemsFile.sam3Objects.length === 0) {
|
|
3206
|
+
console.log("第" + i + "个没有物品");
|
|
3207
|
+
continue;
|
|
3208
|
+
}
|
|
3209
|
+
const { T_cw, cameraMat, itemPosition } = getInfo(itemsFile, i);
|
|
3210
|
+
mesh.geometry.setAttribute("position", new THREE.BufferAttribute(itemPosition, 3));
|
|
3211
|
+
pcIndexMaterial.T_cw = T_cw;
|
|
3212
|
+
pcIndexMaterial.cameraMat = cameraMat;
|
|
3213
|
+
pcIndexMaterial.clearDepth();
|
|
3214
|
+
renderer.renderTarget = pcIndexMaterial.resultTexture.view;
|
|
3215
|
+
renderer.depthTarget = pcIndexMaterial.resultTexture.depthView;
|
|
3216
|
+
renderer.render([points], camera);
|
|
3217
|
+
renderer.renderTarget = polyAreaIndexMaterial.resultTexture.view;
|
|
3218
|
+
renderer.depthTarget = polyAreaIndexMaterial.resultTexture.depthView;
|
|
3219
|
+
renderer.render([mesh], camera);
|
|
3220
|
+
renderer.compute(erodeMaskComputeMaterial);
|
|
3221
|
+
sopcComputeMaterial.setStorageBuffer("pcDepth", pcIndexMaterial.getStorageBuffer("depth"));
|
|
3222
|
+
sopcComputeMaterial.setStorageBuffer("polyAreaIndex", erodeMaskComputeMaterial.getStorageBuffer("result"));
|
|
3223
|
+
renderer.compute(sopcComputeMaterial);
|
|
3224
|
+
}
|
|
3225
|
+
const resultsBuffer = await readGPUBuffer(sopcComputeMaterial.getStorageBuffer("result"), pointCount * 4, Uint32Array);
|
|
3226
|
+
console.log("渲染消耗时间:", performance.now() - t);
|
|
3227
|
+
t = performance.now();
|
|
3228
|
+
const map = /* @__PURE__ */ new Map();
|
|
3229
|
+
for (let i = 0; i < resultsBuffer.length; i++) {
|
|
3230
|
+
const v = resultsBuffer[i];
|
|
3231
|
+
if (v === 4294967295) continue;
|
|
3232
|
+
const itemIndex = v % 200;
|
|
3233
|
+
const fileIndex = (v - itemIndex) / 200;
|
|
3234
|
+
let arrayMap = map.get(fileIndex);
|
|
3235
|
+
if (!arrayMap) {
|
|
3236
|
+
arrayMap = new ArrayMap();
|
|
3237
|
+
map.set(fileIndex, arrayMap);
|
|
3238
|
+
}
|
|
3239
|
+
arrayMap.append(itemIndex, i);
|
|
3240
|
+
}
|
|
3241
|
+
const transcendingCreation = ["window", "calcony railing", "glass balcony railing", "metal balcony railing", "temporary construction guardrail"];
|
|
3242
|
+
const results = new Array(itemsFiles.length);
|
|
3243
|
+
const sort = (pointarr, isTranscendingCreation, position) => {
|
|
3244
|
+
let list = gridClustering(pointarr, gridSize, gridAmount);
|
|
3245
|
+
if (list.length === 1) return list;
|
|
3246
|
+
if (isTranscendingCreation) {
|
|
3247
|
+
const distList = list.map((points2) => getPointDistance(getPointsCenter(points2), position));
|
|
3248
|
+
let indices = Array.from({ length: list.length }, (_, i) => i);
|
|
3249
|
+
indices.sort((a, b) => distList[a] - distList[b]);
|
|
3250
|
+
const min = distList[indices[0]];
|
|
3251
|
+
indices = indices.filter((i) => distList[i] - min < 0.12 * 2);
|
|
3252
|
+
list = indices.map((i) => list[i]);
|
|
3253
|
+
}
|
|
3254
|
+
list.sort((a, b) => b.length - a.length);
|
|
3255
|
+
return list;
|
|
3256
|
+
};
|
|
3257
|
+
map.forEach((arrMap, fileIndex) => {
|
|
3258
|
+
arrMap.forEach((pointIndexs, itemIndex) => {
|
|
3259
|
+
let pointarr = [];
|
|
3260
|
+
pointIndexs.forEach((i) => {
|
|
3261
|
+
pointarr.push(
|
|
3262
|
+
pointsArray[i * 3],
|
|
3263
|
+
pointsArray[i * 3 + 1],
|
|
3264
|
+
pointsArray[i * 3 + 2]
|
|
3265
|
+
);
|
|
3266
|
+
});
|
|
3267
|
+
const itemsFile = itemsFiles[fileIndex];
|
|
3268
|
+
const type = itemsFile.sam3Objects[itemIndex].category;
|
|
3269
|
+
const isTranscendingCreation = transcendingCreation.includes(type);
|
|
3270
|
+
pointarr = sort(pointarr, isTranscendingCreation, itemsFile.position)[0];
|
|
3271
|
+
if (pointarr.length <= 6 * 3) return;
|
|
3272
|
+
if (!results[fileIndex]) results[fileIndex] = new Array(itemsFiles[fileIndex].sam3Objects.length);
|
|
3273
|
+
results[fileIndex][itemIndex] = pointarr;
|
|
3274
|
+
});
|
|
3275
|
+
});
|
|
3276
|
+
renderer.renderTarget = null;
|
|
3277
|
+
renderer.depthTarget = null;
|
|
3278
|
+
console.log("整理结果消耗时间:", performance.now() - t, "点云数量", pointsArray.length / 3, "文件数量", itemsFiles.length);
|
|
3279
|
+
return {
|
|
3280
|
+
renderer,
|
|
3281
|
+
camera,
|
|
3282
|
+
results,
|
|
3283
|
+
pointsArray
|
|
3284
|
+
};
|
|
3285
|
+
}
|
|
3286
|
+
const segmentObjectPointClouds = Object.assign(sopc_, {
|
|
3287
|
+
async getResult(opt) {
|
|
3288
|
+
await initWebgpu();
|
|
3289
|
+
const { results } = await sopc_(opt);
|
|
3290
|
+
await destroyWebgpu();
|
|
3291
|
+
return results;
|
|
3292
|
+
}
|
|
3293
|
+
});
|
|
2294
3294
|
export {
|
|
2295
3295
|
AtomicUint32Array,
|
|
2296
3296
|
BaseMaterial,
|
|
2297
3297
|
BufferGeometry,
|
|
3298
|
+
ComputeMaterial,
|
|
2298
3299
|
CubeCamera,
|
|
2299
3300
|
CubeTexture,
|
|
2300
|
-
DepthMaterial,
|
|
2301
3301
|
GpuComputed,
|
|
2302
3302
|
Object3D,
|
|
2303
|
-
OcclusionMaterial,
|
|
2304
3303
|
PerspectiveCamera,
|
|
2305
3304
|
Renderer,
|
|
2306
3305
|
ShaderMaterial,
|
|
2307
3306
|
Texture,
|
|
3307
|
+
autoWorkgroup,
|
|
2308
3308
|
createBuffer,
|
|
2309
3309
|
createComputePipeline,
|
|
2310
3310
|
createRenderPipeline,
|
|
@@ -2312,6 +3312,7 @@ export {
|
|
|
2312
3312
|
destroyWebgpu,
|
|
2313
3313
|
getAdapter,
|
|
2314
3314
|
getDevice,
|
|
3315
|
+
getNullBG,
|
|
2315
3316
|
getSampler,
|
|
2316
3317
|
initWebgpu,
|
|
2317
3318
|
loadData,
|
|
@@ -2319,6 +3320,7 @@ export {
|
|
|
2319
3320
|
readCubeTexture,
|
|
2320
3321
|
readGPUBuffer,
|
|
2321
3322
|
readTextureBuffer,
|
|
3323
|
+
segmentObjectPointClouds,
|
|
2322
3324
|
shaderLocationMap,
|
|
2323
3325
|
transparentOption
|
|
2324
3326
|
};
|