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