Commit b5cc3395 authored by Sebastian Eichelbaum's avatar Sebastian Eichelbaum
Browse files

[CHANGE] - cleaned up the triangleMeshRenderer code.

parent 84b4ad2b
......@@ -31,6 +31,8 @@
#include <osg/MatrixTransform>
#include <osg/ShapeDrawable>
#include <osg/Vec3>
#include <osg/LightModel>
#include <osg/Material>
#include "../common/math/linearAlgebra/WLinearAlgebra.h"
#include "../common/WPathHelper.h"
......@@ -235,32 +237,99 @@ osg::ref_ptr< osg::Node > wge::generateSolidBoundingBoxNode( const WBoundingBox&
return transform;
}
osg::ref_ptr< osg::Geometry > wge::convertToOsgGeometry( WTriangleMesh* mesh, bool includeNormals )
osg::ref_ptr< osg::Geometry > wge::convertToOsgGeometry( WTriangleMesh::SPtr mesh, bool includeNormals, bool lighting )
{
osg::ref_ptr< osg::Vec3Array > vertices = mesh->getVertexArray();
return wge::convertToOsgGeometry( mesh.get(), includeNormals, lighting );
}
osg::ref_ptr< osg::Geometry > wge::convertToOsgGeometry( WTriangleMesh* mesh, bool includeNormals, bool lighting )
{
osg::ref_ptr< osg::Geometry> geometry( new osg::Geometry );
geometry->setVertexArray( mesh->getVertexArray() );
osg::DrawElementsUInt* surfaceElement;
osg::DrawElementsUInt* triangles = new osg::DrawElementsUInt( osg::PrimitiveSet::TRIANGLES );
triangles->reserve( 3 * mesh->triangleSize() );
for( size_t triangleID = 0; triangleID < mesh->triangleSize(); ++triangleID )
surfaceElement = new osg::DrawElementsUInt( osg::PrimitiveSet::TRIANGLES, 0 );
std::vector< size_t > tris = mesh->getTriangles();
surfaceElement->reserve( tris.size() );
for( unsigned int vertId = 0; vertId < tris.size(); ++vertId )
{
triangles->push_back( mesh->getTriVertId0( triangleID ) );
triangles->push_back( mesh->getTriVertId1( triangleID ) );
triangles->push_back( mesh->getTriVertId2( triangleID ) );
surfaceElement->push_back( tris[vertId] );
}
geometry->addPrimitiveSet( surfaceElement );
osg::ref_ptr< osg::Geometry> geometry( new osg::Geometry );
geometry->setVertexArray( vertices );
geometry->addPrimitiveSet( triangles );
// add the mesh colors
if ( mesh->getVertexColorArray() )
{
geometry->setColorArray( mesh->getVertexColorArray() );
geometry->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
}
else
{
osg::ref_ptr< osg::Vec4Array > colors = osg::ref_ptr< osg::Vec4Array >( new osg::Vec4Array );
colors->push_back( osg::Vec4( 1.0, 1.0, 1.0, 1.0 ) );
geometry->setColorArray( colors );
geometry->setColorBinding( osg::Geometry::BIND_OVERALL );
}
// ------------------------------------------------
// normals
if( includeNormals )
{
geometry->setNormalArray( mesh->getVertexNormalArray( true ) );
geometry->setNormalArray( mesh->getVertexNormalArray() );
geometry->setNormalBinding( osg::Geometry::BIND_PER_VERTEX );
if( lighting )
{
// if normals are specified, we also setup a default lighting.
osg::StateSet* state = geometry->getOrCreateStateSet();
osg::ref_ptr<osg::LightModel> lightModel = new osg::LightModel();
lightModel->setTwoSided( true );
state->setAttributeAndModes( lightModel.get(), osg::StateAttribute::ON );
state->setMode( GL_BLEND, osg::StateAttribute::ON );
{
osg::ref_ptr< osg::Material > material = new osg::Material();
material->setDiffuse( osg::Material::FRONT, osg::Vec4( 1.0, 1.0, 1.0, 1.0 ) );
material->setSpecular( osg::Material::FRONT, osg::Vec4( 0.0, 0.0, 0.0, 1.0 ) );
material->setAmbient( osg::Material::FRONT, osg::Vec4( 0.1, 0.1, 0.1, 1.0 ) );
material->setEmission( osg::Material::FRONT, osg::Vec4( 0.0, 0.0, 0.0, 1.0 ) );
material->setShininess( osg::Material::FRONT, 25.0 );
state->setAttribute( material );
}
}
}
return geometry;
}
osg::ref_ptr< osg::Geometry > wge::convertToOsgGeometry( WTriangleMesh::SPtr mesh, const WColoredVertices& colorMap, const WColor& defaultColor, bool includeNormals, bool lighting )
{
osg::Geometry* geometry = convertToOsgGeometry( mesh.get(), includeNormals, lighting );
// ------------------------------------------------
// colors
osg::ref_ptr< osg::Vec4Array > colors = osg::ref_ptr< osg::Vec4Array >( new osg::Vec4Array );
for( size_t i = 0; i < mesh->vertSize(); ++i )
{
colors->push_back( defaultColor );
}
for( std::map< size_t, WColor >::const_iterator vc = colorMap.getData().begin(); vc != colorMap.getData().end(); ++vc )
{
// ATTENTION: the colormap might not be available and hence an old one, but the new mesh might have triggered the update
if( vc->first < colors->size() )
{
colors->at( vc->first ) = vc->second;
}
}
geometry->setColorArray( colors );
geometry->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
return geometry;
}
osg::ref_ptr< osg::Geode > wge::generateLineStripGeode( const WLine& line, const float thickness, const WColor& color )
{
using osg::ref_ptr;
......
......@@ -40,6 +40,7 @@
#include "../common/math/WPlane.h"
#include "../common/math/linearAlgebra/WLinearAlgebra.h"
#include "../common/WColor.h"
#include "../common/datastructures/WColoredVertices.h"
#include "WExportWGE.h"
#include "WGEGeometryUtils.h"
#include "WGESubdividedPlane.h"
......@@ -90,14 +91,48 @@ namespace wge
/**
* Extract the vertices and triangles from a WTriangleMesh and save them
* into an osg::Geometry.
* into an osg::Geometry. It can use the normals and per-vertex colors of the mesh.
*
* \param mesh the WTriangleMesh used as input
* \param includeNormals When true, calculate the vertex normals and include
* them into the geometry.
* \param lighting if true, a standard lighting is activated for this geometry
* \return an osg::Geometry containing the mesh
* \note mesh cannot be const since osg::Geometry needs non-const pointers to the contained arrays
*/
osg::ref_ptr< osg::Geometry > WGE_EXPORT convertToOsgGeometry( WTriangleMesh* mesh, bool includeNormals = false );
osg::ref_ptr< osg::Geometry > convertToOsgGeometry( WTriangleMesh::SPtr mesh, bool includeNormals = false, bool lighting = false );
/**
* Extract the vertices and triangles from a WTriangleMesh and save them
* into an osg::Geometry. It can use the normals and per-vertex colors of the mesh.
*
* \param mesh the WTriangleMesh used as input
* \param includeNormals When true, calculate the vertex normals and include
* them into the geometry.
* \param lighting if true, a standard lighting is activated for this geometry
* \return an osg::Geometry containing the mesh
* \note mesh cannot be const since osg::Geometry needs non-const pointers to the contained arrays
*/
osg::ref_ptr< osg::Geometry > WGE_EXPORT convertToOsgGeometry( WTriangleMesh* mesh, bool includeNormals = false, bool lighting = false );
/**
* Extract the vertices and triangles from a WTriangleMesh and save them
* into an osg::Geometry. It can use the normals and per-vertex colors of the mesh.
* This method additionally uses the specified vertexID-color map to provide additional coloring.
*
* \param mesh the WTriangleMesh used as input
* \param colorMap the map from vertex to color.
* \param includeNormals When true, calculate the vertex normals and include
* them into the geometry.
* \param defaultColor This color is used in case the colorMap does not provide a color for a vertex
* \param lighting if true, a standard lighting is activated for this geometry*
* \return an osg::Geometry containing the mesh
* \note mesh cannot be const since osg::Geometry needs non-const pointers to the contained arrays
*/
osg::ref_ptr< osg::Geometry > WGE_EXPORT convertToOsgGeometry( WTriangleMesh::SPtr mesh, const WColoredVertices& colorMap,
const WColor& defaultColor = WColor( 1.0, 1.0, 1.0, 1.0 ),
bool includeNormals = false,
bool lighting = false );
/**
* Generates a line geode with thickness and color as parameters.
......
......@@ -40,6 +40,16 @@ class WGE_EXPORT WGEManagedGroupNode: public WGEGroupNode
{
public:
/**
* Shared pointer.
*/
typedef osg::ref_ptr< WGEManagedGroupNode > SPtr;
/**
* Const shared pointer.
*/
typedef osg::ref_ptr< const WGEManagedGroupNode > ConstSPtr;
/**
* Default constructor.
*
......
......@@ -44,6 +44,17 @@ class WGE_EXPORT WTriangleMesh : public WTransferable
{
friend class WTriangleMeshTest;
public:
/**
* Shared pointer
*/
typedef boost::shared_ptr< WTriangleMesh > SPtr;
/**
* Const shared pointer
*/
typedef boost::shared_ptr< const WTriangleMesh > ConstSPtr;
/**
* constructor that already reserves space for a given number of triangles and vertexes
*
......
......@@ -27,11 +27,15 @@
#include <string>
#include <vector>
#include <osg/LightModel>
#include <osg/Geode>
#include "core/graphicsEngine/WGEManagedGroupNode.h"
#include "core/graphicsEngine/WGEUtils.h"
#include "core/graphicsEngine/WTriangleMesh.h"
#include "core/graphicsEngine/WGEGeodeUtils.h"
#include "core/graphicsEngine/shaders/WGEShader.h"
#include "core/kernel/WKernel.h"
#include "WMTriangleMeshRenderer.xpm"
#include "WMTriangleMeshRenderer.h"
......@@ -39,9 +43,7 @@
W_LOADABLE_MODULE( WMTriangleMeshRenderer )
WMTriangleMeshRenderer::WMTriangleMeshRenderer():
WModule(),
m_moduleNode( new WGEGroupNode() ),
m_surfaceGeode( 0 )
WModule()
{
}
......@@ -58,6 +60,7 @@ boost::shared_ptr< WModule > WMTriangleMeshRenderer::factory() const
const char** WMTriangleMeshRenderer::getXPMIcon() const
{
// just return the icon
return WMTriangleMeshRenderer_xpm;
}
......@@ -74,32 +77,37 @@ const std::string WMTriangleMeshRenderer::getDescription() const
void WMTriangleMeshRenderer::connectors()
{
m_meshInput = boost::shared_ptr< WModuleInputData < WTriangleMesh > >(
new WModuleInputData< WTriangleMesh >( shared_from_this(), "mesh", "The mesh to display" )
);
addConnector( m_meshInput );
// this input contains the triangle data
m_meshInput = WModuleInputData< WTriangleMesh >::createAndAdd( shared_from_this(), "mesh", "The mesh to display" );
m_colorMapInput = boost::shared_ptr< WModuleInputData < WColoredVertices > >(
new WModuleInputData< WColoredVertices >( shared_from_this(), "colorMap", "The special colors" )
);
// this input provides an additional map from vertex ID to color. This is especially useful for using the trimesh renderer in conjunction
// with clustering mechanisms and so on
m_colorMapInput = WModuleInputData< WColoredVertices >::createAndAdd( shared_from_this(), "colorMap", "The special colors" );
addConnector( m_colorMapInput );
// call WModules initialization
// call WModule's initialization
WModule::connectors();
}
void WMTriangleMeshRenderer::properties()
{
m_meshColor = m_properties->addProperty( "Mesh Color", "Color of the mesh.", WColor( .9f, .9f, 0.9f, 1.0f ) );
m_mainComponentOnly = m_properties->addProperty( "Main Component", "Main component only", false );
m_opacityProp = m_properties->addProperty( "Opacity %", "Opaqueness of surface.", 100 );
m_opacityProp->setMin( 0 );
m_opacityProp->setMax( 100 );
// some properties need to trigger an update
m_propCondition = boost::shared_ptr< WCondition >( new WCondition() );
// setup all the properties. See header file for their meaning and purpose.
m_mainComponentOnly = m_properties->addProperty( "Main Component", "Main component only", false, m_propCondition );
m_opacity = m_properties->addProperty( "Opacity %", "Opaqueness of surface.", 100.0 );
m_opacity->setMin( 0.0 );
m_opacity->setMax( 100.0 );
m_usePerVertexColor = m_properties->addProperty( "Per vertex color", "", false );
m_externalColormapGroup = m_properties->addPropertyGroup( "External ColorMap.", "All the properties for the external colormap." );
m_externalDefaultColor = m_externalColormapGroup->addProperty( "Default Color", "The color where no mapping is defined.",
WColor( .9f, .9f, 0.9f, 1.0f ), m_propCondition );
m_useExternalColormap = m_externalColormapGroup->addProperty( "External Colormap", "If enabled, the renderer uses the external colormap "
"specified on the input connector \"colorMap\". If not, it uses the mesh colors.", false, m_propCondition );
// call WModule's initialization
WModule::properties();
}
......@@ -124,17 +132,29 @@ struct WMeshSizeComp
void WMTriangleMeshRenderer::moduleMain()
{
// let the main loop awake if the data changes or the properties changed.
// let the main loop awake if the data changes.
m_moduleState.setResetable( true, true );
m_moduleState.add( m_meshInput->getDataChangedCondition() );
m_moduleState.add( m_colorMapInput->getDataChangedCondition() );
m_moduleState.add( m_meshColor->getCondition() );
m_moduleState.add( m_mainComponentOnly->getCondition() );
m_moduleState.add( m_usePerVertexColor->getCondition() );
m_moduleState.add( m_propCondition );
// signal ready state
// signal ready state. The module is now ready to be used.
ready();
////////////////////////////////////////////////////////////////////////////////////////////////////
// setup the main graphics-node:
////////////////////////////////////////////////////////////////////////////////////////////////////
// create a OSG node, which will contain the triangle data and allows easy transformations:
WGEManagedGroupNode::SPtr moduleNode( new WGEManagedGroupNode( m_active ) );
osg::StateSet* moduleNodeState = moduleNode->getOrCreateStateSet();
WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->insert( moduleNode );
// load the GLSL shader:
m_shader = osg::ref_ptr< WGEShader > ( new WGEShader( "WMTriangleMeshRenderer", m_localPath ) );
// set the opacity and material color property as GLSL uniforms:
moduleNodeState->addUniform( new WGEPropertyUniform< WPropDouble >( "u_opacity", m_opacity ) );
// loop until the module container requests the module to quit
while( !m_shutdownFlag() )
......@@ -149,153 +169,60 @@ void WMTriangleMeshRenderer::moduleMain()
{
break;
}
// invalid data
// Get data and check for invalid data.
boost::shared_ptr< WTriangleMesh > mesh = m_meshInput->getData();
boost::shared_ptr< WColoredVertices > colorMap = m_colorMapInput->getData();
if( !mesh )
{
debugLog() << "Invalid Data. Disabling.";
continue;
}
boost::shared_ptr< WProgress > progress = boost::shared_ptr< WProgress >( new WProgress( "Rendering", 3 ) );
m_progress->addSubProgress( progress );
// prepare the geometry node
debugLog() << "Start rendering Mesh";
osg::ref_ptr< osg::Geometry > geometry;
osg::ref_ptr< osg::Geode > geode( new osg::Geode );
if( m_mainComponentOnly->get( true ) )
{
// component decomposition
debugLog() << "Start mesh decomposition";
boost::shared_ptr< std::list< boost::shared_ptr< WTriangleMesh > > > m_components = tm_utils::componentDecomposition( *mesh );
mesh = *std::max_element( m_components->begin(), m_components->end(), WMeshSizeComp() );
debugLog() << "Decomposing mesh done";
renderMesh( *std::max_element( m_components->begin(), m_components->end(), WMeshSizeComp() ) );
}
else
{
renderMesh( mesh );
}
debugLog() << "Rendering Mesh done";
}
WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( m_moduleNode );
}
void WMTriangleMeshRenderer::renderMesh( boost::shared_ptr< WTriangleMesh > mesh )
{
m_moduleNode->remove( m_surfaceGeode );
osg::Geometry* surfaceGeometry = new osg::Geometry();
m_surfaceGeode = osg::ref_ptr< osg::Geode >( new osg::Geode );
surfaceGeometry->setVertexArray( mesh->getVertexArray() );
osg::DrawElementsUInt* surfaceElement;
surfaceElement = new osg::DrawElementsUInt( osg::PrimitiveSet::TRIANGLES, 0 );
std::vector< size_t > tris = mesh->getTriangles();
surfaceElement->reserve( tris.size() );
for( unsigned int vertId = 0; vertId < tris.size(); ++vertId )
{
surfaceElement->push_back( tris[vertId] );
}
surfaceGeometry->addPrimitiveSet( surfaceElement );
// ------------------------------------------------
// normals
surfaceGeometry->setNormalArray( mesh->getVertexNormalArray() );
surfaceGeometry->setNormalBinding( osg::Geometry::BIND_PER_VERTEX );
m_surfaceGeode->addDrawable( surfaceGeometry );
osg::StateSet* state = m_surfaceGeode->getOrCreateStateSet();
++*progress;
// ------------------------------------------------
// colors
osg::ref_ptr< osg::Vec4Array > colors = osg::ref_ptr< osg::Vec4Array >( new osg::Vec4Array );
boost::shared_ptr< WColoredVertices > colorMap = m_colorMapInput->getData();
if( !m_usePerVertexColor->get( true ) )
{
if( !colorMap.get() || m_meshColor->changed() )
{
debugLog() << "No Color Map found, using a single color";
colors->push_back( m_meshColor->get( true ) );
surfaceGeometry->setColorArray( colors );
surfaceGeometry->setColorBinding( osg::Geometry::BIND_OVERALL );
}
else
// Should the colorMap be enabled?
if( m_useExternalColormap->get() && colorMap )
{
debugLog() << "Color Map found... using it";
for( size_t i = 0; i < mesh->vertSize(); ++i )
{
colors->push_back( m_meshColor->get() );
}
for( std::map< size_t, WColor >::const_iterator vc = colorMap->getData().begin(); vc != colorMap->getData().end(); ++vc )
{
// ATTENTION: the colormap might not be available and hence an old one, but the new mesh might have triggered the update
if( vc->first < colors->size() )
{
colors->at( vc->first ) = vc->second;
}
}
surfaceGeometry->setColorArray( colors );
surfaceGeometry->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
// this simply converts our triangle mesh to an OSG geometry.
geometry = wge::convertToOsgGeometry( mesh, *colorMap, m_externalDefaultColor->get(), true, true );
}
}
else
{
debugLog() << "Using vertex colors from triangle mesh";
surfaceGeometry->setColorArray( mesh->getVertexColorArray() );
surfaceGeometry->setColorBinding( osg::Geometry::BIND_PER_VERTEX );
}
osg::ref_ptr<osg::LightModel> lightModel = new osg::LightModel();
lightModel->setTwoSided( true );
state->setAttributeAndModes( lightModel.get(), osg::StateAttribute::ON );
state->setMode( GL_BLEND, osg::StateAttribute::ON );
{
osg::ref_ptr< osg::Material > material = new osg::Material();
material->setDiffuse( osg::Material::FRONT, osg::Vec4( 1.0, 1.0, 1.0, 1.0 ) );
material->setSpecular( osg::Material::FRONT, osg::Vec4( 0.0, 0.0, 0.0, 1.0 ) );
material->setAmbient( osg::Material::FRONT, osg::Vec4( 0.1, 0.1, 0.1, 1.0 ) );
material->setEmission( osg::Material::FRONT, osg::Vec4( 0.0, 0.0, 0.0, 1.0 ) );
material->setShininess( osg::Material::FRONT, 25.0 );
state->setAttribute( material );
}
state->addUniform( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "opacity", m_opacityProp->get( true ) ) ) );
m_moduleNode->insert( m_surfaceGeode );
m_shader = osg::ref_ptr< WGEShader > ( new WGEShader( "WMTriangleMeshRenderer", m_localPath ) );
m_shader->apply( m_surfaceGeode );
WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->insert( m_moduleNode );
m_moduleNode->addUpdateCallback( new TriangleMeshRendererCallback( boost::shared_dynamic_cast< WMTriangleMeshRenderer >( shared_from_this() ) ) );
}
void WMTriangleMeshRenderer::activate()
{
// Draw/hide the surface
if( m_moduleNode )
{
if( m_active->get() )
else if( m_useExternalColormap->get() )
{
m_moduleNode->setNodeMask( 0xFFFFFFFF );
warnLog() << "External colormap not connected.";
geometry = wge::convertToOsgGeometry( mesh, true, true );
}
else
{
m_moduleNode->setNodeMask( 0x0 );
geometry = wge::convertToOsgGeometry( mesh, true, true );
}
++*progress;
// done. Set the new drawable
geode->addDrawable( geometry );
moduleNode->clear();
moduleNode->insert( geode );
debugLog() << "Rendering Mesh done";
++*progress;
progress->finish();
}
// Always call WModule's activate!
WModule::activate();
// it is important to always remove the modules again
WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( moduleNode );
}
void WMTriangleMeshRenderer::update()
{
if( m_opacityProp->changed() )
{
osg::StateSet* rootState = m_surfaceGeode->getOrCreateStateSet();
rootState->addUniform( osg::ref_ptr<osg::Uniform>( new osg::Uniform( "opacity", m_opacityProp->get( true ) ) ) );
}
}
......@@ -27,17 +27,13 @@
#include <string>
#include <osg/Geode>
#include "core/common/datastructures/WColoredVertices.h"
#include "core/graphicsEngine/WGEGroupNode.h"
#include "core/graphicsEngine/shaders/WGEShader.h"
#include "core/graphicsEngine/WTriangleMesh.h"
#include "core/kernel/WModule.h"
#include "core/kernel/WModuleInputData.h"
#include "core/kernel/WModuleOutputData.h"
class WTriangleMesh;
class WGEShader;
/**
* This module renders the triangle mesh given at its input connector
......@@ -50,12 +46,12 @@ class WMTriangleMeshRenderer: public WModule
public:
/**
*
* Constructor. Creates the module skeleton.
*/
WMTriangleMeshRenderer();
/**
*
* Destructor.
*/
virtual ~WMTriangleMeshRenderer();
......@@ -84,11 +80,6 @@ public:
*/
virtual const char** getXPMIcon() const;
/**
* updates shader parameters
*/
void update();
protected:
/**
......@@ -106,75 +97,52 @@ protected:
*/
virtual void properties();
private:
/**
* Callback for m_active. Overwrite this in your modules to handle m_active changes separately.
* A condition used to notify about changes in several properties.
*/
virtual void activate();
private:
boost::shared_ptr< WCondition > m_propCondition;
/**
* An input connector used to get meshes from other modules. The connection management between connectors must not be handled by the module.
*/