Unity绘制六边形体

现在steam上面有很多下棋类/经营类的游戏都是用六边形的地形,比较美观而且实用,去年在版本末期我也自己尝试做了一个绘制六边体的demo,一年没接触unity竟然都要忘光了,赶紧在这边记录一下。
想cv代码可以直接拉到代码章节

功能

能够动态生成一系列可以“挖空中心”的六边形。指定innerWidth为0也可以生成实心的六边体。
在这里插入图片描述
在这里插入图片描述
能够生成平铺/直铺的六边形群,调整之间距离
在这里插入图片描述在这里插入图片描述在这里插入图片描述

绘制思路

将绘制一个六边形看成六个下面这种等腰体,绕中心旋转60度之后合并成一个。
在这里插入图片描述
在这里插入图片描述
一个这种等腰体又可以看成绘制四个面:上面的等腰梯形,内测的长方形,下面的等腰梯形,外侧的长方形,两边无需绘制,因为合并之后不会显示出来。
所以只需要通过三角函数计算出我们所需的所有点->拼出一个面->合成一个等腰体->合成一个六边体。

组件

我们需要一个MeshFilter来设置mesh,一个MeshRenderer来设置mesh的材质。同时需要对mesh所需的内置成员变量有些了解。
在这里插入图片描述

        m_meshFilter = GetComponent<MeshFilter>();m_meshRenderer = GetComponent<MeshRenderer>();m_mesh = new Mesh();m_mesh.name = "HexMesh";m_meshFilter.mesh = m_mesh;m_meshRenderer.material = m_material;//最终数据传入m_mesh.vertices = verticles.ToArray();m_mesh.triangles = tris.ToArray();m_mesh.uv = uvs.ToArray();m_mesh.RecalculateNormals();

具体计算

绘制某个点

根据前面需要绘制的等腰梯形,设A是梯形长边的点,B是梯形短边的点,易得平面内某个点的计算方式
在这里插入图片描述
定义一个CreatePoint接口,根据width和y轴高度height来生成某个点的三维向量,(注意unity下生成图中y轴实际上是三维空间的z轴)

  private Vector3 CreatePoint(float distance, float height, float angle){float rad = angle * Mathf.Deg2Rad; //Mathf接收的参数需要是弧度制return new Vector3(distance * Mathf.Cos(rad), height, distance * Mathf.Sin(rad));}

生成面所需的数据

上文提到的等腰体四个不同面实际上都是四个顶点组成的,并且都是两个点组成的平行的线段,所以我们可以提供一个接口,只需指定高度和半径,就可以画出这四种不同的面,同时存在上下和内外两侧面的朝向是相反的,所以提供reverse接口来进行反向。

    /// <summary>/// 上下底面的单独一个等腰梯形/// </summary>/// <param name="innerRad">内径</param>/// <param name="outerRad">外径</param>/// <param name="heightA">外高</param>/// <param name="heightB">内高</param>/// <param name="point">顺序</param>/// <param name="reverse">连接方向</param>/// <returns></returns>private Face CreateFace(float innerRad, float outerRad, float heightA, float heightB, int point, bool reverse = false){float angle1 = point * 60;float angle2 = angle1 + 60;if (!isFlat){ //竖着排布,初始角度是-30angle1 -= 30;angle2 -= 30;}List<Vector3> verticals = new List<Vector3>();//.......C.//..B.......//..........//...A......Dverticals.Add(CreatePoint(innerRad, heightA, angle1));verticals.Add(CreatePoint(innerRad, heightA, angle2));verticals.Add(CreatePoint(outerRad, heightB, angle2));verticals.Add(CreatePoint(outerRad, heightB, angle1));List<int> tris = new List<int> { 0, 1, 2, 2, 3, 0};List<Vector2> uv = new List<Vector2> { new Vector2(0, 0),new Vector2(1,0),new Vector2(1,1),new Vector2(0,1) };//vertical顺序颠倒,就会按照顺时针绘制。if(reverse){verticals.Reverse();}return new Face(verticals, tris, uv);}

这里有一些关于mesh的基础知识,首先是三个顶点能够组成一个面,从上往下看如果点之间是逆时针顺序的话,就是面向我们的。这里我们添加了四个点。tirs指定其顺序,每三个一组将会连成一个面,uvs代表是渲染的时候的uv坐标,这里如果六边体有规范的话,就需要根据需求设置对应的uv值,这里就不关注这个了。

      List<int> tris = new List<int> { 0, 1, 2, 2, 3, 0};List<Vector2> uv = new List<Vector2> { new Vector2(0, 0),new Vector2(1,0),new Vector2(1,1),new Vector2(0,1) };
public struct Face
{//顶点位置数组public List<Vector3> verticles { get; private set; }//三角形顶点索引数组,按给定的顺序连接顶点,为顺时针三个一组的顺序public List<int> triangles { get; private set; }public List<Vector2> uvs { get; private set; }public Face(List<Vector3> verticles, List<int> triangles, List<Vector2> uvs){this.verticles = verticles;this.triangles = triangles;this.uvs = uvs;}
}

这样能够生产出一个面,接下来我们批量生产所需的面,只需要不断让角度偏移60度(忘记了可以去看上面计算A点坐标),重复刚才的步骤,将所有的面的数据都生成

 private void DrawFaces(){m_faces = new List<Face>();//上表面for(int point = 0; point < 6; point ++){m_faces.Add(CreateFace(innerWidth, outerWidth, height / 2, height / 2, point));}//下表面for (int point = 0; point < 6; point++){m_faces.Add(CreateFace(innerWidth, outerWidth,- height / 2, -height / 2, point,true));}//侧面for (int point = 0; point < 6; point++){m_faces.Add(CreateFace(outerWidth, outerWidth, height / 2, -height / 2, point));}//里侧面for (int point = 0; point < 6; point++){m_faces.Add(CreateFace(innerWidth, innerWidth, height / 2, -height / 2, point,true));}}

组装

刚才我们将数据填入Face,但是Face是不能直接使用的,我们要将刚才生成的顶点信息,uv信息,三角形信息等一次灌入Mesh中,
Mesh提供了成员变量来接收这些数据。
顶点和uv直接添加就可以,注意三角形数据需要根据顶点数据来加下标。

    private void CombineFaces(){List<Vector3> verticles = new List<Vector3>();List<int> tris = new List<int>();List<Vector2> uvs = new List<Vector2>();for(int i = 0; i < m_faces.Count; i++){verticles.AddRange(m_faces[i].verticles); //AddRange方法可以把list中所有数据从头到尾添加到新的listuvs.AddRange(m_faces[i].uvs);//注意:这里需要依次指定指定所有顶点在最终mesh的三角形顺序,由于每个face里面包括四个顶点,每次+4int offset = (4 * i);foreach(int triangle in m_faces[i].triangles){tris.Add(triangle + offset);}}m_mesh.vertices = verticles.ToArray();m_mesh.triangles = tris.ToArray();m_mesh.uv = uvs.ToArray();m_mesh.RecalculateNormals();}

排布

要让游戏能玩,肯定需要一系列整齐布局的六边形,所以我们需要一个动态创建六边形的管理器。

横向布局

在这里插入图片描述
前面我们生成面的时候发现有个isFlat变量,这个变量就是控制了第一个面的生成角度,所以横向的时候能保证六边形是横着的。

    private Face CreateFace(float innerRad, float outerRad, float heightA, float heightB, int point, bool reverse = false){float angle1 = point * 60;float angle2 = angle1 + 60;if (!isFlat){ //竖着排布,初始角度是-30angle1 -= 30;angle2 -= 30;}......

问题是如何计算出每个六边形的中心点在哪。这里用三角函数也非常容易看出来
下面是六边体“直立“”情况下,设两个六边形之间间隔为d,六边形中心到外顶点的距离为L
可以发现Y轴方向每个六边形之间距离为(L * cos(30°) * 2 + d)* sin60°
X轴方向每个六边形之间距离为(L*(cos(30°)*2 + d)
同时注意距离偶数行的X轴要添加一个(L * cos(30°) * 2 + d)*sin30°的偏移

具体计算就初中级别的数学,就不一步步画图了
在这里插入图片描述
同理横向布局也很好计算
可以发现Y轴方向每个六边形之间距离为(L * cos(30°) * 2 + d)
X轴方向每个六边形之间距离为(L*(cos(30°)*2 + d) *sin60°
同时注意距离偶数行的Y轴要添加一个(L * cos(30°) * 2 + d)*sin30°的偏移

在这里插入图片描述
万事具备,我们只需要计算每一行每列的点即可生成蜂窝了。

    public void SetInterval(){centerDistance = outterWidth * 2 * Mathf.Sin(60 * Mathf.Deg2Rad) + interval;}private void UpdateGrid(GameObject[][] girds){if (girds.Length <= 0) return;bool shouldOffset = false;for (int j = 0; j < heightCount; j++){if (!isFlat){shouldOffset = j % 2 != 0;}for (int i = 0; i < widthCount; i++){if (isFlat){shouldOffset = i % 2 != 0;}HexagonRenderer render = girds[i][j].GetComponent<HexagonRenderer>();//计算六边形位置Vector3 pos = Getpos(i, j, shouldOffset);Debug.Log(pos);render.SetAtrributes(innerWidth, outterWidth, height, pos, matrial, isFlat);render.DrawMesh();}}}private Vector3 Getpos(int i, int j, bool shouldOffset){float angle60 = 60 * Mathf.Deg2Rad;float angle30 = 30 * Mathf.Deg2Rad;if (isFlat){if (shouldOffset){return new Vector3(i * centerDistance * Mathf.Sin(angle60) , transform.position.y, j * centerDistance +centerDistance * Mathf.Sin(angle30));}else{return new Vector3(i * centerDistance * Mathf.Sin(angle60), transform.position.y, j * centerDistance);}}else{if (shouldOffset){return new Vector3(i * centerDistance + centerDistance * Mathf.Sin(angle30), transform.position.y, j * centerDistance * Mathf.Sin(angle60));}else{return new Vector3(i * centerDistance, transform.position.y, j * centerDistance * Mathf.Sin(angle60));}}}

完整代码

在场景中创建一个空物体,将GenerateMap.cs挂载在其身上即可,将会自动生成一系列身上挂载HexagonRenderer.cs的物体

GenerateMap.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class GenerateMap : MonoBehaviour
{[Header("Grid Settings")]public int widthCount;public int heightCount;[Header("Layout Settings")]public float innerWidth;public float outterWidth;public float height;public bool isFlat;public Material matrial;/// <summary>/// 六边形之间的间隔/// </summary>public float interval;private float centerDistance;/// <summary>/// 存储所有的六边形/// </summary>private GameObject[][] girds;private bool hasGenerate = false;public void Start(){girds = new GameObject[widthCount][];for (int i = 0; i < girds.Length; i++){girds[i] = new GameObject[heightCount];}SetInterval();GenerateGrid();LayoutGrid();}public void SetInterval(){centerDistance = outterWidth * 2 * Mathf.Sin(60 * Mathf.Deg2Rad) + interval;}/// <summary>/// 设置六边形布局,从左下角生成/// </summary>private void LayoutGrid(){UpdateGrid(girds);}private void GenerateGrid(){if (hasGenerate == true) return;for (int j = 0; j < heightCount; j++){for (int i = 0; i < widthCount; i++){GameObject single = new GameObject($"HEX:({i},{j})", typeof(HexagonRenderer)); //$代表string.formatgirds[i][j] = single;single.transform.SetParent(transform, true);}}hasGenerate = true;}private void UpdateGrid(GameObject[][] girds){if (girds.Length <= 0) return;bool shouldOffset = false;for (int j = 0; j < heightCount; j++){if (!isFlat){shouldOffset = j % 2 != 0;}for (int i = 0; i < widthCount; i++){if (isFlat){shouldOffset = i % 2 != 0;}HexagonRenderer render = girds[i][j].GetComponent<HexagonRenderer>();//计算六边形位置Vector3 pos = Getpos(i, j, shouldOffset);Debug.Log(pos);render.SetAtrributes(innerWidth, outterWidth, height, pos, matrial, isFlat);render.DrawMesh();}}}private Vector3 Getpos(int i, int j, bool shouldOffset){float angle60 = 60 * Mathf.Deg2Rad;float angle30 = 30 * Mathf.Deg2Rad;if (isFlat){if (shouldOffset){return new Vector3(i * centerDistance * Mathf.Sin(angle60) , transform.position.y, j * centerDistance +centerDistance * Mathf.Sin(angle30));}else{return new Vector3(i * centerDistance * Mathf.Sin(angle60), transform.position.y, j * centerDistance);}}else{if (shouldOffset){return new Vector3(i * centerDistance + centerDistance * Mathf.Sin(angle30), transform.position.y, j * centerDistance * Mathf.Sin(angle60));}else{return new Vector3(i * centerDistance, transform.position.y, j * centerDistance * Mathf.Sin(angle60));}}}
}

HexagonRenderer.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public struct Face
{//顶点位置数组public List<Vector3> verticles { get; private set; }//三角形顶点索引数组,按给定的顺序连接顶点,为顺时针三个一组的顺序public List<int> triangles { get; private set; }public List<Vector2> uvs { get; private set; }public Face(List<Vector3> verticles, List<int> triangles, List<Vector2> uvs){this.verticles = verticles;this.triangles = triangles;this.uvs = uvs;}
}
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]public class HexagonRenderer : MonoBehaviour
{private Mesh m_mesh;private MeshFilter m_meshFilter;private MeshRenderer m_meshRenderer;private List<Face> m_faces;private bool isFlat = true;public Material m_material;public float innerWidth;public float outerWidth;public float height;private void Awake(){m_meshFilter = GetComponent<MeshFilter>();m_meshRenderer = GetComponent<MeshRenderer>();m_mesh = new Mesh();m_mesh.name = "HexMesh";m_meshFilter.mesh = m_mesh;m_meshRenderer.material = m_material;}public void SetAtrributes(float innerWidth, float outerWidth, float height, Vector3 position, Material material, bool isFlat){this.innerWidth = innerWidth;this.outerWidth = outerWidth;this.isFlat = isFlat;this.height = height;transform.position = position;m_material = material;m_meshRenderer.material = m_material;DrawMesh();}private void OnEnable(){DrawMesh();}//渲染整个六边形体public void DrawMesh(){DrawFaces();CombineFaces();}private void OnValidate(){}private void DrawFaces(){m_faces = new List<Face>();//上表面for (int point = 0; point < 6; point++){m_faces.Add(CreateFace(innerWidth, outerWidth, height / 2, height / 2, point));}//下表面for (int point = 0; point < 6; point++){m_faces.Add(CreateFace(innerWidth, outerWidth, -height / 2, -height / 2, point, true));}//侧面for (int point = 0; point < 6; point++){m_faces.Add(CreateFace(outerWidth, outerWidth, height / 2, -height / 2, point));}//里侧面for (int point = 0; point < 6; point++){m_faces.Add(CreateFace(innerWidth, innerWidth, height / 2, -height / 2, point, true));}}private void CombineFaces(){List<Vector3> verticles = new List<Vector3>();List<int> tris = new List<int>();List<Vector2> uvs = new List<Vector2>();for (int i = 0; i < m_faces.Count; i++){verticles.AddRange(m_faces[i].verticles);AddRange方法可以把list中所有数据从头到尾添加到新的listuvs.AddRange(m_faces[i].uvs);//注意:这里需要依次指定指定所有顶点在最终mesh的三角形顺序,由于每个face里面包括四个顶点,每次+4int offset = (4 * i);foreach (int triangle in m_faces[i].triangles){tris.Add(triangle + offset);}}m_mesh.vertices = verticles.ToArray();m_mesh.triangles = tris.ToArray();m_mesh.uv = uvs.ToArray();m_mesh.RecalculateNormals();}/// <summary>/// 上下底面的单独一个等腰梯形/// </summary>/// <param name="innerRad">内径</param>/// <param name="outerRad">外径</param>/// <param name="heightA">外高</param>/// <param name="heightB">内高</param>/// <param name="point">顺序</param>/// <param name="reverse">连接方向</param>/// <returns></returns>private Face CreateFace(float innerRad, float outerRad, float heightA, float heightB, int point, bool reverse = false){float angle1 = point * 60;float angle2 = angle1 + 60;if (!isFlat){angle1 -= 30;angle2 -= 30;}List<Vector3> verticals = new List<Vector3>();//.......C.//..B.......//..........//...A......Dverticals.Add(CreatePoint(innerRad, heightA, angle1));verticals.Add(CreatePoint(innerRad, heightA, angle2));verticals.Add(CreatePoint(outerRad, heightB, angle2));verticals.Add(CreatePoint(outerRad, heightB, angle1));List<int> tris = new List<int> { 0, 1, 2, 2, 3, 0 };List<Vector2> uv = new List<Vector2> { new Vector2(0, 0), new Vector2(1, 0), new Vector2(1, 1), new Vector2(0, 1) };if (reverse){verticals.Reverse();}return new Face(verticals, tris, uv);}/// <summary>/// 创造一个顶点/// </summary>/// <param name="distance">距离坐标原点距离</param>/// <param name="height">y轴高度</param>/// <param name="angle">和坐标轴所成夹角</param>/// <returns></returns>private Vector3 CreatePoint(float distance, float height, float angle){float rad = angle * Mathf.Deg2Rad;return new Vector3(distance * Mathf.Cos(rad), height, distance * Mathf.Sin(rad));}
}

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

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

相关文章

音频转换器哪个好?3款电脑软件+3款手机应用

在当今的数字时代&#xff0c;音频转换已成为许多用户日常的需求。为了帮助您找到最佳的音频转换工具&#xff0c;我们将介绍3款电脑软件和3款手机应用。这些工具都各有特点&#xff0c;能够满足不同用户的需求。 1.电脑软件篇 1.1金舟音频大师 金舟音频大师是一款多功能的音…

【LabVIEW 】串口如何读取长度不一致的字符串

工程经验 1、在循环中&#xff0c;加入定时器&#xff0c;这样可以一段时间读取一次。 2、只要获取完整的一帧数据&#xff0c;就可以进行过滤筛选。

力扣128. 最长连续序列(哈希表)

Problem: 128. 最长连续序列 文章目录 题目描述思路复杂度Code 题目描述 思路 1.先将数组中的元素存入到一个set集合中&#xff08;去除重复的元素&#xff09; 2.欲找出最长连续序列&#xff08;先定义两个int变量longestSequence和currentSequence用于记录最长连续序列和当前…

Adobe Acrobat DC中如何合并pdf并生成目录

一、利用 Acrobat 合成pdf目录 &#xff08;一&#xff09;新建标签&#xff08;更改标签等级等&#xff09; 1&#xff0c;用Adobe acrobat 软件打开待添加书签的pdf文档。 2&#xff0c;打开之后点击软件左边栏的书签&#xff08;有时被隐藏了&#xff0c;点击一下界面左边…

第一节 数据操作+数据处理

本系列文章为李沐老师《动手学深度学习》Pytorch版实践学习笔记&#xff0c;相关课程教学、书籍、代码均为开源&#xff0c;可通过以下链接参考学习&#xff1a; 跟李沐学AI的个人空间-跟李沐学AI个人主页-哔哩哔哩视频 (bilibili.com) 前言 — 动手学深度学习 2.0.0 documenta…

高校物品捐赠管理系统|基于springboot高校物品捐赠管理系统设计与实现(源码+数据库+文档)

高校物品捐赠管理系统目录 目录 基于springboot高校物品捐赠管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、用户信息管理 2、捐赠信息管理 3、论坛信息管理 4、公告信息管理 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算…

RabbitMQ讲解与整合

RabbitMq安装 类型概念 租户 RabbitMQ 中有一个概念叫做多租户&#xff0c;每一个 RabbitMQ 服务器都能创建出许多虚拟的消息服务器&#xff0c;这些虚拟的消息服务器就是我们所说的虚拟主机&#xff08;virtual host&#xff09;&#xff0c;一般简称为 vhost。 每一个 vhos…

NLP-词向量、Word2vec

Word2vec Skip-gram算法的核心部分 我们做什么来计算一个词在中心词的上下文中出现的概率&#xff1f; 似然函数 词已知&#xff0c;它的上下文单词的概率 相乘。 然后所有中心词的这个相乘数 再全部相乘&#xff0c;希望得到最大。 目标函数&#xff08;代价函数&#xff0…

如何用CDH+Apache DolphinScheduler开启Kerberos

搭建环境 多台linux主机搭建集群CDH 6.3.2 (Parcel)版本Apache DolphinScheduler1.3.2版本&#xff0c;本流程在CDH已搭建完成并可正常使用后&#xff0c;开启kerberos功能&#xff0c;Apache DolphinScheduler用于大数据任务管理与执行&#xff0c;是很不错的任务调度平台&am…

ZYNQ--MIG核配置

文章目录 MIG核配置界面多通道AXI读写DDR3MIG核配置界面 Clock Period: DDR3 芯片运行时钟周期,这个参数的范围和 FPGA 的芯片类型以及具体类型的速度等级有关。本实验选择 1250ps,对应 800M,这是本次实验所采用芯片可选的最大频率。注意这个时钟是 MIG IP 核产生,并输出给…

压缩视频大小的软件有哪些?5款软件推荐

压缩视频大小的软件有哪些&#xff1f;随着高清摄像设备的普及和网络速度的不断提升&#xff0c;视频文件变得越来越庞大&#xff0c;动辄数百兆甚至数GB的大小常常让用户在分享和存储时感到头疼。幸运的是&#xff0c;市面上有许多优秀的视频压缩软件可以帮助我们轻松应对这一…

NFS服务器挂载失败问题

问题 mount.nfs: requested NFS version or transport protocol is not supported背景&#xff1a;现在做嵌入式开发&#xff0c;需要在板端挂载服务器&#xff0c;读取服务器文件。挂载中遇到该问题。 挂载命令长这样 mount -t nfs -o nolock (XXX.IP):/mnt/disk1/zixi01.ch…

vue实现水印功能

目录 一、应用场景 二、实现原理 三、详细开发 1.水印的实现方式 2.防止用户通过控制台修改样式去除水印效果&#xff08;可跳过&#xff0c;有弊端&#xff09; 3.水印的使用 &#xff08;1&#xff09;单页面/全局使用 &#xff08;2&#xff09;全局使用个别页面去掉…

绘制窗口及窗口位置变化

为了方便窗口的移动 &#xff0c;及相交窗口关闭之后被遮挡窗口的重绘&#xff0c;因此给每个窗口建立一个内存BUF&#xff0c;等到不涉及内容变更的重绘&#xff0c;只需要将该BUF复制到显存之中。 然而&#xff0c;重绘时存在一个被遮挡时如何操作的问题。比如下图中依次为从…

【QT+JS】QT和JS 中的正则表达式 、QT跑JS语言

【QTJS】QT和JS 中的正则表达式 、QT跑JS语言 前言正则表达式QT 中的使用QRegExp自带的cap方法怎么用&#xff1f;QRegExp的非贪婪模式与贪婪模式 JS 中的使用 QT 跑JS 语言 前言 在看大佬的系统代码时候&#xff0c;对其中灵活用到的正则表达式和QT 跑JS 语言部分感觉很陌生&…

iOS App冷启动优化:二进制重排

原理 二进制文件中方法的加载顺序&#xff0c; 取决于方法在代码文件中的书写顺序&#xff0c;而不是调用顺序。 应用程序启动时会调用到的方法是有限的&#xff0c;但可能分散在很多个。 由于内存是分页管理的&#xff0c;要加载就要 整页加载。 这就导致很多完全还用不到的方…

网站添加pwa操作和配置manifest.json后,没有效果排查问题

pwa技术官网&#xff1a;https://web.dev/learn/pwa 应用清单manifest.json文件字段说明&#xff1a;https://web.dev/articles/add-manifest?hlzh-cn Web App Manifest&#xff1a;Web App Manifest | MDN 当网站添加了manifest.json文件后&#xff0c;也引入到html中了&a…

FPGA-FIF0模型与应用场景(IP核)

什么是FIFO FIFO (First In First Out) ,也就是先进先出。FPGA或者ASIC中使用到的FIFO一般指的是对数据的存储具有先进先出特性的一个缓存器,常被用于数据的缓存或者高速异步数据的交互。它与普通存储器的区别是没有外部读写地址线,这样使用起来相对简单,但缺点就是只能顺序写…

python脚本实现全景站点欧拉角转矩阵

效果 脚本 import numpy as np import math import csv import os from settings import *def euler_to_rotation_matrix(roll, pitch, yaw):# 计算旋转矩阵# Z-Y-X转换顺序Rz

java多线程编程(学习笔记)入门

一、多线程创建的三种方式 (1)通过继承Thread本身 (2)通过实现runnable接口 (3)通过 Callable 和 Future 创建线程 其中&#xff0c;前两种不能获取到编程的结果&#xff0c;第三种能获取到结果 二、常见的成员方法 方法名称说明String getName()返回此线程的名称void setNam…