Skip to content

Instantly share code, notes, and snippets.

@paulhoux
Created January 24, 2014 22:55
Show Gist options
  • Save paulhoux/8608510 to your computer and use it in GitHub Desktop.
Save paulhoux/8608510 to your computer and use it in GitHub Desktop.
Test application for the Cinder framework, showing that recalculated normals (based on the average of all connected triangle faces) is just as precise as the original normals (calculated from sphere mathematics).
#include "DebugMesh.h"
using namespace ci;
using namespace ci::geom;
using namespace std;
DebugMesh::DebugMesh(void)
{
enable( Attrib::POSITION );
enable( Attrib::COLOR );
clear();
}
DebugMesh::DebugMesh(const TriMesh& mesh)
{
enable( Attrib::POSITION );
enable( Attrib::COLOR );
setMesh(mesh);
}
DebugMesh::~DebugMesh(void)
{
}
void DebugMesh::clear()
{
mVertices.clear();
mColors.clear();
mIndices.clear();
}
void DebugMesh::setMesh(const TriMesh& mesh)
{
clear();
// check if mesh is valid and count vertices
if(!mesh.hasNormals())
return;
size_t numVertices = mesh.getNumVertices();
if(numVertices < 1)
return;
// reserve memory to prevent reallocations
bool hasTangents = mesh.hasTangents();
size_t numEntriesPerVertex = hasTangents ? 4 : 2;
size_t numIndicesPerVertex = hasTangents ? 6 : 2;
mVertices.reserve( numVertices * numEntriesPerVertex );
mColors.reserve( numVertices * numEntriesPerVertex );
mIndices.reserve( numVertices * numIndicesPerVertex );
// determine the right scale, based on the bounding box
AxisAlignedBox3f bbox = mesh.calcBoundingBox();
Vec3f size = bbox.getMax() - bbox.getMin();
float scale = math<float>::max( math<float>::max( float(size.x), float(size.y) ), float(size.z) ) / 2.0f;
// construct mesh
for(size_t i=0;i<numVertices;++i) {
uint32_t idx = mVertices.size();
mVertices.push_back( mesh.getVertices<3>()[i] );
mVertices.push_back( mesh.getVertices<3>()[i] + scale * mesh.getNormals()[i] );
mColors.push_back( Color(1, 1, 1) );
mColors.push_back( Color(1, 1, 1) );
mIndices.push_back( idx );
mIndices.push_back( idx + 1 );
if(hasTangents)
{
mVertices.push_back( mesh.getVertices<3>()[i] + scale * mesh.getTangents()[i] );
mVertices.push_back( mesh.getVertices<3>()[i] + scale * mesh.getNormals()[i].cross(mesh.getTangents()[i]) );
mColors.push_back( Color(1, 0, 0) );
mColors.push_back( Color(0, 1, 0) );
mIndices.push_back( idx );
mIndices.push_back( idx + 2 );
mIndices.push_back( idx );
mIndices.push_back( idx + 3 );
}
}
}
uint8_t DebugMesh::getAttribDims( Attrib attr ) const
{
switch( attr ) {
case Attrib::POSITION: return 3;
case Attrib::COLOR: return 3;
default:
return 0;
}
}
void DebugMesh::loadInto( Target *target ) const
{
target->copyAttrib( Attrib::POSITION, 3, 0, reinterpret_cast<const float*>(&mVertices.front()), mVertices.size() );
target->copyAttrib( Attrib::COLOR, 3, 0, reinterpret_cast<const float*>(&mColors.front()), mColors.size() );
target->copyIndices( Primitive::LINES, &mIndices.front(), mIndices.size(), 4 );
}
#include "cinder/GeomIo.h"
#include "cinder/TriMesh.h"
class DebugMesh : public ci::geom::Source
{
public:
DebugMesh(void);
DebugMesh(const ci::TriMesh& mesh);
~DebugMesh(void);
void clear();
void setMesh(const ci::TriMesh& mesh);
virtual size_t getNumVertices() const override { return mVertices.size(); }
virtual size_t getNumIndices() const override { return mIndices.size(); }
virtual ci::geom::Primitive getPrimitive() const override { return ci::geom::Primitive::LINES; }
virtual uint8_t getAttribDims( ci::geom::Attrib attr ) const override;
virtual void loadInto( ci::geom::Target *target ) const override;
private:
std::vector<ci::Vec3f> mVertices;
std::vector<ci::Color> mColors;
std::vector<ci::uint32_t> mIndices;
};
#include "cinder/Camera.h"
#include "cinder/GeomIo.h"
#include "cinder/MayaCamUI.h"
#include "cinder/app/AppNative.h"
#include "cinder/app/RendererGl.h"
#include "cinder/gl/gl.h"
#include "cinder/gl/Context.h"
#include "cinder/gl/VboMesh.h"
#include "DebugMesh.h"
using namespace ci;
using namespace ci::app;
using namespace std;
class GeometryApp : public AppNative
{
public:
void setup();
void update();
void draw();
void mouseDown( MouseEvent event );
void mouseDrag( MouseEvent event );
void resize();
private:
CameraPersp mCamera;
MayaCamUI mMayaCam;
gl::VboMeshRef mSphere;
gl::VboMeshRef mOriginalNormals;
gl::VboMeshRef mCalculatedNormals;
};
void GeometryApp::setup()
{
gl::enableDepthRead();
gl::enableDepthWrite();
geom::Sphere sphere = geom::Sphere().segments(10).enable( geom::Attrib::COLOR );
mSphere = gl::VboMesh::create( sphere );
TriMesh mesh(sphere);
mOriginalNormals = gl::VboMesh::create( DebugMesh( mesh ) );
mesh.recalculateNormals();
mCalculatedNormals = gl::VboMesh::create( DebugMesh( mesh ) );
}
void GeometryApp::update()
{
}
void GeometryApp::draw()
{
gl::clear( Color::black() );
gl::setMatrices( mCamera );
gl::GlslProgScope glslProgScope( gl::context()->getStockShader( gl::ShaderDef().color() ) );
gl::draw( mSphere );
gl::draw( mOriginalNormals );
gl::draw( mCalculatedNormals );
}
void GeometryApp::mouseDown( MouseEvent event )
{
mMayaCam.setCurrentCam( mCamera );
mMayaCam.mouseDown( event.getPos() );
}
void GeometryApp::mouseDrag( MouseEvent event )
{
mMayaCam.mouseDrag( event.getPos(), event.isLeftDown(), event.isMiddleDown(), event.isRightDown() );
mCamera = mMayaCam.getCamera();
}
void GeometryApp::resize(void)
{
mCamera.setAspectRatio( getWindowAspectRatio() );
}
CINDER_APP_NATIVE( GeometryApp, RendererGl )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment