+ Improved the normals calculations (however it's still buggy)
+ Reworked 3D plugins to use normals calculations
This commit is contained in:
parent
304cd81ebd
commit
c251fbac75
|
@ -161,10 +161,10 @@ bool IFSG_FACESET::NewNode( IFSG_NODE& aParent )
|
|||
}
|
||||
|
||||
|
||||
bool IFSG_FACESET::CalcNormals( void )
|
||||
bool IFSG_FACESET::CalcNormals( SGNODE** aPtr )
|
||||
{
|
||||
if( m_node )
|
||||
return ((SGFACESET*)m_node)->CalcNormals();
|
||||
return ((SGFACESET*)m_node)->CalcNormals( aPtr );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -289,12 +289,9 @@ void SGVECTOR::normalize( void )
|
|||
double dx = vx * vx;
|
||||
double dy = vy * vy;
|
||||
double dz = vz * vz;
|
||||
double dv2 = dx + dy + dz;
|
||||
double dv2 = sqrt( dx + dy + dz );
|
||||
|
||||
// note: placing the limit at 1e-14 ensures that
|
||||
// models representing mm to 1e-4 precision can
|
||||
// be accepted before the calculations blow up
|
||||
if( (dx + dy + dz) < 1e-14 )
|
||||
if( (dx + dy + dz) < 1e-8 )
|
||||
{
|
||||
// use the default; the numbers are too small
|
||||
// to be believable
|
||||
|
@ -304,13 +301,9 @@ void SGVECTOR::normalize( void )
|
|||
return;
|
||||
}
|
||||
|
||||
dx /= dv2;
|
||||
dy /= dv2;
|
||||
dz /= dv2;
|
||||
|
||||
vx = sqrt( dx );
|
||||
vy = sqrt( dy );
|
||||
vz = sqrt( dz );
|
||||
vx /= dv2;
|
||||
vy /= dv2;
|
||||
vz /= dv2;
|
||||
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -316,8 +316,11 @@ bool SGCOORDS::ReadCache( std::ifstream& aFile, SGNODE* parentNode )
|
|||
}
|
||||
|
||||
|
||||
bool SGCOORDS::CalcNormals( void )
|
||||
bool SGCOORDS::CalcNormals( SGNODE** aPtr )
|
||||
{
|
||||
if( aPtr )
|
||||
*aPtr = NULL;
|
||||
|
||||
if( NULL == m_Parent )
|
||||
return false;
|
||||
|
||||
|
@ -342,7 +345,12 @@ bool SGCOORDS::CalcNormals( void )
|
|||
np = new SGNORMALS( m_Parent );
|
||||
|
||||
if( S3D::CalcTriangleNormals( coords, ilist, np->norms ) )
|
||||
{
|
||||
if( aPtr )
|
||||
*aPtr = np;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
delete np;
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ public:
|
|||
* calculates normals for this coordinate list and sets the
|
||||
* normals list in the parent SGFACESET
|
||||
*/
|
||||
bool CalcNormals( void );
|
||||
bool CalcNormals( SGNODE** aPtr );
|
||||
|
||||
void ReNameNodes( void );
|
||||
bool WriteVRML( std::ofstream& aFile, bool aReuseFlag );
|
||||
|
|
|
@ -1041,7 +1041,7 @@ void SGFACESET::GatherCoordIndices( std::vector< int >& aIndexList )
|
|||
}
|
||||
|
||||
|
||||
bool SGFACESET::CalcNormals( void )
|
||||
bool SGFACESET::CalcNormals( SGNODE** aPtr )
|
||||
{
|
||||
if( m_RCoords )
|
||||
{
|
||||
|
@ -1050,7 +1050,7 @@ bool SGFACESET::CalcNormals( void )
|
|||
if( !fp )
|
||||
return false;
|
||||
|
||||
return fp->CalcNormals();
|
||||
return fp->CalcNormals( aPtr );
|
||||
}
|
||||
|
||||
if( NULL == m_Coords || m_Coords->coords.empty() )
|
||||
|
@ -1059,5 +1059,5 @@ bool SGFACESET::CalcNormals( void )
|
|||
if( m_Normals && !m_Normals->norms.empty( ) )
|
||||
return true;
|
||||
|
||||
return m_Coords->CalcNormals();
|
||||
return m_Coords->CalcNormals( aPtr );
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ public:
|
|||
bool AddRefNode( SGNODE* aNode );
|
||||
bool AddChildNode( SGNODE* aNode );
|
||||
|
||||
bool CalcNormals( void );
|
||||
bool CalcNormals( SGNODE** aPtr );
|
||||
|
||||
void ReNameNodes( void );
|
||||
bool WriteVRML( std::ofstream& aFile, bool aReuseFlag );
|
||||
|
|
|
@ -32,7 +32,8 @@
|
|||
|
||||
#include "3d_cache/sg/sg_helpers.h"
|
||||
#include "3d_cache/sg/sg_node.h"
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
// formats a floating point number for text output to a VRML file
|
||||
void S3D::FormatFloat( std::string& result, double value )
|
||||
|
@ -310,14 +311,50 @@ bool S3D::ReadColor( std::ifstream& aFile, SGCOLOR& aColor )
|
|||
}
|
||||
|
||||
|
||||
struct TRIAD
|
||||
static bool degenerate( glm::dvec3* pts )
|
||||
{
|
||||
int p1;
|
||||
int p2;
|
||||
int p3;
|
||||
double dx, dy, dz;
|
||||
|
||||
dx = pts[1].x - pts[0].x;
|
||||
dy = pts[1].y - pts[0].y;
|
||||
dz = pts[1].z - pts[0].z;
|
||||
|
||||
if( ( dx*dx + dy*dy + dz*dz ) < 1e-15 )
|
||||
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-15 )
|
||||
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-15 )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
static void calcTriad( glm::dvec3* pts, glm::dvec3& tri )
|
||||
{
|
||||
if( degenerate( pts ) )
|
||||
{
|
||||
tri = glm::dvec3( 0.0, 0.0, 0.0 );
|
||||
return;
|
||||
}
|
||||
|
||||
// normal * 2 * area
|
||||
tri = cross( pts[1] - pts[0], pts[2] - pts[0] );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
bool S3D::CalcTriangleNormals( std::vector< SGPOINT > coords,
|
||||
std::vector< int >& index, std::vector< SGVECTOR >& norms )
|
||||
{
|
||||
|
@ -355,7 +392,7 @@ bool S3D::CalcTriangleNormals( std::vector< SGPOINT > coords,
|
|||
return false;
|
||||
}
|
||||
|
||||
std::map< int, std::list< TRIAD > >vmap;
|
||||
std::map< int, std::list< glm::dvec3 > >vmap;
|
||||
|
||||
int p1, p2, p3;
|
||||
|
||||
|
@ -377,17 +414,14 @@ bool S3D::CalcTriangleNormals( std::vector< SGPOINT > coords,
|
|||
return false;
|
||||
}
|
||||
|
||||
// ignore degenerate triangle indices; note that it is still possible to
|
||||
// have degenerate vertices and these may cause problems
|
||||
if( p1 == p2 || p2 == p3 || p3 == p1 )
|
||||
continue;
|
||||
glm::dvec3 tri;
|
||||
glm::dvec3 trip[3];
|
||||
trip[0] = glm::dvec3( coords[p1].x, coords[p1].y, coords[p1].z );
|
||||
trip[1] = glm::dvec3( coords[p2].x, coords[p2].y, coords[p2].z );
|
||||
trip[2] = glm::dvec3( coords[p3].x, coords[p3].y, coords[p3].z );
|
||||
calcTriad( trip, tri );
|
||||
|
||||
TRIAD tri;
|
||||
tri.p1 = p1;
|
||||
tri.p2 = p2;
|
||||
tri.p3 = p3;
|
||||
|
||||
std::map< int, std::list< TRIAD > >::iterator ip = vmap.find( p1 );
|
||||
std::map< int, std::list< glm::dvec3 > >::iterator ip = vmap.find( p1 );
|
||||
|
||||
if( ip != vmap.end() )
|
||||
{
|
||||
|
@ -395,7 +429,8 @@ bool S3D::CalcTriangleNormals( std::vector< SGPOINT > coords,
|
|||
}
|
||||
else
|
||||
{
|
||||
vmap.insert( std::pair < int, std::list < TRIAD > > ( p1, std::list < TRIAD >( 1, tri ) ) );
|
||||
vmap.insert( std::pair < int, std::list < glm::dvec3 > >
|
||||
( p1, std::list < glm::dvec3 >( 1, tri ) ) );
|
||||
}
|
||||
|
||||
ip = vmap.find( p2 );
|
||||
|
@ -406,10 +441,11 @@ bool S3D::CalcTriangleNormals( std::vector< SGPOINT > coords,
|
|||
}
|
||||
else
|
||||
{
|
||||
vmap.insert( std::pair < int, std::list < TRIAD > > ( p2, std::list < TRIAD >( 1, tri ) ) );
|
||||
vmap.insert( std::pair < int, std::list < glm::dvec3 > >
|
||||
( p2, std::list < glm::dvec3 >( 1, tri ) ) );
|
||||
}
|
||||
|
||||
ip = vmap.find( p2 );
|
||||
ip = vmap.find( p3 );
|
||||
|
||||
if( ip != vmap.end() )
|
||||
{
|
||||
|
@ -417,12 +453,13 @@ bool S3D::CalcTriangleNormals( std::vector< SGPOINT > coords,
|
|||
}
|
||||
else
|
||||
{
|
||||
vmap.insert( std::pair < int, std::list < TRIAD > > ( p3, std::list < TRIAD >( 1, tri ) ) );
|
||||
vmap.insert( std::pair < int, std::list < glm::dvec3 > >
|
||||
( p3, std::list < glm::dvec3 >( 1, tri ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
std::map< int, std::list< TRIAD > >::iterator sM = vmap.begin();
|
||||
std::map< int, std::list< TRIAD > >::iterator eM = vmap.end();
|
||||
std::map< int, std::list< glm::dvec3 > >::iterator sM = vmap.begin();
|
||||
std::map< int, std::list< glm::dvec3 > >::iterator eM = vmap.end();
|
||||
size_t idx = 0;
|
||||
|
||||
while( sM != eM )
|
||||
|
@ -436,53 +473,17 @@ bool S3D::CalcTriangleNormals( std::vector< SGPOINT > coords,
|
|||
++idx;
|
||||
}
|
||||
|
||||
std::list< TRIAD >::iterator sT = sM->second.begin();
|
||||
std::list< TRIAD >::iterator eT = sM->second.end();
|
||||
|
||||
double nx = 0.0;
|
||||
double ny = 0.0;
|
||||
double nz = 0.0;
|
||||
|
||||
// XXX - TODO:
|
||||
// eliminate equal face normals in order to prevent distortion of the true vertex normal
|
||||
std::list< glm::dvec3 >::iterator sT = sM->second.begin();
|
||||
std::list< glm::dvec3 >::iterator eT = sM->second.end();
|
||||
glm::dvec3 norm( 0.0, 0.0, 0.0 );
|
||||
|
||||
while( sT != eT )
|
||||
{
|
||||
double x0, x1, x2;
|
||||
double y0, y1, y2;
|
||||
double z0, z1, z2;
|
||||
|
||||
x1 = coords[sT->p2].x - coords[sT->p1].x;
|
||||
y1 = coords[sT->p2].y - coords[sT->p1].y;
|
||||
z1 = coords[sT->p2].z - coords[sT->p1].z;
|
||||
|
||||
x2 = coords[sT->p3].x - coords[sT->p1].x;
|
||||
y2 = coords[sT->p3].y - coords[sT->p1].y;
|
||||
z2 = coords[sT->p3].z - coords[sT->p1].z;
|
||||
|
||||
x0 = (y1 * z2) - (z1 * y2);
|
||||
y0 = (z1 * x2) - (x1 * z2);
|
||||
z0 = (x1 * y2) - (y1 * x2);
|
||||
|
||||
double m = sqrt( x0*x0 + y0*y0 + z0*z0 );
|
||||
|
||||
// add the normal to the normal accumulated for this facet
|
||||
|
||||
if( m < 1e-12 )
|
||||
{
|
||||
nz += 1.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
nx += ( x0 / m );
|
||||
ny += ( y0 / m );
|
||||
nz += ( z0 / m );
|
||||
}
|
||||
|
||||
norm += *sT;
|
||||
++sT;
|
||||
}
|
||||
|
||||
norms.push_back( SGVECTOR( nx, ny, nz ) );
|
||||
norms.push_back( SGVECTOR( norm.x, norm.y, norm.z ) );
|
||||
|
||||
++idx;
|
||||
++sM;
|
||||
|
|
|
@ -48,7 +48,7 @@ public:
|
|||
bool NewNode( SGNODE* aParent );
|
||||
bool NewNode( IFSG_NODE& aParent );
|
||||
|
||||
bool CalcNormals( void );
|
||||
bool CalcNormals( SGNODE** aPtr );
|
||||
};
|
||||
|
||||
#endif // IFSG_FACESET_H
|
||||
|
|
|
@ -199,15 +199,13 @@ SCENEGRAPH* Load( char const* aFileName )
|
|||
int cidx[12] = { 0, 3, 1, 0, 2, 3, 1, 3, 2, 0, 1, 2 };
|
||||
coordIdx->SetIndices( 3, cidx );
|
||||
|
||||
// the vertex normals in this case are the normalized
|
||||
// vertex points
|
||||
SGVECTOR norm[4];
|
||||
norm[0] = SGVECTOR( -1.0, 0.0, -SQ2 );
|
||||
norm[1] = SGVECTOR( 1.0, 0.0, -SQ2 );
|
||||
norm[2] = SGVECTOR( 0.0, -1.0, SQ2 );
|
||||
norm[3] = SGVECTOR( 0.0, 1.0, SQ2 );
|
||||
IFSG_NORMALS* np = new IFSG_NORMALS( *face );
|
||||
np->SetNormalList( 4, norm );
|
||||
// note: track the sets of faces since all faces need to be
|
||||
// instantiated before we can calculate the normals list;
|
||||
// this is due to the need for all vertices to be referenced
|
||||
// in the index lists; however we have a single coordinate
|
||||
// list and 4 associated vertex lists so the requirement is
|
||||
// not met until all faces are instantiated.
|
||||
SGNODE* face1 = face->GetRawPtr();
|
||||
|
||||
// create an appearance; appearances are owned by shapes
|
||||
// magenta
|
||||
|
@ -221,9 +219,9 @@ SCENEGRAPH* Load( char const* aFileName )
|
|||
shape->NewNode( *tx1 );
|
||||
face->NewNode( *shape );
|
||||
face->AddRefNode( *cp );
|
||||
face->AddRefNode( *np );
|
||||
coordIdx->NewNode( *face );
|
||||
coordIdx->SetIndices( 3, &cidx[3] );
|
||||
SGNODE* face2 = face->GetRawPtr();
|
||||
// red
|
||||
material->NewNode( *shape );
|
||||
material->SetSpecular( 1.0, 0.0, 0.0 );
|
||||
|
@ -235,9 +233,9 @@ SCENEGRAPH* Load( char const* aFileName )
|
|||
shape->NewNode( *tx1 );
|
||||
face->NewNode( *shape );
|
||||
face->AddRefNode( *cp );
|
||||
face->AddRefNode( *np );
|
||||
coordIdx->NewNode( *face );
|
||||
coordIdx->SetIndices( 3, &cidx[6] );
|
||||
SGNODE* face3 = face->GetRawPtr();
|
||||
// green
|
||||
material->NewNode( *shape );
|
||||
material->SetSpecular( 0.0, 1.0, 0.0 );
|
||||
|
@ -249,9 +247,9 @@ SCENEGRAPH* Load( char const* aFileName )
|
|||
shape->NewNode( *tx1 );
|
||||
face->NewNode( *shape );
|
||||
face->AddRefNode( *cp );
|
||||
face->AddRefNode( *np );
|
||||
coordIdx->NewNode( *face );
|
||||
coordIdx->SetIndices( 3, &cidx[9] );
|
||||
SGNODE* face4 = face->GetRawPtr();
|
||||
// blue
|
||||
material->NewNode( *shape );
|
||||
material->SetSpecular( 0.0, 0.0, 1.0 );
|
||||
|
@ -259,6 +257,21 @@ SCENEGRAPH* Load( char const* aFileName )
|
|||
material->SetAmbient( 0.9 );
|
||||
material->SetShininess( 0.3 );
|
||||
|
||||
// note: now that the faces are instantiated we
|
||||
// can calculate the per-vertex normals
|
||||
SGNODE* np;
|
||||
face->Attach( face1 );
|
||||
face->CalcNormals( &np );
|
||||
|
||||
if( np )
|
||||
{
|
||||
face->Attach( face2 );
|
||||
face->AddRefNode( np );
|
||||
face->Attach( face3 );
|
||||
face->AddRefNode( np );
|
||||
face->Attach( face4 );
|
||||
face->AddRefNode( np );
|
||||
}
|
||||
|
||||
// create a copy of the entire tetrahedron shifted Z+2 and rotated 2/3PI
|
||||
IFSG_TRANSFORM* tx2 = new IFSG_TRANSFORM( tx0->GetRawPtr() );
|
||||
|
@ -274,7 +287,6 @@ SCENEGRAPH* Load( char const* aFileName )
|
|||
delete coordIdx;
|
||||
delete material;
|
||||
delete cp;
|
||||
delete np;
|
||||
delete tx0;
|
||||
delete tx1;
|
||||
delete tx2;
|
||||
|
|
|
@ -204,7 +204,7 @@ SCENEGRAPH* Load( char const* aFileName )
|
|||
IFSG_COORDINDEX* coordIdx = new IFSG_COORDINDEX( *face );
|
||||
coordIdx->SetIndices( indices.size(), &indices[0] );
|
||||
|
||||
if( !face->CalcNormals() )
|
||||
if( !face->CalcNormals( NULL ) )
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::cerr << __FILE__ << ": " << __FUNCTION__ << ": " << __LINE__ << "\n";
|
||||
|
|
|
@ -1344,28 +1344,32 @@ bool VRML_LAYER::addTriplet( VERTEX_3D* p0, VERTEX_3D* p1, VERTEX_3D* p2 )
|
|||
{
|
||||
double dx0 = p1->x - p0->x;
|
||||
double dx1 = p2->x - p0->x;
|
||||
double dx2 = p2->x - p1->x;
|
||||
|
||||
double dy0 = p1->y - p0->y;
|
||||
double dy1 = p2->y - p0->y;
|
||||
double dy2 = p2->y - p1->y;
|
||||
|
||||
dx0 *= dx0;
|
||||
dx1 *= dx1;
|
||||
dx2 *= dx2;
|
||||
|
||||
dy0 *= dy0;
|
||||
dy1 *= dy1;
|
||||
dy2 *= dy2;
|
||||
|
||||
// this number is chosen because we shall only write 9 decimal places
|
||||
// at most on the VRML output
|
||||
double err = 0.000000001;
|
||||
|
||||
// test if the triangles are degenerate (parallel sides)
|
||||
|
||||
if( dx0 < err && dx0 > -err && dx1 < err && dx1 > -err )
|
||||
// test if the triangles are degenerate (equal points)
|
||||
if( ( dx0 + dy0 ) < err )
|
||||
return false;
|
||||
|
||||
if( dy0 < err && dy0 > -err && dy1 < err && dy1 > -err )
|
||||
if( ( dx1 + dy1 ) < err )
|
||||
return false;
|
||||
|
||||
double sl0 = dy0 / dx0;
|
||||
double sl1 = dy1 / dx1;
|
||||
|
||||
double dsl = sl1 - sl0;
|
||||
|
||||
if( dsl < err && dsl > -err )
|
||||
if( ( dx2 + dy2 ) < err )
|
||||
return false;
|
||||
|
||||
triplets.push_back( TRIPLET_3D( p0->o, p1->o, p2->o ) );
|
||||
|
|
Loading…
Reference in New Issue