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); }
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()); }
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); }
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; } }