Unity实现DBSCAN

参考连接

直接上代码,把脚本挂载到场景中的物体上,运行应该就就能看到效果。

csharp 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TestDBSCAN : MonoBehaviour
{

    private List<GameObject> goList = new List<GameObject>();
    private List<Vector3> posList = new List<Vector3>();
    // Start is called before the first frame update
    void Start()
    {
        //创建随机点
        for (int j = 0; j < 5; j++)
        {
            for (int i = 0; i < 100; i++)
            {
                GameObject go = GameObject.CreatePrimitive(PrimitiveType.Sphere);
                go.transform.localScale = Vector3.one * 0.1f;
                go.transform.position = Random.insideUnitSphere * 5;
                go.transform.position += Vector3.one * j * 10;
                goList.Add(go);
                posList.Add(go.transform.position);
            }
        }

        //执行算法
        int[] result = DBSCAN.Cluster(posList, 3, 4);

        Dictionary<int, List<GameObject>> dic = new Dictionary<int, List<GameObject>>();

        //将算法结果分组
        for (int i = 0; i < result.Length; i++)
        {
            int key = result[i];
            if (dic.ContainsKey(key))
            {
                dic[key].Add(goList[i]);
            }
            else
            {
                List<GameObject> tempList = new List<GameObject>();
                tempList.Add(goList[i]);
                dic.Add(key, tempList);
            }
        }

        //对GameObject进行分组
        foreach (var item in dic)
        {
            GameObject goParent = new GameObject();
            goParent.name = item.Key.ToString();
            foreach (var item2 in item.Value)
            {
                item2.transform.SetParent(goParent.transform);
            }
        }

    }

}

public class DBSCAN
{
    /// <summary>
    /// 
    /// </summary>
    /// <param name="points">点的集合</param>
    /// <param name="minPts">最小个数</param>
    /// <param name="eps">最小半径</param>
    /// <returns></returns>
    public static int[] Cluster(List<Vector3> points, int minPts, int eps)
    {
        int n = points.Count;
        int[] labels = new int[n];
        int clusterId = 0;

        // 初始化所有点的标签为-1,表示未分类
        for (int i = 0; i < n; i++)
        {
            labels[i] = -1;
        }

        // 遍历所有点
        for (int i = 0; i < n; i++)
        {
            Vector3 p = points[i];
            // 如果点已经分类,则跳过
            if (labels[i] != -1)
            {
                continue;
            }
            // 找到p的邻居点
            List<Vector3> neighbors = GetNeighbors(points, p, eps);
            // 如果邻居点数量小于minPts,则将p标记为噪声点
            if (neighbors.Count < minPts)
            {
                labels[i] = 0;
                continue;
            }
            // 新建一个簇
            clusterId++;
            labels[i] = clusterId;
            // 扩展簇
            ExpandCluster(points, labels, neighbors, clusterId, eps, minPts);
        }
        return labels;
    }

    public static void ExpandCluster(List<Vector3> points, int[] labels, List<Vector3> neighbors, int clusterId, int eps, int minPts)
    {
        // 遍历邻居点
        for (int i = 0; i < neighbors.Count; i++)
        {
            Vector3 q = neighbors[i];
            int index = points.IndexOf(q);
            // 如果邻居点未分类,则将其加入簇中
            if (labels[index] == -1)
            {
                labels[index] = clusterId;
                // 找到q的邻居点
                List<Vector3> qNeighbors = GetNeighbors(points, q, eps);
                // 如果邻居点数量大于等于minPts,则将其加入扩展簇的邻居点列表中
                if (qNeighbors.Count >= minPts)
                {
                    neighbors.AddRange(qNeighbors);
                }
            }
            // 如果邻居点已经被分类为噪声点,则将其重新分类到当前簇中
            else if (labels[index] == 0)
            {
                labels[index] = clusterId;
            }
        }
    }

    private static List<Vector3> GetNeighbors(List<Vector3> list, Vector3 corePoint, float radius)
    {
        List<Vector3> result = new List<Vector3>();
        foreach (var p in list)
        {
            if (Vector3.Distance(corePoint, p) <= radius)
                result.Add(p);
        }
        return result;
    }
}
相关推荐
相信神话20214 小时前
Godot Shader 中 mix 函数的用法
游戏引擎·godot
郝学胜-神的一滴4 小时前
Horse3D游戏引擎研发笔记(七):在QtOpenGL环境下,使用改进的Uniform变量管理方式绘制多彩四边形
c++·3d·unity·游戏引擎·图形渲染·虚幻·unreal engine
巨龙之路7 小时前
Unity的Cursor.lockState
unity·游戏引擎
★YUI★9 小时前
学习制作记录(选项UI以及存档系统)8.24
学习·游戏·ui·unity·c#
枯萎穿心攻击15 小时前
从 Unity UGUI 到 Unreal UMG 的交互与高效实践:UI 事件、坐标系适配与性能优化
开发语言·ui·unity·性能优化·ue5·游戏引擎·虚幻引擎
SmalBox1 天前
【渲染流水线】[逐片元阶段]-[深度测试]以UnityURP为例
unity·渲染
Thomas_YXQ2 天前
Unity3D编辑器扩展-物体批量替换设置材质
游戏·unity·编辑器·游戏引擎·材质
雪下的新火2 天前
Unity-HDRP场景搭建-那山
经验分享·笔记·unity·游戏引擎·场景搭建
郝学胜-神的一滴3 天前
深度解析游戏引擎中的相机:视图矩阵
程序人生·unity·矩阵·游戏引擎·godot·图形渲染·虚幻