Cute_demon_attacks/meng_yao/Assets/Scene/NavMeshExport.cs
2024-12-09 11:56:41 +08:00

173 lines
5.7 KiB
C#

using System.IO;
using System.Text;
using UnityEditor;
using UnityEngine.SceneManagement;
using UnityEngine;
using UnityEngine.AI;
//navmesh导出数据
public class NavMeshExport : MonoBehaviour
{
private GameObject _testMap;
[MenuItem("Tools/Export NavMesh Data")]
private static void Export()
{
NavMeshTriangulation triangulatedNavMesh = NavMesh.CalculateTriangulation();
Mesh mesh = new Mesh();
mesh.name = "_NavMesh";
mesh.vertices = triangulatedNavMesh.vertices;
mesh.triangles = triangulatedNavMesh.indices;
string baseName = "navmesh_" + SceneManager.GetActiveScene().name;
string fileName = Application.dataPath + "/navmesh/" + baseName + ".obj";
ExportNavmesh(mesh, fileName);
AssetDatabase.Refresh();
string assetName = fileName.Replace(Application.dataPath, "Assets");
GameObject navMesh = Instantiate(AssetDatabase.LoadAssetAtPath<GameObject>(assetName));
navMesh.name = baseName;
ExportNavData(navMesh);
Debug.Log("导出完成:" + baseName);
AssetDatabase.Refresh();
}
[MenuItem("Tools/NavMesh Data Test")]
private static void Test()
{
GameObject obj = GameObject.Find("_NavMesh");
Vector3[] localVectors = obj.GetComponent<MeshFilter>().sharedMesh.vertices;
int[] triangles = obj.GetComponent<MeshFilter>().sharedMesh.triangles;
//把mesh的本地坐标转成世界坐标
Vector3[] worldVectors = new Vector3[localVectors.Length];
for (int i = 0; i < localVectors.Length; ++i)
{
Vector3 pos = obj.transform.TransformPoint(localVectors[i]);
worldVectors[i] = pos;
}
//检测点
Vector3 checkPoint = GameObject.Find("TestPoint").transform.position;
bool _isInside = false;
for (int i = 0; i < triangles.Length; i += 3)
{
//Debug.Log(string.Format("{0},{1},{2}", triangles[i], triangles[i + 1], triangles[i + 2]));
if (IsInside(worldVectors[triangles[i]], worldVectors[triangles[i + 1]], worldVectors[triangles[i + 2]], checkPoint))
{
_isInside = true;
break;
}
}
if (_isInside)
Debug.Log("该点合法");
else
Debug.Log("该点非法");
}
private static string ParseMesh(Mesh mesh)
{
StringBuilder sb = new StringBuilder();
sb.Append("g ").Append(mesh.name).Append("\n");
foreach (Vector3 v in mesh.vertices)
{
sb.Append(string.Format("v {0} {1} {2}\n", v.x, v.y, v.z));
}
sb.Append("\n");
foreach (Vector3 v in mesh.normals)
{
sb.Append(string.Format("vn {0} {1} {2}\n", v.x, v.y, v.z));
}
sb.Append("\n");
foreach (Vector3 v in mesh.uv)
{
sb.Append(string.Format("vt {0} {1}\n", v.x, v.y));
}
for (int m = 0; m < mesh.subMeshCount; m++)
{
sb.Append("\n");
int[] triangles = mesh.GetTriangles(m);
for (int i = 0; i < triangles.Length; i += 3)
{
sb.Append(string.Format("f {0}/{0}/{0} {1}/{1}/{1} {2}/{2}/{2}\n", triangles[i] + 1, triangles[i + 1] + 1, triangles[i + 2] + 1));
}
}
return sb.ToString();
}
private static void ExportNavmesh(Mesh mesh, string filename)
{
using (StreamWriter sw = new StreamWriter(filename))
{
sw.Write(ParseMesh(mesh));
}
}
private static void ExportNavData(GameObject obj)
{
Vector3[] localVectors = obj.transform.Find("_NavMesh").GetComponent<MeshFilter>().sharedMesh.vertices;
int[] triangles = obj.transform.Find("_NavMesh").GetComponent<MeshFilter>().sharedMesh.triangles;
//把mesh的本地坐标转成世界坐标
Vector3[] worldVectors = new Vector3[localVectors.Length];
for (int i = 0; i < localVectors.Length; i++)
{
Vector3 pos = obj.transform.TransformPoint(localVectors[i]);
worldVectors[i] = pos;
}
StringBuilder sb = new StringBuilder();
sb.Append("local nav = {\n");
for (int i = 0; i < triangles.Length; i += 3)
{
sb.AppendFormat("\t{{{0},{1},{2}}},\n", _VectorToLua(worldVectors[triangles[i]]), _VectorToLua(worldVectors[triangles[i + 1]]), _VectorToLua(worldVectors[triangles[i + 2]]));
}
sb.Append("}\n");
sb.Append("return nav");
using (StreamWriter sw = new StreamWriter(Application.dataPath + "/navmesh/" + obj.name + ".lua"))
{
sw.Write(sb.ToString());
}
DestroyImmediate(obj);
}
private static string _VectorToLua(Vector3 vec)
{
return string.Format("{{{0},{1},{2}}}", vec.x, vec.y, vec.z);
}
//判断点是否在三角形内
public static bool IsInside(Vector3 A, Vector3 B, Vector3 C, Vector3 P)
{
Vector3 v0 = C - A;
Vector3 v1 = B - A;
Vector3 v2 = P - A;
float dot00 = Vector3.Dot(v0, v0);
float dot01 = Vector3.Dot(v0, v1);
float dot02 = Vector3.Dot(v0, v2);
float dot11 = Vector3.Dot(v1, v1);
float dot12 = Vector3.Dot(v1, v2);
float inverDeno = 1 / (dot00 * dot11 - dot01 * dot01);
float u = (dot11 * dot02 - dot01 * dot12) * inverDeno;
if (u < 0 || u > 1) // if u out of range, return directly
{
return false;
}
float v = (dot00 * dot12 - dot01 * dot02) * inverDeno;
if (v < 0 || v > 1) // if v out of range, return directly
{
return false;
}
return u + v <= 1;
}
}