Commit ddaa52ae authored by schurade's avatar schurade
Browse files

[ADD] loop subdivsion for triangle meshes

parent 0665bc51
......@@ -73,9 +73,13 @@ void WTriangleMesh2::addVertex( wmath::WPosition vert )
void WTriangleMesh2::addTriangle( size_t vert0, size_t vert1, size_t vert2 )
{
if ( m_triangles.size() == m_countTriangles * 3 )
{
m_triangles.resize( m_countTriangles * 3 + 3 );
}
m_triangles[ m_countTriangles * 3 ] = vert0;
m_triangles[ m_countTriangles * 3 +1 ] = vert1;
m_triangles[ m_countTriangles * 3 +2 ] = vert2;
m_triangles[ m_countTriangles * 3 + 1 ] = vert1;
m_triangles[ m_countTriangles * 3 + 2 ] = vert2;
++m_countTriangles;
}
......@@ -89,32 +93,38 @@ void WTriangleMesh2::addTriangle( osg::Vec3 vert0, osg::Vec3 vert1, osg::Vec3 ve
void WTriangleMesh2::setVertexNormal( size_t index, osg::Vec3 normal )
{
WAssert( index < m_countVerts, "set vertex normal: index out of range" );
( *m_vertNormals )[index] = normal;
}
void WTriangleMesh2::setVertexNormal( size_t index, wmath::WPosition normal )
{
WAssert( index < m_countVerts, "set vertex normal: index out of range" );
setVertexNormal( index, osg::Vec3( normal[0], normal[1], normal[2] ) );
}
void WTriangleMesh2::setVertexColor( size_t index, osg::Vec4 color )
{
WAssert( index < m_countVerts, "set vertex color: index out of range" );
( *m_vertColors )[index] = color;
}
void WTriangleMesh2::setVertexColor( size_t index, WColor color )
{
WAssert( index < m_countVerts, "set vertex color: index out of range" );
setVertexColor( index, osg::Vec4( color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha() ) );
}
void WTriangleMesh2::setTriangleColor( size_t index, osg::Vec4 color )
{
WAssert( index < m_countTriangles, "set triangle color: index out of range" );
( *m_triangleColors )[index] = color;
}
void WTriangleMesh2::setTriangleColor( size_t index, WColor color )
{
WAssert( index < m_countTriangles, "set triangle color: index out of range" );
setTriangleColor( index, osg::Vec4( color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha() ) );
}
......@@ -144,22 +154,26 @@ std::vector< size_t >WTriangleMesh2::getTriangles()
osg::Vec3 WTriangleMesh2::getVertex( size_t index )
{
WAssert( index < m_countVerts, "get vertex: index out of range" );
return ( *m_verts )[index];
}
wmath::WPosition WTriangleMesh2::getVertexAsPosition( size_t index )
{
WAssert( index < m_countVerts, "get vertex as position: index out of range" );
return wmath::WPosition( ( *m_verts )[index][0], ( *m_verts )[index][1], ( *m_verts )[index][2] );
}
wmath::WPosition WTriangleMesh2::getVertexAsPosition( size_t triangleIndex, size_t vertNum )
{
osg::Vec3 v = getVertex( triangleIndex, vertNum );
WAssert( triangleIndex < m_countTriangles, "get vertex as position: index out of range" );
osg::Vec3 v = getTriVert( triangleIndex, vertNum );
return wmath::WPosition( v[0], v[1], v[2] );
}
void WTriangleMesh2::removeVertex( size_t index )
{
WAssert( index < m_countVerts, "remove vertex: index out of range" );
if ( m_vertexIsInTriangle[ index ].size() > 0 )
{
return;
......@@ -178,6 +192,7 @@ void WTriangleMesh2::removeVertex( size_t index )
void WTriangleMesh2::removeTriangle( size_t index )
{
WAssert( index < m_countTriangles, "remove triangle: index out of range" );
m_triangles.erase( m_triangles.begin() + index * 3, m_triangles.begin() + index * 3 + 3 );
m_meshDirty = true;
}
......@@ -191,6 +206,9 @@ void WTriangleMesh2::recalcVertNormals()
{
updateVertsInTriangles();
( *m_vertNormals ).resize( m_countVerts );
( *m_triangleNormals ).resize( m_countTriangles );
for ( size_t i = 0; i < m_countTriangles; ++i )
{
( *m_triangleNormals )[i] = calcTriangleNormal( i );
......@@ -216,20 +234,20 @@ void WTriangleMesh2::updateVertsInTriangles()
{
m_vertexIsInTriangle.clear();
std::vector< size_t >v;
m_vertexIsInTriangle.resize( m_countVerts, v );
m_vertexIsInTriangle.resize( ( *m_verts ).size(), v );
for ( size_t i = 0; i < m_countTriangles; ++i )
{
m_vertexIsInTriangle[ m_triangles[i*3] ].push_back( i );
m_vertexIsInTriangle[ m_triangles[i*3+1] ].push_back( i );
m_vertexIsInTriangle[ m_triangles[i*3+2] ].push_back( i );
m_vertexIsInTriangle[ getTriVertId0( i ) ].push_back( i );
m_vertexIsInTriangle[ getTriVertId1( i ) ].push_back( i );
m_vertexIsInTriangle[ getTriVertId2( i ) ].push_back( i );
}
}
osg::Vec3 WTriangleMesh2::calcTriangleNormal( size_t triangle )
{
osg::Vec3 v1( getVertex( triangle, 1 ) - getVertex( triangle, 0 ) );
osg::Vec3 v2( getVertex( triangle, 2 ) - getVertex( triangle, 0 ) );
osg::Vec3 v1( getTriVert( triangle, 1 ) - getTriVert( triangle, 0 ) );
osg::Vec3 v2( getTriVert( triangle, 2 ) - getTriVert( triangle, 0 ) );
osg::Vec3 tempNormal( 0, 0, 0 );
......@@ -271,13 +289,13 @@ size_t WTriangleMesh2::triangleSize()
void WTriangleMesh2::calcNeighbors()
{
std::vector<size_t> v( 3, -1 );
m_triangleNeighbors.resize( m_countTriangles, v );
m_triangleNeighbors.resize( ( *m_triangleNormals ).size(), v );
for ( size_t triId = 0; triId < m_countTriangles; ++triId )
{
size_t coVert0 = m_triangles[triId*3];
size_t coVert1 = m_triangles[triId*3+1];
size_t coVert2 = m_triangles[triId*3+1];
size_t coVert0 = getTriVertId0( triId );
size_t coVert1 = getTriVertId1( triId );
size_t coVert2 = getTriVertId2( triId );
m_triangleNeighbors[triId][0] = getNeighbor( coVert0, coVert1, triId );
m_triangleNeighbors[triId][1] = getNeighbor( coVert1, coVert2, triId );
......@@ -303,3 +321,220 @@ size_t WTriangleMesh2::getNeighbor( const size_t coVert1, const size_t coVert2,
}
return triangleNum;
}
void WTriangleMesh2::doLoopSubD()
{
m_numTriVerts = m_countVerts;
m_numTriFaces = m_countTriangles;
( *m_verts ).resize( m_numTriVerts * 4 );
m_triangles.resize( m_numTriFaces * 4 * 3 );
updateVertsInTriangles();
osg::Vec3* newVertexPositions = new osg::Vec3[m_numTriVerts];
//std::cout << "loop subdivision pass 1" << std::endl;
for ( size_t i = 0; i < m_numTriVerts; ++i )
{
newVertexPositions[i] = loopCalcNewPosition( i );
}
//std::cout << "loop subdivision pass 2" << std::endl;
for ( size_t i = 0; i < m_numTriFaces; ++i )
{
loopInsertCenterTriangle( i );
}
( *m_verts ).resize( m_countVerts );
std::vector< size_t >v;
m_vertexIsInTriangle.resize( ( *m_verts ).size(), v );
//std::cout << "loop subdivision pass 3" << std::endl;
for ( size_t i = 0; i < m_numTriFaces; ++i )
{
loopInsertCornerTriangles( i );
}
//std::cout << "loop subdivision pass 4" << std::endl;
for ( size_t i = 0; i < m_numTriVerts; ++i )
{
( *m_verts )[i] = newVertexPositions[i];
}
delete[] newVertexPositions;
m_meshDirty = true;
}
osg::Vec3 WTriangleMesh2::loopCalcNewPosition( size_t vertId )
{
std::vector< size_t > starP = m_vertexIsInTriangle[vertId];
int starSize = starP.size();
osg::Vec3 oldPos = getVertex( vertId );
double alpha = loopGetAlpha( starSize );
double scale = 1.0 - ( static_cast<double>( starSize ) * alpha );
oldPos *= scale;
osg::Vec3 newPos;
int edgeV = 0;
for ( int i = 0; i < starSize; i++ )
{
edgeV = loopGetNextVertex( starP[i], vertId );
osg::Vec3 translate = getVertex( edgeV );
newPos += translate;
}
newPos *= alpha;
return oldPos + newPos;
}
void WTriangleMesh2::loopInsertCenterTriangle( size_t triId )
{
size_t edgeVerts[3];
edgeVerts[0] = loopCalcEdgeVert( triId, getTriVertId0( triId ), getTriVertId1( triId ), getTriVertId2( triId ) );
edgeVerts[1] = loopCalcEdgeVert( triId, getTriVertId1( triId ), getTriVertId2( triId ), getTriVertId0( triId ) );
edgeVerts[2] = loopCalcEdgeVert( triId, getTriVertId2( triId ), getTriVertId0( triId ), getTriVertId1( triId ) );
addTriangle( edgeVerts[0], edgeVerts[1], edgeVerts[2] );
}
size_t WTriangleMesh2::loopCalcEdgeVert( size_t triId, size_t edgeV1, size_t edgeV2, size_t V3 )
{
size_t neighborVert = -1;
size_t neighborFaceNum = -1;
osg::Vec3 edgeVert;
neighborFaceNum = getNeighbor( edgeV1, edgeV2, triId );
if ( neighborFaceNum == triId )
{
osg::Vec3 edgeVert = ( ( *m_verts )[edgeV1] + ( *m_verts )[edgeV2] ) / 2.0;
size_t vertId = m_countVerts;
addVertex( edgeVert );
return vertId;
}
else if ( neighborFaceNum > triId )
{
neighborVert = loopGetThirdVert( edgeV1, edgeV2, neighborFaceNum );
osg::Vec3 edgePart = ( *m_verts )[edgeV1] + ( *m_verts )[edgeV2];
osg::Vec3 neighborPart = ( *m_verts )[neighborVert] + ( *m_verts )[V3];
edgeVert = ( ( edgePart * ( 3.0 / 8.0 ) ) + ( neighborPart * ( 1.0 / 8.0 ) ) );
size_t vertId = m_countVerts;
addVertex( edgeVert );
return vertId;
}
else
{
size_t neighborCenterP = neighborFaceNum + m_numTriFaces;
size_t neighborP = neighborFaceNum;
if ( getTriVertId0( neighborP ) == edgeV2 )
{
return getTriVertId0( neighborCenterP );
}
else if ( getTriVertId1( neighborP ) == edgeV2 )
{
return getTriVertId1( neighborCenterP );
}
else
{
return getTriVertId2( neighborCenterP );
}
}
return -1;
}
void WTriangleMesh2::loopInsertCornerTriangles( size_t triId )
{
// comment: center are twisted from the orignal vertices.
// original: 0, 1, 2
// center: a, b, c
// reAsgnOrig: 0, a, c
// addTris: 1, b, a
// addTris: 2, c, b
//
size_t originalTri0 = getTriVertId0( triId );
size_t originalTri1 = getTriVertId1( triId );
size_t originalTri2 = getTriVertId2( triId );
size_t centerTri0 = getTriVertId0( triId + m_numTriFaces );
size_t centerTri1 = getTriVertId1( triId + m_numTriFaces );
size_t centerTri2 = getTriVertId2( triId + m_numTriFaces );
addTriangle( originalTri1, centerTri1, centerTri0 );
addTriangle( originalTri2, centerTri2, centerTri1 );
loopSetTriangle( triId, originalTri0, centerTri0, centerTri2 );
}
void WTriangleMesh2::loopSetTriangle( size_t triId, size_t vertId1, size_t vertId2, size_t vertId3 )
{
loopEraseTriangleFromVertex( triId, getTriVertId1( triId ) );
loopEraseTriangleFromVertex( triId, getTriVertId2( triId ) );
setTriVert0( triId, vertId1 );
setTriVert1( triId, vertId2 );
setTriVert2( triId, vertId3 );
m_vertexIsInTriangle[vertId2].push_back( triId );
m_vertexIsInTriangle[vertId3].push_back( triId );
}
void WTriangleMesh2::loopEraseTriangleFromVertex( size_t triId, size_t vertId )
{
std::vector< size_t > temp;
for ( size_t i = 0; i < m_vertexIsInTriangle[vertId].size(); ++i )
{
if ( triId != m_vertexIsInTriangle[vertId][i] )
temp.push_back( m_vertexIsInTriangle[vertId][i] );
}
m_vertexIsInTriangle[vertId] = temp;
}
double WTriangleMesh2::loopGetAlpha( int n )
{
double answer;
if ( n > 3 )
{
double center = ( 0.375 + ( 0.25 * cos( ( 2.0 * 3.14159265358979 ) / static_cast<double>( n ) ) ) );
answer = ( 0.625 - ( center * center ) ) / static_cast<double>( n );
}
else
{
answer = 3.0 / 16.0;
}
return answer;
}
size_t WTriangleMesh2::loopGetNextVertex( size_t triNum, size_t vertNum )
{
if ( getTriVertId0( triNum ) == vertNum )
{
return getTriVertId1( triNum );
}
else if ( getTriVertId1( triNum ) == vertNum )
{
return getTriVertId2( triNum );
}
return getTriVertId0( triNum );
}
size_t WTriangleMesh2::loopGetThirdVert( size_t coVert1, size_t coVert2, size_t triangleNum )
{
if ( !( getTriVertId0( triangleNum ) == coVert1 ) && !( getTriVertId0( triangleNum ) == coVert2 ) )
{
return getTriVertId0( triangleNum );
}
else if ( !( getTriVertId1( triangleNum ) == coVert1 ) && !( getTriVertId1( triangleNum ) == coVert2 ) )
{
return getTriVertId1( triangleNum );
}
return getTriVertId2( triangleNum );
}
......@@ -34,6 +34,8 @@
#include "../WTransferable.h"
#include "../math/WVector3D.h"
#include "../WAssert.h"
/**
* Triangle mesh data structure allowing for convenient access of the elements.
*/
......@@ -204,11 +206,11 @@ public:
/**
* getter
*
* \param triangleIndex
* \param triId
* \param vertNum
* \return vertex
*/
osg::Vec3 getVertex( size_t triangleIndex, size_t vertNum );
osg::Vec3 getTriVert( size_t triId, size_t vertNum );
/**
* getter
......@@ -241,6 +243,11 @@ public:
*/
size_t triangleSize();
/**
* performs a loop subdivision on the triangle mesh
*/
void doLoopSubD();
protected:
static boost::shared_ptr< WPrototyped > m_prototype; //!< The prototype as singleton.
private:
......@@ -309,6 +316,139 @@ private:
*/
size_t getNeighbor( const size_t coVert1, const size_t coVert2, const size_t triangleNum );
/**
* higher level access function to the triangle vector, sets the first vertex of a triangle to
* a given vertex id
*
* \param triId the id of the triangle to modify
* \param vertId new id of the first vertex
*/
void setTriVert0( size_t triId, size_t vertId );
/**
* higher level access function to the triangle vector, sets the second vertex of a triangle to
* a given vertex id
*
* \param triId the id of the triangle to modify
* \param vertId new id of the second vertex
*/
void setTriVert1( size_t triId, size_t vertId );
/**
* higher level access function to the triangle vector, sets the third vertex of a triangle to
* a given vertex id
*
* \param triId the id of the triangle to modify
* \param vertId new id of the third vertex
*/
void setTriVert2( size_t triId, size_t vertId );
/**
* returns the id of the first vertex of a triangle
*
* \param triId id of the triangle
* \return id of the vertex
*/
size_t getTriVertId0( size_t triId );
/**
* returns the id of the second vertex of a triangle
*
* \param triId id of the triangle
* \return id of the vertex
*/
size_t getTriVertId1( size_t triId );
/**
* return the id of the third vertex of a triangle
*
* \param triId id of the triangle
* \return id of the vertex
*/
size_t getTriVertId2( size_t triId );
// the next functions are helper functions for the loop subdivision algorithm and exist only for that
// purpose, for more information read http://research.microsoft.com/en-us/um/people/cloop/thesis.pdf
/**
* changes the vertex ids of a triangle
*
* \param triId
* \param vertId1
* \param vertId2
* \param vertId3
*/
void loopSetTriangle( size_t triId, size_t vertId1, size_t vertId2, size_t vertId3 );
/**
* erases a triangle from the vertexe's list of triangles it is part of
*
* \param triId
* \param vertId
*/
void loopEraseTriangleFromVertex( size_t triId, size_t vertId );
/**
* calculates the new position of a vertex depending on it's location in the grid and number of neighbors
*
* \param vertId the vertex id
* \return new position in 3D space
*/
osg::Vec3 loopCalcNewPosition( size_t vertId );
/**
* inserts the center triangle in a given triangle,
*
* \param triId the triangle id
*/
void loopInsertCenterTriangle( size_t triId );
/**
* inserts the 3 corner triangles in a given triangle
*
* \param triId the triangle id
*/
void loopInsertCornerTriangles( size_t triId );
/**
* calculates the vertex id for a given edge, inserts a new vertex of none exists yet
*
* \param triId the triangle id
* \param edgeV1
* \param edgeV2
* \param V3
* \return index of the vertex
*/
size_t loopCalcEdgeVert( size_t triId, size_t edgeV1, size_t edgeV2, size_t V3 );
/**
* loop helper function
* \param n
* \return alpha
*/
double loopGetAlpha( int n );
/**
* returns the id of the next vertex int he triangle
*
* \param triNum id of the triangle
* \param vertNum id of the vertex
* \return id of the next vertex
*/
size_t loopGetNextVertex( size_t triNum, size_t vertNum );
/**
* returns the id of the third vertex of a triangle for two given vertexes
*
* \param coVert1
* \param coVert2
* \param triangleNum
* \return id of the third vertex
*/
size_t loopGetThirdVert( size_t coVert1, size_t coVert2, size_t triangleNum );
size_t m_countVerts; //!< number of vertexes in the mesh
......@@ -335,18 +475,23 @@ private:
std::vector < std::vector< size_t > >m_vertexIsInTriangle; //!< for each vertex, list of triangles it is part of
std::vector< std::vector< size_t > > m_triangleNeighbors; //!< edge neighbors for each triangle
size_t m_numTriVerts; //!< stores the number of vertexes before the loop subdivion is run, needed by the loop algorithm
size_t m_numTriFaces; //!< stores the number of triangles before the loop subdivion is run, needed by the loop algorithm
};
inline void WTriangleMesh2::addVertex( osg::Vec3 vert )
{
( *m_verts )[m_countVerts++] = vert;
if ( ( *m_verts ).size() == m_countVerts )
{
( *m_verts ).resize( m_countVerts + 1 );
}
( *m_verts )[m_countVerts] = vert;
++m_countVerts;
}
inline osg::Vec3 WTriangleMesh2::getVertex( size_t triangleIndex, size_t vertNum )
{
return ( *m_verts )[ m_triangles[ triangleIndex * 3 + vertNum] ];
}
inline const std::string WTriangleMesh2::getName() const
{
......@@ -358,4 +503,50 @@ inline const std::string WTriangleMesh2::getDescription() const
return "Triangle mesh data structure allowing for convenient access of the elements.";
}
inline void WTriangleMesh2::setTriVert0( size_t triId, size_t vertId )
{
WAssert( triId < m_countTriangles, "set tri vert 0: triangle id out of range" );
WAssert( vertId < m_countVerts, "vertex id out of range" );
m_triangles[ triId * 3 ] = vertId;
}
inline void WTriangleMesh2::setTriVert1( size_t triId, size_t vertId )
{
WAssert( triId < m_countTriangles, "set tri vert 1: triangle id out of range" );
WAssert( vertId < m_countVerts, "vertex id out of range" );
m_triangles[ triId * 3 + 1] = vertId;
}
inline void WTriangleMesh2::setTriVert2( size_t triId, size_t vertId )
{
WAssert( triId < m_countTriangles, "set tri vert 2: triangle id out of range" );
WAssert( vertId < m_countVerts, "vertex id out of range" );
m_triangles[ triId * 3 + 2] = vertId;
}
inline osg::Vec3 WTriangleMesh2::getTriVert( size_t triId, size_t vertNum )
{
WAssert( triId < m_countTriangles, "triangle id out of range" );
return ( *m_verts )[ m_triangles[ triId * 3 + vertNum] ];
}
inline size_t WTriangleMesh2::getTriVertId0( size_t triId )
{
WAssert( triId < m_countTriangles, "get tri vert id 0: triangle id out of range" );
return m_triangles[triId * 3];
}
inline size_t WTriangleMesh2::getTriVertId1( size_t triId )