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