2025-04-03 02:30:16 +08:00

235 lines
8.2 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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