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