Пример #1
0
        private float ComputeLeastSquares(Vec4 alphax_sum, Vec4 betax_sum, Vec4 alphabeta_sum, out Vec4 a, out Vec4 b)
        {
            Vec4 alpha2_sum = alphax_sum.SplatW();
            Vec4 beta2_sum  = betax_sum.SplatW();

            // compute the least-squares optimal points
            Vec4 factor = alphabeta_sum.NegativeMultiplySubtract(alphabeta_sum, alpha2_sum * beta2_sum).Reciprocal();

            a = betax_sum.NegativeMultiplySubtract(alphabeta_sum, alphax_sum * beta2_sum) * factor;
            b = alphax_sum.NegativeMultiplySubtract(alphabeta_sum, betax_sum * alpha2_sum) * factor;

            // clamp to the grid
            a = a.Clamp(Vec4.Zero, Vec4.One);
            b = b.Clamp(Vec4.Zero, Vec4.One);
            a = GRID.MultiplyAdd(a, HALF).Truncate() * GRIDRCP;
            b = GRID.MultiplyAdd(b, HALF).Truncate() * GRIDRCP;

            // compute the error (we skip the constant xxsum)
            Vec4 e1 = (a * a * alpha2_sum) + (b * b * beta2_sum);
            Vec4 e2 = a.NegativeMultiplySubtract(alphax_sum, a * b * alphabeta_sum);
            Vec4 e3 = b.NegativeMultiplySubtract(betax_sum, e2);
            Vec4 e4 = e3 * 2 + e1;

            // apply the metric to the error term
            Vec4 e5 = e4 * m_metric;

            return(e5.X + e5.Y + e5.Z);
        }
Пример #2
0
        public static Vec3 ComputePrincipleComponent(Sym3x3 matrix)
        {
            Vec4 row0 = new Vec4(matrix[0], matrix[1], matrix[2], 0.0f);
            Vec4 row1 = new Vec4(matrix[1], matrix[3], matrix[4], 0.0f);
            Vec4 row2 = new Vec4(matrix[2], matrix[4], matrix[5], 0.0f);
            Vec4 v    = new Vec4(1.0f);

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

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

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

            return(v.GetVec3());
        }
Пример #3
0
        private float SolveLeastSquares(out Vec4 start, out Vec4 end)
        {
            // accumulate all the quantities we need
            int count = m_colours.Count;

            float alpha2_sum    = 0;
            float beta2_sum     = 0;
            float alphabeta_sum = 0;

            var alphax_sum = Vec4.Zero;
            var betax_sum  = Vec4.Zero;

            for (int i = 0; i < count; ++i)
            {
                var alpha = m_alpha[i];
                var beta  = m_beta[i];
                var x     = m_weighted[i];

                alpha2_sum    += alpha * alpha;
                beta2_sum     += beta * beta;
                alphabeta_sum += alpha * beta;
                alphax_sum    += alpha * x;
                betax_sum     += beta * x;
            }

            // zero where non-determinate
            Vec4 a, b;

            if (beta2_sum == 0)
            {
                a = alphax_sum / alpha2_sum;
                b = Vec4.Zero;
            }
            else if (alpha2_sum == 0)
            {
                a = Vec4.Zero;
                b = betax_sum / beta2_sum;
            }
            else
            {
                var factor = 1.0f / (alpha2_sum * beta2_sum - alphabeta_sum * alphabeta_sum);

                a = (alphax_sum * beta2_sum - betax_sum * alphabeta_sum) * factor;
                b = (betax_sum * alpha2_sum - alphax_sum * alphabeta_sum) * factor;
            }

            // clamp the output to [0, 1]
            a = a.Clamp(Vec4.Zero, Vec4.One);
            b = b.Clamp(Vec4.Zero, Vec4.One);

            // clamp to the grid
            a = GRID.MultiplyAdd(a, HALF).Truncate() * GRIDRCP;
            b = GRID.MultiplyAdd(b, HALF).Truncate() * GRIDRCP;

            // compute the error
            var e1 = a * a * alpha2_sum + b * b * beta2_sum /*+ m_xxsum*/
                     + 2 * (a * b * alphabeta_sum - a * alphax_sum - b * betax_sum);

            // apply the metric to the error term
            float error = Vec4.Dot(e1, m_metricSqr);

            // save the start and end
            start = a;
            end   = b;
            return(error);
        }
Пример #4
0
        protected override void Compress4(BlockWindow block)
        {
            // declare variables
            var count = m_colours.Count;

            // prepare an ordering using the principle axis
            ConstructOrdering(m_principle, 0);

            // check all possible clusters and iterate on the total order
            Vec4  beststart = Vec4.Zero;
            Vec4  bestend = Vec4.Zero;
            float m_besterror = float.MaxValue;
            float besterror = m_besterror;
            var   bestindices = new Byte[16];
            int   bestiteration = 0;
            int   besti = 0, bestj = 0, bestk = 0;

            // loop over iterations (we avoid the case that all points in first or last cluster)
            for (int iterationIndex = 0; ;)
            {
                // first cluster [0,i) is at the start
                Vec4 part0 = Vec4.Zero;
                for (int i = 0; i < count; ++i)
                {
                    // second cluster [i,j) is one third along
                    Vec4 part1 = Vec4.Zero;
                    for (int j = i; ;)
                    {
                        // third cluster [j,k) is two thirds along
                        Vec4 part2 = (j == 0) ? m_points_weights[0] : Vec4.Zero;
                        int  kmin  = (j == 0) ? 1 : j;
                        for (int k = kmin; ;)
                        {
                            // last cluster [k,count) is at the end
                            Vec4 part3 = m_xsum_wsum - part2 - part1 - part0;

                            // compute least squares terms directly
                            Vec4 alphax_sum    = ONETHIRD_ONETHIRD2.MultiplyAdd(part2, TWOTHIRDS_TWOTHIRDS2.MultiplyAdd(part1, part0));
                            Vec4 betax_sum     = ONETHIRD_ONETHIRD2.MultiplyAdd(part1, TWOTHIRDS_TWOTHIRDS2.MultiplyAdd(part2, part3));
                            Vec4 alphabeta_sum = TWONINETHS * (part1 + part2).SplatW();

                            var error = ComputeLeastSquares(alphax_sum, betax_sum, alphabeta_sum, out Vec4 a, out Vec4 b);

                            // keep the solution if it wins
                            if (error < besterror)
                            {
                                beststart     = a;
                                bestend       = b;
                                besterror     = error;
                                besti         = i;
                                bestj         = j;
                                bestk         = k;
                                bestiteration = iterationIndex;
                            }

                            // advance
                            if (k == count)
                            {
                                break;
                            }
                            part2 += m_points_weights[k];
                            ++k;
                        }

                        // advance
                        if (j == count)
                        {
                            break;
                        }
                        part1 += m_points_weights[j];
                        ++j;
                    }

                    // advance
                    part0 += m_points_weights[i];
                }

                // stop if we didn't improve in this iteration
                if (bestiteration != iterationIndex)
                {
                    break;
                }

                // advance if possible
                ++iterationIndex;
                if (iterationIndex == m_iterationCount)
                {
                    break;
                }

                // stop if a new iteration is an ordering that has already been tried
                Vec3 axis = (bestend - beststart).GetVec3();
                if (!ConstructOrdering(axis, iterationIndex))
                {
                    break;
                }
            }

            // save the block if necessary
            if (besterror < m_besterror)
            {
                // remap the indices
                var orderIndex = 16 * bestiteration;

                var unordered = new Byte[16];
                for (int m = 0; m < besti; ++m)
                {
                    unordered[m_order[orderIndex + m]] = 0;
                }
                for (int m = besti; m < bestj; ++m)
                {
                    unordered[m_order[orderIndex + m]] = 2;
                }
                for (int m = bestj; m < bestk; ++m)
                {
                    unordered[m_order[orderIndex + m]] = 3;
                }
                for (int m = bestk; m < count; ++m)
                {
                    unordered[m_order[orderIndex + m]] = 1;
                }

                m_colours.RemapIndices(unordered, bestindices);

                // save the block
                block.WriteColourBlock4(beststart.GetVec3(), bestend.GetVec3(), bestindices);

                // save the error
                m_besterror = besterror;
            }
        }