rm-webgpu-compute-tasks 0.0.8 → 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.8",
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,8 @@ 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;
426
424
  groundZ?: number;
427
425
  }
428
426
 
package/src/index.js CHANGED
@@ -2216,22 +2216,6 @@ async function trajectoryHandle(baseUrl, trajectoryData) {
2216
2216
  pointCloudArray
2217
2217
  };
2218
2218
  }
2219
- function getPointsCenter(arr) {
2220
- let x = 0, y = 0, z = 0;
2221
- for (let i = 0; i < arr.length; i += 3) {
2222
- x += arr[i];
2223
- y += arr[i + 1];
2224
- z += arr[i + 2];
2225
- }
2226
- const count = arr.length / 3;
2227
- return { x: x / count, y: y / count, z: z / count };
2228
- }
2229
- function getPointDistance(p1, p2) {
2230
- const dx = p2.x - p1.x;
2231
- const dy = p2.y - p1.y;
2232
- const dz = p2.z - p1.z;
2233
- return Math.sqrt(dx * dx + dy * dy + dz * dz);
2234
- }
2235
2219
  class OcclusionMaterial extends ShaderMaterial {
2236
2220
  constructor(opt) {
2237
2221
  super({
@@ -2652,6 +2636,7 @@ const fragmentShader = (
2652
2636
  @location(0) vId: vec4<f32>,
2653
2637
  ) -> @location(0) vec4<f32> {
2654
2638
  return vId;
2639
+ // return vec4(1.0, 0, 0, 1);
2655
2640
  }
2656
2641
  `
2657
2642
  );
@@ -2665,7 +2650,8 @@ class PolyAreaIndexMaterial extends ShaderMaterial {
2665
2650
  side: "none",
2666
2651
  uniforms: {
2667
2652
  imageSize: { value: new Vector2(width, height) }
2668
- }
2653
+ },
2654
+ topology: "point-list"
2669
2655
  });
2670
2656
  this.resultTexture = resultTexture;
2671
2657
  }
@@ -2802,93 +2788,19 @@ class ArrayMap extends MapEnhance {
2802
2788
  return this.get(key);
2803
2789
  }
2804
2790
  }
2805
- class UnionFindSet {
2806
- parent;
2807
- rank;
2808
- constructor(size) {
2809
- this.parent = Array(size).fill(0).map((_, index) => index);
2810
- this.rank = Array(size).fill(1);
2811
- }
2812
- // 查找操作,使用路径压缩优化
2813
- find(x) {
2814
- if (this.parent[x] !== x) {
2815
- this.parent[x] = this.find(this.parent[x]);
2816
- }
2817
- return this.parent[x];
2818
- }
2819
- // 合并操作,使用按秩合并优化
2820
- union(x, y) {
2821
- let rootX = this.find(x);
2822
- let rootY = this.find(y);
2823
- if (rootX !== rootY) {
2824
- if (this.rank[rootX] > this.rank[rootY]) {
2825
- this.parent[rootY] = rootX;
2826
- } else if (this.rank[rootX] < this.rank[rootY]) {
2827
- this.parent[rootX] = rootY;
2828
- } else {
2829
- this.parent[rootY] = rootX;
2830
- this.rank[rootX] += 1;
2831
- }
2832
- }
2833
- }
2834
- /** 获取所有集合
2835
- * @returns
2836
- */
2837
- getAllSets() {
2838
- const sets = new ArrayMap();
2839
- for (const el of this.parent.keys()) {
2840
- const root = this.find(el);
2841
- sets.append(root, el);
2842
- }
2843
- return sets;
2844
- }
2845
- }
2846
- function hash(ix, iy, iz) {
2847
- return ix * 73856093 ^ iy * 19349663 ^ iz * 83492791;
2848
- }
2849
- function voxelization(pointsArray, size = 0.05) {
2850
- const inv = 1 / size, keySet = /* @__PURE__ */ new Set(), result = [], points = [];
2851
- for (let i = 0; i < pointsArray.length; i += 3) {
2852
- 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);
2853
- if (keySet.has(key)) continue;
2854
- keySet.add(key);
2855
- result.push(xi, yi, zi);
2856
- points.push(pointsArray[i], pointsArray[i + 1], pointsArray[i + 2]);
2857
- }
2858
- return { result, keySet, points };
2859
- }
2860
- function gridClustering(pointsArray, size = 0.05, threshold = 2) {
2861
- const { result, points, keySet } = voxelization(new Float32Array(pointsArray), size), unionFindSet = new UnionFindSet(keySet.size), keys = [...keySet.values()];
2862
- const indexMap = /* @__PURE__ */ new Map();
2863
- keys.forEach((v, i) => indexMap.set(v, i));
2864
- keys.forEach((key, i) => {
2865
- const x = result[i * 3];
2866
- const y = result[i * 3 + 1];
2867
- const z = result[i * 3 + 2];
2868
- for (let i2 = -threshold; i2 <= threshold; i2++) {
2869
- for (let j = -threshold; j <= threshold; j++) {
2870
- for (let k = -threshold; k <= threshold; k++) {
2871
- const xx = x + i2, yy = y + j, zz = z + k;
2872
- if (xx === x && yy === y && zz === z) continue;
2873
- const id = hash(xx, yy, zz);
2874
- if (!keySet.has(id)) continue;
2875
- unionFindSet.union(indexMap.get(key), indexMap.get(id));
2876
- }
2877
- }
2878
- }
2879
- });
2880
- return unionFindSet.getAllSets().map(
2881
- (list) => list.flatMap((i) => {
2882
- const x = points[i * 3];
2883
- const y = points[i * 3 + 1];
2884
- const z = points[i * 3 + 2];
2885
- return [x, y, z];
2886
- })
2887
- );
2888
- }
2889
2791
  const beforeCcde$1 = (
2890
2792
  /* wgsl*/
2891
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
+
2892
2804
  fn packUint(v: u32) -> vec4<f32>{
2893
2805
  return vec4(
2894
2806
  f32(v & 255u),
@@ -2906,9 +2818,17 @@ const beforeCcde$1 = (
2906
2818
  return (a << 24u) | (b << 16u) | (g << 8u) | r;
2907
2819
  }
2908
2820
 
2909
- fn isEmpty(value: u32) -> bool {
2821
+ fn isPolyEmpty(value: u32) -> bool {
2910
2822
  return value == 0xff000000 || value == 0x0 ;
2911
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
+ }
2912
2832
  `
2913
2833
  );
2914
2834
  const mainCode$1 = (
@@ -2917,93 +2837,105 @@ const mainCode$1 = (
2917
2837
  let width = i32(uniforms.size.x);
2918
2838
  let height = i32(uniforms.size.y);
2919
2839
  let half = i32(uniforms.kernelSize / 2);
2840
+ let depthTol = uniforms.depthTol;
2920
2841
 
2921
2842
  let x = i32(id.x);
2922
2843
  let y = i32(id.y);
2923
2844
 
2924
2845
  let idx = u32(y) * u32(width) + u32(x);
2925
2846
 
2926
- // 当前像素
2927
- let center = unPackUint(textureLoad(map, vec2<i32>(x, y), 0));
2928
-
2929
- // 如果当前就是空,直接空
2930
- if ( isEmpty(center) ) {
2931
- result[idx] = 0xff000000;
2847
+ // 判断是不是多边形区域
2848
+ let polyPackedIndex = polyAreaIndex[idx];
2849
+ if(isPolyEmpty(polyPackedIndex)) {
2932
2850
  return;
2933
2851
  }
2934
2852
 
2935
- // 是否被腐蚀
2936
- 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
+ // }
2937
2859
 
2938
- // 遍历邻域
2939
- for (var ky = -half; ky <= half; ky = ky + 1) {
2940
- let ny = y + ky;
2860
+ // 获取当前点云深度值
2861
+ // let depthU32 = pcDepth[idx];
2862
+ // let depthF32 = orderedUintToFloat(depthU32);
2941
2863
 
2942
- if (ny < 0 || ny >= height) {
2943
- continue;
2944
- }
2864
+ // 获取范围内最小深度值和对应点云索引
2865
+ let maxDepth = 10000.0;
2866
+ var minDepth = maxDepth;
2867
+ var minPcUv = vec2<i32>(0, 0);
2945
2868
 
2869
+ for (var ky = -half; ky <= half; ky = ky + 1) {
2870
+ let ny = y + ky;
2946
2871
  for (var kx = -half; kx <= half; kx = kx + 1) {
2947
2872
  let nx = x + kx;
2948
2873
 
2949
- if (nx < 0 || nx >= width) {
2874
+ if (nx < 0 || ny < 0 || nx >= width || ny >= height ) {
2950
2875
  continue;
2951
2876
  }
2952
2877
 
2953
- let neighbor = unPackUint(textureLoad(map, vec2<i32>(nx, ny), 0));
2878
+ let idx = u32(ny) * u32(width) + u32(nx);
2954
2879
 
2955
- // 只要有一个是空 腐蚀
2956
- if (isEmpty(neighbor) || neighbor != center) {
2957
- eroded = true;
2958
- break;
2959
- }
2960
- }
2880
+ let depthU32 = pcDepth[idx];
2881
+ let depthF32 = orderedUintToFloat( depthU32 );
2961
2882
 
2962
- if (eroded) {
2963
- break;
2883
+ if(depthF32 < minDepth) {
2884
+ minDepth = depthF32;
2885
+ minPcUv.x = nx;
2886
+ minPcUv.y = ny;
2887
+ }
2964
2888
  }
2965
2889
  }
2966
2890
 
2967
- // 写结果
2968
- if (eroded) {
2969
- result[idx] = 0xff000000;
2970
- } else {
2971
- result[idx] = center;
2891
+ // 是否找到最小值, 当前判断条件为未找到
2892
+ if(minDepth >= maxDepth) {
2893
+ return;
2972
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;
2973
2904
  `
2974
2905
  );
2975
- class ErodeMaskComputeMaterial extends ComputeMaterial {
2976
- 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);
2977
2910
  super({
2978
2911
  maxSize: [width, height],
2979
2912
  mainCode: mainCode$1,
2980
2913
  beforeCcde: beforeCcde$1,
2981
2914
  uniforms: {
2982
- 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
2983
2921
  size: { value: new Vector2(width, height) },
2984
2922
  kernelSize: { value: kernelSize },
2985
- // 建议从3开始
2923
+ depthTol: { value: 0.05 },
2986
2924
  result: {
2987
- value: new Uint32Array(width * height),
2925
+ value: result,
2988
2926
  write: true
2989
2927
  }
2990
2928
  }
2991
2929
  });
2930
+ this.result = result;
2931
+ }
2932
+ clearResult() {
2933
+ this.uniforms.result.value = this.result;
2992
2934
  }
2993
2935
  }
2994
2936
  const beforeCcde = (
2995
2937
  /* wgsl*/
2996
2938
  `
2997
- // fn orderedUintToFloat(u: u32) -> f32 {
2998
- // let mask = select(0x80000000u, 0xffffffffu, (u & 0x80000000u) != 0u);
2999
- // return bitcast<f32>(u ^ mask);
3000
- // }
3001
-
3002
- fn orderedUintToFloat(u: u32) -> f32 {
3003
- let restored = select(u ^ 0xffffffffu, u, (u & 0x80000000u) != 0u);
3004
- return bitcast<f32>(restored);
3005
- }
3006
-
3007
2939
  fn packUint(v: u32) -> vec4<f32>{
3008
2940
  return vec4(
3009
2941
  f32(v & 255u),
@@ -3018,19 +2950,11 @@ const beforeCcde = (
3018
2950
  let g = u32(color.g * 255.0);
3019
2951
  let b = u32(color.b * 255.0);
3020
2952
  let a = u32(color.a * 255.0);
3021
- return (a << 24u) | (b << 16u) | (g << 8u) | r;
3022
- }
3023
-
3024
- fn isPolyEmpty(value: u32) -> bool {
3025
- return value == 0xff000000 || value == 0x0 ;
2953
+ return (a << 24u) | (b << 16u) | (g << 8u) | r;
3026
2954
  }
3027
2955
 
3028
2956
  fn isEmpty(value: u32) -> bool {
3029
- return value == 0xff000000;
3030
- }
3031
-
3032
- fn isDepthEmpty(value: u32) -> bool {
3033
- return value == 0xffffffff;
2957
+ return value == 0xff000000 || value == 0x0;
3034
2958
  }
3035
2959
  `
3036
2960
  );
@@ -3040,101 +2964,116 @@ const mainCode = (
3040
2964
  let width = i32(uniforms.size.x);
3041
2965
  let height = i32(uniforms.size.y);
3042
2966
  let half = i32(uniforms.kernelSize / 2);
3043
- let depthTol = uniforms.depthTol;
3044
2967
 
3045
2968
  let x = i32(id.x);
3046
2969
  let y = i32(id.y);
3047
2970
 
3048
2971
  let idx = u32(y) * u32(width) + u32(x);
3049
2972
 
3050
- // 判断是不是多边形区域
3051
- let polyPackedIndex = polyAreaIndex[idx];
3052
- if(isPolyEmpty(polyPackedIndex)) {
3053
- return;
3054
- }
2973
+ // 当前像素
2974
+ let center = unPackUint(textureLoad(map, vec2<i32>(x, y), 0));
3055
2975
 
3056
- // 获取多边形当前坐标有没有点云(获取深度值判断也是一样的, 深度值和点云索引图一一对应)
3057
- let packedIndex = textureLoad(pcIndexMap, vec2<i32>(x, y), 0);
3058
- let pointIndex = unPackUint(packedIndex);
3059
- if(isEmpty(pointIndex)) {
2976
+ // 当前非空,保持原值
2977
+ if (!isEmpty(center)) {
2978
+ result[idx] = center;
3060
2979
  return;
3061
2980
  }
3062
2981
 
3063
- // 获取当前点云深度值
3064
- let depthU32 = pcDepth[idx];
3065
- let depthF32 = orderedUintToFloat(depthU32);
3066
-
3067
- // 获取范围内最小深度值和对应点云索引
3068
- let maxDepth = 10000.0;
3069
- var minDepth = maxDepth;
3070
- var minPcUv = vec2<i32>(0, 0);
2982
+ // 膨胀:空像素尝试被邻域填充
2983
+ var dilatedValue: u32 = 0xff000000;
3071
2984
 
3072
2985
  for (var ky = -half; ky <= half; ky = ky + 1) {
3073
2986
  let ny = y + ky;
2987
+
2988
+ if (ny < 0 || ny >= height) {
2989
+ continue;
2990
+ }
2991
+
3074
2992
  for (var kx = -half; kx <= half; kx = kx + 1) {
3075
2993
  let nx = x + kx;
3076
2994
 
3077
- if (nx < 0 || ny < 0 || nx >= width || ny >= height ) {
2995
+ if (nx < 0 || nx >= width) {
3078
2996
  continue;
3079
2997
  }
3080
2998
 
3081
- let idx = u32(ny) * u32(width) + u32(nx);
3082
-
3083
- let depthU32 = pcDepth[idx];
3084
- let depthF32 = orderedUintToFloat( depthU32 );
2999
+ let neighbor = unPackUint(textureLoad(map, vec2<i32>(nx, ny), 0));
3085
3000
 
3086
- if(depthF32 < minDepth) {
3087
- minDepth = depthF32;
3088
- minPcUv.x = nx;
3089
- minPcUv.y = ny;
3001
+ // 只要找到非空邻居,直接采用它的值
3002
+ if (!isEmpty(neighbor)) {
3003
+ dilatedValue = neighbor;
3004
+ break;
3090
3005
  }
3091
3006
  }
3092
- }
3093
3007
 
3094
- // 是否找到最小值, 当前判断条件为未找到
3095
- if(minDepth >= maxDepth) {
3096
- return;
3097
- }
3098
-
3099
- // 判断当前点深度和最小深度的差值是否小于阈值
3100
- if(abs(depthF32 - minDepth) > depthTol) {
3101
- return;
3008
+ if (!isEmpty(dilatedValue)) {
3009
+ break;
3010
+ }
3102
3011
  }
3103
3012
 
3104
- let finalPackedIndex = textureLoad(pcIndexMap, minPcUv, 0);
3105
- let finalPointIndex = unPackUint(packedIndex);
3106
- result[finalPointIndex] = polyPackedIndex;
3013
+ result[idx] = dilatedValue;
3107
3014
  `
3108
3015
  );
3109
- class SOPCComputeMaterial extends ComputeMaterial {
3110
- result;
3111
- constructor(width, height, count, pcIndexTexture, kernelSize = 15) {
3112
- const result = new Uint32Array(count).fill(4294967295);
3016
+ class DilateMaskComputeMaterial extends ComputeMaterial {
3017
+ constructor(width = 1920, height = 1200, texture, kernelSize = 3) {
3113
3018
  super({
3114
3019
  maxSize: [width, height],
3115
3020
  mainCode,
3116
3021
  beforeCcde,
3117
3022
  uniforms: {
3118
- pcIndexMap: { value: pcIndexTexture },
3119
- // 空白填充 0xff_00_00_00
3120
- pcDepth: { value: new Uint32Array() },
3121
- // 默认填充 0xff_ff_ff_ff
3122
- polyAreaIndex: { value: new Uint32Array() },
3123
- // 空白填充 0xff_00_00_00
3023
+ map: { value: texture },
3124
3024
  size: { value: new Vector2(width, height) },
3125
3025
  kernelSize: { value: kernelSize },
3126
- depthTol: { value: 0.05 },
3127
3026
  result: {
3128
- value: result,
3027
+ value: new Uint32Array(width * height),
3129
3028
  write: true
3130
3029
  }
3131
3030
  }
3132
3031
  });
3133
- this.result = result;
3134
3032
  }
3135
- clearResult() {
3136
- 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
+ }
3137
3075
  }
3076
+ return clusters;
3138
3077
  }
3139
3078
  async function load(base, urls) {
3140
3079
  let points = await loadPCDCustom(base + "/data/rgb_global_map.pcd");
@@ -3164,16 +3103,11 @@ function getInfo(itemsFile, cindex) {
3164
3103
  itemsFile.sam3Objects.forEach((item) => count += item.coordinates.length);
3165
3104
  const itemPosition = [];
3166
3105
  for (let i = 0; i < itemsFile.sam3Objects.length; i++) {
3167
- const item = itemsFile.sam3Objects[i], path = item.coordinates.map((coordinate) => new THREE.Vector2(coordinate[0], coordinate[1])), triangles = THREE.ShapeUtils.triangulateShape(path, []);
3168
- triangles.forEach(
3169
- (list) => list.forEach(
3170
- (index) => itemPosition.push(
3171
- path[index].x,
3172
- path[index].y,
3173
- cindex * 200 + i + 1
3174
- )
3175
- )
3176
- );
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
+ });
3177
3111
  }
3178
3112
  return {
3179
3113
  cameraMat,
@@ -3187,10 +3121,8 @@ async function sopc_(opt) {
3187
3121
  const {
3188
3122
  base,
3189
3123
  urls,
3190
- erodeMaskSize = 3,
3124
+ dilateMaskSize = 2,
3191
3125
  kernelSize = 15,
3192
- gridSize = 0.05,
3193
- gridAmount = 2,
3194
3126
  groundZ = 0
3195
3127
  } = opt;
3196
3128
  console.log("开始计算");
@@ -3201,7 +3133,7 @@ async function sopc_(opt) {
3201
3133
  canvasWidth = window.innerWidth ?? canvasWidth;
3202
3134
  canvasHeight = window.innerHeight ?? canvasHeight;
3203
3135
  }
3204
- 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(
3205
3137
  new BufferGeometry().setAttribute("position", new THREE.BufferAttribute(pointsArray, 3)),
3206
3138
  pcIndexMaterial
3207
3139
  ), mesh = new Object3D(
@@ -3229,9 +3161,9 @@ async function sopc_(opt) {
3229
3161
  renderer.renderTarget = polyAreaIndexMaterial.resultTexture.view;
3230
3162
  renderer.depthTarget = polyAreaIndexMaterial.resultTexture.depthView;
3231
3163
  renderer.render([mesh], camera);
3232
- renderer.compute(erodeMaskComputeMaterial);
3164
+ renderer.compute(dilateMaskComputeMaterial);
3233
3165
  sopcComputeMaterial.setStorageBuffer("pcDepth", pcIndexMaterial.getStorageBuffer("depth"));
3234
- sopcComputeMaterial.setStorageBuffer("polyAreaIndex", erodeMaskComputeMaterial.getStorageBuffer("result"));
3166
+ sopcComputeMaterial.setStorageBuffer("polyAreaIndex", dilateMaskComputeMaterial.getStorageBuffer("result"));
3235
3167
  renderer.compute(sopcComputeMaterial);
3236
3168
  }
3237
3169
  const resultsBuffer = await readGPUBuffer(sopcComputeMaterial.getStorageBuffer("result"), pointCount * 4, Uint32Array);
@@ -3250,21 +3182,15 @@ async function sopc_(opt) {
3250
3182
  }
3251
3183
  arrayMap.append(itemIndex - 1, i);
3252
3184
  }
3253
- const transcendingCreation = ["window", "calcony railing", "glass balcony railing", "metal balcony railing", "temporary construction guardrail"];
3254
- const results = new Array(itemsFiles.length);
3255
- const sort = (pointarr, isTranscendingCreation, position) => {
3256
- let list = gridClustering(pointarr, gridSize, gridAmount);
3257
- if (list.length === 1) return list;
3258
- if (isTranscendingCreation) {
3259
- const distList = list.map((points2) => getPointDistance(getPointsCenter(points2), position));
3260
- let indices = Array.from({ length: list.length }, (_, i) => i);
3261
- indices.sort((a, b) => distList[a] - distList[b]);
3262
- const min = distList[indices[0]];
3263
- indices = indices.filter((i) => distList[i] - min < 0.12 * 2);
3264
- list = indices.map((i) => list[i]);
3265
- }
3266
- list.sort((a, b) => b.length - a.length);
3267
- return list;
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
+ ]);
3268
3194
  };
3269
3195
  map.forEach((arrMap, fileIndex) => {
3270
3196
  arrMap.forEach((pointIndexs, itemIndex) => {
@@ -3276,15 +3202,11 @@ async function sopc_(opt) {
3276
3202
  pointsArray[i * 3 + 2]
3277
3203
  );
3278
3204
  });
3279
- const itemsFile = itemsFiles[fileIndex];
3280
- const type = itemsFile.sam3Objects[itemIndex].category;
3281
- const isTranscendingCreation = transcendingCreation.includes(type);
3282
- pointarr = sort(pointarr, isTranscendingCreation, itemsFile.position)[0];
3205
+ pointarr = sort(pointarr);
3283
3206
  if (!results[fileIndex]) results[fileIndex] = new Array(itemsFiles[fileIndex].sam3Objects.length).fill([]);
3284
3207
  results[fileIndex][itemIndex] = pointarr;
3285
3208
  });
3286
3209
  });
3287
- console.log(results, itemsFiles[0]);
3288
3210
  renderer.renderTarget = null;
3289
3211
  renderer.depthTarget = null;
3290
3212
  console.log("整理结果消耗时间:", performance.now() - t, "点云数量", pointsArray.length / 3, "文件数量", itemsFiles.length);