Unity 绘制Mesh线条
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public struct SegmentPoint
{
public Vector3 normal;
public Vector3 pos;
};
public class DrawMesh_Plane : MonoBehaviour {
MeshFilter meshFilter;
/// <summary>
/// 面片中的最后一个点
/// </summary>
SegmentPoint lastPoint;
SegmentPoint penultPoint;
bool startDraw = false;
bool twoPoint = false;
/// <summary>
/// 线条半径
/// </summary>
float r;
/// <summary>
/// 包含meshfilter、meshrenderer、材质球组件的预设体
/// </summary>
public GameObject linePrefab;
public Transform lineParent;
/// <summary>
/// 平滑点数
/// </summary>
public int smooth = 3;
[HideInInspector]
public Color lineColor;
public VRTracketObjManager vrtom;
public bool usePressure;
public DrawMeshManager drawMeshManager;
void Start()
{
lineColor = drawMeshManager.color;
}
void Update()
{
DrawMeshByCollider();
}
void DrawMeshVR()
{
var device = SteamVR_Controller.Input((int)vrtom.trackedObj_Left.index);
if (device.GetPress(SteamVR_Controller.ButtonMask.Trigger))
{
if (usePressure)
{
r = device.GetAxis(Valve.VR.EVRButtonId.k_EButton_Axis1).x * drawMeshManager.brushRadius;
}
else
{
r = drawMeshManager.brushRadius;
}
if (!startDraw && !twoPoint)
{
GameObject line = Instantiate(linePrefab);
line.transform.SetParent(lineParent);
meshFilter = line.GetComponent<MeshFilter>();
line.GetComponent<MeshRenderer>().material.SetColor("_Color", lineColor);
if (drawMeshManager.addStep != null)
{
drawMeshManager.addStep(line);
}
}
float dis = Vector3.Distance(vrtom.leftPenPoint.position, lastPoint.pos);
if (!startDraw)
{
lastPoint.pos = vrtom.leftPenPoint.position;
lastPoint.normal = -vrtom.leftPenPoint.up;
startDraw = true;
}
else if (!twoPoint && dis > drawMeshManager.spaceDis)
{
SegmentPoint hitP;
hitP.pos = vrtom.leftPenPoint.position;
hitP.normal = -vrtom.leftPenPoint.up;
meshFilter.mesh = CreateStartMesh(lastPoint, hitP);
penultPoint = lastPoint;
lastPoint = hitP;
twoPoint = true;
}
else if (dis > drawMeshManager.spaceDis)
{
SegmentPoint hitP;
hitP.pos = vrtom.leftPenPoint.position;
hitP.normal = -vrtom.leftPenPoint.up;
SegmentPoint[] newSP = SmoothPoints(lastPoint, penultPoint, hitP);
List<Vector3> nv = new List<Vector3>();
for (int i = 0; i <= newSP.Length - 2; i++)
{
nv.AddRange(ComputeVertex(newSP[i], newSP[i + 1]));
}
penultPoint = newSP[newSP.Length - 2];
lastPoint = hitP;
SetMesh(nv.ToArray());
}
}
if (device.GetPressUp(SteamVR_Controller.ButtonMask.Trigger))
{
startDraw = false;
twoPoint = false;
meshFilter = null;
}
}
/// <summary>
/// 贴合模型画线
/// </summary>
void DrawMeshByCollider()
{
r = drawMeshManager.brushRadius;
if (Input.GetMouseButton(0))
{
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit) && hit.collider.tag == TagManager.Line)
{
if (!startDraw && !twoPoint)
{
GameObject line = Instantiate(linePrefab);
line.transform.SetParent(lineParent);
meshFilter = line.GetComponent<MeshFilter>();
line.GetComponent<MeshRenderer>().material.SetColor("_Color", lineColor);
if (drawMeshManager.addStep != null)
{
drawMeshManager.addStep(line);
}
}
float dis = Vector3.Distance(hit.point, lastPoint.pos);
if (!startDraw) //开始创建第一个点
{
lastPoint.pos = hit.point;
lastPoint.normal = hit.normal;
startDraw = true;
}
else if (!twoPoint && dis > drawMeshManager.spaceDis) //开始创建第一个面片
{
SegmentPoint hitP;
hitP.pos = hit.point;
hitP.normal = hit.normal;
meshFilter.mesh = CreateStartMesh(lastPoint, hitP);
penultPoint = lastPoint;
lastPoint = hitP;
twoPoint = true;
}
else if (dis > drawMeshManager.spaceDis)
{
SegmentPoint hitP;
hitP.pos = hit.point;
hitP.normal = hit.normal;
SegmentPoint[] newSP = SmoothPoints(lastPoint, penultPoint, hitP);
List<Vector3> nv = new List<Vector3>();
for (int i = 0; i <= newSP.Length - 2; i++)
{
nv.AddRange(ComputeVertex(newSP[i], newSP[i + 1]));
}
penultPoint = newSP[newSP.Length - 2];
lastPoint = hitP;
SetMesh(nv.ToArray());
}
}
else
{
startDraw = false;
twoPoint = false;
meshFilter = null;
}
}
if (Input.GetMouseButtonUp(0))
{
startDraw = false;
twoPoint = false;
meshFilter = null;
}
}
/// <summary>
/// 创建第一个面片
/// </summary>
/// <param name="startP"></param>
/// <param name="endP"></param>
/// <returns></returns>
Mesh CreateStartMesh(SegmentPoint startP,SegmentPoint endP)
{
Vector3 v1 = endP.pos - startP.pos;
Vector3 d1 = Vector3.Cross(v1.normalized, startP.normal);
Vector3 d2 = Vector3.Cross(v1.normalized, endP.normal);
d1 = d1.normalized;
Vector3 p0, p1, p2, p3;
p0 = startP.pos - d1 * r * 0.5f + startP.normal * drawMeshManager.expand;
p1 = startP.pos + d1 * r * 0.5f + startP.normal * drawMeshManager.expand;
p2 = endP.pos - d2 * r * 0.5f + endP.normal * drawMeshManager.expand;
p3 = endP.pos + d2 * r * 0.5f + endP.normal * drawMeshManager.expand;
Vector3[] newVertices = {p0, p1, p2, p3 };
Vector2[] newUV = { new Vector2(p0.x, p0.y), new Vector2(p1.x, p1.y), new Vector2(p2.x, p2.y), new Vector2(p3.x, p3.y) };
int[] newTriangles = { 0, 1, 2, 1, 3, 2 };
Mesh mesh = new Mesh();
mesh.vertices = newVertices;
mesh.uv = newUV;
mesh.triangles = newTriangles;
return mesh;
}
/// <summary>
/// 获取原先面片
/// </summary>
/// <param name="vert"></param>
/// <param name="uvs"></param>
/// <param name="tri"></param>
void GetMesh(out List<Vector3> vert,out List<Vector2> uvs,out List<int> tri)
{
vert = new List<Vector3>();
uvs = new List<Vector2>();
tri = new List<int>();
vert.AddRange(meshFilter.mesh.vertices);
uvs.AddRange(meshFilter.mesh.uv);
tri.AddRange(meshFilter.mesh.triangles);
}
public void GenerateMesh(LineData ld)
{
GameObject l = Instantiate(linePrefab);
l.AddComponent<MeshFilter>();
l.AddComponent<MeshRenderer>();
l.transform.position = ld.position;
l.transform.eulerAngles = ld.rotation;
Vector3[] newVertices = ld.vertex;
Vector2[] newUV = ld.uv;
int[] newTriangles = ld.triangle;
Mesh mesh = new Mesh();
mesh.vertices = newVertices;
mesh.uv = newUV;
mesh.triangles = newTriangles;
l.GetComponent<MeshFilter>().mesh = mesh;
l.GetComponent<MeshRenderer>().material.color = ld.color;
}
/// <summary>
/// 使用贝塞尔平滑线段
/// </summary>
/// <param name="last"></param>
/// <param name="penult"></param>
/// <param name="current"></param>
/// <returns></returns>
SegmentPoint[] SmoothPoints(SegmentPoint last, SegmentPoint penult, SegmentPoint current)
{
float d = 1f / (float)smooth;
SegmentPoint[] ps = new SegmentPoint[smooth - 1];
for (int i = 0; i < ps.Length; i++)
{
float t = d * (i + 1);
ps[i].pos = (1 - t) * (1 - t) * penult.pos + 2 * t * (1 - t) * last.pos + t * t * current.pos;
ps[i].normal = Vector3.LerpUnclamped(penult.normal, current.normal, t);
}
List<SegmentPoint> segs = new List<SegmentPoint>();
segs.Add(penult);
segs.AddRange(ps);
segs.Add(current);
return segs.ToArray();
}
Vector3[] ComputeVertex(SegmentPoint p1,SegmentPoint p2)
{
Vector3 dir = p2.pos - p1.pos;
Vector3 d = Vector3.Cross(dir, p2.normal).normalized;
Vector3[] ps = new Vector3[2];
ps[0] = p2.pos - d * 0.5f * r + p2.normal * drawMeshManager.expand;
ps[1] = p2.pos + d * 0.5f * r + p2.normal * drawMeshManager.expand;
return ps;
}
/// <summary>
/// 添加mesh
/// </summary>
/// <param name="vetexes"></param>
void SetMesh(Vector3[] vertexes)
{
List<Vector3> vert;
List<Vector2> uvs;
List<int> tri;
GetMesh(out vert, out uvs, out tri);
Vector3[] newVert = vertexes;
Vector2[] newUv = new Vector2[vertexes.Length];
for (int i = 0; i < newVert.Length; i++)
{
newUv[i] = newVert[i];
}
vert.RemoveAt(vert.Count - 1);
vert.RemoveAt(vert.Count - 1);
vert.AddRange(newVert);
uvs.RemoveAt(uvs.Count - 1);
uvs.RemoveAt(uvs.Count - 1);
uvs.AddRange(newUv);
int[] newTri = new int[vert.Count * 3 - 6];
for (int i = 0; i < newTri.Length / 6; i++)
{
if (i == 0)
{
newTri[i] = 0;
newTri[i + 1] = 1;
newTri[i + 2] = 2;
newTri[i + 3] = 1;
newTri[i + 4] = 3;
newTri[i + 5] = 2;
}
else
{
newTri[i * 6] = newTri[i * 6 - 6] + 2;
newTri[i * 6 + 1] = newTri[i * 6 - 5] + 2;
newTri[i * 6 + 2] = newTri[i * 6 - 4] + 2;
newTri[i * 6 + 3] = newTri[i * 6 - 3] + 2;
newTri[i * 6 + 4] = newTri[i * 6 - 2] + 2;
newTri[i * 6 + 5] = newTri[i * 6 - 1] + 2;
}
}
Mesh m = new Mesh();
m.SetVertices(vert);
m.uv = uvs.ToArray();
m.triangles = newTri;
meshFilter.mesh.Clear();
meshFilter.mesh = m;
}
} =====================================================================
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using LitJson;
using System.Text;
using System.IO;
using UnityEditor;
public class DrawMeshManager : MonoBehaviour {
/// <summary>
/// 线条半径
/// </summary>
public float brushRadius = 0.01f;
/// <summary>
/// 点之间最小间隔
/// </summary>
public float spaceDis = 0.04f;
/// <summary>
/// 面片向外扩展距离
/// </summary>
public float expand = 0.01f;
public Color color;
public float alpha;
public delegate void AddStep(GameObject gameObj);
public AddStep addStep;
/// <summary>
/// 最大保存步数
/// </summary>
public int maxCount = 10;
public GameObject line;
public GameObject tips;
List<GameObject> allLine = new List<GameObject>();
LineData[] allLineData ;
StringBuilder stringB;
string filepath;
// Use this for initialization
void Start () {
filepath = Application.dataPath + @"/StreamingAssets/json_line.txt";
addStep = new AddStep(AddDrawStep);
}
// Update is called once per frame
void Update () {
}
void AddDrawStep(GameObject mesh)
{
if (allLine.Count == maxCount)
{
allLine.RemoveAt(maxCount - allLine.Count);
}
allLine.Add(mesh);
}
void Undo()
{
if (Input.GetKeyDown(KeyCode.Z))
{
if (allLine.Count > 0)
{
Destroy(allLine[allLine.Count - 1]);
allLine.RemoveAt(allLine.Count - 1);
}
}
}
public void SaveI()
{
SaveAsyn();
}
void SaveAsyn()
{
allLineData = new LineData[line.transform.childCount];
print(allLineData.Length);
for (int i = 0; i < allLineData.Length; i++)
{
allLineData[i] = new LineData();
allLineData[i].name = line.transform.GetChild(i).name;
allLineData[i].position = line.transform.GetChild(i).position;
allLineData[i].rotation = line.transform.GetChild(i).eulerAngles;
allLineData[i].vertex = line.transform.GetChild(i).GetComponent<MeshFilter>().mesh.vertices;
allLineData[i].uv = line.transform.GetChild(i).GetComponent<MeshFilter>().mesh.uv;
allLineData[i].triangle = line.transform.GetChild(i).GetComponent<MeshFilter>().mesh.triangles;
allLineData[i].color = line.transform.GetChild(i).GetComponent<MeshRenderer>().material.color;
}
StringBuilder sb = LineData2Jason(allLineData);
stringB = sb;
//Loom.RunAsync(()=> { WriteToText(sb,filepath); });
WriteToText(sb, filepath);
//AssetDatabase.Refresh();
}
void WriteToText(StringBuilder sb,string filepath)
{
FileInfo t = new FileInfo(filepath);
if (!File.Exists(filepath))
{
File.Delete(filepath);
}
StreamWriter sw = t.CreateText();
sw.WriteLine(sb.ToString());
sw.Close();
sw.Dispose();
}
/// <summary>
/// 所有line转换为json
/// </summary>
/// <param name="ld"></param>
/// <returns></returns>
StringBuilder LineData2Jason(LineData[] ld)
{
StringBuilder sb = new StringBuilder();
JsonWriter writer = new JsonWriter(sb);
writer.WriteObjectStart();
writer.WritePropertyName("allLine");
writer.WriteArrayStart();
foreach (LineData data in ld)
{
writer.WriteObjectStart();
writer.WritePropertyName("name");
writer.Write(data.name);
writer.WritePropertyName("position");
writer.WriteArrayStart();
writer.WriteObjectStart();
writer.WritePropertyName("x");
writer.Write(data.position.x.ToString("F5"));
writer.WritePropertyName("y");
writer.Write(data.position.x.ToString("F5"));
writer.WritePropertyName("z");
writer.Write(data.position.x.ToString("F5"));
writer.WriteObjectEnd();
writer.WriteArrayEnd();
writer.WritePropertyName("rotation");
writer.WriteArrayStart();
writer.WriteObjectStart();
writer.WritePropertyName("x");
writer.Write(data.rotation.x.ToString("F5"));
writer.WritePropertyName("y");
writer.Write(data.rotation.y.ToString("F5"));
writer.WritePropertyName("z");
writer.Write(data.rotation.z.ToString("F5"));
writer.WriteObjectEnd();
writer.WriteArrayEnd();
writer.WritePropertyName("vertex");
writer.WriteArrayStart();
for (int i = 0; i < data.vertex.Length; i++)
{
writer.WriteObjectStart();
writer.WritePropertyName("index");
writer.Write(i.ToString());
writer.WritePropertyName("x");
writer.Write(data.vertex[i].x.ToString("F5"));
writer.WritePropertyName("y");
writer.Write(data.vertex[i].y.ToString("F5"));
writer.WritePropertyName("z");
writer.Write(data.vertex[i].z.ToString("F5"));
writer.WriteObjectEnd();
}
writer.WriteArrayEnd();
writer.WritePropertyName("uv");
writer.WriteArrayStart();
for (int i = 0; i < data.uv.Length; i++)
{
writer.WriteObjectStart();
writer.WritePropertyName("index");
writer.Write(i.ToString());
writer.WritePropertyName("x");
writer.Write(data.uv[i].x.ToString("F5"));
writer.WritePropertyName("y");
writer.Write(data.uv[i].y.ToString("F5"));
writer.WriteObjectEnd();
}
writer.WriteArrayEnd();
writer.WritePropertyName("triangle");
writer.WriteArrayStart();
for (int i = 0; i < data.triangle.Length; i++)
{
writer.WriteObjectStart();
writer.WritePropertyName("index");
writer.Write(i.ToString());
writer.WritePropertyName("value");
writer.Write(data.triangle[i].ToString());
writer.WriteObjectEnd();
}
writer.WriteArrayEnd();
writer.WritePropertyName("color");
writer.WriteArrayStart();
writer.WriteObjectStart();
writer.WritePropertyName("r");
writer.Write(data.color.r.ToString("F5"));
writer.WritePropertyName("g");
writer.Write(data.color.g.ToString("F5"));
writer.WritePropertyName("b");
writer.Write(data.color.b.ToString("F5"));
writer.WritePropertyName("a");
writer.Write(data.color.a.ToString("F5"));
writer.WriteObjectEnd();
writer.WriteArrayEnd();
writer.WriteObjectEnd();
}
writer.WriteArrayEnd();
writer.WriteObjectEnd();
return sb;
}
public void Read()
{
LineData[] ld;
StreamReader sr = File.OpenText(filepath);
string strLine = sr.ReadToEnd();
JsonData jd = JsonMapper.ToObject(strLine);
JsonData lineArray = jd["allLine"];
ld = new LineData[lineArray.Count];
for (int i = 0; i < lineArray.Count; i++)
{
ld[i] = new LineData();
JsonData name, px, py, pz, rx, ry, rz, cr, cg, cb, ca;
name = lineArray[i]["name"];
JsonData position = lineArray[i]["position"];
px = position[0]["x"];
py = position[0]["y"];
pz = position[0]["z"];
JsonData rotation = lineArray[i]["rotation"];
rx = rotation[0]["x"];
ry = rotation[0]["y"];
rz = rotation[0]["z"];
JsonData color = lineArray[i]["color"];
cr = color[0]["r"];
cg = color[0]["g"];
cb = color[0]["b"];
ca = color[0]["a"];
ld[i].name = (string)name;
ld[i].position.x = float.Parse((string)px);
ld[i].position.y = float.Parse((string)py);
ld[i].position.z = float.Parse((string)pz);
ld[i].rotation.x = float.Parse((string)rx);
ld[i].rotation.y = float.Parse((string)ry);
ld[i].rotation.z = float.Parse((string)rz);
ld[i].color.r = float.Parse((string)cr);
ld[i].color.g = float.Parse((string)cg);
ld[i].color.b = float.Parse((string)cb);
ld[i].color.a = float.Parse((string)ca);
JsonData vertex = lineArray[i]["vertex"];
ld[i].vertex = new Vector3[vertex.Count];
ld[i].uv = new Vector2[vertex.Count];
for (int j = 0; j < vertex.Count; j++)
{
ld[i].vertex[j] = new Vector3();
JsonData vx, vy, vz;
vx = vertex[j]["x"];
vy = vertex[j]["y"];
vz = vertex[j]["z"];
ld[i].uv[j] = new Vector2();
ld[i].vertex[j].x = float.Parse((string)vx);
ld[i].vertex[j].y = float.Parse((string)vy);
ld[i].vertex[j].z = float.Parse((string)vz);
ld[i].uv[j] = ld[i].vertex[j];
}
JsonData triangle = lineArray[i]["triangle"];
ld[i].triangle = new int[triangle.Count];
for (int j = 0; j < triangle.Count; j++)
{
ld[i].triangle[j] = int.Parse((string)triangle[j]["value"]);
}
}
CreateMesh(ld);
}
void CreateMesh(LineData[] ld)
{
for (int i = 0; i < ld.Length; i++)
{
//drawMesh.GenerateMesh(ld[i]);
}
}
}
Unity 绘制Mesh线条的更多相关文章
- Unity中Mesh分解与边缘高亮加上深度检测
一个比较简单的需求,不过遇到些坑,记录下. 房间有多个模型,每个模型可能多个SubMesh,点击后,需要能具体到是那个SubMesh,并且在这个SubMesh上显示边缘高光,以及能个性这单个SubMe ...
- Quartz2D常见图形的绘制:线条、多边形、圆
UI高级 Quartz2D http://ios.itcast.cn iOS学院 掌握 drawRect:方法的使用 常见图形的绘制:线条.多边形.圆 绘图状态的设置:文字颜色.线宽等 图形上下文状 ...
- unity 绘制三角形
哎 该学的还是要学 参考:http://www.narkii.com/club/thread-369573-1.html unity 顶点绘制三角形 脚本绘制; 其实filter和render就是进行 ...
- unity绘制线和绘制面
绘制线条代码,其实就是指定至少两个点,然后赋予贴图即可,不废话,上代码: using UnityEngine; using System.Collections; public class LineT ...
- Unity 绘制多边形
最近工程需要用到一个多边形用来查看角色属性,于是就研究了下Mesh用网格做了一个.遗憾的的 UGUI 渲染不了 3D 物体,然后又用了一段时间研究了下UGUI的网格绘制. 不过终于还是完成了,虽然有些 ...
- 关于Unity中Mesh网格的详解
3D模型 通过3D建模软件所建出来的点和面,如以三角形为主的点和面,比如人的脑袋一个球,就是由各种各样的三角形组成的点和面. 点和面以及纹理坐标都是通过3D建模软件建模出来的. Unity会帮我们把模 ...
- Unity中用Mesh画一个圆环
Probuider 前几天在做一个小项目的时候,用到了Unity自带的一个包ProBuilder其中的Arch生成1/4圆. 挺好玩的,可以在直接Unity中根据需要用Mesh定制生成图形,而不用建模 ...
- Unity - 绘制正五边形网格
本文简述了Unity中绘制正五边形网格的基本方法:计算顶点信息.设置三角形覆盖信息.创建配置mesh 绘制方法 基本思路:计算出五边形顶点坐标信息作为数组,设置三角形包围方式,再创建新的mesh配置v ...
- Unity的Mesh压缩:为什么我的内存没有变化?
0x00 前言 最近和朋友聊天,谈到了Mesh的内存优化问题,他发现开启Model Importer面板上的Mesh Compression选项之后,内存并没有什么变化.事实上,期望开启Mesh Co ...
随机推荐
- 关于python、pip、anaconda安装的一些记录
写这篇博客是因为自己这段时间总是倒腾python的环境,其间倒腾崩了好几次.....无奈之下还是梳理一下. PYTHON 首在安装python3.6的之后,我安装了anaconda3,这样我的电脑上p ...
- Java线程设计模式(五)
多线程的设计模式:Future模式.Master-Worker模式,生产消费者模式 public interface Data { String getRequest(); } public clas ...
- php-sql-server-2017
Download the Microsoft Drivers for PHP for SQL Server https://docs.microsoft.com/en-us/sql/connect/p ...
- 关于vue-svg-icon的使用方式
前言 工作中用到svg格式的图标,既然是svg,当然不想用古老的img方式引用,希望能凭借定义svg的fill属性,随意定义图标的颜色:同时不想将整段svg代码写入组建内,于是找到了使用vue-svg ...
- Python七大原则,24种设计模式
七大设计原则:1.单一职责原则[SINGLE RESPONSIBILITY PRINCIPLE]:一个类负责一项职责.2.里氏替换原则[LISKOV SUBSTITUTION PRINCIPLE]:继 ...
- Python——Str
在Python内存中,字符串是以unicode形式存储的. str格式,最常用的数据类型格式,分别有 (' ') 引号 ,(" ")双引号,(''' ''')三引号 开头和结尾的引 ...
- 【转】TI DSP C6657学习之——编译静态库.lib
熟悉C++开发的的小伙伴都知道,我们一般代码中往往要引入许多第三方编译好的库,有些是静态链接库static library, 有些是动态链接库dll.引入库的目的一是减少代码的编译时间,二是只提供函数 ...
- [https][tls] 如何使用wireshark查看tls/https加密消息--使用keylog
姊妹篇: [ipsec][strongswan] 使用wireshark查看strongswan ipsec esp ikev1 ikev2的加密内容 [https][tls] 如何使用wiresha ...
- GCC使用总结
概念 GCC一开始是linux系统集成的用来编译C程序的编译器(GNU C Compiler),目前GCC已经不仅仅支持C语言了,因而其缩写名单意义也变成(GNU Compiler Collectio ...
- Red Hat Enterprise Linux 8正式发布
现在CENTOS 8还没有发布. 了解其主要特点. https://developers.redhat.com/blog/2019/05/07/red-hat-enterprise-linux-8-n ...