NLDClient-yudde/ProjectNLD/Assets/Code/Scripts/Gameplay/Vehicle/TireMark/TireMarkPanel.cs

315 lines
11 KiB
C#
Raw Normal View History

2023-10-19 15:00:19 +08:00
using UnityEngine.Rendering;
namespace Gameplay.Vehicle.TireMark
{
using UnityEngine;
public class TireMarkPanel
{
public GameObject rootObj;
public RenderTexture rt;
// TODO: 这个size可以调整
private readonly int _textureSize = 2048;
private Vector3 _centerPos;
private Vector3 _halfSize;
public TireMarkPanel(GameObject rootObj)
{
this.rootObj = rootObj;
}
public void Init()
{
// 创建一个空的贴图,RenderTexture
rt = new RenderTexture(_textureSize, _textureSize, 0, RenderTextureFormat.Default);
// 设置基础颜色为 透明
Graphics.SetRenderTarget(rt);
GL.Clear(true, true, Color.clear);
Graphics.SetRenderTarget(null);
var meshRenderer = rootObj.transform.GetChild(0).GetComponent<MeshRenderer>();
meshRenderer.material.mainTexture = rt;
// 获取区块大小
var centerPos = rootObj.transform.position;
var size = rootObj.transform.localScale;
var halfSize = size / 2;
_centerPos = centerPos;
_halfSize = halfSize;
}
public void Dispose()
{
Object.Destroy(rt);
rt = null;
}
private readonly Vector2[] _cachePosList = new Vector2[4];
private readonly Vector3[] _cacheUVList = new Vector3[4];
public void Draw(TireMarkDrawData drawData,
CommandBuffer cmd, int debugIndex)
{
// 根据drawData的数据,将贴图上的像素点进行修改
var start = drawData.start;
var end = drawData.end;
var width = drawData.width;
if (drawData.needCalc)
{
drawData.needCalc = false;
if (drawData.isFirst)
{
drawData.isFirst = false;
// 获取绘制四边形
var c1 = start.pos;
var c2 = end.pos;
var startLeft = start.rot * new Vector3(width / 2, 0, 0);
var p1 = start.pos + startLeft;
var p2 = start.pos - startLeft;
var endLeft = end.rot * new Vector3(width / 2, 0, 0);
var p3 = end.pos + endLeft;
var p4 = end.pos - endLeft;
// 当c1-p1 与 c2-p3相交时,将p3重置为p1
var isIntersect = _IsLineIntersect(c1, p1, c2, p3);
if (isIntersect)
{
p3 = p1;
}
// 当c1-p2 与 c2-p4相交时,将p4重置为p2
isIntersect = _IsLineIntersect(c1, p2, c2, p4);
if (isIntersect)
{
p4 = p2;
}
drawData.cacheP1 = p1;
drawData.cacheP2 = p2;
drawData.cacheP3 = p3;
drawData.cacheP4 = p4;
drawData.cacheC1 = c2;
}
else
{
var c1 = drawData.cacheC1;
var c2 = end.pos;
var p1 = drawData.cacheP1;
var p2 = drawData.cacheP2;
var endLeft = end.rot * new Vector3(width / 2, 0, 0);
var p3 = end.pos + endLeft;
var p4 = end.pos - endLeft;
// 当c1-p1 与 c2-p3相交时,将p3重置为p1
var isIntersect = _IsLineIntersect(c1, p1, c2, p3);
if (isIntersect)
{
p3 = p1;
}
// 当c1-p2 与 c2-p4相交时,将p4重置为p2
isIntersect = _IsLineIntersect(c1, p2, c2, p4);
if (isIntersect)
{
p4 = p2;
}
drawData.cacheP1 = p1;
drawData.cacheP2 = p2;
drawData.cacheP3 = p3;
drawData.cacheP4 = p4;
drawData.cacheC1 = c2;
}
}
// 根据四个点,计算出贴图上的uv坐标
var pos1 = _GetTexturePos(drawData.cacheP1);
var pos2 = _GetTexturePos(drawData.cacheP2);
var pos3 = _GetTexturePos(drawData.cacheP3);
var pos4 = _GetTexturePos(drawData.cacheP4);
drawData.cacheP1 = drawData.cacheP3;
drawData.cacheP2 = drawData.cacheP4;
// 重排四个uv,确保uv1234是顺时针排列的
var posList = _cachePosList;
posList[0] = pos1;
posList[1] = pos2;
posList[2] = pos3;
posList[3] = pos4;
// _SortUV(posList);
var isAllOut = true;
for (int i = 0; i < posList.Length; i++)
{
var pos = posList[i];
if (pos.x is > -1 and < 1 && pos.y is > -1 and < 1)
{
isAllOut = false;
break;
}
}
if (isAllOut)
{
return;
}
var uvList = _cacheUVList;
var halfUVWidth = drawData.uvWidth / 2f;
uvList[0] = new Vector3(0.5f - halfUVWidth, drawData.start.uvY % 1f, drawData.start.alpha);
uvList[1] = new Vector3(0.5f + halfUVWidth, drawData.start.uvY % 1f, drawData.start.alpha);
uvList[2] = new Vector3(0.5f - halfUVWidth, drawData.end.uvY % 1f, drawData.end.alpha);
uvList[3] = new Vector3(0.5f + halfUVWidth, drawData.end.uvY % 1f, drawData.end.alpha);
// TODO: 等待调试
// var combieStr = "进行绘制 " + debugIndex + ":";
// combieStr += "pos1:" + pos1 + " ";
// combieStr += "pos2:" + pos2 + " ";
// combieStr += "pos3:" + pos3 + " ";
// combieStr += "pos4:" + pos4 + " ";
// DebugUtil.LogError(combieStr);
// 绘制四边形
DrawQuadrilateral(cmd, rt, posList, uvList, drawData.t2d, drawData.color);
}
private readonly Vector3[] _cacheVertices = new Vector3[4];
private readonly Color[] _cacheUV = new Color[4];
private readonly Mesh _cacheMesh = new Mesh();
private readonly int[] _cacheIndices =
{
0, 1,
3, 2
};
private static readonly int MainTex = Shader.PropertyToID("_MainTex");
private static readonly int MainColor = Shader.PropertyToID("_MainColor");
private void DrawQuadrilateral(CommandBuffer cmd,
RenderTexture targetTexture,
Vector2[] screenPosList,
Vector3[] uvList,
Texture2D texture2D,
Color color)
{
// 创建 CommandBuffer
cmd.SetRenderTarget(targetTexture);
// 设置四边形的顶点和 UV 坐标信息
Vector3[] vertices = _cacheVertices;
Color[] uv = _cacheUV;
// 0 1 2 2 1 3
vertices[0] = new Vector3(screenPosList[0].x, screenPosList[0].y, 0f);
vertices[1] = new Vector3(screenPosList[1].x, screenPosList[1].y, 0f);
vertices[2] = new Vector3(screenPosList[2].x, screenPosList[2].y, 0f);
vertices[3] = new Vector3(screenPosList[3].x, screenPosList[3].y, 0f);
uv[0] = new Color(uvList[0].x, uvList[0].y, uvList[0].z);
uv[1] = new Color(uvList[1].x, uvList[1].y, uvList[1].z);
uv[2] = new Color(uvList[2].x, uvList[2].y, uvList[2].z);
uv[3] = new Color(uvList[3].x, uvList[3].y, uvList[3].z);
// for (int i = 0; i < 4; i++)
// {
// // uv坐标 就是 屏幕坐标
// vertices[i] = new Vector3(screenPosList[i].x, -screenPosList[i].y, 0f); // 将 UV 坐标映射到屏幕空间
// }
// TEST
// vertices[0] = new Vector3(-0.094f, 0.289f, 0);
// vertices[1] = new Vector3(-0.007f, 0.239f, 0);
// vertices[2] = new Vector3(-0.181f, 0.339f, 0);
// vertices[3] = new Vector3(-0.186f, 0.330f, 0);
// 创建 Mesh
var mesh = _cacheMesh;
mesh.vertices = vertices;
mesh.colors = uv;
mesh.SetIndices(_cacheIndices, MeshTopology.Quads, 0);
// 设置材质和绘制命令
var material = TireMarkManager.instance.drawMat;
material.SetTexture(MainTex, texture2D);
material.SetColor(MainColor, color);
cmd.DrawMesh(mesh, Matrix4x4.identity, material);
}
private void _SortUV(Vector2[] uvList)
{
// 重排四个uv,确保uv1234是顺时针排列的
Vector2 center = Vector2.zero;
for (int i = 0; i < uvList.Length; i++)
{
center += uvList[i];
}
center /= uvList.Length;
System.Array.Sort(uvList, (a,
b) =>
{
float cross = (a.x - center.x) * (b.y - center.y) - (b.x - center.x) * (a.y - center.y);
if (cross > 0f)
{
return -1;
}
else if (cross < 0f)
{
return 1;
}
else
{
return 0;
}
});
}
private Vector2 _GetTexturePos(Vector3 pos)
{
// 根据pos和自身_bounds计算出uv坐标
var x = (pos.x - _centerPos.x) / _halfSize.x;
var z = (pos.z - _centerPos.z) / _halfSize.z;
return new Vector2(x, z);
}
private bool _IsLineIntersect(Vector3 p1,
Vector3 p2,
Vector3 p3,
Vector3 p4)
{
// 判断两条线段是否相交
Vector2 A = new Vector2(p1.x, p1.z);
Vector2 B = new Vector2(p2.x, p2.z);
Vector2 C = new Vector2(p3.x, p3.z);
Vector2 D = new Vector2(p4.x, p4.z);
float denominator = (B.y - A.y) * (D.x - C.x) - (A.x - B.x) * (C.y - D.y);
if (denominator == 0f)
{
return false; // 平行或共线,不相交
}
float numerator1 = (A.x - C.x) * (D.y - C.y) - (A.y - C.y) * (D.x - C.x);
float numerator2 = (A.x - C.x) * (B.y - A.y) - (A.y - C.y) * (B.x - A.x);
float t1 = numerator1 / denominator;
float t2 = numerator2 / denominator;
// 如果 t1 和 t2 在 0~1 之间,则两线段相交
if (t1 >= 0f && t1 <= 1f && t2 >= 0f && t2 <= 1f)
{
return true;
}
return false;
}
}
}