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.
Files changed (3) hide show
  1. package/package.json +1 -1
  2. package/src/index.d.ts +107 -48
  3. 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 = navigator.gpu.getPreferredCanvasFormat(),
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
- env;
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 = vertexCommon + options.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.env = options.env;
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 value;
1331
+ return value_;
1264
1332
  },
1265
1333
  set value(v) {
1266
- if (getUniformType(v) !== type) return;
1267
- value = set(v, value);
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") textureListener(key, value, type);
1323
- else defaultListener(key, value, type);
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
- entries.push({
1425
+ const format = item.value?.texture?.format ?? "rgba8unorm";
1426
+ const opt = {
1354
1427
  binding: item.binding,
1355
- visibility: GPUShaderStage.FRAGMENT,
1356
- texture: item.type === "texture_cube" ? {
1357
- "viewDimension": "cube"
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 type
1495
+ * @param mtype
1416
1496
  * @returns
1417
1497
  */
1418
- _generateUniformWGSL(type) {
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 type2 = this._bufferUniforms[key].type;
1424
- if (type2 === "mat4")
1503
+ const type = this._bufferUniforms[key].type;
1504
+ if (type === "mat4")
1425
1505
  code += ` ${key} : mat4x4<f32>,
1426
1506
  `;
1427
- else if (type2 === "mat3")
1507
+ else if (type === "mat3")
1428
1508
  code += ` ${key} : mat3x3<f32>,
1429
1509
  `;
1430
- else if (type2 === "vec2")
1510
+ else if (type === "vec2")
1431
1511
  code += ` ${key} : vec2<f32>,
1432
1512
  `;
1433
- else if (type2 === "vec3")
1513
+ else if (type === "vec3")
1434
1514
  code += ` ${key} : vec3<f32>,
1435
1515
  `;
1436
- else if (type2 === "vec4")
1516
+ else if (type === "vec4")
1437
1517
  code += ` ${key} : vec4<f32>,
1438
1518
  `;
1439
- else if (type2 === "f32")
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 (type === "fragment") {
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
- @group(2) @binding(${b})
1453
- var ${key} : texture_2d<f32>;
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
- @group(2) @binding(${b})
1461
- var ${key} : texture_cube<f32>;
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 env = { ...this.env };
1518
- for (const key2 of attrMap.keys()) env[key2] = true;
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, env)}`
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, env)}`
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
- format: colorFormat,
1543
- blend: this.blend,
1544
- writeMask: this.writeMask
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
- this.uniformArray.set([value.x, value.y, value.z], offset);
1583
- offset += 3;
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[offset++] = c.r;
1594
- this.uniformArray[offset++] = c.g;
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[offset + 0] = m[0];
1606
- this.uniformArray[offset + 1] = m[1];
1607
- this.uniformArray[offset + 2] = m[2];
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 DepthMaterial extends ShaderMaterial {
1712
- constructor(opt = {}) {
1801
+ class ComputeMaterial extends ShaderMaterial {
1802
+ workgroupCount;
1803
+ workgroupSize;
1804
+ constructor(opt) {
1713
1805
  super({
1714
- vertex: (
1715
- /* wgsl */
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
- class OcclusionMaterial extends ShaderMaterial {
1772
- constructor(opt) {
1773
- super({
1774
- vertex: (
1775
- /* wgsl */
1776
- `
1777
- struct VertexOutput {
1778
- @builtin(position) Position : vec4<f32>,
1779
- @location(0) worldDir: vec3<f32>,
1780
- @location(1) near: f32,
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
- side: opt.side ?? "none",
1848
- topology: opt.topology ?? "triangle-list",
1849
- uniforms: {
1850
- cubeTexture: { value: opt.cubeTexture },
1851
- results: { value: opt.results ?? new Uint32Array([0, 0, 0]), write: true, atomic: true }
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
- static packUint(v) {
1856
- const vec4 = new Vector4();
1857
- vec4.set(
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(1, mesh.bindGroup);
2005
- pass.setBindGroup(2, mesh.material.bindGroup);
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
- async function loadData(base, linesJson_) {
2210
- const t = performance.now();
2211
- const trajectory = await loadTrajectory(base), { pointClouds, pointCloudArray, trajectoryList } = await trajectoryHandle(base, trajectory), linesJson = linesJson_ ?? await loadLines(base), { map, rectArray, indexArray } = linesToBuffer(linesJson);
2212
- console.log("加载耗时", performance.now() - t);
2213
- return {
2214
- pointClouds,
2215
- pointCloudArray,
2216
- trajectoryList,
2217
- map,
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
- async function obstacleDetection_(opt) {
2224
- const {
2225
- base,
2226
- size = 512,
2227
- near = 0.01,
2228
- far = 100,
2229
- canvasWidth = 1400,
2230
- canvasHeight = 800,
2231
- fov = 75,
2232
- linesJson
2233
- } = opt;
2234
- let t = performance.now();
2235
- 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);
2236
- console.log("数据加载耗时", performance.now() - t);
2237
- t = performance.now();
2238
- camera.up = new THREE.Vector3(0, 0, 1);
2239
- camera.position.set(0, 0, 5);
2240
- camera.lookAt(new THREE.Vector3(0, 0, 0));
2241
- 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(
2242
- new BufferGeometry().setAttribute("position", new THREE.BufferAttribute(new Float32Array(rectArray), 3)).setAttribute("id", new THREE.Uint32BufferAttribute(new Uint32Array(indexArray), 1)),
2243
- new OcclusionMaterial({
2244
- cubeTexture: depthCubeTexture,
2245
- results: new Uint32Array(indexCount)
2246
- // indexCount 个 uint8
2247
- })
2248
- ), pointsObject3D = new Object3D(
2249
- new BufferGeometry().setAttribute("position", new THREE.BufferAttribute(new Float32Array(), 3)),
2250
- new DepthMaterial({ topology: "point-list" })
2251
- );
2252
- for (let i = 0; i < trajectoryList.length; i++) {
2253
- const trajectory = trajectoryList[i];
2254
- pointsObject3D.geometry.setAttribute("position", new THREE.BufferAttribute(new Float32Array(pointClouds[i]), 3));
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
  };