235 lines
8.2 KiB
C#
235 lines
8.2 KiB
C#
|
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]);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 获取地形的高度
|
|||
|
/// </summary>
|
|||
|
/// <param name="fX"></param>
|
|||
|
/// <param name="fY"></param>
|
|||
|
/// <returns></returns>
|
|||
|
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;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 返回结束位置与矩形大小
|
|||
|
/// </summary>
|
|||
|
/// <param name="startX"></param>
|
|||
|
/// <param name="startY"></param>
|
|||
|
/// <param name="showSize"></param>
|
|||
|
/// <returns></returns>
|
|||
|
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);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|