Commit beb22bc0 authored by Andreas Schwarzkopf's avatar Andreas Schwarzkopf

[FIX #294] Fixed errors in subdivision, documentation and style

parent 44030964
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2013 OpenWalnut Community, BSV-Leipzig and CNCF-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
/*
* ButterflyFactory.cpp
*
* Created on: 30.06.2013
* Author: renegade
*/
#include "ButterflyFactory.h"
#include "core/kernel/WKernel.h"
namespace butterfly
{
float ButterflyFactory::w = 0.0f,
ButterflyFactory::factor[4][7] = {{0.75f, 5.0f/12.0f, -1.0f/12.0f, -1.0f/12.0f, 0.0f, 0.0f, 0.0f}, //NOLINT
{0.875f, 3.0f/8.0f, -1.0f/8.0f, 0.0f, -1.0f/8.0f, 0.0f, 0.0f},//NOLINT
{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},//NOLINT
{0.5f-w, 0.0f, 0.125f+2*w, -0.0625f-w, w, -0.0625f-w, 0.125f+2*w}},//NOLINT
ButterflyFactory::s1 = 9.0f / 16.0f,
ButterflyFactory::s2 = -1.0f / 16.0f;
ButterflyFactory::ButterflyFactory()
{
iterations = 0;
maxTriangles = 0;
verts = new VertexFactory();
triCount = 0;
}
ButterflyFactory::~ButterflyFactory()
{
// TODO(schwarzkopf): Auto-generated destructor stub
}
void ButterflyFactory::assignSettings( WPropInt m_iterations, WPropDouble m_maxTriangles10n )
{
this->iterations = m_iterations->get();
this->maxTriangles = ( size_t ) pow( 10, m_maxTriangles10n->get() );
this->mesh = mesh;
}
void ButterflyFactory::examineInputMesh()
{
triCount = 0;
verts = new VertexFactory( mesh );
boost::shared_ptr< WTriangleMesh > tmpMesh( new WTriangleMesh( 0, 0 ) );
triMesh = tmpMesh;
try
{
while( true )
{
verts->registerTriangle( mesh->getTriVertId0( triCount ), triCount );
verts->registerTriangle( mesh->getTriVertId1( triCount ), triCount );
verts->registerTriangle( mesh->getTriVertId2( triCount ), triCount );
triCount++;
}
}
catch( ... )
{
}
for( size_t i = 0; i < verts->getVertexCount(); i++ )
{
osg::Vec3d vec = mesh->getVertex( i );
triMesh->addVertex( osg::Vec3( vec.x(), vec.y(), vec.z() ) );
}
verts->examineCircularityAll();
}
boost::shared_ptr< WTriangleMesh > ButterflyFactory::getInterpolatedMesh( boost::shared_ptr< WTriangleMesh > inputMesh )
{
this->mesh = inputMesh;
examineInputMesh();
for( size_t iteration = 0; iteration < iterations && triCount * 4 <= maxTriangles; iteration++ )
{
size_t vertCount = verts->getVertexCount();
for( size_t triIdx = 0; triIdx < triCount; triIdx++ )
{
size_t id0 = mesh->getTriVertId0( triIdx );
size_t id1 = mesh->getTriVertId1( triIdx );
size_t id2 = mesh->getTriVertId2( triIdx );
if( !verts->neighborExists( id0, id1 ) )
{
verts->attachMid( id0, id1, vertCount++ );
triMesh->addVertex( calcMid( id0, id1 ) );
}
if( !verts->neighborExists( id0, id2 ) )
{
verts->attachMid( id0, id2, vertCount++ );
triMesh->addVertex( calcMid( id0, id2 ) );
}
if( !verts->neighborExists( id1, id2 ) )
{
verts->attachMid( id1, id2, vertCount++ );
triMesh->addVertex( calcMid( id1, id2 ) );
}
long mid0_1 = verts->getMidID( id0, id1 ), // NOLINT
mid0_2 = verts->getMidID( id0, id2 ),
mid1_2 = verts->getMidID( id1, id2 );
triMesh->addTriangle( id0, mid0_1, mid0_2 );
triMesh->addTriangle( id1, mid1_2, mid0_1 );
triMesh->addTriangle( id2, mid0_2, mid1_2 );
triMesh->addTriangle( mid0_1, mid1_2, mid0_2 );
}
mesh = triMesh;
if( iteration + 1 < iterations )
examineInputMesh();
}
return mesh;
}
osg::Vec3 ButterflyFactory::calcMid( size_t vertID1, size_t vertID2 )
{
int bound1 = verts->getBoundCountClass( vertID1 ),
bound2 = verts->getBoundCountClass( vertID2 ),
k1 = verts->getNeighbourVertexCount( vertID1 ),
k2 = verts->getNeighbourVertexCount( vertID2 );
if( bound1 == 1 )
k1 += k1 - 2;
if( bound2 == 1 )
k2 += k2 - 2;
Vec3 final = Vec3( 0.0f, 0.0f, 0.0f );
if( bound1 < 2 && bound2 < 2 && bound1 >= 0 && bound2 >= 0 )
{
if( bound1 != 1 || bound2 != 1 )
{ //Case 1: two vertices of valence 6
if( k1 == 6 && k2 == 6 )
{
final = add( Vec3( 0.0f, 0.0f, 0.0f ), getKNeighbourValueBoundary( vertID1, vertID2, false, false ), 1.0f );
final = add( final, getKNeighbourValueBoundary( vertID2, vertID1, true, false ), 1.0f );
}
else if( k1 != 6 || k2 != 6 )
{ //Case 2/3: at least one vertex of valence!=6
final = add( Vec3( 0.0f, 0.0f, 0.0f ), getKNeighbourValueBoundary( vertID1, vertID2, false, true ), 0.5f );
final = add( final, getKNeighbourValueBoundary( vertID2, vertID1, false, true ), 0.5f );
}
}
else
{ //Case 4: >=1 vertex on a bound
int start1 = verts->getNeighbourIndex( vertID1, vertID2 ),
start2 = verts->getNeighbourIndex( vertID2, vertID1 );
size_t boundNeighbour = verts->getVertexProperty( vertID1 )->getNeighbourVertices()[k1/2-start1];
final = add( Vec3( 0.0f, 0.0f, 0.0f ), mesh->getVertex( boundNeighbour ), s2 );
boundNeighbour = verts->getVertexProperty( vertID2 )->getNeighbourVertices()[k2/2-start2];
final = add( final, mesh->getVertex( boundNeighbour ), s2 );
final = add( final, mesh->getVertex( vertID1 ), s1 );
final = add( final, mesh->getVertex( vertID2 ), s1 );
}
}
else
final = calcMean( vertID1, vertID2 );
return final;
}
Vec3 ButterflyFactory::calcMean( size_t vertID1, size_t vertID2 )
{
Vec3 p1 = mesh->getVertex( vertID1 ),
p2 = mesh->getVertex( vertID2 );
return osg::Vec3( ( p1.x() + p2.x() ) / 2, ( p1.y() + p2.y() ) / 2, ( p1.z() + p2.z() ) / 2 );
}
Vec3 ButterflyFactory::add( Vec3 base, Vec3 sum, float factor )
{
float baseX = base.x(), baseY = base.y(), baseZ = base.z();
float sumX = sum.x(), sumY = sum.y(), sumZ = sum.z();
float x = baseX + sumX * factor,
y = baseY + sumY * factor,
z = baseZ + sumZ * factor;
return Vec3( x, y, z );
}
Vec3 ButterflyFactory::getKNeighbourValueBoundary( size_t stencilCenterVertID, size_t directedNeighbourVertID, bool isSecondK6, bool treatK6AsKn )
{
int start = verts->getNeighbourIndex( stencilCenterVertID, directedNeighbourVertID );
float k = verts->getVertexProperty( stencilCenterVertID )->getNeighbourVertexCount();
int bounds = verts->getBoundCountClass( stencilCenterVertID );
if( bounds == 1 )
k += k - 2;
int k_row = static_cast<int>( k + 0.3f ) - 3;
bool hasCustomWeight = ( k == 3 || k == 4 || ( k == 6 && !treatK6AsKn ) );
Vec3 final = add( Vec3( 0.0f, 0.0f, 0.0f ), mesh->getVertex( stencilCenterVertID ),
hasCustomWeight ? factor[k_row][0] : factor[0][0] );
for( int i = 0; i < k; i++)
{
float j = i - start;
if( j < 0.0f )
j = k + j;
bool isBehindBound = ( bounds == 1 && i > k / 2 );
int i_mirrored = isBehindBound ?i-k/2 :i,
k_col = 1 + static_cast<int>( j + 0.3f );
int neighbourID = verts->getVertexProperty( stencilCenterVertID )->getNeighbourVertices()[i_mirrored];
float s_j = hasCustomWeight ?factor[k_row][k_col]
:( 0.25f + cos( 2.0f * M_PI * j / k ) + 0.5f * cos( 4.0f * M_PI * j / k ) ) / k;
Vec3 value = mesh->getVertex( neighbourID );
if( isBehindBound )
{ //Case 4: >=1 vertex on a bound
value = add( mesh->getVertex( stencilCenterVertID ), value, -1.0f );
value = add( mesh->getVertex( stencilCenterVertID ), value, 1.0f );
}
if( !isSecondK6 || treatK6AsKn || ( j != 1 && j != 5 ) )
final = add( final, value, s_j );
}
return final;
}
} /* namespace std */
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2013 OpenWalnut Community, BSV-Leipzig and CNCF-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
/*
* ButterflyFactory.h
*
* Created on: 30.06.2013
* Author: renegade
*/
#ifndef BUTTERFLYFACTORY_H_
#define BUTTERFLYFACTORY_H_
#include "core/kernel/WModule.h"
#include "structure/VertexFactory.h"
using osg::Vec3;
namespace butterfly
{
class ButterflyFactory
{
public:
ButterflyFactory();
virtual ~ButterflyFactory();
void assignSettings( WPropInt m_iterations, WPropDouble m_maxTriangles10n );
boost::shared_ptr< WTriangleMesh > getInterpolatedMesh( boost::shared_ptr< WTriangleMesh > inputMmesh );
private:
static float w, factor[4][7], s1, s2;
void examineInputMesh();
osg::Vec3 calcMid( size_t vertID1, size_t vertID2 );
osg::Vec3 calcMean( size_t vertID1, size_t vertID2 );
osg::Vec3 add( Vec3 base, Vec3 sum, float factor );
Vec3 getKNeighbourValueBoundary( size_t stencilCenterVertID, size_t directedNeighbourVertID, bool isSecondK6, bool treatK6AsKn );
size_t iterations;
size_t maxTriangles;
boost::shared_ptr< WTriangleMesh > mesh, triMesh;
VertexFactory* verts;
size_t triCount;
};
} /* namespace butterfly */
#endif // BUTTERFLYFACTORY_H
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
// Additional copyright information:
// This class partially relies on the Butterfly Subdivision algorithm.
// that dates from Denis Zorin, Peter Schroeder, Wim Sweldens, Nira Dyn, David
// Levin and John A. Gregory. The original algorithm is depicted in:
// http://wwwmath.tau.ac.il/~niradyn/papers/butterfly.pdf
// http://mrl.nyu.edu/~dzorin/papers/zorin1996ism.pdf
// This work was required especially in the methods calcNewVertex and
// getInterpolatedValue.
#include <string>
#include <vector>
#include "WButterflyCalculator.h"
#include "WSubdivisionValidator.h"
#include "core/kernel/WKernel.h"
namespace butterfly
{
float WButterflyCalculator::m_w = 0.0f;
float WButterflyCalculator::m_weights[4][7] =
{{0.75f, 5.0f / 12.0f, -1.0f / 12.0f, -1.0f / 12.0f, 0.0f, 0.0f, 0.0f}, /*Valence=3*///NOLINT
{0.875f, 3.0f / 8.0f, -1.0f / 8.0f, 0.0f, -1.0f / 8.0f, 0.0f, 0.0f},/*Valence=4*///NOLINT
{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},//NOLINT
{0.5f - m_w, 0.0f, 0.0625f + m_w, -0.0625f - m_w, m_w, -0.0625f - m_w, 0.0625f + m_w}};/*Valence=6*///NOLINT
float WButterflyCalculator::m_weightCenterAtBorder = 9.0f / 16.0f;
float WButterflyCalculator::m_weightRimAtBorder = -1.0f / 16.0f;
WButterflyCalculator::WButterflyCalculator()
{
m_verts = new WVertexFactory();
}
WButterflyCalculator::~WButterflyCalculator()
{
// TODO(schwarzkopf): Auto-generated destructor stub
}
void WButterflyCalculator::assignInputMesh( boost::shared_ptr< WTriangleMesh > inputMesh,
WVertexFactory* vertexProperties )
{
this->m_inputMesh = inputMesh;
this->m_verts = vertexProperties;
}
void WButterflyCalculator::setButterflySettingW( float butterflySettingW )
{
m_w = butterflySettingW;
m_weights[3][0] = 0.5f - m_w;
m_weights[3][2] = 0.0625f + m_w;
m_weights[3][3] = -0.0625f - m_w;
m_weights[3][4] = m_w;
m_weights[3][5] = -0.0625f - m_w;
m_weights[3][6] = 0.0625f + m_w;
}
osg::Vec3 WButterflyCalculator::calcNewVertex( size_t vertID1, size_t vertID2 )
{
int bound1 = m_verts->getProperty( vertID1 )->getBoundClass();
int bound2 = m_verts->getProperty( vertID2 )->getBoundClass();
int valence1 = m_verts->getProperty( vertID1 )->getValence();
int valence2 = m_verts->getProperty( vertID2 )->getValence();
if( bound1 == 1 )
valence1 += valence1 - 2;
if( bound2 == 1 )
valence2 += valence2 - 2;
Vec3 final = Vec3( 0.0f, 0.0f, 0.0f );
if ( bound1 < 2 && bound2 < 2 && bound1 >= 0 && bound2 >= 0 )
{
if( bound1 != 1 || bound2 != 1 )
{ //Case 1: two vertices of valence 6
if ( valence1 == 6 && valence2 == 6 )
{
final = m_verts->add( Vec3( 0.0f, 0.0f, 0.0f ),
getInterpolatedValue( vertID1, vertID2, false ), 1.0f );
final = m_verts->add( final,
getInterpolatedValue( vertID2, vertID1, false ), 1.0f );
}
else if( valence1 != 6 || valence2 != 6 )
{ //Case 2/3: at least one vertex of valence!=6
final = m_verts->add( Vec3( 0.0f, 0.0f, 0.0f ),
getInterpolatedValue( vertID1, vertID2, true ), 0.5f );
final = m_verts->add( final,
getInterpolatedValue( vertID2, vertID1, true ), 0.5f );
}
}
else
{ //Case 4: >=1 vertex on a bound
int start1 = m_verts->getProperty( vertID1 )->getStencilNeighbourIndex( vertID2 );
int start2 = m_verts->getProperty( vertID2 )->getStencilNeighbourIndex( vertID1 );
size_t boundNeighbour = m_verts->getProperty( vertID1 )->getStencilNeighbourID( valence1 / 2 - start1 );
final = m_verts->add( Vec3( 0.0f, 0.0f, 0.0f ), m_inputMesh->getVertex( boundNeighbour ), m_weightRimAtBorder );
boundNeighbour = m_verts->getProperty( vertID2 )->getStencilNeighbourID( valence2 / 2 - start2 );
final = m_verts->add( final, m_inputMesh->getVertex( boundNeighbour ), m_weightRimAtBorder );
final = m_verts->add( final, m_inputMesh->getVertex( vertID1 ), m_weightCenterAtBorder );
final = m_verts->add( final, m_inputMesh->getVertex( vertID2 ), m_weightCenterAtBorder );
}
}
else
final = calcMean( vertID1, vertID2 );
return final;
}
Vec3 WButterflyCalculator::calcMean( size_t vertID1, size_t vertID2 )
{
Vec3 vert1 = m_inputMesh->getVertex( vertID1 ),
vert2 = m_inputMesh->getVertex( vertID2 );
float coordX = ( vert1.x() + vert2.x() ) / 2.0f,
coordY = ( vert1.y() + vert2.y() ) / 2.0f,
coordZ = ( vert1.z() + vert2.z() ) / 2.0f;
return osg::Vec3( coordX , coordY, coordZ );
}
Vec3 WButterflyCalculator::getInterpolatedValue( size_t stencilCenterVertID,
size_t directedNeighbourVertID, bool isIrregular )
{
WVertexProperty* property = m_verts->getProperty( stencilCenterVertID );
int start = property->getStencilNeighbourIndex( directedNeighbourVertID );
float valence = property->getValence();
int bounds = property->getBoundClass();
if ( bounds == 1 )
valence += valence - 2;
int weightRow = static_cast<int>( valence + 0.3f ) - 3;
bool hasCustomWeight = ( valence == 3 || valence == 4 || ( valence == 6 && !isIrregular ) );
Vec3 final = m_verts->add( Vec3( 0.0f, 0.0f, 0.0f ), m_inputMesh->getVertex( stencilCenterVertID ),
hasCustomWeight ? m_weights[weightRow][0] : m_weights[0][0] );
for ( int index = 0; index < valence; index++ )
{
float neighbour = index - start;
if ( neighbour < 0.0f )
neighbour = valence + neighbour;
bool isBehindBound = ( bounds == 1 && index > valence / 2 );
int i_mirrored = isBehindBound ?index-valence/2 :index,
weightCol = 1 + static_cast<int>( neighbour + 0.3f );
int neighbourID = property->getStencilNeighbourID( i_mirrored );
float weight = hasCustomWeight ?m_weights[weightRow][weightCol]
:( 0.25f + cos( 2.0f * M_PI * neighbour / valence )
+ 0.5f * cos( 4.0f * M_PI * neighbour / valence ) ) / valence;
Vec3 value = m_inputMesh->getVertex( neighbourID );
if ( isBehindBound )
{ //Case 4: >=1 vertex on a bound
value = m_verts->add( m_inputMesh->getVertex( stencilCenterVertID ), value, -1.0f );
value = m_verts->add( m_inputMesh->getVertex( stencilCenterVertID ), value, 1.0f );
}
final = m_verts->add( final, value, weight );
}
return final;
}
} /* namespace std */
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
// Additional copyright information:
// This class partially relies on the Butterfly Subdivision algorithm.
// that dates from Denis Zorin, Peter Schroeder, Wim Sweldens, Nira Dyn, David
// Levin and John A. Gregory. The original algorithm is depicted in:
// http://wwwmath.tau.ac.il/~niradyn/papers/butterfly.pdf
// http://mrl.nyu.edu/~dzorin/papers/zorin1996ism.pdf
// This work was required especially in the methods calcNewVertex and
// getInterpolatedValue.
#ifndef WBUTTERFLYCALCULATOR_H_
#define WBUTTERFLYCALCULATOR_H_
#include <string>
#include <vector>
#include "core/kernel/WModule.h"
#include "structure/WVertexFactory.h"
#include "WSubdivisionValidator.h"
using osg::Vec3;
namespace butterfly
{
/**
* Class that depicts the whole Butterfly subdivision algorithm but nothing more as such.
*/
class WButterflyCalculator
{
public:
/**
* Butterfly subdivision tool object creating instance.
*/
WButterflyCalculator();
/**
* Destroys the Butterfly instance object and its substructures.
*/
virtual ~WButterflyCalculator();
/**
* Assigns the input mesh andd its analyzed data that are required for the butterfly subdivision.
* \author schwarzkopf
* \param inputMesh Triangle mesh that should be subdivided
* \param vertexProperties The analyzed data of the input triangle mesh
*/
void assignInputMesh( boost::shared_ptr< WTriangleMesh > inputMesh,
WVertexFactory* vertexProperties );
/**
* Set the general Butterfly Subdivision setting w that affects the subdivision. See the algorithm
* documentation for the exact meaning. It's usually chosen substantially small. The original
* authors used 0.0f.
* \author schwarzkopf
* \param butterflySettingW The general butterfly subdivision parameter w.
*/
void setButterflySettingW( float butterflySettingW );
/**
* Calculate the subdivided new vertex between two vertices using the Butterfly Subdivision.
* algorithm.
* \author schwarzkopf
* \param vertID1 First vertex to subdivide between.
* \param vertID2 Second vertex ID to subdivide between
* \return Calculated coordinates.
*/
osg::Vec3 calcNewVertex( size_t vertID1, size_t vertID2 );
private:
/**
* The general Butterfly Subdivision setting w that affects the subdivision. See the algorithm
* documentation for the exact meaning. It's usually chosen substantially small. The original
* authors used 0.0f.
*/
static float m_w;
/**
* Butterfly subdivision Weights for each neighbor which always are applied for valences 3 and 4.
* Valence 6 is applied for Butterfly stencils where both valences are 6.
* The first row starts with valence 6. The first column starts with the center vertex weight.
* Then comes the Neighbor vertex connected to the other stencil center vertex.
*/
static float m_weights[4][7];
/**
* Weight where both stencil centers lie on a border. This weight is for a stencil center.
*/
static float m_weightCenterAtBorder;
/**
* Weight where both stencil centers lie on a border. This weight is beside the stencil
* centers.
*/
static float m_weightRimAtBorder;
/**
* Calculate a subdivided mit point between two vertices using the mean calculation.
* \author schwarzkopf
* \param vertID1 First vertex to subdivide between.
* \param vertID2 Second vertex ID to subdivide between.
* \return Mean between the two vertices.
*/
osg::Vec3 calcMean( size_t vertID1, size_t vertID2 );
/**
* Calculate the coordinates of a stencil half using the Butterfly subdivision algorithm.
* \param stencilCenterVertID Vertex ID of the stencil center. Coordinates are calculated
* for that value.
* \param directedNeighbourVertID Vertex ID of the other half of the whole butterfly stencil.