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]);
}
}
}