Пример #1
0
        public ClusterFit(ColourSet colours, SquishFlags flags, float?metric)
            : base(colours, flags)
        {
            // set the iteration count
            _mIterationCount = (MFlags & SquishFlags.KColourIterativeClusterFit) != 0 ? 8 : 1;

            // initialise the metric (old perceptual = 0.2126f, 0.7152f, 0.0722f)
            if (metric != null)
            {
                //m_metric = Vec4( metric[0], metric[1], metric[2], 1.0f );
            }
            else
            {
                _mMetric = new Vector4(1.0f);
            }

            // initialise the best error
            _mBesterror = new Vector4(float.MaxValue);

            // cache some values
            var count  = MColours.Count;
            var values = MColours.Points;

            // get the covariance matrix
            var covariance = Sym3X3.ComputeWeightedCovariance(count, values, MColours.Weights);

            // compute the principle component
            _mPrinciple = Sym3X3.ComputePrincipleComponent(covariance);
        }
Пример #2
0
        public static Sym3X3 ComputeWeightedCovariance(int n, Vector3[] points, float[] weights)
        {
            // compute the centroid
            var total    = 0.0f;
            var centroid = new Vector3(0.0f);

            for (var i = 0; i < n; ++i)
            {
                total    += weights[i];
                centroid += weights[i] * points[i];
            }
            if (total > float.Epsilon)
            {
                centroid /= total;
            }

            // accumulate the covariance matrix
            var covariance = new Sym3X3(0.0f);

            for (var i = 0; i < n; ++i)
            {
                var a = points[i] - centroid;
                var 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 ComputePrincipleComponent(Sym3X3 matrix)
        {
            var row0 = new Vector4(matrix[0], matrix[1], matrix[2], 0.0f);
            var row1 = new Vector4(matrix[1], matrix[3], matrix[4], 0.0f);
            var row2 = new Vector4(matrix[2], matrix[4], matrix[5], 0.0f);
            var v    = new Vector4(1.0f);

            for (var i = 0; i < 8; ++i)
            {
                // matrix multiply
                var w = row0 * v.SplatX();
                w = Helpers.MultiplyAdd(row1, v.SplatY(), w);
                w = Helpers.MultiplyAdd(row2, v.SplatZ(), w);

                // get max component from xyz in all channels
                var a = Vector4.Max(w.SplatX(), Vector4.Max(w.SplatY(), w.SplatZ()));

                // divide through and advance
                v = w * Helpers.Reciprocal(a);
            }

            return(v.ToVector3());
        }
Пример #4
0
        public RangeFit(ColourSet colours, SquishFlags flags, float?metric)
            : base(colours, flags)
        {
            // initialise the metric (old perceptual = 0.2126f, 0.7152f, 0.0722f)
            if (metric != null)
            {
                //m_metric = new Vector3( metric[0], metric[1], metric[2] );
            }
            else
            {
                _mMetric = new Vector3(1.0f);
            }

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

            // cache some values
            var count   = MColours.Count;
            var values  = MColours.Points;
            var weights = MColours.Weights;

            // get the covariance matrix
            var covariance = Sym3X3.ComputeWeightedCovariance(count, values, weights);

            // compute the principle component
            var principle = Sym3X3.ComputePrincipleComponent(covariance);

            // get the min and max range as the codebook endpoints
            var start = new Vector3(0.0f);
            var end   = new Vector3(0.0f);

            if (count > 0)
            {
                float max;

                // compute the range
                start = end = values[0];
                var min = max = Vector3.Dot(values[0], principle);
                for (var i = 1; i < count; ++i)
                {
                    var 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]
            var one  = new Vector3(1.0f);
            var zero = new Vector3(0.0f);

            start = Vector3.Min(one, Vector3.Max(zero, start));
            end   = Vector3.Min(one, Vector3.Max(zero, end));

            // clamp to the grid and save
            var grid    = new Vector3(31.0f, 63.0f, 31.0f);
            var gridrcp = new Vector3(1.0f / 31.0f, 1.0f / 63.0f, 1.0f / 31.0f);
            var half    = new Vector3(0.5f);

            _mStart = Helpers.Truncate(grid * start + half) * gridrcp;
            _mEnd   = Helpers.Truncate(grid * end + half) * gridrcp;
        }