fix SmoothMetaTriangles()
mainly fixes celshading, as it's about coincident vertices with varying normal smoothing params
This commit is contained in:
parent
02f1fccb14
commit
a5d0ae72d1
|
|
@ -1167,99 +1167,116 @@ void SmoothMetaTriangles(){
|
||||||
const float defaultShadeAngle = degrees_to_radians( npDegrees );
|
const float defaultShadeAngle = degrees_to_radians( npDegrees );
|
||||||
|
|
||||||
for( auto& [ d, list ] : metaVerts ){
|
for( auto& [ d, list ] : metaVerts ){
|
||||||
if( list.size() > 1 ){
|
if( list.size() > 1 || ( list.size() == 1 && list.front().m_triangles.size() > 1 ) ){
|
||||||
float maxShadeAngle = 0.f;
|
float maxShadeAngle = 0.f;
|
||||||
|
|
||||||
std::vector<metaVertex_t*> verts;
|
struct VT{ metaVertex_t *vertex; metaTriangle_t *triangle; float angle{}; bool skipped{}; bool smoothed{}; Vector3 newnormal{ 0 }; };
|
||||||
verts.reserve( list.size() );
|
std::vector<VT> verts;
|
||||||
for( auto& v : list )
|
for( auto& v : list )
|
||||||
verts.push_back( &v );
|
for( auto* t : v.m_triangles )
|
||||||
/* allocate shade angle table */
|
verts.push_back( VT{ &v, t } );
|
||||||
std::vector<float> shadeAngles( list.size(), 179 );
|
|
||||||
/* allocate smoothed table */
|
|
||||||
std::vector<std::uint8_t> smoothed( list.size(), false );
|
|
||||||
/* get per-vertex smoothing angle */
|
/* get per-vertex smoothing angle */
|
||||||
for( size_t i = 0; i < verts.size(); ++i )
|
for( auto& v : verts )
|
||||||
{
|
{
|
||||||
for( metaTriangle_t *tri : verts[i]->m_triangles )
|
float shadeAngle = defaultShadeAngle;
|
||||||
{
|
/* get shade angle from shader */
|
||||||
float shadeAngle = defaultShadeAngle;
|
if ( v.triangle->si->shadeAngleDegrees > 0.0f ) {
|
||||||
/* get shade angle from shader */
|
shadeAngle = degrees_to_radians( v.triangle->si->shadeAngleDegrees );
|
||||||
if ( tri->si->shadeAngleDegrees > 0.0f ) {
|
}
|
||||||
shadeAngle = degrees_to_radians( tri->si->shadeAngleDegrees );
|
/* get shade angle from entity */
|
||||||
}
|
else if ( v.triangle->shadeAngleDegrees > 0.0f ) {
|
||||||
/* get shade angle from entity */
|
shadeAngle = degrees_to_radians( v.triangle->shadeAngleDegrees );
|
||||||
else if ( tri->shadeAngleDegrees > 0.0f ) {
|
|
||||||
shadeAngle = degrees_to_radians( tri->shadeAngleDegrees );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* flag verts */
|
|
||||||
value_minimize( shadeAngles[i], shadeAngle );
|
|
||||||
smoothed[i] = shadeAngles[i] <= 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
value_maximize( maxShadeAngle, shadeAngles[i] );
|
/* flag verts */
|
||||||
|
v.angle = shadeAngle;
|
||||||
|
v.skipped = shadeAngle <= 0;
|
||||||
|
|
||||||
|
value_maximize( maxShadeAngle, shadeAngle );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( maxShadeAngle > 0 ){
|
if( maxShadeAngle > 0 ){
|
||||||
/* go through the list of vertexes */
|
/* go through the list of vertexes */
|
||||||
for ( size_t i = 0; i < verts.size(); ++i )
|
for ( auto v = verts.begin(); v != verts.end(); ++v )
|
||||||
{
|
{
|
||||||
/* already smoothed? */
|
/* already smoothed? */
|
||||||
if ( smoothed[ i ] ) {
|
if ( v->skipped || v->smoothed ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clear */
|
/* clear */
|
||||||
Vector3 average( 0 );
|
Vector3 average( 0 );
|
||||||
std::vector<metaVertex_t*> smoothedVerts;
|
std::vector<VT*> smoothedVerts;
|
||||||
std::vector<Vector3> votes;
|
std::vector<Vector3> votes;
|
||||||
|
|
||||||
/* test the rest, including self */
|
/* test the rest, including self */
|
||||||
for ( size_t j = i; j < verts.size(); ++j )
|
for ( auto v2 = v; v2 != verts.end(); ++v2 )
|
||||||
{
|
{
|
||||||
/* already smoothed? */
|
/* already smoothed? */
|
||||||
if ( smoothed[ j ] ) {
|
if ( v2->skipped || v2->smoothed ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* use smallest shade angle */
|
/* use smallest shade angle */
|
||||||
const float shadeAngle = std::min( shadeAngles[ i ], shadeAngles[ j ] );
|
const float shadeAngle = std::min( v->angle, v2->angle );
|
||||||
|
|
||||||
/* check shade angle */
|
/* check shade angle */
|
||||||
const double dot = std::clamp( vector3_dot( verts[ i ]->normal, verts[ j ]->normal ), -1.0, 1.0 );
|
const double dot = std::clamp( vector3_dot( v->vertex->normal, v2->vertex->normal ), -1.0, 1.0 );
|
||||||
if ( acos( dot ) + THETA_EPSILON >= shadeAngle ) {
|
if ( acos( dot ) + THETA_EPSILON >= shadeAngle ) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add to the list */
|
/* add to the list */
|
||||||
smoothedVerts.push_back( verts[j] );
|
smoothedVerts.push_back( v2.operator->() );
|
||||||
|
|
||||||
/* flag vertex */
|
|
||||||
smoothed[ j ] = true;
|
|
||||||
|
|
||||||
/* see if this normal has already been voted */
|
/* see if this normal has already been voted */
|
||||||
if( std::none_of( votes.begin(), votes.end(),
|
if( std::none_of( votes.begin(), votes.end(),
|
||||||
[normal = verts[j]->normal]( const Vector3& vote ){
|
[normal = v2->vertex->normal]( const Vector3& vote ){
|
||||||
return vector3_equal_epsilon( normal, vote, EQUAL_NORMAL_EPSILON );
|
return vector3_equal_epsilon( normal, vote, EQUAL_NORMAL_EPSILON );
|
||||||
} ) )
|
} ) )
|
||||||
{ /* add a new vote */
|
{ /* add a new vote */
|
||||||
average += verts[ j ]->normal;
|
average += v2->vertex->normal;
|
||||||
votes.push_back( verts[ j ]->normal );
|
votes.push_back( v2->vertex->normal );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* flag vertices */
|
||||||
/* don't average for less than 2 verts */
|
/* don't average for less than 2 verts */
|
||||||
if ( smoothedVerts.size() > 1 ) {
|
if ( smoothedVerts.size() > 1 && VectorNormalize( average ) != 0 ) {
|
||||||
/* average normal */
|
for ( auto *v : smoothedVerts ){
|
||||||
if ( VectorNormalize( average ) != 0 ) {
|
v->smoothed = true;
|
||||||
/* smooth */
|
v->newnormal = average;
|
||||||
for ( auto v : smoothedVerts )
|
}
|
||||||
v->normal = average;
|
numSmoothed++;
|
||||||
numSmoothed++;
|
}
|
||||||
|
else{
|
||||||
|
for ( auto *v : smoothedVerts ){
|
||||||
|
v->skipped = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* reconstruct meta data from smoothed verts */
|
||||||
|
if( std::any_of( verts.cbegin(), verts.cend(), []( const VT& vt ){ return vt.smoothed; } ) ){
|
||||||
|
decltype( list ) newlist;
|
||||||
|
for( auto& v : verts ){
|
||||||
|
bspDrawVert_t newv = *v.vertex;
|
||||||
|
if( v.smoothed )
|
||||||
|
newv.normal = v.newnormal;
|
||||||
|
|
||||||
|
auto it = std::find_if( newlist.begin(), newlist.end(), [&newv]( const metaVertex_t& v ){
|
||||||
|
return bspDrawVert_equal( newv, v );
|
||||||
|
} );
|
||||||
|
if( it == newlist.end() ){ /* insert vertex */
|
||||||
|
newlist.push_back( newv );
|
||||||
|
it = --newlist.end();
|
||||||
|
it->m_metaVertexGroup = &list;
|
||||||
|
}
|
||||||
|
/* link vertex <> triangle */
|
||||||
|
it->m_triangles.push_back( v.triangle );
|
||||||
|
*std::find( v.triangle->m_vertices.begin(), v.triangle->m_vertices.end(), v.vertex ) = it.operator->();
|
||||||
|
}
|
||||||
|
list.swap( newlist );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user