/// <summary> /// 对贴花的模型重新映射UV /// </summary> /// <param name="decalMesh"></param> /// <param name="decalNormal"></param> /// <returns></returns> /// <remarks>UV展开算法需要进一步研究,这里使用最基本的算法</remarks> private Mesh RemapDecalMapUV(Mesh decalMesh, Vector3 decalNormal) { List <Mapped2DVector> vertexMappedTo2DList = new List <Mapped2DVector>(); float xMin = float.MaxValue; float yMin = float.MaxValue; float xMax = float.MinValue; float yMax = float.MinValue; Vector2[] mappedUV = new Vector2[decalMesh.uv.Length]; for (int i = 0; i < decalMesh.vertexCount; ++i) { Vector3 vertexPosition = decalMesh.vertices[i]; Mapped2DVector posMapTo2D = Mapped2DVector.MapVector3ToVector2(vertexPosition, decalNormal); xMin = Mathf.Min(xMin, posMapTo2D.MappedVector2.x); xMax = Mathf.Max(xMax, posMapTo2D.MappedVector2.x); yMin = Mathf.Min(yMin, posMapTo2D.MappedVector2.y); yMax = Mathf.Max(yMax, posMapTo2D.MappedVector2.y); vertexMappedTo2DList.Add(posMapTo2D); } float uSize = xMax - xMin; float vSize = yMax - yMin; for (int i = 0; i < vertexMappedTo2DList.Count; ++i) { Mapped2DVector mapped2DVector = vertexMappedTo2DList[i]; float u = (mapped2DVector.MappedVector2.x - xMin) / uSize; float v = 1 - (mapped2DVector.MappedVector2.y - yMin) / vSize; //MapVector3ToVector2里的y坐标系是向下的,与正常uv的相反 mappedUV[i] = new Vector2(u, v); } decalMesh.uv = mappedUV; return(decalMesh); }
/// <summary> /// Andrew monotone chain算法,计算凸边形 /// </summary> /// <param name="inVertices">输入的无序3维点</param> /// <param name="uAxis">降维x方向</param> /// <param name="vAxis">降维y方向</param> /// <param name="convexHullVertices">输出凸边形顶点</param> /// <param name="triangles">triangle indices</param> /// <param name="uvs">输出uv</param> /// <returns></returns> public static bool CreateConvexHullByMonotoneChain(List <Vector3> inVertices, Vector3 uAxis, Vector3 vAxis, out Vector3[] convexHullVertices, out Vector2[] uvs, out int[] triangles, TriangleWindingOrder triangleWindingOrder = TriangleWindingOrder.CounterClockWise) { convexHullVertices = new Vector3[0]; uvs = new Vector2[0]; triangles = new int[0]; if (inVertices.Count < 3) { return(false); } float uMax = float.MinValue; float uMin = float.MaxValue; float vMax = float.MinValue; float vMin = float.MaxValue; //3D降维到2D Dictionary <Vector2, Mapped2DVector> vector2DAndMappedDict = new Dictionary <Vector2, Mapped2DVector>(); for (int i = 0; i < inVertices.Count; ++i) { Mapped2DVector mappedVector = new Mapped2DVector(inVertices[i], uAxis, vAxis); if (!vector2DAndMappedDict.ContainsKey(mappedVector.MappedVector2)) { vector2DAndMappedDict.Add(mappedVector.MappedVector2, mappedVector); uMax = Mathf.Max(uMax, mappedVector.MappedVector2.x); uMin = Mathf.Min(uMin, mappedVector.MappedVector2.x); vMax = Mathf.Max(vMax, mappedVector.MappedVector2.y); vMin = Mathf.Min(vMin, mappedVector.MappedVector2.y); } } List <Vector2> inVertexPoints = vector2DAndMappedDict.Keys.ToList(); List <Vector2> convexHullByMonotoneChain = MonotoneChain(inVertexPoints.ToArray()).ToList(); convexHullVertices = new Vector3[convexHullByMonotoneChain.Count]; uvs = new Vector2[convexHullByMonotoneChain.Count]; //计算uv for (int i = 0; i < convexHullByMonotoneChain.Count; ++i) { Vector2 point2D = convexHullByMonotoneChain[i]; convexHullVertices[i] = vector2DAndMappedDict[point2D].OriginalVector; Vector2 pointUV = new Vector2(); pointUV.x = MathUtils.Remap(point2D.x, uMax, uMin, 1, 0); pointUV.y = MathUtils.Remap(point2D.y, vMax, vMin, 1, 0); uvs[i] = pointUV; } //根据WindingOrder计算triangle int index = 1; triangles = new int[(convexHullByMonotoneChain.Count - 2) * 3]; for (int i = 0; i < triangles.Length; i += 3) { triangles[i] = 0; if (triangleWindingOrder == TriangleWindingOrder.CounterClockWise) { triangles[i + 1] = index; triangles[i + 2] = index + 1; } else { triangles[i + 1] = index + 1; triangles[i + 2] = index; } index++; } return(true); }