Unity3D Mesh小课堂(三)圆形与圆环
之前我们介绍了如何绘制一个三角形的Mesh。今天讲解一下如何绘制一个圆形的Mesh。
Unity3D中Mesh的基本单位是三角形,而圆形就是由许许多多的三角形组成的。那么我们就知道了绘制圆形的Mesh需要两个变量
public float Radius = 5; //半径public int Segments = 50; //分割数
先加上基本的代码
[RequireComponent(typeof(MeshRenderer), typeof(MeshFilter))]
public class TestCircle : MonoBehaviour {public float Radius = 5; //半径public int Segments = 50; //分割数private MeshFilter meshFilter;void Awake(){meshFilter = GetComponent<MeshFilter>();meshFilter.mesh = CreateMesh(Radius, Segments);}Mesh CreateMesh(float radius, int segments){Mesh mesh = new Mesh ();return mesh;}
}
那么CreateMesh这个方法要怎么实现呢?
首先是vertices(顶点)
int vlen = 1 + segments;Vector3[] vertices = new Vector3[vlen];vertices[0] = Vector3.zero;float angleDegree = 360;float angle = Mathf.Deg2Rad * angleDegree;float currAngle = angle / 2;float deltaAngle = angle / segments;for (int i = 1; i < vlen; i++){float cosA = Mathf.Cos(currAngle);float sinA = Mathf.Sin(currAngle);vertices[i] = new Vector3 (cosA * radius, 0, sinA * radius);currAngle -= deltaAngle;}
vertices[0]保存圆心坐标,后面的segments个Vector3保存圆(边)上的点。
接着是triangles(三角形),里面实际保存的是vertices的下标
int tlen = segments * 3;int[] triangles = new int[tlen];for (int i = 0, vi = 1; i < tlen - 3; i += 3, vi++){triangles[i] = 0;triangles[i + 1] = vi;triangles[i + 2] = vi + 1;}triangles [tlen - 3] = 0;triangles [tlen - 2] = vlen - 1;triangles [tlen - 1] = 1;
为了完成闭环,将最后一个三角形单独拎出来。
需要注意的是:三角形必须是顺时针取顶点。
最后是uv(纹理坐标),不太理解是什么的,可以先看一下之前的博文:为三角形添加纹理
Vector2[] uvs = new Vector2[vlen];for (int i = 0; i < vlen; i++){uvs [i] = new Vector2 (vertices[i].x / radius / 2 + 0.5f, vertices[i].z / radius / 2 + 0.5f);}
最后把属性赋给mesh就可以了
mesh.vertices = vertices;mesh.triangles = triangles;mesh.uv = uvs;
我们测试一下,导入一张图片
我特意找了一张圆外不透明的图片。
新建一个material,shader使用Unlit/Texture,选择这张图片作为纹理。
新建一个GameObject,添加TestCircel作为组件,讲MeshRenderer的Material设置为新建的material。
点击运行,就可以看到圆了。
接下来稍微提升一下难度:假如我需要一个圆环Mesh怎么办?
圆形是由segments个等腰三角形组成的,圆环就是有segments个等腰梯形组成的。
那么等腰梯形由什么组成?两个三角形(多个也是可以的)。
首先添加一个变量,内圆半径
public float InnerRadius = 3; //内圆半径
CreateMesh方法也相应的增加了一个参数。
vertices(顶点)
int vlen = segments * 2 + 2;Vector3[] vertices = new Vector3[vlen];float angleDegree = 360;float angle = Mathf.Deg2Rad * angleDegree;float currAngle = angle / 2;float deltaAngle = angle / segments;for (int i = 0; i < vlen; i+=2){float cosA = Mathf.Cos(currAngle);float sinA = Mathf.Sin(currAngle);vertices[i] = new Vector3 (cosA * innerRadius, 0, sinA * innerRadius);vertices[i + 1] = new Vector3 (cosA * radius, 0, sinA * radius);currAngle -= deltaAngle;}
每一个步长(2)保存梯形(非平行边)的两个顶点的坐标。我们为180度和-180度分别创建了两个值相等的点,是为了方便triangles的计算。
triangles(三角形)
int tlen = segments * 6;int[] triangles = new int[tlen];for (int i = 0, vi = 0; i < tlen; i += 6, vi+=2){triangles[i] = vi;triangles[i + 1] = vi + 1;triangles[i + 2] = vi + 3;triangles[i + 3] = vi + 3;triangles[i + 4] = vi + 2;triangles[i + 5] = vi;}
把每个分割梯形再分割成两个三角形。仍然需要注意的是:三角形必须是顺时针取顶点。
uv(纹理坐标)代码不变
然后我们就得到了一个被打了马赛克的圆(误)
假如我们需要一个扇形/扇面怎么办?其实我已经预留好了修改的余地,把顶点代码片段里的
float angleDegree = 360;
去掉,作为参数输入即可。InnerRadius=0就是扇形,InnerRadius>0就是扇面。
加上Gizmos,调整一下代码
using UnityEngine;
using System.Collections;[RequireComponent(typeof(MeshRenderer), typeof(MeshFilter))]
public class TestCircle : MonoBehaviour {public float Radius = 5; //半径public int Segments = 50; //分割数public float InnerRadius = 3; //内圆半径public float AngleDegree = 90;private CircleMeshCreator _creator = new CircleMeshCreator();private MeshFilter _meshFilter;void Awake(){_meshFilter = GetComponent<MeshFilter>();}void Update(){_meshFilter.mesh = _creator.CreateMesh(Radius, Segments, InnerRadius, AngleDegree);}void OnDrawGizmos(){Gizmos.color = Color.gray;DrawMesh();}void OnDrawGizmosSelected(){Gizmos.color = Color.green;DrawMesh();}private void DrawMesh(){Mesh mesh = _creator.CreateMesh(Radius, Segments, InnerRadius, AngleDegree);int[] tris = mesh.triangles;for (int i = 0; i < tris.Length; i+=3){Gizmos.DrawLine(TransformToWorld(mesh.vertices[tris[i]]), TransformToWorld(mesh.vertices[tris[i + 1]]));Gizmos.DrawLine(TransformToWorld(mesh.vertices[tris[i]]), TransformToWorld(mesh.vertices[tris[i + 2]]));Gizmos.DrawLine(TransformToWorld(mesh.vertices[tris[i+1]]), TransformToWorld(mesh.vertices[tris[i + 2]]));}}private Vector3 TransformToWorld(Vector3 src){return transform.TransformPoint(src);}private class CircleMeshCreator{private static readonly int PRECISION = 1000;private float _radius;private int _segments;private float _innerRadius;private float _angleDegree;private Mesh _cacheMesh ;public Mesh CreateMesh(float radius, int segments, float innerRadius, float angleDegree){if (checkDiff(radius, segments, innerRadius, angleDegree)){Mesh newMesh = Create(radius, segments, innerRadius, angleDegree);if (newMesh != null){_cacheMesh = newMesh;this._radius = radius;this._segments = segments;this._innerRadius = innerRadius;this._angleDegree = angleDegree;}}return _cacheMesh;}private Mesh Create(float radius, int segments, float innerRadius, float angleDegree){if (segments <= 0){segments = 1;#if UNITY_EDITORDebug.Log("segments must be larger than zero.");#endif}Mesh mesh = new Mesh();int vlen = segments * 2 + 2;Vector3[] vertices = new Vector3[vlen];float angle = Mathf.Deg2Rad * angleDegree;float currAngle = angle / 2;float deltaAngle = angle / segments;for (int i = 0; i < vlen; i+=2){float cosA = Mathf.Cos(currAngle);float sinA = Mathf.Sin(currAngle);vertices[i] = new Vector3 (cosA * innerRadius, 0, sinA * innerRadius);vertices[i + 1] = new Vector3 (cosA * radius, 0, sinA * radius);currAngle -= deltaAngle;}int tlen = segments * 6;int[] triangles = new int[tlen];for (int i = 0, vi = 0; i < tlen; i += 6, vi+=2){triangles[i] = vi;triangles[i + 1] = vi + 1;triangles[i + 2] = vi + 3;triangles[i + 3] = vi + 3;triangles[i + 4] = vi + 2;triangles[i + 5] = vi;}Vector2[] uvs = new Vector2[vlen];for (int i = 0; i < vlen; i++){uvs [i] = new Vector2 (vertices[i].x / radius / 2 + 0.5f, vertices[i].z / radius / 2 + 0.5f);}mesh.vertices = vertices;mesh.triangles = triangles;mesh.uv = uvs;return mesh;}private bool checkDiff(float radius, int segments, float innerRadius, float angleDegree){return segments != this._segments || (int)((angleDegree - this._angleDegree) * PRECISION) != 0 ||(int)((radius - this._radius) * PRECISION) != 0 || (int)((innerRadius - this._innerRadius) * PRECISION) != 0;}}}
恩,改成这样,应该命名为TestSector更为合适一点。
最后附上源码下载链接
Unity3D Mesh小课堂(三)圆形与圆环相关推荐
- 微信小程序 三 圆形图片
圆形图片和圆形其它控件一样 home.wxss .profile{width: 50rpx;height: 50rpx;border: 0 solid #ff0000;border-radius: 1 ...
- 【机器视觉运动控制一体机小课堂】三分钟进行轮廓提取
背景 轮廓提取是基于边缘轮廓的算法,可用于需要提取工件轮廓信息后进行加工处理的检测加工项目,可广泛应用于点胶.激光切割.工件打磨等需要提取工件轮廓的领域. 轮廓是一种能存储一系列点集的数据结构,可分为 ...
- 锚杆拉拔试验弹性模量计算_【安全宣教】煤亮子小课堂(十三)——锚杆的锚固力和拉拔力...
每天学习一点点,每天进步一点点,<煤亮子"小"课堂>开讲了.在今天的节目里,掘进准备队副队长冯文军,与大家一起分享锚杆的锚固力和拉拔力. REC 今天的知识点是锚杆的锚 ...
- 宝付国际跨境知识小课堂 | 人民币外汇市场是个啥?
全球化浪潮下,因为各个经济体的比较利益差异,产生了货物.服务.人员或资本之间的流动.各个经济体使用的当地货币不同,为了贸易或资本流动及其价值定价,本国的货币需要兑换成另一国的货币来结算,这个货币兑换的 ...
- 云原生小课堂|Envoy请求流程源码解析(三):请求解析
前言 Envoy 是一款面向 Service Mesh 的高性能网络代理服务.它与应用程序并行运行,通过以平台无关的方式提供通用功能来抽象网络.当基础架构中的所有服务流量都通过 Envoy 网格时 ...
- 【视觉运控一体机小课堂】三分钟搭建机器视觉开发环境
回顾之前课程正运动技术与大家分享了,VPLC系列机器视觉运动控制一体机快速入门和应用案例等系列课程. 今天,我们来讲解一下正运动技术VPLC系列控制器ZDevelop编程软件如何来建立ZVision软 ...
- 【机器视觉运动控制一体机小课堂】三分钟进行灰度匹配
背景 不同的模板匹配方法,其操作步骤也不一样,其生成模板的方式也有不同的地方,在之前的课程中我们讲述了基于形状的模板匹配,本期课程我们去了解一下基于灰度值的模板匹配. 基于灰度值的模板匹配适用于图像内 ...
- 微信小程序 环形进度条_微信小程序实现圆形进度条实例分享
本文主要和大家分享微信小程序实现圆形进度条实例,希望能帮助到大家. 小程序中使用圆形倒计时,效果图: 思路使用2个canvas 一个是背景圆环,一个是彩色圆环. 使用setInterval 让彩色圆环 ...
- 微信小程序之圆形进度条(自定义组件)
前言 昨天在微信小程序实现了圆形进度条,今天想把这个圆形进度条做成一个组件,方便以后直接拿来用. 根据官方文档自定义组件一步一步来 创建自定义组件 第一步创建项目结构 打开微信开发者工具创建一个项目, ...
最新文章
- Navicat 9如何连接ORACLE10G数据库
- jquery删除数组中的某个元素下标越界_Java数据结构和算法(二)—数组
- JdbcTemplate类中的execute方法
- xilinx SoC学习笔记之PetaLinux
- ningbooj--1655--木块拼接(贪心)
- 135.002 智能合约设计-——多员工薪酬系统
- android源码解析------Media多媒体framework层分析
- 软件设计精要与模式(第2版)
- 我就是认真:Linux SWAP 深度解读(必须收藏)
- php编码怎么变西欧了403,你知道一个简单的PHP脚本在ip检查后抛出403吗?
- 传统车道线检测之黄白线、虚实车道线检测(附python代码)
- eleme饿了么vue项目随笔,随时更新,想到哪里写到哪里比较凌乱一直更新
- 从无刷直流电动机控制系统电磁兼容设计,谈电磁干扰原理
- 互斥锁、自旋锁、读写锁和文件锁
- css td 比例,CSS设置表格TD宽度布局
- dalao的背包九讲
- C#把月日年帶有 AM、PM的时间格式转换为正常时间格式
- 《孩子,你慢慢来》的读书笔记与读后感2600字
- Tecplot操作记录
- android开发指纹解锁,Android-指纹解锁技术
热门文章
- php把变量转换为字符串,php如何将变量转换成字符串
- 如何将Excel中的数据复制到CAD中?
- 张晨光老师高薪就业系列 面试之五 集锦
- 2019年1+X 证书 Web 前端开发中级理论考试——易错题、陌生但又会考到的题目原题+答案(文章含五套题的内容)
- 在移动硬盘上安装win to go(Windows 10)和Linux to go(ubantu)双系统
- 天宫一号将在酒泉发射
- 【杂项】通过Excel为字符串产生条码
- 阿里EasyExcel小数点精度问题和无故多了个.0
- Python爬虫实战,requests模块,爬虫采集网易财经股票交易数据
- 学习C语言基础(1)C程序模板