rm-webgpu-compute-tasks 0.0.7 → 0.0.9

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rm-webgpu-compute-tasks",
3
- "version": "0.0.7",
3
+ "version": "0.0.9",
4
4
  "description": "",
5
5
  "main": "./src/index.js",
6
6
  "types": "./src/index.d.ts",
package/src/index.d.ts CHANGED
@@ -419,10 +419,9 @@ declare function obstacleDetection_(opt: ICreateObstacleDetection): Promise<{
419
419
  declare interface Option_2 {
420
420
  base: string;
421
421
  urls: string[];
422
- erodeMaskSize?: number;
422
+ dilateMaskSize?: number;
423
423
  kernelSize?: number;
424
- gridSize?: number;
425
- gridAmount?: number;
424
+ groundZ?: number;
426
425
  }
427
426
 
428
427
  export declare class PerspectiveCamera extends THREE.PerspectiveCamera {
package/src/index.js CHANGED
@@ -457,7 +457,12 @@ async function initWebgpu(opt = {}) {
457
457
  if (!navigator.gpu) throw new Error("该环境不支持webgpu");
458
458
  if (!adapter) adapter = await navigator.gpu.requestAdapter(opt);
459
459
  if (!adapter) throw new Error("获取适配器失败");
460
- device = await adapter.requestDevice(opt);
460
+ device = await adapter.requestDevice({
461
+ requiredLimits: {
462
+ maxBufferSize: adapter.limits.maxBufferSize
463
+ },
464
+ ...opt
465
+ });
461
466
  if (!adapter) throw new Error("获取设备失败");
462
467
  GpuComputed.set(adapter, device);
463
468
  return { device, adapter };
@@ -1333,7 +1338,7 @@ class ShaderMaterial {
1333
1338
  set value(v) {
1334
1339
  if (getUniformType(v, uniforms[key]?.atomic) !== type) return;
1335
1340
  v = set(v, value_);
1336
- if ("copy" in value_ && typeof value_.copy === "function") value_.copy(v);
1341
+ if (typeof value_ === "object" && "copy" in value_ && typeof value_.copy === "function") value_.copy(v);
1337
1342
  else value_ = v;
1338
1343
  }
1339
1344
  };
@@ -2211,22 +2216,6 @@ async function trajectoryHandle(baseUrl, trajectoryData) {
2211
2216
  pointCloudArray
2212
2217
  };
2213
2218
  }
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 };
2223
- }
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
2219
  class OcclusionMaterial extends ShaderMaterial {
2231
2220
  constructor(opt) {
2232
2221
  super({
@@ -2570,7 +2559,7 @@ class PointCloudsIndexMaterial extends ShaderMaterial {
2570
2559
  cameraMat: { value: new Matrix3() },
2571
2560
  T_cw: { value: new Matrix4() },
2572
2561
  imageSize: { value: new Vector2(width, height) },
2573
- groundZ: { value: -0.911335763281652 + 0.1 },
2562
+ groundZ: { value: -1 },
2574
2563
  depth: { value: depthU32, write: true, atomic: true }
2575
2564
  },
2576
2565
  topology: "point-list"
@@ -2647,6 +2636,7 @@ const fragmentShader = (
2647
2636
  @location(0) vId: vec4<f32>,
2648
2637
  ) -> @location(0) vec4<f32> {
2649
2638
  return vId;
2639
+ // return vec4(1.0, 0, 0, 1);
2650
2640
  }
2651
2641
  `
2652
2642
  );
@@ -2660,7 +2650,8 @@ class PolyAreaIndexMaterial extends ShaderMaterial {
2660
2650
  side: "none",
2661
2651
  uniforms: {
2662
2652
  imageSize: { value: new Vector2(width, height) }
2663
- }
2653
+ },
2654
+ topology: "point-list"
2664
2655
  });
2665
2656
  this.resultTexture = resultTexture;
2666
2657
  }
@@ -2797,93 +2788,19 @@ class ArrayMap extends MapEnhance {
2797
2788
  return this.get(key);
2798
2789
  }
2799
2790
  }
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
2791
  const beforeCcde$1 = (
2885
2792
  /* wgsl*/
2886
2793
  `
2794
+ // fn orderedUintToFloat(u: u32) -> f32 {
2795
+ // let mask = select(0x80000000u, 0xffffffffu, (u & 0x80000000u) != 0u);
2796
+ // return bitcast<f32>(u ^ mask);
2797
+ // }
2798
+
2799
+ fn orderedUintToFloat(u: u32) -> f32 {
2800
+ let restored = select(u ^ 0xffffffffu, u, (u & 0x80000000u) != 0u);
2801
+ return bitcast<f32>(restored);
2802
+ }
2803
+
2887
2804
  fn packUint(v: u32) -> vec4<f32>{
2888
2805
  return vec4(
2889
2806
  f32(v & 255u),
@@ -2901,9 +2818,17 @@ const beforeCcde$1 = (
2901
2818
  return (a << 24u) | (b << 16u) | (g << 8u) | r;
2902
2819
  }
2903
2820
 
2904
- fn isEmpty(value: u32) -> bool {
2821
+ fn isPolyEmpty(value: u32) -> bool {
2905
2822
  return value == 0xff000000 || value == 0x0 ;
2906
2823
  }
2824
+
2825
+ fn isEmpty(value: u32) -> bool {
2826
+ return value == 0xff000000;
2827
+ }
2828
+
2829
+ fn isDepthEmpty(value: u32) -> bool {
2830
+ return value == 0xffffffff;
2831
+ }
2907
2832
  `
2908
2833
  );
2909
2834
  const mainCode$1 = (
@@ -2912,93 +2837,105 @@ const mainCode$1 = (
2912
2837
  let width = i32(uniforms.size.x);
2913
2838
  let height = i32(uniforms.size.y);
2914
2839
  let half = i32(uniforms.kernelSize / 2);
2840
+ let depthTol = uniforms.depthTol;
2915
2841
 
2916
2842
  let x = i32(id.x);
2917
2843
  let y = i32(id.y);
2918
2844
 
2919
2845
  let idx = u32(y) * u32(width) + u32(x);
2920
2846
 
2921
- // 当前像素
2922
- let center = unPackUint(textureLoad(map, vec2<i32>(x, y), 0));
2923
-
2924
- // 如果当前就是空,直接空
2925
- if ( isEmpty(center) ) {
2926
- result[idx] = 0xff000000;
2847
+ // 判断是不是多边形区域
2848
+ let polyPackedIndex = polyAreaIndex[idx];
2849
+ if(isPolyEmpty(polyPackedIndex)) {
2927
2850
  return;
2928
2851
  }
2929
2852
 
2930
- // 是否被腐蚀
2931
- var eroded = false;
2853
+ // 获取多边形当前坐标有没有点云(获取深度值判断也是一样的, 深度值和点云索引图一一对应)
2854
+ // let packedIndex = textureLoad(pcIndexMap, vec2<i32>(x, y), 0);
2855
+ // let pointIndex = unPackUint(packedIndex);
2856
+ // if(isEmpty(pointIndex)) {
2857
+ // return;
2858
+ // }
2932
2859
 
2933
- // 遍历邻域
2934
- for (var ky = -half; ky <= half; ky = ky + 1) {
2935
- let ny = y + ky;
2860
+ // 获取当前点云深度值
2861
+ // let depthU32 = pcDepth[idx];
2862
+ // let depthF32 = orderedUintToFloat(depthU32);
2936
2863
 
2937
- if (ny < 0 || ny >= height) {
2938
- continue;
2939
- }
2864
+ // 获取范围内最小深度值和对应点云索引
2865
+ let maxDepth = 10000.0;
2866
+ var minDepth = maxDepth;
2867
+ var minPcUv = vec2<i32>(0, 0);
2940
2868
 
2869
+ for (var ky = -half; ky <= half; ky = ky + 1) {
2870
+ let ny = y + ky;
2941
2871
  for (var kx = -half; kx <= half; kx = kx + 1) {
2942
2872
  let nx = x + kx;
2943
2873
 
2944
- if (nx < 0 || nx >= width) {
2874
+ if (nx < 0 || ny < 0 || nx >= width || ny >= height ) {
2945
2875
  continue;
2946
2876
  }
2947
2877
 
2948
- let neighbor = unPackUint(textureLoad(map, vec2<i32>(nx, ny), 0));
2878
+ let idx = u32(ny) * u32(width) + u32(nx);
2949
2879
 
2950
- // 只要有一个是空 腐蚀
2951
- if (isEmpty(neighbor) || neighbor != center) {
2952
- eroded = true;
2953
- break;
2954
- }
2955
- }
2880
+ let depthU32 = pcDepth[idx];
2881
+ let depthF32 = orderedUintToFloat( depthU32 );
2956
2882
 
2957
- if (eroded) {
2958
- break;
2883
+ if(depthF32 < minDepth) {
2884
+ minDepth = depthF32;
2885
+ minPcUv.x = nx;
2886
+ minPcUv.y = ny;
2887
+ }
2959
2888
  }
2960
2889
  }
2961
2890
 
2962
- // 写结果
2963
- if (eroded) {
2964
- result[idx] = 0xff000000;
2965
- } else {
2966
- result[idx] = center;
2891
+ // 是否找到最小值, 当前判断条件为未找到
2892
+ if(minDepth >= maxDepth) {
2893
+ return;
2967
2894
  }
2895
+
2896
+ // 判断当前点深度和最小深度的差值是否小于阈值
2897
+ // if(abs(depthF32 - minDepth) > depthTol) {
2898
+ // return;
2899
+ // }
2900
+
2901
+ let finalPackedIndex = textureLoad(pcIndexMap, minPcUv, 0);
2902
+ let finalPointIndex = unPackUint(finalPackedIndex);
2903
+ result[finalPointIndex] = polyPackedIndex;
2968
2904
  `
2969
2905
  );
2970
- class ErodeMaskComputeMaterial extends ComputeMaterial {
2971
- constructor(width = 1920, height = 1200, texture, kernelSize = 3) {
2906
+ class SOPCComputeMaterial extends ComputeMaterial {
2907
+ result;
2908
+ constructor(width, height, count, pcIndexTexture, kernelSize = 15) {
2909
+ const result = new Uint32Array(count).fill(4294967295);
2972
2910
  super({
2973
2911
  maxSize: [width, height],
2974
2912
  mainCode: mainCode$1,
2975
2913
  beforeCcde: beforeCcde$1,
2976
2914
  uniforms: {
2977
- map: { value: texture },
2915
+ pcIndexMap: { value: pcIndexTexture },
2916
+ // 空白填充 0xff_00_00_00
2917
+ pcDepth: { value: new Uint32Array() },
2918
+ // 默认填充 0xff_ff_ff_ff
2919
+ polyAreaIndex: { value: new Uint32Array() },
2920
+ // 空白填充 0xff_00_00_00
2978
2921
  size: { value: new Vector2(width, height) },
2979
2922
  kernelSize: { value: kernelSize },
2980
- // 建议从3开始
2923
+ depthTol: { value: 0.05 },
2981
2924
  result: {
2982
- value: new Uint32Array(width * height),
2925
+ value: result,
2983
2926
  write: true
2984
2927
  }
2985
2928
  }
2986
2929
  });
2930
+ this.result = result;
2931
+ }
2932
+ clearResult() {
2933
+ this.uniforms.result.value = this.result;
2987
2934
  }
2988
2935
  }
2989
2936
  const beforeCcde = (
2990
2937
  /* wgsl*/
2991
2938
  `
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
2939
  fn packUint(v: u32) -> vec4<f32>{
3003
2940
  return vec4(
3004
2941
  f32(v & 255u),
@@ -3013,19 +2950,11 @@ const beforeCcde = (
3013
2950
  let g = u32(color.g * 255.0);
3014
2951
  let b = u32(color.b * 255.0);
3015
2952
  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 ;
2953
+ return (a << 24u) | (b << 16u) | (g << 8u) | r;
3021
2954
  }
3022
2955
 
3023
2956
  fn isEmpty(value: u32) -> bool {
3024
- return value == 0xff000000;
3025
- }
3026
-
3027
- fn isDepthEmpty(value: u32) -> bool {
3028
- return value == 0xffffffff;
2957
+ return value == 0xff000000 || value == 0x0;
3029
2958
  }
3030
2959
  `
3031
2960
  );
@@ -3035,101 +2964,116 @@ const mainCode = (
3035
2964
  let width = i32(uniforms.size.x);
3036
2965
  let height = i32(uniforms.size.y);
3037
2966
  let half = i32(uniforms.kernelSize / 2);
3038
- let depthTol = uniforms.depthTol;
3039
2967
 
3040
2968
  let x = i32(id.x);
3041
2969
  let y = i32(id.y);
3042
2970
 
3043
2971
  let idx = u32(y) * u32(width) + u32(x);
3044
2972
 
3045
- // 判断是不是多边形区域
3046
- let polyPackedIndex = polyAreaIndex[idx];
3047
- if(isPolyEmpty(polyPackedIndex)) {
3048
- return;
3049
- }
2973
+ // 当前像素
2974
+ let center = unPackUint(textureLoad(map, vec2<i32>(x, y), 0));
3050
2975
 
3051
- // 获取多边形当前坐标有没有点云(获取深度值判断也是一样的, 深度值和点云索引图一一对应)
3052
- let packedIndex = textureLoad(pcIndexMap, vec2<i32>(x, y), 0);
3053
- let pointIndex = unPackUint(packedIndex);
3054
- if(isEmpty(pointIndex)) {
2976
+ // 当前非空,保持原值
2977
+ if (!isEmpty(center)) {
2978
+ result[idx] = center;
3055
2979
  return;
3056
2980
  }
3057
2981
 
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);
2982
+ // 膨胀:空像素尝试被邻域填充
2983
+ var dilatedValue: u32 = 0xff000000;
3066
2984
 
3067
2985
  for (var ky = -half; ky <= half; ky = ky + 1) {
3068
2986
  let ny = y + ky;
2987
+
2988
+ if (ny < 0 || ny >= height) {
2989
+ continue;
2990
+ }
2991
+
3069
2992
  for (var kx = -half; kx <= half; kx = kx + 1) {
3070
2993
  let nx = x + kx;
3071
2994
 
3072
- if (nx < 0 || ny < 0 || nx >= width || ny >= height ) {
2995
+ if (nx < 0 || nx >= width) {
3073
2996
  continue;
3074
2997
  }
3075
2998
 
3076
- let idx = u32(ny) * u32(width) + u32(nx);
3077
-
3078
- let depthU32 = pcDepth[idx];
3079
- let depthF32 = orderedUintToFloat( depthU32 );
2999
+ let neighbor = unPackUint(textureLoad(map, vec2<i32>(nx, ny), 0));
3080
3000
 
3081
- if(depthF32 < minDepth) {
3082
- minDepth = depthF32;
3083
- minPcUv.x = nx;
3084
- minPcUv.y = ny;
3001
+ // 只要找到非空邻居,直接采用它的值
3002
+ if (!isEmpty(neighbor)) {
3003
+ dilatedValue = neighbor;
3004
+ break;
3085
3005
  }
3086
3006
  }
3087
- }
3088
3007
 
3089
- // 是否找到最小值, 当前判断条件为未找到
3090
- if(minDepth >= maxDepth) {
3091
- return;
3092
- }
3093
-
3094
- // 判断当前点深度和最小深度的差值是否小于阈值
3095
- if(abs(depthF32 - minDepth) > depthTol) {
3096
- return;
3008
+ if (!isEmpty(dilatedValue)) {
3009
+ break;
3010
+ }
3097
3011
  }
3098
3012
 
3099
- let finalPackedIndex = textureLoad(pcIndexMap, minPcUv, 0);
3100
- let finalPointIndex = unPackUint(packedIndex);
3101
- result[finalPointIndex] = polyPackedIndex;
3013
+ result[idx] = dilatedValue;
3102
3014
  `
3103
3015
  );
3104
- class SOPCComputeMaterial extends ComputeMaterial {
3105
- result;
3106
- constructor(width, height, count, pcIndexTexture, kernelSize = 15) {
3107
- const result = new Uint32Array(count).fill(4294967295);
3016
+ class DilateMaskComputeMaterial extends ComputeMaterial {
3017
+ constructor(width = 1920, height = 1200, texture, kernelSize = 3) {
3108
3018
  super({
3109
3019
  maxSize: [width, height],
3110
3020
  mainCode,
3111
3021
  beforeCcde,
3112
3022
  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
3023
+ map: { value: texture },
3119
3024
  size: { value: new Vector2(width, height) },
3120
3025
  kernelSize: { value: kernelSize },
3121
- depthTol: { value: 0.05 },
3122
3026
  result: {
3123
- value: result,
3027
+ value: new Uint32Array(width * height),
3124
3028
  write: true
3125
3029
  }
3126
3030
  }
3127
3031
  });
3128
- this.result = result;
3129
3032
  }
3130
- clearResult() {
3131
- this.uniforms.result.value = this.result;
3033
+ }
3034
+ function euclideanClusterExtraction(points, distanceThreshold = 0.2, minClusterSize = 1, maxClusterSize = Infinity) {
3035
+ const pointCount = points.length / 3;
3036
+ const visited = new Uint8Array(pointCount);
3037
+ const clusters = [];
3038
+ const thresholdSq = distanceThreshold * distanceThreshold;
3039
+ function distanceSq(a, b) {
3040
+ const ai = a * 3;
3041
+ const bi = b * 3;
3042
+ const dx = points[ai] - points[bi];
3043
+ const dy = points[ai + 1] - points[bi + 1];
3044
+ const dz = points[ai + 2] - points[bi + 2];
3045
+ return dx * dx + dy * dy + dz * dz;
3046
+ }
3047
+ function regionQuery(index) {
3048
+ const neighbors = [];
3049
+ for (let i = 0; i < pointCount; i++) {
3050
+ if (distanceSq(index, i) <= thresholdSq) {
3051
+ neighbors.push(i);
3052
+ }
3053
+ }
3054
+ return neighbors;
3055
+ }
3056
+ for (let i = 0; i < pointCount; i++) {
3057
+ if (visited[i]) continue;
3058
+ visited[i] = 1;
3059
+ const cluster = [];
3060
+ const queue = [i];
3061
+ while (queue.length > 0) {
3062
+ const current = queue.pop();
3063
+ cluster.push(current);
3064
+ const neighbors = regionQuery(current);
3065
+ for (const neighbor of neighbors) {
3066
+ if (!visited[neighbor]) {
3067
+ visited[neighbor] = 1;
3068
+ queue.push(neighbor);
3069
+ }
3070
+ }
3071
+ }
3072
+ if (cluster.length >= minClusterSize && cluster.length <= maxClusterSize) {
3073
+ clusters.push(cluster);
3074
+ }
3132
3075
  }
3076
+ return clusters;
3133
3077
  }
3134
3078
  async function load(base, urls) {
3135
3079
  let points = await loadPCDCustom(base + "/data/rgb_global_map.pcd");
@@ -3159,16 +3103,11 @@ function getInfo(itemsFile, cindex) {
3159
3103
  itemsFile.sam3Objects.forEach((item) => count += item.coordinates.length);
3160
3104
  const itemPosition = [];
3161
3105
  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
- );
3106
+ const item = itemsFile.sam3Objects[i];
3107
+ const index = cindex * 200 + i + 1;
3108
+ item.coordinates.map((p) => {
3109
+ itemPosition.push(p[0], p[1], index);
3110
+ });
3172
3111
  }
3173
3112
  return {
3174
3113
  cameraMat,
@@ -3182,10 +3121,9 @@ async function sopc_(opt) {
3182
3121
  const {
3183
3122
  base,
3184
3123
  urls,
3185
- erodeMaskSize = 3,
3124
+ dilateMaskSize = 2,
3186
3125
  kernelSize = 15,
3187
- gridSize = 0.05,
3188
- gridAmount = 2
3126
+ groundZ = 0
3189
3127
  } = opt;
3190
3128
  console.log("开始计算");
3191
3129
  let t = performance.now();
@@ -3195,7 +3133,7 @@ async function sopc_(opt) {
3195
3133
  canvasWidth = window.innerWidth ?? canvasWidth;
3196
3134
  canvasHeight = window.innerHeight ?? canvasHeight;
3197
3135
  }
3198
- const 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(
3136
+ const 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), dilateMaskComputeMaterial = new DilateMaskComputeMaterial(width, height, polyAreaIndexMaterial.resultTexture, dilateMaskSize), sopcComputeMaterial = new SOPCComputeMaterial(width, height, pointCount, pcIndexMaterial.resultTexture, kernelSize), points = new Object3D(
3199
3137
  new BufferGeometry().setAttribute("position", new THREE.BufferAttribute(pointsArray, 3)),
3200
3138
  pcIndexMaterial
3201
3139
  ), mesh = new Object3D(
@@ -3203,6 +3141,7 @@ async function sopc_(opt) {
3203
3141
  polyAreaIndexMaterial
3204
3142
  );
3205
3143
  camera.position.set(1, 1, 1);
3144
+ pcIndexMaterial.groundZ = groundZ;
3206
3145
  console.log("文件加载耗时:", performance.now() - t);
3207
3146
  t = performance.now();
3208
3147
  for (let i = 0; i < itemsFiles.length; i++) {
@@ -3222,9 +3161,9 @@ async function sopc_(opt) {
3222
3161
  renderer.renderTarget = polyAreaIndexMaterial.resultTexture.view;
3223
3162
  renderer.depthTarget = polyAreaIndexMaterial.resultTexture.depthView;
3224
3163
  renderer.render([mesh], camera);
3225
- renderer.compute(erodeMaskComputeMaterial);
3164
+ renderer.compute(dilateMaskComputeMaterial);
3226
3165
  sopcComputeMaterial.setStorageBuffer("pcDepth", pcIndexMaterial.getStorageBuffer("depth"));
3227
- sopcComputeMaterial.setStorageBuffer("polyAreaIndex", erodeMaskComputeMaterial.getStorageBuffer("result"));
3166
+ sopcComputeMaterial.setStorageBuffer("polyAreaIndex", dilateMaskComputeMaterial.getStorageBuffer("result"));
3228
3167
  renderer.compute(sopcComputeMaterial);
3229
3168
  }
3230
3169
  const resultsBuffer = await readGPUBuffer(sopcComputeMaterial.getStorageBuffer("result"), pointCount * 4, Uint32Array);
@@ -3241,23 +3180,17 @@ async function sopc_(opt) {
3241
3180
  arrayMap = new ArrayMap();
3242
3181
  map.set(fileIndex, arrayMap);
3243
3182
  }
3244
- arrayMap.append(itemIndex, i);
3245
- }
3246
- const transcendingCreation = ["window", "calcony railing", "glass balcony railing", "metal balcony railing", "temporary construction guardrail"];
3247
- const results = new Array(itemsFiles.length);
3248
- const sort = (pointarr, isTranscendingCreation, position) => {
3249
- let list = gridClustering(pointarr, gridSize, gridAmount);
3250
- if (list.length === 1) return list;
3251
- if (isTranscendingCreation) {
3252
- const distList = list.map((points2) => getPointDistance(getPointsCenter(points2), position));
3253
- let indices = Array.from({ length: list.length }, (_, i) => i);
3254
- indices.sort((a, b) => distList[a] - distList[b]);
3255
- const min = distList[indices[0]];
3256
- indices = indices.filter((i) => distList[i] - min < 0.12 * 2);
3257
- list = indices.map((i) => list[i]);
3258
- }
3259
- list.sort((a, b) => b.length - a.length);
3260
- return list;
3183
+ arrayMap.append(itemIndex - 1, i);
3184
+ }
3185
+ const results = new Array(itemsFiles.length).fill([]).map(() => []);
3186
+ const sort = (pointarr) => {
3187
+ let list = euclideanClusterExtraction(pointarr, 0.2).sort((a, b) => b.length - a.length);
3188
+ if (list.length === 1) return pointarr;
3189
+ return list[0].flatMap((i) => [
3190
+ pointarr[i * 3],
3191
+ pointarr[i * 3 + 1],
3192
+ pointarr[i * 3 + 2]
3193
+ ]);
3261
3194
  };
3262
3195
  map.forEach((arrMap, fileIndex) => {
3263
3196
  arrMap.forEach((pointIndexs, itemIndex) => {
@@ -3269,11 +3202,7 @@ async function sopc_(opt) {
3269
3202
  pointsArray[i * 3 + 2]
3270
3203
  );
3271
3204
  });
3272
- const itemsFile = itemsFiles[fileIndex];
3273
- const type = itemsFile.sam3Objects[itemIndex].category;
3274
- const isTranscendingCreation = transcendingCreation.includes(type);
3275
- pointarr = sort(pointarr, isTranscendingCreation, itemsFile.position)[0];
3276
- if (pointarr.length <= 6 * 3) return;
3205
+ pointarr = sort(pointarr);
3277
3206
  if (!results[fileIndex]) results[fileIndex] = new Array(itemsFiles[fileIndex].sam3Objects.length).fill([]);
3278
3207
  results[fileIndex][itemIndex] = pointarr;
3279
3208
  });