예제 #1
0
        public ClusterFit(ColourSet colours, SquishFlags flags)
            : base(colours, flags)
        {
            // set the iteration count
            m_iterationCount = ((m_flags & SquishFlags.kColourIterativeClusterFit) != 0) ? kMaxIterations : 1;

            // initialise the best error
            m_besterror = Vector4.one * float.MaxValue;

            // initialise the metric
            bool perceptual = ((m_flags & SquishFlags.kColourMetricPerceptual) != 0);

            if (perceptual)
            {
                m_metric = new Vector4(0.2126f, 0.7152f, 0.0722f, 0.0f);
            }
            else
            {
                m_metric = Vector4.one;
            }

            // cache some values
            int count = m_colours.GetCount();

            Vector3[] values = m_colours.GetPoints();

            // get the covariance matrix
            Sym3x3 covariance = math.ComputeWeightedCovariance(count, values, m_colours.GetWeights());

            // compute the principle component
            m_principle = math.ComputePrincipleComponent(covariance);
        }
예제 #2
0
        public static Sym3x3 ComputeWeightedCovariance(int n, Vector3[] points, float[] weights)
        {
            // compute the centroid
            float   total    = 0.0f;
            Vector3 centroid = Vector3.zero;

            for (int i = 0; i < n; ++i)
            {
                total    += weights[i];
                centroid += weights[i] * points[i];
            }
            centroid /= total;

            // accumulate the covariance matrix
            Sym3x3 covariance = new Sym3x3();

            for (int i = 0; i < n; ++i)
            {
                Vector3 a = points[i] - centroid;
                Vector3 b = weights[i] * a;

                covariance[0] += a.x * b.x;
                covariance[1] += a.x * b.y;
                covariance[2] += a.x * b.z;
                covariance[3] += a.y * b.y;
                covariance[4] += a.y * b.z;
                covariance[5] += a.z * b.z;
            }

            // return it
            return(covariance);
        }
예제 #3
0
        public static Vector3 GetMultiplicity1Evector(Sym3x3 matrix, float evalue)
        {
            // compute M
            Sym3x3 m = new Sym3x3();

            m[0] = matrix[0] - evalue;
            m[1] = matrix[1];
            m[2] = matrix[2];
            m[3] = matrix[3] - evalue;
            m[4] = matrix[4];
            m[5] = matrix[5] - evalue;

            // compute U
            Sym3x3 u = new Sym3x3();

            u[0] = m[3] * m[5] - m[4] * m[4];
            u[1] = m[2] * m[4] - m[1] * m[5];
            u[2] = m[1] * m[4] - m[2] * m[3];
            u[3] = m[0] * m[5] - m[2] * m[2];
            u[4] = m[1] * m[2] - m[4] * m[0];
            u[5] = m[0] * m[3] - m[1] * m[1];

            // find the largest component
            float mc = Mathf.Abs(u[0]);
            int   mi = 0;

            for (int i = 1; i < 6; ++i)
            {
                float c = Mathf.Abs(u[i]);
                if (c > mc)
                {
                    mc = c;
                    mi = i;
                }
            }

            // pick the column with this component
            switch (mi)
            {
            case 0:
                return(new Vector3(u[0], u[1], u[2]));

            case 1:
            case 3:
                return(new Vector3(u[1], u[3], u[4]));

            default:
                return(new Vector3(u[2], u[4], u[5]));
            }
        }
예제 #4
0
        public static Vector3 GetMultiplicity2Evector(Sym3x3 matrix, float evalue)
        {
            // compute M
            Sym3x3 m = new Sym3x3();

            m[0] = matrix[0] - evalue;
            m[1] = matrix[1];
            m[2] = matrix[2];
            m[3] = matrix[3] - evalue;
            m[4] = matrix[4];
            m[5] = matrix[5] - evalue;

            // find the largest component
            float mc = Mathf.Abs(m[0]);
            int   mi = 0;

            for (int i = 1; i < 6; ++i)
            {
                float c = Mathf.Abs(m[i]);
                if (c > mc)
                {
                    mc = c;
                    mi = i;
                }
            }

            // pick the first eigenvector based on this index
            switch (mi)
            {
            case 0:
            case 1:
                return(new Vector3(-m[1], m[0], 0.0f));

            case 2:
                return(new Vector3(m[2], 0.0f, -m[0]));

            case 3:
            case 4:
                return(new Vector3(0.0f, -m[4], m[3]));

            default:
                return(new Vector3(0.0f, -m[5], m[4]));
            }
        }
예제 #5
0
        public RangeFit(ColourSet colours, SquishFlags flags)
            : base(colours, flags)
        {
            // initialise the metric
            bool perceptual = ((m_flags & SquishFlags.kColourMetricPerceptual) != 0);

            if (perceptual)
            {
                m_metric = new Vector3(0.2126f, 0.7152f, 0.0722f);
            }
            else
            {
                m_metric = Vector3.one;
            }

            // initialise the best error
            m_besterror = float.MaxValue;

            // cache some values
            int count = m_colours.GetCount();

            Vector3[] values  = m_colours.GetPoints();
            float[]   weights = m_colours.GetWeights();

            // get the covariance matrix
            Sym3x3 covariance = math.ComputeWeightedCovariance(count, values, weights);

            // compute the principle component
            Vector3 principle = math.ComputePrincipleComponent(covariance);

            // get the min and max range as the codebook endpoints
            Vector3 start = Vector3.zero;
            Vector3 end   = Vector3.zero;

            if (count > 0)
            {
                float min, max;

                // compute the range
                start = end = values[0];
                min   = max = Vector3.Dot(values[0], principle);
                for (int i = 1; i < count; ++i)
                {
                    float val = Vector3.Dot(values[i], principle);
                    if (val < min)
                    {
                        start = values[i];
                        min   = val;
                    }
                    else if (val > max)
                    {
                        end = values[i];
                        max = val;
                    }
                }
            }

            // clamp the output to [0, 1]
            start = Vector3.Min(Vector3.one, Vector3.Max(Vector3.zero, start));
            end   = Vector3.Min(Vector3.one, Vector3.Max(Vector3.zero, end));

            // clamp to the grid and save

            Vector3 half = Vector3.one * (0.5f);

            m_start = Vector3.Scale(math.Truncate(Vector3.Scale(grid, start) + half), gridrcp);
            m_end   = Vector3.Scale(math.Truncate(Vector3.Scale(grid, end) + half), gridrcp);
        }
예제 #6
0
        public static Vector3 ComputePrincipleComponent(Sym3x3 matrix)
        {
            // compute the cubic coefficients
            float c0 = matrix[0] * matrix[3] * matrix[5]
                + 2.0f * matrix[1] * matrix[2] * matrix[4]
                - matrix[0] * matrix[4] * matrix[4]
                - matrix[3] * matrix[2] * matrix[2]
                - matrix[5] * matrix[1] * matrix[1];
            float c1 = matrix[0] * matrix[3] + matrix[0] * matrix[5] + matrix[3] * matrix[5]
                - matrix[1] * matrix[1] - matrix[2] * matrix[2] - matrix[4] * matrix[4];
            float c2 = matrix[0] + matrix[3] + matrix[5];

            // compute the quadratic coefficients
            float a = c1 - (1.0f / 3.0f) * c2 * c2;
            float b = (-2.0f / 27.0f) * c2 * c2 * c2 + (1.0f / 3.0f) * c1 * c2 - c0;

            // compute the root count check
            float Q = 0.25f * b * b + (1.0f / 27.0f) * a * a * a;

            // test the multiplicity
            if (float.Epsilon < Q)
            {
                // only one root, which implies we have a multiple of the identity
                return Vector3.one;
            }
            else if (Q < -float.Epsilon)
            {
                // three distinct roots
                float theta = Mathf.Atan2(Mathf.Sqrt(-Q), -0.5f * b);
                float rho = Mathf.Sqrt(0.25f * b * b - Q);

                float rt = Mathf.Pow(rho, 1.0f / 3.0f);
                float ct = Mathf.Cos(theta / 3.0f);
                float st = Mathf.Sin(theta / 3.0f);

                float l1 = (1.0f / 3.0f) * c2 + 2.0f * rt * ct;
                float l2 = (1.0f / 3.0f) * c2 - rt * (ct + (float)Mathf.Sqrt(3.0f) * st);
                float l3 = (1.0f / 3.0f) * c2 - rt * (ct - (float)Mathf.Sqrt(3.0f) * st);

                // pick the larger
                if (Mathf.Abs(l2) > Mathf.Abs(l1))
                    l1 = l2;
                if (Mathf.Abs(l3) > Mathf.Abs(l1))
                    l1 = l3;

                // get the eigenvector
                return GetMultiplicity1Evector(matrix, l1);
            }
            else // if( -FLT_EPSILON <= Q && Q <= FLT_EPSILON )
            {
                // two roots
                float rt;
                if (b < 0.0f)
                    rt = -Mathf.Pow(-0.5f * b, 1.0f / 3.0f);
                else
                    rt = Mathf.Pow(0.5f * b, 1.0f / 3.0f);

                float l1 = (1.0f / 3.0f) * c2 + rt;		// repeated
                float l2 = (1.0f / 3.0f) * c2 - 2.0f * rt;

                // get the eigenvector
                if (Mathf.Abs(l1) > Mathf.Abs(l2))
                    return GetMultiplicity2Evector(matrix, l1);
                else
                    return GetMultiplicity1Evector(matrix, l2);
            }
        }
예제 #7
0
        public static Vector3 GetMultiplicity2Evector(Sym3x3 matrix, float evalue)
        {
            // compute M
            Sym3x3 m = new Sym3x3();
            m[0] = matrix[0] - evalue;
            m[1] = matrix[1];
            m[2] = matrix[2];
            m[3] = matrix[3] - evalue;
            m[4] = matrix[4];
            m[5] = matrix[5] - evalue;

            // find the largest component
            float mc = Mathf.Abs(m[0]);
            int mi = 0;
            for (int i = 1; i < 6; ++i)
            {
                float c = Mathf.Abs(m[i]);
                if (c > mc)
                {
                    mc = c;
                    mi = i;
                }
            }

            // pick the first eigenvector based on this index
            switch (mi)
            {
                case 0:
                case 1:
                    return new Vector3(-m[1], m[0], 0.0f);

                case 2:
                    return new Vector3(m[2], 0.0f, -m[0]);

                case 3:
                case 4:
                    return new Vector3(0.0f, -m[4], m[3]);

                default:
                    return new Vector3(0.0f, -m[5], m[4]);
            }
        }
예제 #8
0
        public static Vector3 GetMultiplicity1Evector(Sym3x3 matrix, float evalue)
        {
            // compute M
            Sym3x3 m = new Sym3x3();
            m[0] = matrix[0] - evalue;
            m[1] = matrix[1];
            m[2] = matrix[2];
            m[3] = matrix[3] - evalue;
            m[4] = matrix[4];
            m[5] = matrix[5] - evalue;

            // compute U
            Sym3x3 u = new Sym3x3();
            u[0] = m[3] * m[5] - m[4] * m[4];
            u[1] = m[2] * m[4] - m[1] * m[5];
            u[2] = m[1] * m[4] - m[2] * m[3];
            u[3] = m[0] * m[5] - m[2] * m[2];
            u[4] = m[1] * m[2] - m[4] * m[0];
            u[5] = m[0] * m[3] - m[1] * m[1];

            // find the largest component
            float mc = Mathf.Abs(u[0]);
            int mi = 0;
            for (int i = 1; i < 6; ++i)
            {
                float c = Mathf.Abs(u[i]);
                if (c > mc)
                {
                    mc = c;
                    mi = i;
                }
            }

            // pick the column with this component
            switch (mi)
            {
                case 0:
                    return new Vector3(u[0], u[1], u[2]);

                case 1:
                case 3:
                    return new Vector3(u[1], u[3], u[4]);

                default:
                    return new Vector3(u[2], u[4], u[5]);
            }
        }
예제 #9
0
        public static Sym3x3 ComputeWeightedCovariance(int n, Vector3[] points, float[] weights)
        {
            // compute the centroid
            float total = 0.0f;
            Vector3 centroid = Vector3.zero;
            for (int i = 0; i < n; ++i)
            {
                total += weights[i];
                centroid += weights[i] * points[i];
            }
            centroid /= total;

            // accumulate the covariance matrix
            Sym3x3 covariance = new Sym3x3();
            for (int i = 0; i < n; ++i)
            {
                Vector3 a = points[i] - centroid;
                Vector3 b = weights[i] * a;

                covariance[0] += a.x * b.x;
                covariance[1] += a.x * b.y;
                covariance[2] += a.x * b.z;
                covariance[3] += a.y * b.y;
                covariance[4] += a.y * b.z;
                covariance[5] += a.z * b.z;
            }

            // return it
            return covariance;
        }
예제 #10
0
        public static Vector3 ComputePrincipleComponent(Sym3x3 matrix)
        {
            // compute the cubic coefficients
            float c0 = matrix[0] * matrix[3] * matrix[5]
                       + 2.0f * matrix[1] * matrix[2] * matrix[4]
                       - matrix[0] * matrix[4] * matrix[4]
                       - matrix[3] * matrix[2] * matrix[2]
                       - matrix[5] * matrix[1] * matrix[1];
            float c1 = matrix[0] * matrix[3] + matrix[0] * matrix[5] + matrix[3] * matrix[5]
                       - matrix[1] * matrix[1] - matrix[2] * matrix[2] - matrix[4] * matrix[4];
            float c2 = matrix[0] + matrix[3] + matrix[5];

            // compute the quadratic coefficients
            float a = c1 - (1.0f / 3.0f) * c2 * c2;
            float b = (-2.0f / 27.0f) * c2 * c2 * c2 + (1.0f / 3.0f) * c1 * c2 - c0;

            // compute the root count check
            float Q = 0.25f * b * b + (1.0f / 27.0f) * a * a * a;

            // test the multiplicity
            if (float.Epsilon < Q)
            {
                // only one root, which implies we have a multiple of the identity
                return(Vector3.one);
            }
            else if (Q < -float.Epsilon)
            {
                // three distinct roots
                float theta = Mathf.Atan2(Mathf.Sqrt(-Q), -0.5f * b);
                float rho   = Mathf.Sqrt(0.25f * b * b - Q);

                float rt = Mathf.Pow(rho, 1.0f / 3.0f);
                float ct = Mathf.Cos(theta / 3.0f);
                float st = Mathf.Sin(theta / 3.0f);

                float l1 = (1.0f / 3.0f) * c2 + 2.0f * rt * ct;
                float l2 = (1.0f / 3.0f) * c2 - rt * (ct + (float)Mathf.Sqrt(3.0f) * st);
                float l3 = (1.0f / 3.0f) * c2 - rt * (ct - (float)Mathf.Sqrt(3.0f) * st);

                // pick the larger
                if (Mathf.Abs(l2) > Mathf.Abs(l1))
                {
                    l1 = l2;
                }
                if (Mathf.Abs(l3) > Mathf.Abs(l1))
                {
                    l1 = l3;
                }

                // get the eigenvector
                return(GetMultiplicity1Evector(matrix, l1));
            }
            else // if( -FLT_EPSILON <= Q && Q <= FLT_EPSILON )
            {
                // two roots
                float rt;
                if (b < 0.0f)
                {
                    rt = -Mathf.Pow(-0.5f * b, 1.0f / 3.0f);
                }
                else
                {
                    rt = Mathf.Pow(0.5f * b, 1.0f / 3.0f);
                }

                float l1 = (1.0f / 3.0f) * c2 + rt;             // repeated
                float l2 = (1.0f / 3.0f) * c2 - 2.0f * rt;

                // get the eigenvector
                if (Mathf.Abs(l1) > Mathf.Abs(l2))
                {
                    return(GetMultiplicity2Evector(matrix, l1));
                }
                else
                {
                    return(GetMultiplicity1Evector(matrix, l2));
                }
            }
        }