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

315 lines
11 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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