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 +1 -1
- package/src/index.d.ts +2 -3
- package/src/index.js +180 -251
package/package.json
CHANGED
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
|
-
|
|
422
|
+
dilateMaskSize?: number;
|
|
423
423
|
kernelSize?: number;
|
|
424
|
-
|
|
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(
|
|
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: -
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
2935
|
-
|
|
2860
|
+
// 获取当前点云深度值
|
|
2861
|
+
// let depthU32 = pcDepth[idx];
|
|
2862
|
+
// let depthF32 = orderedUintToFloat(depthU32);
|
|
2936
2863
|
|
|
2937
|
-
|
|
2938
|
-
|
|
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
|
|
2878
|
+
let idx = u32(ny) * u32(width) + u32(nx);
|
|
2949
2879
|
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
eroded = true;
|
|
2953
|
-
break;
|
|
2954
|
-
}
|
|
2955
|
-
}
|
|
2880
|
+
let depthU32 = pcDepth[idx];
|
|
2881
|
+
let depthF32 = orderedUintToFloat( depthU32 );
|
|
2956
2882
|
|
|
2957
|
-
|
|
2958
|
-
|
|
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
|
|
2964
|
-
|
|
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
|
|
2971
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2923
|
+
depthTol: { value: 0.05 },
|
|
2981
2924
|
result: {
|
|
2982
|
-
value:
|
|
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)
|
|
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
|
|
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
|
|
3047
|
-
if(isPolyEmpty(polyPackedIndex)) {
|
|
3048
|
-
return;
|
|
3049
|
-
}
|
|
2973
|
+
// 当前像素
|
|
2974
|
+
let center = unPackUint(textureLoad(map, vec2<i32>(x, y), 0));
|
|
3050
2975
|
|
|
3051
|
-
//
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
if(isEmpty(pointIndex)) {
|
|
2976
|
+
// 当前非空,保持原值
|
|
2977
|
+
if (!isEmpty(center)) {
|
|
2978
|
+
result[idx] = center;
|
|
3055
2979
|
return;
|
|
3056
2980
|
}
|
|
3057
2981
|
|
|
3058
|
-
//
|
|
3059
|
-
|
|
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 ||
|
|
2995
|
+
if (nx < 0 || nx >= width) {
|
|
3073
2996
|
continue;
|
|
3074
2997
|
}
|
|
3075
2998
|
|
|
3076
|
-
let
|
|
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
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3001
|
+
// 只要找到非空邻居,直接采用它的值
|
|
3002
|
+
if (!isEmpty(neighbor)) {
|
|
3003
|
+
dilatedValue = neighbor;
|
|
3004
|
+
break;
|
|
3085
3005
|
}
|
|
3086
3006
|
}
|
|
3087
|
-
}
|
|
3088
3007
|
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
}
|
|
3093
|
-
|
|
3094
|
-
// 判断当前点深度和最小深度的差值是否小于阈值
|
|
3095
|
-
if(abs(depthF32 - minDepth) > depthTol) {
|
|
3096
|
-
return;
|
|
3008
|
+
if (!isEmpty(dilatedValue)) {
|
|
3009
|
+
break;
|
|
3010
|
+
}
|
|
3097
3011
|
}
|
|
3098
3012
|
|
|
3099
|
-
|
|
3100
|
-
let finalPointIndex = unPackUint(packedIndex);
|
|
3101
|
-
result[finalPointIndex] = polyPackedIndex;
|
|
3013
|
+
result[idx] = dilatedValue;
|
|
3102
3014
|
`
|
|
3103
3015
|
);
|
|
3104
|
-
class
|
|
3105
|
-
|
|
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
|
-
|
|
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:
|
|
3027
|
+
value: new Uint32Array(width * height),
|
|
3124
3028
|
write: true
|
|
3125
3029
|
}
|
|
3126
3030
|
}
|
|
3127
3031
|
});
|
|
3128
|
-
this.result = result;
|
|
3129
3032
|
}
|
|
3130
|
-
|
|
3131
|
-
|
|
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]
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
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
|
-
|
|
3124
|
+
dilateMaskSize = 2,
|
|
3186
3125
|
kernelSize = 15,
|
|
3187
|
-
|
|
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),
|
|
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(
|
|
3164
|
+
renderer.compute(dilateMaskComputeMaterial);
|
|
3226
3165
|
sopcComputeMaterial.setStorageBuffer("pcDepth", pcIndexMaterial.getStorageBuffer("depth"));
|
|
3227
|
-
sopcComputeMaterial.setStorageBuffer("polyAreaIndex",
|
|
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
|
|
3247
|
-
const
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
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
|
-
|
|
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
|
});
|