Unity3D 八叉树划分空间和可视化

news2024/12/23 19:58:57

也许更好的阅读体验

成果展示

所有层
第一层

第二层

代码

OctreeNode
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class OctreeNode
{
    //空间内包含的物体
    public List<GameObject> areaObjects;
    //空间中心
    public Vector3 center;
    //空间大小
    public float size;
    //子节点个数 
    private int kidCount = 8;
    //子节点
    public OctreeNode[] kids;
    //构造函数
    public OctreeNode (Vector3 center, float size)
    {
        this.center = center;
        this.size = size;
        kids = new OctreeNode[kidCount];
        areaObjects = new List<GameObject>();
    }
    #region 八个子节点中心对应的偏移方向
    public static Vector3[] centerOffset = new Vector3[8] {
        new Vector3 (-1, 1, -1),
        new Vector3 (1, 1, -1),
        new Vector3 (-1, 1, 1),
        new Vector3 (1, 1, 1),
        new Vector3 (-1, -1, -1),
        new Vector3 (1, -1, -1),
        new Vector3 (-1, -1, 1),
        new Vector3 (1, -1, 1)
    };
    #endregion

    #region 空间和内部物体管理
    //空间内物体树
    public int objectCount => areaObjects.Count;
    //把该空间画出来
    public void DrawGizmos ()
    {
        Gizmos.DrawWireCube(center, Vector3.one * size);
    }
    //判断是否包含某个点
    public bool Contains (Vector3 position)
    {
        float halfSize = size / 2.0f;
        return Mathf.Abs(position.x - center.x) <= halfSize &&
            Mathf.Abs(position.y - center.y) <= halfSize &&
            Mathf.Abs(position.z - center.z) <= halfSize;
    }
    //清理空间内物体
    public void Clear ()
    {
        areaObjects.Clear();
    }
    //添加物体
    public void AddGameObject (GameObject obj)
    {
        areaObjects.Add(obj);
    }
    #endregion

}

Orctree
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.Design.Serialization;
using Unity.VisualScripting;
using UnityEngine;

//可视化模式
public enum OctreeDebugMode
{
    AllDepth,
    TargetDepth
}
public class Octree : MonoBehaviour
{

    #region 物体生成和构建八叉树
    //生成物体数
    [Range(0, 500)]
    public int genCount = 500;
    //物体生成范围
    [Range(1, 300)]
    public float range = 100;
    //生成的物体
    public List<GameObject> sceneObjects;
    //Octree最大层数
    [Range(1, 8)]
    public int maxDepth = 3;
    //Octree的根节点
    public OctreeNode root;


    // Start is called before the first frame update
    void Start()
    {
        GenObjects();
        OctreePartition();
    }

    //随机生成一些cube
    private void GenObjects()
    {
        float genRange = range * 0.5f;
        sceneObjects = new List<GameObject>();

        for (int i = 0; i < genCount; ++i)
        {
            GameObject obj = GameObject.CreatePrimitive(PrimitiveType.Cube);
            obj.transform.position = new Vector3(Random.Range(-genRange, genRange),
                Random.Range(-genRange, genRange),
                Random.Range(-genRange, genRange));
            obj.hideFlags = HideFlags.HideInHierarchy;
            sceneObjects.Add(obj);
        }
    }
    //进行八叉树划分
    private void OctreePartition ()
    {
        //设定根节点
        Vector3 origin = Vector3.one;
        root = new OctreeNode(Vector3.zero, range);
        root.areaObjects = sceneObjects;
        //往下生成八叉树 根节点层数为1
        GenerateOcetree(root, range, 2);
    }
    //递归往下生成八叉树
    private void GenerateOcetree (OctreeNode root, float range, int depth)
    {
        //depth是当前生成的层数
        if (depth > maxDepth) return;
        //下一层的大小
        float halfRange = range / 2.0f;
        //根节点偏移量
        float rootOffset = halfRange / 2.0f;
        for (int i = 0; i < 8; ++i)
        {
            Vector3 origin = root.center + OctreeNode.centerOffset[i] * rootOffset;
            root.kids[i] = new OctreeNode(origin, halfRange);
        }
        PartitionSceneObjects(root);
        for (int i = 0; i < 8; ++i)
        {
            if (root.kids[i].objectCount >= 2) GenerateOcetree(root.kids[i], halfRange, depth + 1);
        }
    }
    //把空间内物体划分给子节点
    private void PartitionSceneObjects(OctreeNode root)
    {
        foreach (GameObject obj in root.areaObjects)
        {
            foreach (OctreeNode kid in root.kids)
            {
                if (kid.Contains(obj.transform.position))
                {
                    kid.AddGameObject(obj);
                }
            }
        }
    }
    #endregion

    #region 可视化
    //是否显示八叉树
    public bool showOctree = true;
    //可视化类型
    public OctreeDebugMode octreeDebugMode;
    //可视化层数
    [Range(0, 8)]
    public int displayDepth = 3;
    //不同深度的可视化颜色
    public Color[] displayColor;
    private void OnDrawGizmos()
    {
        if (root == null) return;
        if (showOctree && displayDepth <= maxDepth)
        {
            //显示所有深度的空间范围
            if (octreeDebugMode == OctreeDebugMode.AllDepth)
            {
                DrawNode(root, 1);
            }
            //显示指定深度的空间范围(第displayDepth层)
            else if (octreeDebugMode == OctreeDebugMode.TargetDepth)
            {
                if (displayDepth > 0 && displayColor.Length >= displayDepth) 
                {
                    Color color = displayColor[displayDepth - 1];
                    color.a = 0.5f;
                    Gizmos.color = color;
                    DrawTargetDepth(root, displayDepth);
                }
            }
        }
    }
    //绘制所有节点 当前深度为depth
    private void DrawNode(OctreeNode root, int depth)
    {
        if (root == null || depth > maxDepth) return;
        Color color = displayColor[depth - 1];
        color.a = 0.5f;
        Gizmos.color = color;
        root.DrawGizmos();
        foreach (OctreeNode kid in root.kids)
        {
            DrawNode(kid, depth + 1);
        }
    }
    //绘制指定层
    private void DrawTargetDepth (OctreeNode root, int targetDepth)
    {
        --targetDepth;
        if (root == null || targetDepth < 0) return;
        Debug.Log(targetDepth);
        if (targetDepth == 0)
        {
            root.DrawGizmos();
            return;
        }
        foreach (OctreeNode kid in root.kids)
        {
            DrawTargetDepth(kid, targetDepth);
        }
    }
    #endregion
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1842384.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL:SELECT list is not in GROUP BY clause 报错 解决方案

一、前言 一大早上测试环境&#xff0c;发现测试环境的MySQL报错了。 SELECT list is not in GROUP BY clause and contains nonaggregated column二、解决方案 官方文档中提到&#xff1a; 大致意思&#xff1a; 用于GROUP BY的SQL / 92标准要求满足以下条件&#xff1a; SE…

RA6M1语音识别演示板

介绍&#xff1a; 本应用说明解释了瑞萨电子语音识别演示的硬件规格 主板RTK0EA0004D00001BJ&#xff0c;采用RA6M1 应用图示&#xff1a; 开发板如图所示&#xff1a; 原理图&#xff1a; 学下布局&#xff1a;

如何在软件开发时代实现技术+业务的双重突破?【含资源】

在当前的软件开发时代&#xff0c;许多企业面临着核心技术缺失、专业人才短缺以及产品能力单一等问题&#xff0c; 迫切需要加强技术实力&#xff0c;补充和扩展原有的业务和行业能力。 将技术与业务需求深度结合&#xff0c;构建适应时代需求的技术业务模式&#xff0c;成为软…

EulerOS 安装docker 拉取opengauss 、redis镜像

#下载docker包 wget https://download.docker.com/linux/static/stable/x86_64/docker-18.09.9.tgz #解压 tar zxf docker-18.09.9.tgz #移动解压后的文件夹到/usr/bin mv docker/* /usr/bin #写入docker.service cat >/usr/lib/systemd/system/docker.service <<E…

“2024国际数字能源展”推动绿色低碳发展,助力实现“双碳”目标

随着全球气候变化问题的日益严峻&#xff0c;构建现代能源体系、推动绿色低碳发展已成为各国共同的使命和追求。在这一背景下&#xff0c;我国提出了“四个革命、一个合作”的能源安全新战略&#xff0c;旨在推动能源生产消费革命&#xff0c;保障国家能源安全&#xff0c;助力…

避雷!紧急停止投稿,毕业神刊Aging危险了,被数据库“On Hold“!

本周投稿推荐 SSCI • 中科院2区&#xff0c;6.0-7.0&#xff08;录用友好&#xff09; EI • 各领域沾边均可&#xff08;2天录用&#xff09; CNKI • 7天录用-检索&#xff08;急录友好&#xff09; SCI&EI • 4区生物医学类&#xff0c;0.5-1.0&#xff08;录用…

惠普8596E频谱分析仪

8590E系列频谱分析仪具有各种各样的性能、功能&#xff0c;其价格亦是为适应用户的承受能力而确定的。用户可以从价格低廉、具有基本性能的分析仪直至高性能分析仪中进行挑选&#xff0c;无论选择哪种分析仪&#xff0c;都会感受到8590系列频谱分析仪便于使用且高度可靠。这些仪…

ICC2如何写DCG需要的floorplan信息

我正在「拾陆楼」和朋友们讨论有趣的话题,你⼀起来吧? 拾陆楼知识星球入口 DCG需要哪些floorplan信息呢? 1)fixed属性的port和mem / ip / io 2)boundary信息 3)电源域形状 前两条都可以写到def里,电源域需要用脚本处理,这里分享一下脚本。 set_fixed_objects [ge…

简易在线浮动客服-网站右侧悬停浮动在线客服代码

本文将介绍如何制作一个简单的在线浮动客服&#xff0c;这是一个网站右侧悬浮窗的在线客服&#xff0c;并分享完整的代码实现。 CSS /* 基础样式重置 */body, html {margin: 0;padding: 0;font-family: Arial, sans-serif;}/* 固定小部件位置 */.fixed-widget {position: fixe…

Day14—基于Langchain-chatchat搭建本地智能

一、基于Langchain-chatchat搭建本地智能 知识问答系统 1、项目介绍 基于 ChatGLM 等大语言模型与 Langchain 等应用框架实现&#xff0c;开一种利用 langchain 思想实现的基于本地知识库的问答应用&#xff0c;目标期望建立一套对中文场景与开源模型支持友好、可离线运行的知…

fastapi给文档页面docs/加锁

加锁后效果如下&#xff1a; 如图docs/页面打开默认是茶壶&#xff0c;需加上定制参数才能正常访问 &#xff1a; 具体实现如下&#xff1a; 1. 安装依赖包&#xff1a; pip install fastapi-cdn-host>0.5.2 || pip install --upgrade gitssh://gitgithub.com/waketzheng…

XGBoost算法详解

XGBoost算法详解 XGBoost&#xff08;Extreme Gradient Boosting&#xff09;是一种高效的梯度提升决策树&#xff08;GBDT&#xff09;实现&#xff0c;因其高性能和灵活性在机器学习竞赛中广泛使用。本文将详细介绍XGBoost算法的原理&#xff0c;并展示其在实际数据集上的应…

hbuilderx如何打包ios app,如何生成证书

hbuilderx可以打包ios app, 但是打包的时候&#xff0c;却需要两个证书文件&#xff0c;我们又如何生成这两个证书文件呢&#xff1f; 点击hbuilderx的官网链接&#xff0c;教程是需要使用mac电脑苹果开发者账号去创建这两个文件&#xff0c;可是问题来了&#xff0c;我们没有…

代码随想录算法训练营第六十五天 | 岛屿数量 深搜、岛屿数量 广搜、岛屿的最大面积

岛屿数量 深搜 题目链接&#xff1a;99. 岛屿数量 文字讲解&#xff1a;99. 岛屿数量 | 代码随想录 解题思路 本题已经说明&#xff0c;只有水平方向和竖直方向才能组成岛屿 本题思路&#xff0c;是遇到一个没有遍历过的节点陆地&#xff0c;计数器就加一&#xff0c;然后把…

【STC8A8K64D4开发板】第3-2讲:温湿度传感器DHT11

第3-2讲&#xff1a;温湿度传感器DHT11 学习目的了解DHT11数字温湿度传感器的基本原理及其数据格式。掌握STC8A8K64D4与DHT11单总线通信的程序设计&#xff0c;通信步骤&#xff0c;数据校验等。 硬件电路设计 湿敏元件简介 湿敏元件是最简单的湿度传感器。湿敏元件比较常见的…

基于GWO-CNN-LSTM数据时间序列预测(多输入单输出)-多维时间序列模型-MATLAB实现

基于GWO-CNN-LSTM数据时间序列预测(多输入单输出)-多维时间序列模型-MATLAB实现 基于灰狼优化&#xff08;Grey Wolf Optimizer, GWO&#xff09;、卷积神经网络&#xff08;Convolutional Neural Network, CNN&#xff09;和长短期记忆网络&#xff08;Long Short-Term Memor…

Socket编程之多进程模型

一、多进程模型概述 基于最初的阻塞网络 I/O &#xff0c;若服务器要为多个客户端提供支持&#xff0c;在较为传统的手段中&#xff0c;多进程模型是常用的选择&#xff0c;即为每个客户端都分配一个进程来处理其请求。 服务器的主进程主要负责对客户连接的监听&#xff0c;一旦…

【docker安装rabbitmq】

docker安装rabbitmq 1.查阅rabbitmq的Dokcer Hub官方说明 rabbitmq地址&#xff0c;因为我们需要使用的是带管理界面的rabbitmq服务。所以我们需要下载的rabbitmq:management镜像 docker pull rabbitmq:management2.启动rabbitmq 2.1.快速启动 One of the important thing…

Linux:配置本地yum源仓库

目录 一、挂载光盘到目录下 二、配置本地yum源仓库 一、挂载光盘到目录下 mount /dev/cdrom /mnt/ #把光盘挂载到/mnt目录下 挂载 设备 目录或文件夹 注&#xff1a;最好是空的 原来的数据将被隐藏一个挂载点同一时只能挂载一个设备。 mount /dev…

opencv中凸包运算函数convexHull()的使用

操作系统&#xff1a;ubuntu22.04OpenCV版本&#xff1a;OpenCV4.9IDE:Visual Studio Code编程语言&#xff1a;C11 1.功能描述 该函数cv::convexHull用于寻找一组二维点集的凸包&#xff0c;采用的是Sklansky算法[242]&#xff0c;当前实现中具有O(N logN)的时间复杂度。 1…