// indices arrays are optional - if null is passed the index will be 0, 1, 2... up to values array length.
        // this is done to avoid allocating a separate array just to pass linear indices
        internal static UVTransform CalculateDelta(IList <Vector2> src, IList <int> srcIndices, IList <Vector2> dst, IList <int> dstIndices)
        {
            // rotate to match target points by comparing the angle between old UV and new auto projection
            Vector2 dstAngle = dst[GetIndex(dstIndices, 1)] - dst[GetIndex(dstIndices, 0)];
            Vector2 srcAngle = src[GetIndex(srcIndices, 1)] - src[GetIndex(srcIndices, 0)];

            float rotation = Vector2.Angle(dstAngle, srcAngle);

            if (Vector2.Dot(Vector2.Perpendicular(dstAngle), srcAngle) < 0)
            {
                rotation = 360f - rotation;
            }

            Vector2 dstCenter = dstIndices == null?Bounds2D.Center(dst) : Bounds2D.Center(dst, dstIndices);

            // inverse the rotation to get an axis-aligned scale
            Vector2 dstSize = GetRotatedSize(dst, dstIndices, dstCenter, -rotation);

            var srcBounds = srcIndices == null ? new Bounds2D(src) : new Bounds2D(src, srcIndices);

            return(new UVTransform()
            {
                translation = dstCenter - srcBounds.center,
                rotation = rotation,
                scale = dstSize.DivideBy(srcBounds.size)
            });
        }
Exemple #2
0
 public MeshAndTextures(ProBuilderMesh mesh, PivotPoint pivot, HandleOrientation orientation) : base(mesh, pivot, orientation, k_CollectCoincidentVertices)
 {
     m_Textures = new List <Vector4>();
     mesh.GetUVs(k_TextureChannel, m_Textures);
     m_Origins      = new List <Vector4>(m_Textures);
     preApplyMatrix = Matrix4x4.Translate(-Bounds2D.Center(m_Origins, mesh.selectedIndexesInternal));
 }
        /// <summary>
        /// Reset the AutoUnwrapParameters of a set of faces to best match their current UV coordinates.
        /// </summary>
        /// <remarks>
        /// Auto UVs do not support distortion, so this conversion process cannot be loss-less. However as long as there
        /// is minimal skewing the results are usually very close.
        /// </remarks>
        internal static void SetAutoAndAlignUnwrapParamsToUVs(ProBuilderMesh mesh, IEnumerable <Face> facesToConvert)
        {
            var origins = mesh.textures.ToArray();
            var faces   = facesToConvert as Face[] ?? facesToConvert.ToArray();

            foreach (var face in faces)
            {
                face.uv           = AutoUnwrapSettings.defaultAutoUnwrapSettings;
                face.elementGroup = -1;
                face.textureGroup = -1;
                face.manualUV     = false;
            }

            mesh.RefreshUV(faces);
            var textures = mesh.texturesInternal;

            foreach (var face in faces)
            {
                var indices  = face.indexesInternal;
                var distinct = face.distinctIndexesInternal;

                // rotate to match target points by comparing the angle between old UV and new auto projection
                Vector2 dstAngle = origins[indices[1]] - origins[indices[0]];
                Vector2 srcAngle = textures[indices[1]] - textures[indices[0]];
                float   rotation = Vector2.Angle(dstAngle, srcAngle);
                if (Vector2.Dot(Vector2.Perpendicular(dstAngle), srcAngle) < 0)
                {
                    rotation = 360f - rotation;
                }

                // inverse the rotation to get an axis-aligned scale
                Vector2 dstCenter = Bounds2D.Center(origins, indices);

                for (int i = 0, c = distinct.Length; i < c; i++)
                {
                    origins[distinct[i]] = origins[distinct[i]].RotateAroundPoint(dstCenter, -rotation);
                }

                var dstBounds = new Bounds2D(origins, indices);
                var srcBounds = new Bounds2D(textures, indices);

                Vector2 scale       = dstBounds.size.DivideBy(srcBounds.size);
                Vector2 translation = dstCenter - srcBounds.center;

                var uv = face.uv;
                uv.offset   = -translation;
                uv.rotation = rotation;
                uv.scale    = scale;
                face.uv     = uv;
            }

            mesh.RefreshUV(faces);
        }
    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));
    }
Exemple #5
0
        /**
         * Attempts to translate, rotate, and scale @points to match @target as closely as possible.
         * Only points[0, target.Length] coordinates are used in the matching process - points[target.Length, points.Length]
         * are just along for the ride.
         */
        public static Transform2D MatchCoordinates(Vector2[] points, Vector2[] target)
        {
            int length = points.Length < target.Length ? points.Length : target.Length;

            Bounds2D t_bounds = new Bounds2D(target, length); // only match the bounds of known matching points

            // move points to the center of target
            Vector2 translation = t_bounds.center - Bounds2D.Center(points, length);

            Vector2[] transformed = new Vector2[points.Length];
            for (int i = 0; i < points.Length; i++)
            {
                transformed[i] = points[i] + translation;
            }

            // rotate to match target points
            Vector2 target_angle = target[1] - target[0], transform_angle = transformed[1] - transformed[0];

            float angle = Vector2.Angle(target_angle, transform_angle);
            float dot   = Vector2.Dot(Vector2.Perpendicular(target_angle), transform_angle);

            if (dot < 0)
            {
                angle = 360f - angle;
            }

            for (int i = 0; i < points.Length; i++)
            {
                transformed[i] = transformed[i].RotateAroundPoint(t_bounds.center, angle);
            }

            // and lastly scale
            Bounds2D p_bounds = new Bounds2D(transformed, length);
            Vector2  scale    = t_bounds.size.DivideBy(p_bounds.size);

            // for(int i = 0; i < points.Length; i++)
            //  transformed[i] = transformed[i].ScaleAroundPoint(t_bounds.center, scale);

            return(new Transform2D(translation, angle, scale));
        }