/// <summary> /// Provided two faces, this method will attempt to project @f2 and align its size, rotation, and position to match /// the shared edge on f1. Returns true on success, false otherwise. /// </summary> /// <param name="mesh"></param> /// <param name="f1"></param> /// <param name="f2"></param> /// <param name="channel"></param> /// <returns></returns> public static bool AutoStitch(ProBuilderMesh mesh, Face f1, Face f2, int channel) { var wings = WingedEdge.GetWingedEdges(mesh, new [] { f1, f2 }); var sharedEdge = wings.FirstOrDefault(x => x.face == f1 && x.opposite != null && x.opposite.face == f2); if (sharedEdge == null) { return(false); } if (f1.manualUV) { f2.manualUV = true; } f1.textureGroup = -1; f2.textureGroup = -1; Projection.PlanarProject(mesh, f2); if (AlignEdges(mesh, f2, sharedEdge.edge.local, sharedEdge.opposite.edge.local, channel)) { if (!f2.manualUV) { UvUnwrapping.SetAutoAndAlignUnwrapParamsToUVs(mesh, new [] { f2 }); } return(true); } return(false); }
public void SetManualFaceToAuto_MatchesOriginalUVs( [ValueSource("AutoUVOffsetParameters")] Vector2 offset, [ValueSource("AutoUVRotationParameters")] float rotation, [ValueSource("AutoUVScaleParameters")] Vector2 scale) { var unwrap = face.uv; unwrap.offset = offset; unwrap.rotation = rotation; unwrap.scale = scale; face.uv = unwrap; // Verify that UV settings have actually been applied Assume.That(face.uv.offset, Is.EqualTo(offset)); Assume.That(face.uv.rotation, Is.EqualTo(rotation)); Assume.That(face.uv.scale, Is.EqualTo(scale)); Assume.That(face.manualUV, Is.EqualTo(false)); mesh.Refresh(RefreshMask.UV); // Verify that the UVs are in the correct place Assume.That(GetEdgeRotation(mesh, verticalEdge), Is.EqualTo(rotation).Within(.1f)); Assume.That(GetEdgeScale(mesh, verticalEdge), Is.EqualTo(scale.y).Within(.1f)); Assume.That(GetEdgeScale(mesh, horizontalEdge), Is.EqualTo(scale.x).Within(.1f)); // Offset is flipped in code for legacy reasons var center = Bounds2D.Center(mesh.texturesInternal, face.distinctIndexesInternal); Assume.That(center.x, Is.EqualTo(-offset.x).Within(.1f)); Assume.That(center.y, Is.EqualTo(-offset.y).Within(.1f)); face.uv = AutoUnwrapSettings.defaultAutoUnwrapSettings; face.manualUV = true; // Verify that UV settings have been reset Assume.That(face.uv.offset, Is.EqualTo(new Vector2(0f, 0f))); Assume.That(face.uv.rotation, Is.EqualTo(0f)); Assume.That(face.uv.scale, Is.EqualTo(new Vector2(1f, 1f))); Assume.That(face.manualUV, Is.EqualTo(true)); // This sets the manualFlag to false, sets the AutoUnwrap settings, and rebuilds UVs UvUnwrapping.SetAutoAndAlignUnwrapParamsToUVs(mesh, new [] { face }); Assert.That(face.uv.offset.x, Is.EqualTo(offset.x).Within(.1f)); Assert.That(face.uv.offset.y, Is.EqualTo(offset.y).Within(.1f)); Assert.That(face.uv.rotation, Is.EqualTo(rotation).Within(.1f)); Assert.That(face.uv.scale.x, Is.EqualTo(scale.x).Within(.1f)); Assert.That(face.uv.scale.y, Is.EqualTo(scale.y).Within(.1f)); Assert.That(face.manualUV, Is.EqualTo(false)); }
static List <ProBuilderMesh> CombineToNewMeshes(IEnumerable <ProBuilderMesh> meshes) { if (meshes == null) { throw new ArgumentNullException("meshes"); } if (!meshes.Any() || meshes.Count() < 2) { return(null); } var vertices = new List <Vertex>(); var faces = new List <Face>(); var autoUvFaces = new List <Face>(); var sharedVertices = new List <SharedVertex>(); var sharedTextures = new List <SharedVertex>(); int offset = 0; var materialMap = new List <Material>(); AccumulateMeshesInfo( meshes, offset, ref vertices, ref faces, ref autoUvFaces, ref sharedVertices, ref sharedTextures, ref materialMap ); var res = SplitByMaxVertexCount(vertices, faces, sharedVertices, sharedTextures); var pivot = meshes.LastOrDefault().transform.position; foreach (var m in res) { m.renderer.sharedMaterials = materialMap.ToArray(); InternalMeshUtility.FilterUnusedSubmeshIndexes(m); m.SetPivot(pivot); UvUnwrapping.SetAutoAndAlignUnwrapParamsToUVs(m, autoUvFaces); } return(res); }
protected override void OnToolDisengaged() { var isFaceMode = ProBuilderEditor.selectMode.ContainsFlag(SelectMode.TextureFace | SelectMode.Face); foreach (var mesh in elementSelection) { if (!(mesh is MeshAndTextures)) { continue; } var textures = ((MeshAndTextures)mesh).textures; mesh.mesh.SetUVs(k_TextureChannel, textures); if (isFaceMode) { UvUnwrapping.SetAutoAndAlignUnwrapParamsToUVs(mesh.mesh, mesh.mesh.selectedFacesInternal.Where(x => !x.manualUV)); } else { var indices = new HashSet <int>(mesh.elementGroups.SelectMany(x => x.indices)); foreach (var face in mesh.mesh.facesInternal) { foreach (var index in face.distinctIndexesInternal) { if (indices.Contains(index)) { face.manualUV = true; break; } } } } } }
public override Bounds RebuildMesh(ProBuilderMesh mesh, Vector3 size, Quaternion rotation) { var meshSize = Math.Abs(size); m_Radius = System.Math.Min(meshSize.x, meshSize.z); var height = meshSize.y; var subdivAxis = m_NumberOfSides; // template is outer ring - radius refers to outer ring always Vector3[] template = new Vector3[subdivAxis]; for (int i = 0; i < subdivAxis; i++) { Vector2 ct = Math.PointInCircumference(m_Radius, i * (360f / subdivAxis), Vector2.zero); template[i] = new Vector3(ct.x, -height / 2f, ct.y); } List <Vector3> v = new List <Vector3>(); List <Face> f = new List <Face>(); // build sides for (int i = 0; i < subdivAxis; i++) { // side face v.Add(template[i]); v.Add((i < subdivAxis - 1) ? template[i + 1] : template[0]); v.Add(Vector3.up * height / 2f); // bottom face v.Add(template[i]); v.Add((i < subdivAxis - 1) ? template[i + 1] : template[0]); v.Add(Vector3.down * height / 2f); } List <Face> sideFaces = new List <Face>(); for (int i = 0; i < subdivAxis * 6; i += 6) { Face face = new Face(new int[3] { i + 2, i + 1, i + 0 }); f.Add(face); sideFaces.Add(face); f.Add(new Face(new int[3] { i + 3, i + 4, i + 5 })); } var sizeSigns = Math.Sign(size); for (int i = 0; i < v.Count; i++) { v[i] = Vector3.Scale(rotation * v[i], sizeSigns); } var sizeSign = Mathf.Sign(size.x) * Mathf.Sign(size.y) * Mathf.Sign(size.z); if (sizeSign < 0) { foreach (var face in f) { face.Reverse(); } } mesh.RebuildWithPositionsAndFaces(v, f); mesh.unwrapParameters = new UnwrapParameters() { packMargin = 30f }; // Set the UVs manually for the side faces, so that they are uniform. // Calculate the UVs for the first face, then set the others to the same. var firstFace = sideFaces[0]; var uv = firstFace.uv; uv.anchor = AutoUnwrapSettings.Anchor.LowerLeft; firstFace.uv = uv; firstFace.manualUV = true; // Always use up vector for projection of side faces. // Otherwise the lines in the PB texture end up crooked. UvUnwrapping.Unwrap(mesh, firstFace, projection: Vector3.up); for (int i = 1; i < sideFaces.Count; i++) { var sideFace = sideFaces[i]; sideFace.manualUV = true; UvUnwrapping.CopyUVs(mesh, firstFace, sideFace); } mesh.RefreshUV(sideFaces); return(UpdateBounds(mesh, size, rotation, new Bounds())); }
/// <summary> /// Merge a collection of <see cref="ProBuilderMesh"/> objects to as few meshes as possible. It will re-use the meshTarget object as the first /// destination for the first <see cref="ProBuilderMesh.maxVertexCount"/> -1 vertices. If the sum of vertices is above <see cref="ProBuilderMesh.maxVertexCount"/> - 1 /// it will generate new meshes unless there is a single mesh left in which case it will append it to the return list. /// </summary> /// <param name="meshes">A collection of meshes to be merged. Note: it is expected that meshes includes meshTarget.</param> /// <param name="meshTarget">A mesh which will be used as the starting point for merging and which will be kept as reference/target.</param> /// <returns> /// A list of merged meshes. In most cases this will be a single mesh corresponding to meshTarget. However it can be multiple in cases /// where the resulting vertex count exceeds the maximum allowable value. /// </returns> public static List <ProBuilderMesh> Combine(IEnumerable <ProBuilderMesh> meshes, ProBuilderMesh meshTarget) { if (meshes == null) { throw new ArgumentNullException("meshes"); } if (meshTarget == null) { throw new ArgumentNullException("meshTarget"); } if (!meshes.Any() || meshes.Count() < 2) { return(null); } if (!meshes.Contains(meshTarget)) { return(null); } var vertices = new List <Vertex>(meshTarget.GetVertices()); var faces = new List <Face>(meshTarget.facesInternal); var sharedVertices = new List <SharedVertex>(meshTarget.sharedVertices); var sharedTextures = new List <SharedVertex>(meshTarget.sharedTextures); int offset = meshTarget.vertexCount; var materialMap = new List <Material>(meshTarget.renderer.sharedMaterials); var targetTransform = meshTarget.transform; var firstMeshContributors = new List <ProBuilderMesh>(); var remainderMeshContributors = new List <ProBuilderMesh>(); var currentMeshVertexCount = offset; foreach (var mesh in meshes) { if (mesh != meshTarget) { if (currentMeshVertexCount + mesh.vertexCount < ProBuilderMesh.maxVertexCount) { currentMeshVertexCount += mesh.vertexCount; firstMeshContributors.Add(mesh); } else { remainderMeshContributors.Add(mesh); } } } var autoUvFaces = new List <Face>(); AccumulateMeshesInfo( firstMeshContributors, offset, ref vertices, ref faces, ref autoUvFaces, ref sharedVertices, ref sharedTextures, ref materialMap, targetTransform ); meshTarget.SetVertices(vertices); meshTarget.faces = faces; meshTarget.sharedVertices = sharedVertices; meshTarget.sharedTextures = sharedTextures != null?sharedTextures.ToArray() : null; meshTarget.renderer.sharedMaterials = materialMap.ToArray(); meshTarget.ToMesh(); meshTarget.Refresh(); UvUnwrapping.SetAutoAndAlignUnwrapParamsToUVs(meshTarget, autoUvFaces); MeshValidation.EnsureMeshIsValid(meshTarget, out int removedVertices); var returnedMesh = new List <ProBuilderMesh>() { meshTarget }; if (remainderMeshContributors.Count > 1) { var newMeshes = CombineToNewMeshes(remainderMeshContributors); foreach (var mesh in newMeshes) { MeshValidation.EnsureMeshIsValid(mesh, out removedVertices); returnedMesh.Add(mesh); } } else if (remainderMeshContributors.Count == 1) { returnedMesh.Add(remainderMeshContributors[0]); } return(returnedMesh); }
public TranslateTextureSelection(ProBuilderMesh mesh, PivotPoint pivot) : base(mesh, pivot) { var faces = mesh.faces; m_FaceAndScale = mesh.selectedFaceIndexes.Select(x => new SimpleTuple <Face, Vector2>(faces[x], UvUnwrapping.GetUVTransform(mesh, faces[x]).scale)) .ToArray(); }