Fixed VRML normals calculations
This commit is contained in:
parent
06e766b8b2
commit
bf3d2b252e
|
@ -381,11 +381,17 @@ bool S3D_FILENAME_RESOLVER::addPath( const S3D_ALIAS& aPath )
|
|||
|
||||
if( !path.DirExists() )
|
||||
{
|
||||
wxString msg = _T( "The given path does not exist" );
|
||||
msg.append( wxT( "\n" ) );
|
||||
msg.append( tpath.m_pathvar );
|
||||
// suppress the message if the missing pathvar is the
|
||||
// legacy KISYS3DMOD variable
|
||||
if( aPath.m_pathvar.compare( wxT( "${KISYS3DMOD}" ) ) )
|
||||
{
|
||||
wxString msg = _T( "The given path does not exist" );
|
||||
msg.append( wxT( "\n" ) );
|
||||
msg.append( tpath.m_pathvar );
|
||||
wxMessageBox( msg, _T( "3D model search path" ) );
|
||||
}
|
||||
|
||||
tpath.m_pathexp.clear();
|
||||
wxMessageBox( msg, _T( "3D model search path" ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -133,7 +133,7 @@ PANEL_PREV_3D::PANEL_PREV_3D( wxWindow* aParent, S3D_CACHE* aCacheManager ) :
|
|||
aParent->FindWindowByLabel( wxT( "3D_MODEL_SELECTOR" ), aParent );
|
||||
|
||||
wxFloatingPointValidator< float > valScale( 6 );
|
||||
valScale.SetRange( 0.001, 100 );
|
||||
valScale.SetRange( 0.0001, 10000 );
|
||||
wxFloatingPointValidator< float > valRotate( 2 );
|
||||
valRotate.SetRange( -180.0, 180.0 );
|
||||
wxFloatingPointValidator< float > valOffset( 6 );
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
|
||||
#include "wrlfacet.h"
|
||||
|
||||
#define LOWER_LIMIT (1e-12)
|
||||
|
||||
|
||||
static bool VDegenerate( glm::vec3* pts )
|
||||
{
|
||||
|
@ -42,21 +44,21 @@ static bool VDegenerate( glm::vec3* pts )
|
|||
dy = pts[1].y - pts[0].y;
|
||||
dz = pts[1].z - pts[0].z;
|
||||
|
||||
if( ( dx*dx + dy*dy + dz*dz ) < 1e-9 )
|
||||
if( ( dx*dx + dy*dy + dz*dz ) < LOWER_LIMIT )
|
||||
return true;
|
||||
|
||||
dx = pts[2].x - pts[0].x;
|
||||
dy = pts[2].y - pts[0].y;
|
||||
dz = pts[2].z - pts[0].z;
|
||||
|
||||
if( ( dx*dx + dy*dy + dz*dz ) < 1e-9 )
|
||||
if( ( dx*dx + dy*dy + dz*dz ) < LOWER_LIMIT )
|
||||
return true;
|
||||
|
||||
dx = pts[2].x - pts[1].x;
|
||||
dy = pts[2].y - pts[1].y;
|
||||
dz = pts[2].z - pts[1].z;
|
||||
|
||||
if( ( dx*dx + dy*dy + dz*dz ) < 1e-9 )
|
||||
if( ( dx*dx + dy*dy + dz*dz ) < LOWER_LIMIT )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
@ -84,8 +86,16 @@ static WRLVEC3F VCalcTriNorm( const WRLVEC3F& p1, const WRLVEC3F& p2, const WRLV
|
|||
return result;
|
||||
|
||||
// normal
|
||||
tri = cross( pts[2] - pts[0], pts[1] - pts[0] );
|
||||
normalize( tri );
|
||||
tri = glm::cross( pts[2] - pts[0], pts[1] - pts[0] );
|
||||
|
||||
float dn = sqrtf( tri.x * tri.x + tri.y * tri.y + tri.z * tri.z );
|
||||
|
||||
if( dn > LOWER_LIMIT )
|
||||
{
|
||||
tri.x /= dn;
|
||||
tri.y /= dn;
|
||||
tri.z /= dn;
|
||||
}
|
||||
|
||||
result.x = tri.x;
|
||||
result.y = tri.y;
|
||||
|
@ -95,34 +105,6 @@ static WRLVEC3F VCalcTriNorm( const WRLVEC3F& p1, const WRLVEC3F& p2, const WRLV
|
|||
}
|
||||
|
||||
|
||||
static float VCalcAreaSq( const WRLVEC3F& p1, const WRLVEC3F& p2, const WRLVEC3F& p3 )
|
||||
{
|
||||
// calculate the area squared for the triangle using Heron's formula
|
||||
|
||||
// note: p1 = reference vertex
|
||||
float dx, dy, dz;
|
||||
|
||||
dx = p2.x - p1.x;
|
||||
dy = p2.y - p1.y;
|
||||
dz = p2.z - p1.z;
|
||||
float a = sqrtf( dx*dx + dy*dy + dz*dz );
|
||||
|
||||
dx = p3.x - p2.x;
|
||||
dy = p3.y - p2.y;
|
||||
dz = p3.z - p2.z;
|
||||
float b = sqrtf( dx*dx + dy*dy + dz*dz );
|
||||
|
||||
dx = p3.x - p1.x;
|
||||
dy = p3.y - p1.y;
|
||||
dz = p3.z - p1.z;
|
||||
float c = sqrtf( dx*dx + dy*dy + dz*dz );
|
||||
|
||||
float s = (a + b + c) * 0.5;
|
||||
|
||||
return s*(s - a)*(s - b)*(s - c);
|
||||
}
|
||||
|
||||
|
||||
static float VCalcCosAngle( const WRLVEC3F& p1, const WRLVEC3F& p2, const WRLVEC3F& p3 )
|
||||
{
|
||||
// note: p1 = reference vertex
|
||||
|
@ -149,8 +131,16 @@ static float VCalcCosAngle( const WRLVEC3F& p1, const WRLVEC3F& p2, const WRLVEC
|
|||
float dn = 2.0 * l12 * l13;
|
||||
|
||||
// place a limit to prevent calculations from blowing up
|
||||
if( dn < 1e-15 )
|
||||
if( dn < LOWER_LIMIT )
|
||||
{
|
||||
if( (p12 + p13 - p23) < FLT_EPSILON )
|
||||
return -1.0;
|
||||
|
||||
if( (p12 + p13 - p23) > FLT_EPSILON )
|
||||
return 1.0;
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
float cosAngle = (p12 + p13 - p23) / dn;
|
||||
|
||||
|
@ -233,18 +223,18 @@ void FACET::AddColor( const SGCOLOR& aColor )
|
|||
}
|
||||
|
||||
|
||||
void FACET::CalcFaceNormal()
|
||||
float FACET::CalcFaceNormal()
|
||||
{
|
||||
// note: this calculation assumes that the face is a convex polygon;
|
||||
// concave polygons may be supported in the future via functions which
|
||||
// split the polygon into triangles
|
||||
|
||||
if( vertices.size() < 3 )
|
||||
return;
|
||||
return 0.0;
|
||||
|
||||
// check if the values were already calculated
|
||||
if( vertices.size() == vnweight.size() )
|
||||
return;
|
||||
return 0.0;
|
||||
|
||||
WRLVEC3F lCPts[3];
|
||||
|
||||
|
@ -261,12 +251,35 @@ void FACET::CalcFaceNormal()
|
|||
|
||||
vnweight.clear();
|
||||
WRLVEC3F wnorm = face_normal;
|
||||
float a2 = VCalcAreaSq( lCPts[1], lCPts[0], lCPts[2] );
|
||||
wnorm.x *= a2;
|
||||
wnorm.y *= a2;
|
||||
wnorm.z *= a2;
|
||||
|
||||
// calculate area:
|
||||
size_t nv = vertices.size();
|
||||
float a1 = 0.0;
|
||||
glm::vec3 sum( 0.0, 0.0, 0.0 );
|
||||
size_t j = 0;
|
||||
|
||||
for( size_t i = 1; i < nv; ++i, ++j )
|
||||
sum += glm::cross( *((glm::vec3*)&vertices[j]), *((glm::vec3*)&vertices[i]) );
|
||||
|
||||
a1 = fabs( glm::dot( *((glm::vec3*)&face_normal), sum ) );
|
||||
float a2 = acosf( VCalcCosAngle( lCPts[1], lCPts[0], lCPts[2] ) );
|
||||
|
||||
wnorm.x *= a1 * a2;
|
||||
wnorm.y *= a1 * a2;
|
||||
wnorm.z *= a1 * a2;
|
||||
vnweight.push_back( wnorm );
|
||||
|
||||
float maxV = fabs( wnorm.x );
|
||||
float tV = fabs( wnorm.y );
|
||||
|
||||
if( tV > maxV )
|
||||
maxV = tV;
|
||||
|
||||
tV = fabs( wnorm.z );
|
||||
|
||||
if( tV > maxV )
|
||||
maxV = tV;
|
||||
|
||||
while( sV != eV )
|
||||
{
|
||||
lCPts[0] = lCPts[1];
|
||||
|
@ -275,11 +288,26 @@ void FACET::CalcFaceNormal()
|
|||
++sV;
|
||||
|
||||
WRLVEC3F wnorm = face_normal;
|
||||
a2 = VCalcAreaSq( lCPts[1], lCPts[0], lCPts[2] );
|
||||
wnorm.x *= a2;
|
||||
wnorm.y *= a2;
|
||||
wnorm.z *= a2;
|
||||
a2 = acosf( VCalcCosAngle( lCPts[1], lCPts[0], lCPts[2] ) );
|
||||
wnorm.x *= a1 * a2;
|
||||
wnorm.y *= a1 * a2;
|
||||
wnorm.z *= a1 * a2;
|
||||
vnweight.push_back( wnorm );
|
||||
|
||||
tV = fabs( wnorm.x );
|
||||
|
||||
if( tV > maxV )
|
||||
maxV = tV;
|
||||
|
||||
tV = fabs( wnorm.y );
|
||||
|
||||
if( tV > maxV )
|
||||
maxV = tV;
|
||||
|
||||
tV = fabs( wnorm.z );
|
||||
|
||||
if( tV > maxV )
|
||||
maxV = tV;
|
||||
}
|
||||
|
||||
lCPts[0] = lCPts[1];
|
||||
|
@ -287,13 +315,28 @@ void FACET::CalcFaceNormal()
|
|||
lCPts[2] = vertices.front();
|
||||
|
||||
wnorm = face_normal;
|
||||
a2 = VCalcAreaSq( lCPts[1], lCPts[0], lCPts[2] );
|
||||
wnorm.x *= a2;
|
||||
wnorm.y *= a2;
|
||||
wnorm.z *= a2;
|
||||
a2 = acosf( VCalcCosAngle( lCPts[1], lCPts[0], lCPts[2] ) );
|
||||
wnorm.x *= a1 * a2;
|
||||
wnorm.y *= a1 * a2;
|
||||
wnorm.z *= a1 * a2;
|
||||
vnweight.push_back( wnorm );
|
||||
|
||||
return;
|
||||
tV = fabs( wnorm.x );
|
||||
|
||||
if( tV > maxV )
|
||||
maxV = tV;
|
||||
|
||||
tV = fabs( wnorm.y );
|
||||
|
||||
if( tV > maxV )
|
||||
maxV = tV;
|
||||
|
||||
tV = fabs( wnorm.z );
|
||||
|
||||
if( tV > maxV )
|
||||
maxV = tV;
|
||||
|
||||
return maxV;
|
||||
}
|
||||
|
||||
|
||||
|
@ -302,6 +345,9 @@ void FACET::CalcVertexNormal( int aIndex, std::list< FACET* > &aFacetList, float
|
|||
if( vertices.size() < 3 )
|
||||
return;
|
||||
|
||||
if( vnweight.size() != vertices.size() )
|
||||
return;
|
||||
|
||||
if( norms.size() != vertices.size() )
|
||||
norms.resize( vertices.size() );
|
||||
|
||||
|
@ -318,21 +364,6 @@ void FACET::CalcVertexNormal( int aIndex, std::list< FACET* > &aFacetList, float
|
|||
{
|
||||
if( *sI == aIndex )
|
||||
{
|
||||
if( vnweight.size() != vertices.size() )
|
||||
{
|
||||
size_t os = vertices.size();
|
||||
CalcFaceNormal();
|
||||
|
||||
// check if degenerate vertices were deleted
|
||||
if( os != vertices.size() )
|
||||
{
|
||||
sI = indices.begin();
|
||||
eI = indices.end();
|
||||
idx = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// first set the default (weighted) normal value
|
||||
norms[idx] = vnweight[idx];
|
||||
|
||||
|
@ -353,14 +384,11 @@ void FACET::CalcVertexNormal( int aIndex, std::list< FACET* > &aFacetList, float
|
|||
|
||||
float thrs = VCalcCosAngle( fp[0], face_normal, fp[1] );
|
||||
|
||||
if( aCreaseLimit <= thrs )
|
||||
if( aCreaseLimit <= thrs && (*sF)->GetWeightedNormal( aIndex, fp[1] ) )
|
||||
{
|
||||
if( GetWeightedNormal( aIndex, fp[1] ) )
|
||||
{
|
||||
norms[idx].x += fp[1].x * thrs;
|
||||
norms[idx].y += fp[1].y * thrs;
|
||||
norms[idx].z += fp[1].z * thrs;
|
||||
}
|
||||
norms[idx].x += fp[1].x;
|
||||
norms[idx].y += fp[1].y;
|
||||
norms[idx].z += fp[1].z;
|
||||
}
|
||||
|
||||
++sF;
|
||||
|
@ -371,13 +399,21 @@ void FACET::CalcVertexNormal( int aIndex, std::list< FACET* > &aFacetList, float
|
|||
+ norms[idx].y * norms[idx].y
|
||||
+ norms[idx].z * norms[idx].z );
|
||||
|
||||
if( dn > FLT_EPSILON )
|
||||
if( dn > LOWER_LIMIT )
|
||||
{
|
||||
norms[idx].x /= dn;
|
||||
norms[idx].y /= dn;
|
||||
norms[idx].z /= dn;
|
||||
}
|
||||
|
||||
// if the normals is an invalid normal this test will pass
|
||||
if( fabs( norms[idx].x ) < 0.5
|
||||
&& fabs( norms[idx].y ) < 0.5
|
||||
&& fabs( norms[idx].z ) < 0.5 )
|
||||
{
|
||||
norms[idx] = face_normal;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -399,6 +435,9 @@ bool FACET::GetWeightedNormal( int aIndex, WRLVEC3F& aNorm )
|
|||
if( vertices.size() < 3 )
|
||||
return false;
|
||||
|
||||
if( vnweight.size() != vertices.size() )
|
||||
return false;
|
||||
|
||||
std::vector< int >::iterator sI = indices.begin();
|
||||
std::vector< int >::iterator eI = indices.end();
|
||||
int idx = 0;
|
||||
|
@ -407,21 +446,6 @@ bool FACET::GetWeightedNormal( int aIndex, WRLVEC3F& aNorm )
|
|||
{
|
||||
if( *sI == aIndex )
|
||||
{
|
||||
if( vnweight.size() != vertices.size() )
|
||||
{
|
||||
size_t os = vertices.size();
|
||||
CalcFaceNormal();
|
||||
|
||||
// check if degenerate vertices were deleted
|
||||
if( os != vertices.size() )
|
||||
{
|
||||
sI = indices.begin();
|
||||
eI = indices.end();
|
||||
idx = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
aNorm = vnweight[idx];
|
||||
return true;
|
||||
}
|
||||
|
@ -444,13 +468,7 @@ bool FACET::GetFaceNormal( WRLVEC3F& aNorm )
|
|||
return false;
|
||||
|
||||
if( vnweight.size() != vertices.size() )
|
||||
{
|
||||
CalcFaceNormal();
|
||||
|
||||
// check if the polygon was invalidated
|
||||
if( vertices.size() < 3 )
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
|
||||
aNorm = face_normal;
|
||||
return true;
|
||||
|
@ -664,6 +682,25 @@ void FACET::CollectVertices( std::vector< std::list< FACET* > >& aFacetList )
|
|||
}
|
||||
|
||||
|
||||
void FACET::Renormalize( float aMaxValue )
|
||||
{
|
||||
//return;
|
||||
if( vnweight.empty() || aMaxValue < LOWER_LIMIT )
|
||||
return;
|
||||
|
||||
size_t vs = vnweight.size();
|
||||
|
||||
for( size_t i = 0; i < vs; ++i )
|
||||
{
|
||||
vnweight[i].x /= aMaxValue;
|
||||
vnweight[i].y /= aMaxValue;
|
||||
vnweight[i].z /= aMaxValue;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
SHAPE::~SHAPE()
|
||||
{
|
||||
std::list< FACET* >::iterator sF = facets.begin();
|
||||
|
@ -702,15 +739,20 @@ SGNODE* SHAPE::CalcShape( SGNODE* aParent, SGNODE* aColor, WRL1_ORDER aVertexOrd
|
|||
|
||||
int maxIdx = 0;
|
||||
int tmi;
|
||||
float maxV = 0.0;
|
||||
float tV;
|
||||
|
||||
while( sF != eF )
|
||||
{
|
||||
(*sF)->CalcFaceNormal();
|
||||
tV = (*sF)->CalcFaceNormal();
|
||||
tmi = (*sF)->GetMaxIndex();
|
||||
|
||||
if( tmi > maxIdx )
|
||||
maxIdx = tmi;
|
||||
|
||||
if( tV > maxV )
|
||||
maxV = tV;
|
||||
|
||||
++sF;
|
||||
}
|
||||
|
||||
|
@ -726,6 +768,7 @@ SGNODE* SHAPE::CalcShape( SGNODE* aParent, SGNODE* aColor, WRL1_ORDER aVertexOrd
|
|||
|
||||
while( sF != eF )
|
||||
{
|
||||
(*sF)->Renormalize( tV );
|
||||
(*sF)->CollectVertices( flist );
|
||||
++sF;
|
||||
}
|
||||
|
|
|
@ -77,9 +77,13 @@ public:
|
|||
/**
|
||||
* Function CalcFaceNormal
|
||||
* calculates the normal to the facet assuming a CCW orientation
|
||||
* and performs the calculation of the angle weighted vertex normals
|
||||
* and performs the calculation of the angle weighted vertex normals.
|
||||
*
|
||||
* @return is the max. magnitude of any component of a vector
|
||||
*/
|
||||
void CalcFaceNormal();
|
||||
float CalcFaceNormal();
|
||||
|
||||
void Renormalize( float aMaxValue );
|
||||
|
||||
/**
|
||||
* Function CalcVertexNormal
|
||||
|
|
Loading…
Reference in New Issue