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 +1 -1
- package/src/index.d.ts +1 -3
- package/src/index.js +168 -246
package/package.json
CHANGED
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
2940
|
-
|
|
2860
|
+
// 获取当前点云深度值
|
|
2861
|
+
// let depthU32 = pcDepth[idx];
|
|
2862
|
+
// let depthF32 = orderedUintToFloat(depthU32);
|
|
2941
2863
|
|
|
2942
|
-
|
|
2943
|
-
|
|
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
|
|
2878
|
+
let idx = u32(ny) * u32(width) + u32(nx);
|
|
2954
2879
|
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
eroded = true;
|
|
2958
|
-
break;
|
|
2959
|
-
}
|
|
2960
|
-
}
|
|
2880
|
+
let depthU32 = pcDepth[idx];
|
|
2881
|
+
let depthF32 = orderedUintToFloat( depthU32 );
|
|
2961
2882
|
|
|
2962
|
-
|
|
2963
|
-
|
|
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
|
|
2969
|
-
|
|
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
|
|
2976
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2923
|
+
depthTol: { value: 0.05 },
|
|
2986
2924
|
result: {
|
|
2987
|
-
value:
|
|
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)
|
|
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
|
|
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
|
|
3052
|
-
if(isPolyEmpty(polyPackedIndex)) {
|
|
3053
|
-
return;
|
|
3054
|
-
}
|
|
2973
|
+
// 当前像素
|
|
2974
|
+
let center = unPackUint(textureLoad(map, vec2<i32>(x, y), 0));
|
|
3055
2975
|
|
|
3056
|
-
//
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
if(isEmpty(pointIndex)) {
|
|
2976
|
+
// 当前非空,保持原值
|
|
2977
|
+
if (!isEmpty(center)) {
|
|
2978
|
+
result[idx] = center;
|
|
3060
2979
|
return;
|
|
3061
2980
|
}
|
|
3062
2981
|
|
|
3063
|
-
//
|
|
3064
|
-
|
|
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 ||
|
|
2995
|
+
if (nx < 0 || nx >= width) {
|
|
3078
2996
|
continue;
|
|
3079
2997
|
}
|
|
3080
2998
|
|
|
3081
|
-
let
|
|
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
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3001
|
+
// 只要找到非空邻居,直接采用它的值
|
|
3002
|
+
if (!isEmpty(neighbor)) {
|
|
3003
|
+
dilatedValue = neighbor;
|
|
3004
|
+
break;
|
|
3090
3005
|
}
|
|
3091
3006
|
}
|
|
3092
|
-
}
|
|
3093
3007
|
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
}
|
|
3098
|
-
|
|
3099
|
-
// 判断当前点深度和最小深度的差值是否小于阈值
|
|
3100
|
-
if(abs(depthF32 - minDepth) > depthTol) {
|
|
3101
|
-
return;
|
|
3008
|
+
if (!isEmpty(dilatedValue)) {
|
|
3009
|
+
break;
|
|
3010
|
+
}
|
|
3102
3011
|
}
|
|
3103
3012
|
|
|
3104
|
-
|
|
3105
|
-
let finalPointIndex = unPackUint(packedIndex);
|
|
3106
|
-
result[finalPointIndex] = polyPackedIndex;
|
|
3013
|
+
result[idx] = dilatedValue;
|
|
3107
3014
|
`
|
|
3108
3015
|
);
|
|
3109
|
-
class
|
|
3110
|
-
|
|
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
|
-
|
|
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:
|
|
3027
|
+
value: new Uint32Array(width * height),
|
|
3129
3028
|
write: true
|
|
3130
3029
|
}
|
|
3131
3030
|
}
|
|
3132
3031
|
});
|
|
3133
|
-
this.result = result;
|
|
3134
3032
|
}
|
|
3135
|
-
|
|
3136
|
-
|
|
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]
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
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
|
-
|
|
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),
|
|
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(
|
|
3164
|
+
renderer.compute(dilateMaskComputeMaterial);
|
|
3233
3165
|
sopcComputeMaterial.setStorageBuffer("pcDepth", pcIndexMaterial.getStorageBuffer("depth"));
|
|
3234
|
-
sopcComputeMaterial.setStorageBuffer("polyAreaIndex",
|
|
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
|
|
3254
|
-
const
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
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
|
-
|
|
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);
|