//=========== Copyright © Valve Corporation, All rights reserved. ============// // // Purpose: Quadric math functionality used for squared distance error metrics. // //===========================================================================// #ifndef QUADRIC_H #define QUADRIC_H #if defined( COMPILER_MSVC ) #pragma once #endif #include "vector.h" #include "cholesky.h" // this class holds a quadric error function and implements integrating and evaluating these functions. // see "Surface Simplfication using Quadric Error metrics. Garland, Heckbert" // http://mgarland.org/files/papers/quadric2.pdf (updated version) // NOTE: This will be expanded using Hughes Hoppe's method for including interpolated vertex attributes in a future version class CQuadricError { public: CQuadricError() {} // used this to track down error void CheckDebug() { Assert( IsFinite(m_coefficients[0]) ); } // integrate these by summing coefficients FORCEINLINE CQuadricError& operator+=(const CQuadricError &inError) { for ( int i = 0; i < ARRAYSIZE(m_coefficients); i++ ) { m_coefficients[i] += inError.m_coefficients[i]; } return *this; } CQuadricError operator+(const CQuadricError& inError0 ) const { CQuadricError tmp; for ( int i = 0; i < ARRAYSIZE(m_coefficients); i++ ) { tmp.m_coefficients[i] = inError0.m_coefficients[i] + m_coefficients[i]; } return tmp; } // assignment CQuadricError& operator=(const CQuadricError &inError0) { for ( int i = 0; i < ARRAYSIZE(m_coefficients); i++ ) { m_coefficients[i] = inError0.m_coefficients[i]; } return *this; } CQuadricError& operator*=( float flScale ) { for ( int i = 0; i < ARRAYSIZE(m_coefficients); i++ ) { m_coefficients[i] *= flScale; } return *this; } // solves for the point with minimum error (inverts the matrix) Vector SolveForMinimumError() { matrix3x4_t tmp( m_coefficients[0], m_coefficients[1]*0.5f, m_coefficients[2]*0.5f, m_coefficients[3]*0.5f, m_coefficients[1]*0.5f, m_coefficients[4], m_coefficients[5]*0.5f, m_coefficients[6]*0.5f, m_coefficients[2]*0.5f, m_coefficients[5]*0.5f, m_coefficients[7], m_coefficients[8]*0.5f ); return CholeskySolve( tmp ); } // clear all coefficients void SetToZero() { for ( int i = 0; i < ARRAYSIZE(m_coefficients); i++ ) { m_coefficients[i] = 0.0f; } } // usually these are initialized by summing quadrics for the planes coincident at each vert (one per triangle) // these are helpers to do that void InitFromPlane( const Vector &vNormal, float flDist, float flScale ) { float flScale2 = flScale * 2.0f; m_coefficients[0] = vNormal.x * vNormal.x * flScale; // a^2 m_coefficients[1] = vNormal.x * vNormal.y * flScale2; // 2ab m_coefficients[2] = vNormal.x * vNormal.z * flScale2; // 2ac m_coefficients[3] = vNormal.x * flDist * flScale2; // 2ad m_coefficients[4] = vNormal.y * vNormal.y * flScale; // b^2 m_coefficients[5] = vNormal.y * vNormal.z * flScale2; // 2bc m_coefficients[6] = vNormal.y * flDist * flScale2; // 2bd m_coefficients[7] = vNormal.z * vNormal.z * flScale; // c^2 m_coefficients[8] = vNormal.z * flDist * flScale2; // cd m_coefficients[9] = flDist * flDist * flScale; // d^2 } void InitFromTriangle( const Vector &v0, const Vector &v1, const Vector &v2, float flMinArea ) { Vector vNormal = CrossProduct( v2 - v0, v1 - v0 ); float flArea = 0.5f * vNormal.NormalizeInPlace(); flArea = MAX(flMinArea, flArea); float flDist = -DotProduct(vNormal, v0); InitFromPlane( vNormal, flDist, flArea ); } // this evaluates the error at a point in space inline float ComputeError( const Vector &v0 ) { float x = v0.x; float y = v0.y; float z = v0.z; float flVertex[9]; flVertex[0] = x * x; flVertex[1] = x * y; flVertex[2] = x * z; flVertex[3] = x; flVertex[4] = y * y; flVertex[5] = y * z; flVertex[6] = y; flVertex[7] = z * z; flVertex[8] = z; float flTotal = m_coefficients[9]; for ( int i = 0; i < 9; i++ ) { flTotal += flVertex[i] * m_coefficients[i]; } return flTotal; } private: float m_coefficients[10]; }; #endif // QUADRIC_H