315 lines
11 KiB
C#
315 lines
11 KiB
C#
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;
|
||
}
|
||
}
|
||
}
|