using UnityEngine; namespace MindPowerSdk { public partial class MPMap { public const float SEA_LEVEL = 0.0f; private static readonly int[,] Offset = { { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } }; private MPTile GetGroupTile(int x, int y, int no) { return GetTile(x + Offset[no, 0], y + Offset[no, 1]); } /// /// 获取地形的高度 /// /// /// /// public float GetHeight(float fX, float fY) { // 将浮点坐标转换为整数坐标(取整) int nX = (int)fX; int nY = (int)fY; // 计算四个角点的坐标(构成一个单位矩形) float fx1 = (float)nX; float fx2 = (float)nX + 1; float fy1 = (float)nY; float fy2 = (float)nY + 1; // 初始化四个顶点的高度(默认海平面) float[] fHeight = new float[4] { SEA_LEVEL, SEA_LEVEL, SEA_LEVEL, SEA_LEVEL }; // 获取基准瓦片 MPTile pTile = GetTile(nX, nY); // 遍历四个顶点获取实际高度 for (int i = 0; i < 4; i++) { MPTile pCurTile = GetGroupTile(nX, nY, i); fHeight[i] = pCurTile.Height; } // 构建四个三维顶点 Vector3 v0 = new Vector3(fx1, fy1, fHeight[0]); Vector3 v1 = new Vector3(fx2, fy1, fHeight[1]); Vector3 v2 = new Vector3(fx1, fy2, fHeight[2]); Vector3 v3 = new Vector3(fx2, fy2, fHeight[3]); // 创建射线(从高处垂直向下) Vector3 vOrig = new Vector3(fX, fY, 20.0f); // 起点 Vector3 vDir = new Vector3(0, 0, -1); // 方向向下 float u, v; // 用于存储交点参数 Vector3 vPickPos; // 检测与第一个三角形(v0-v1-v2)的相交 if (IntersectTri(v0, v1, v2, vOrig, vDir, out u, out v)) { vPickPos = v0 + u * (v1 - v0) + v * (v2 - v0); return vPickPos.z; // 返回交点的Z值(高度) } // 检测与第二个三角形(v2-v1-v3)的相交 if (IntersectTri(v2, v1, v3, vOrig, vDir, out u, out v)) { vPickPos = v2 + u * (v1 - v2) + v * (v3 - v2); return vPickPos.z; } // 无交点返回0 return 0.0f; } // Unity版本的三角形射线相交检测 bool IntersectTri(Vector3 v0, Vector3 v1, Vector3 v2, Vector3 origin, Vector3 direction, out float u, out float v) { u = v = 0; Vector3 edge1 = v1 - v0; Vector3 edge2 = v2 - v0; // 计算行列式 Vector3 pvec = Vector3.Cross(direction, edge2); float det = Vector3.Dot(edge1, pvec); // 背面剔除(det > 0 可改为 det < 0 如果需要双面检测) if (det < Mathf.Epsilon) return false; // 计算U参数并测试范围 Vector3 tvec = origin - v0; u = Vector3.Dot(tvec, pvec); if (u < 0 || u > det) return false; // 计算V参数并测试范围 Vector3 qvec = Vector3.Cross(tvec, edge1); v = Vector3.Dot(direction, qvec); if (v < 0 || u + v > det) return false; // 归一化参数 float invDet = 1.0f / det; u *= invDet; v *= invDet; return true; } /// /// 返回结束位置与矩形大小 /// /// /// /// /// public RectInt GetRect(short startX, short startY, int showSize) { int endX = Mathf.Min(startX + showSize, Width); int endY = Mathf.Min(startY + showSize, Height); // 本次宽高 int width = endX - startX; int height = endY - startY; return new RectInt(endX, endY, width, height); } public Mesh GenMesh(short startX, short startY, int showSize) { RectInt rect = GetRect(startX, startY, showSize); // 顶点 int verticesNum = (rect.width) * (rect.height) * 4; Vector3[] vertices = new Vector3[verticesNum]; int[] triangles = new int[verticesNum * 6]; Vector2[] uv0 = new Vector2[verticesNum]; Vector2[] uv2 = new Vector2[verticesNum]; int vertIdx = 0; int triIdx = 0; for (short y = startY; y < rect.y; y++) { for (short x = startX; x < rect.x; x++) { // 添加4个顶点 for (int i = 0; i < 4; i++) { MPTile tile = GetGroupTile(x, y, i); vertices[vertIdx + i] = new Vector3(x + Offset[i, 0], tile.Height, (y + Offset[i, 1]) * -1); // Debug.Log($"{x},{y}"); // uv 整个mesh映射到一张贴图上 int rx = x - startX; // int ry = rect.y - y - 2; int ry = y - startY + 1; uv0[vertIdx + i] = new Vector2((rx + Offset[i, 0]) / (float)rect.width, (ry + Offset[i, 1]) * -1 / (float)rect.height); uv2[vertIdx + i] = new Vector2(Offset[i, 0], Offset[i, 1] * -1); } triangles[triIdx + 0] = vertIdx + 2; triangles[triIdx + 1] = vertIdx + 0; triangles[triIdx + 2] = vertIdx + 3; triangles[triIdx + 3] = vertIdx + 0; triangles[triIdx + 4] = vertIdx + 1; triangles[triIdx + 5] = vertIdx + 3; vertIdx += 4; triIdx += 6; } } Mesh mesh = new Mesh(); mesh.SetVertices(vertices); mesh.SetTriangles(triangles, 0); mesh.SetUVs(0, uv0); mesh.SetUVs(2, uv2); return mesh; } public (Texture2D, Texture2D) GenTxtNoTexture(short startX, short startY, int showSize) { RectInt rect = GetRect(startX, startY, showSize); Texture2D texture1 = new Texture2D(rect.width, rect.height, TextureFormat.RGBA32, false, true); // 贴图值: texNo texture1.filterMode = FilterMode.Point; Texture2D texture2 = new Texture2D(rect.width, rect.height, TextureFormat.RGBA32, false, true); // 遮罩值:alphaNo texture2.filterMode = FilterMode.Point; for (short y = startY; y < rect.y; y++) { for (short x = startX; x < rect.x; x++) { MPTile tile = GetTile(x, y); // 4层数据 float r = (tile.TexLayer[0].TexNo - 1) / 64f; float g = (tile.TexLayer[1].TexNo - 1) / 64f; float b = (tile.TexLayer[2].TexNo - 1) / 64f; float a = (tile.TexLayer[3].TexNo - 1) / 64f; int rx = x - startX; int ry = rect.y - 1 - y; texture1.SetPixel(rx, ry, new Color(r, g, b, a)); var alphaNo = new Color( (tile.TexLayer[0].AlphaNo - 1) / 16f, (tile.TexLayer[1].AlphaNo - 1) / 16f, (tile.TexLayer[2].AlphaNo - 1) / 16f, (tile.TexLayer[3].AlphaNo - 1) / 16f); texture2.SetPixel(rx, ry, alphaNo); if (alphaNo.r > 48 || alphaNo.g > 48 || alphaNo.b > 48 || alphaNo.a > 48) { Debug.LogError($"{rx},{ry}|{alphaNo}"); } } } texture1.Apply(); texture2.Apply(); return (texture1, texture2); } } }