static void genPlaneResult(unsigned int width, unsigned int height, ci::TriMesh& mesh) { mesh.clear(); float demiW = static_cast<float>(width / 2); float demiH = static_cast<float>(height / 2); for (float j = -demiH; j < demiH; ++j) { for (float i = -demiW; i < demiW; ++i) { mesh.appendVertex(ci::Vec3f(i, j, 0.0f)); mesh.appendTexCoord(ci::Vec2f( (i + demiW) / width, (j + demiH) / height )); } } //For create face algorithme size_t w = width - 1; size_t h = height - 1; for (size_t j = 0; j < h; ++j) { for (size_t i = 0; i < w; ++i) { mesh.appendTriangle(width * j + i, width * (j + 1) + i, width * j + i + 1); mesh.appendTriangle(width * j + i + 1, width * (j + 1) + i, width * (j + 1) + i + 1); } } }
void ZoaDebugFunctions::trimeshDrawNormals( ci::TriMesh &mesh ) { std::vector<ci::Vec3f> meshVertices = mesh.getVertices(); std::vector<ci::Vec3f> meshNormals = mesh.getNormals(); for( size_t i = 3; i < meshNormals.size(); i+=4 ) { float t = 0.5f; // Because T is 0.5 it's not really necessary but the we could project along the plane this way ci::Vec3f midPoint = ci::Vec3f( (1.0f - t) * ( meshVertices[i-2] ) + t * ( meshVertices[i] ) ); ci::Vec3f normal = meshNormals[i]*10; ci::gl::drawVector( midPoint, midPoint+normal, 10, 2.5); } }
void DelaunayMeshMaker::fileDrop( FileDropEvent event ){ try { mSurface = loadImage( event.getFile( 0 ) ); int width = mSurface.getWidth(); int height = mSurface.getHeight(); app::setWindowSize( width, height ); mFbo = gl::Fbo( width, height, false ); mBorderPoints.clear(); mBorderPoints.push_back( Vec2f::zero() ); mBorderPoints.push_back( Vec2f( (float)width, 0 ) ); mBorderPoints.push_back( Vec2f( (float)width ,(float)height ) ); mBorderPoints.push_back( Vec2f( 0 ,(float)height ) ); mSteinerPoints.clear(); mMesh.clear(); tesselate(); } catch( ... ) { console() << "unable to load the texture file!" << std::endl; }; }
void DelaunayMeshMaker::setup() { mSurface = loadImage( app::loadAsset( "texture0.jpg" ) ); int width = mSurface.getWidth(); int height = mSurface.getHeight(); app::setWindowSize( width, height ); mFbo = gl::Fbo( width, height, false ); mBorderPoints.push_back( Vec2f::zero() ); mBorderPoints.push_back( Vec2f( (float)width, 0 ) ); mBorderPoints.push_back( Vec2f( (float)width ,(float)height ) ); mBorderPoints.push_back( Vec2f( 0 ,(float)height ) ); mMesh.clear(); mParams = params::InterfaceGl( "Parameters", Vec2i( 300, 250 ) ); mParams.addParam( "Alpha", &mAlpha, "max=1.0 min=0.0 step=0.005" ); mParams.addParam( "Blend", &mBlend ); mParams.addParam( "Phong Shading", &mApplyPhongShading ); mParams.addParam( "Depth Offset", &mDepthOffset, "step=0.1" ); mParams.addParam( "Draw wireframe", &mDrawWireframe ); mParams.addSeparator(); mParams.addText("Edge detection"); mParams.addParam( "Edge detection scale down", &mScaleDown, "min=1" ); mParams.addParam( "Minimum threshold", &mCannyMinThreshold, "min=0.0f" ); mParams.addParam( "Maximum threshold", &mCannyMaxThreshold, "min=0.0f" ); mParams.addSeparator(); mParams.addButton( "Tesselate", std::bind( &DelaunayMeshMaker::tesselate, this ) ); mScaleDown = 8; mScaleDownPrev = mScaleDown; mCannyMinThreshold = 60.0; mCannyMaxThreshold = 70.0; mAlpha = 0.0f; mBlend = false; mApplyPhongShading = false; mDrawWireframe = false; mDepthOffset = 0.0f; mPrevDepthOffset = mDepthOffset; mPrevBlend = mBlend; mPhongShader = gl::GlslProg( loadAsset("phong_vert.glsl"), loadAsset("phong_frag.glsl") ); mEdgeDetectSurface = edgeDetect( Surface8u( mSurface ), mCannyMinThreshold, mCannyMaxThreshold, mScaleDownPrev ); mTesselator = Tesselator::makeTesselator(); mTesselator->sDone.connect( boost::bind( &DelaunayMeshMaker::onTesselationDone, this ) ); }
void DelaunayMeshMaker::update(){ mTesselator->update(); if( mNeedsProcessing && mTesselator->isRunning() ){ mTesselator->interrupt(); }else if( mNeedsProcessing && !mTesselator->isRunning() ){ mNeedsProcessing = false; mTesselator->process( mBorderPoints, mSteinerPoints, mBlend, mSurface, mDepthOffset ); } if( mBlend != mPrevBlend ){ mPrevBlend = mBlend; } if( mDepthOffset != mPrevDepthOffset ){ std::vector<Vec3f> verts = mMesh.getVertices(); std::vector<Vec3f> newVerts; int count = 0; for( auto itr = verts.begin(); itr != verts.end(); ++itr ){ float z = (*itr).z; newVerts.push_back( Vec3f( (*itr).x, (*itr).y, mDepthRandom[count] * mDepthOffset ) ); count++; } mMesh.getVertices().swap( newVerts ); mMesh.recalculateNormals(); mVboMesh = gl::VboMesh( mMesh ); mPrevDepthOffset = mDepthOffset; } if( mScaleDown != mScaleDownPrev ){ mScaleDownPrev = mScaleDown; mEdgeDetectSurface = edgeDetect( Surface8u( mSurface ), mCannyMinThreshold, mCannyMaxThreshold, mScaleDownPrev ); } }
void ZoaDebugFunctions::calculateTriMeshNormals( ci::TriMesh &mesh ) { const std::vector<ci::Vec3f>& vertices = mesh.getVertices(); const std::vector<uint32_t>& indices = mesh.getIndices(); // remove all current normals std::vector<ci::Vec3f>& normals = mesh.getNormals(); normals.reserve( mesh.getNumVertices() ); normals.clear(); // set the normal for each vertex to (0, 0, 0) for(size_t i=0; i < mesh.getNumVertices(); ++i) normals.push_back( ci::Vec3f::zero() ); // Average out the normal for each vertex at an index for(size_t i=0; i< mesh.getNumTriangles(); ++i) { ci::Vec3f v0 = vertices[ indices[i * 3] ]; ci::Vec3f v1 = vertices[ indices[i * 3 + 1] ]; ci::Vec3f v2 = vertices[ indices[i * 3 + 2] ]; // calculate normal and normalize it, so each of the normals equally contributes to the final result ci::Vec3f e0 = v2 - v0; ci::Vec3f e1 = v2 - v1; ci::Vec3f n = e0.cross(e1).normalized(); // add the normal to the final result, so we get an average of the normals of each triangle normals[ indices[i * 3] ] += n; normals[ indices[i * 3 + 1] ] += n; normals[ indices[i * 3 + 2] ] += n; } // the normals are probably not normalized by now, so make sure their lengths will be 1.0 as expected for(size_t i=0;i< normals.size();++i) { normals[i].normalize(); } }
void ZoaDebugFunctions::addQuadToMesh( ci::TriMesh& mesh, const ci::Vec3f& P0, const ci::Vec3f& P1, const ci::Vec3f& P2, const ci::Vec3f& P3, const ci::ColorA& color ) { ci::Vec3f e0 = P2 - P0; ci::Vec3f e1 = P2 - P1; ci::Vec3f n = e0.cross(e1).normalized(); mesh.appendVertex( P0 ); mesh.appendColorRGBA( color ); mesh.appendNormal( n ); mesh.appendVertex( P1 ); mesh.appendColorRGBA( color ); mesh.appendNormal( n ); mesh.appendVertex( P2 ); mesh.appendColorRGBA( color ); mesh.appendNormal( n ); mesh.appendVertex( P3 ); mesh.appendColorRGBA( color ); mesh.appendNormal( n ); int vert0 = mesh.getNumVertices() - 4; int vert1 = mesh.getNumVertices() - 1; int vert2 = mesh.getNumVertices() - 2; int vert3 = mesh.getNumVertices() - 3; mesh.appendTriangle( vert0, vert3, vert1 ); mesh.appendTriangle( vert3, vert2, vert1 ); }
void DelaunayMeshMaker::draw() { gl::clear(); gl::pushMatrices(); gl::pushModelView(); gl::color( ColorA::white() ); if( mMesh.getNumTriangles() > 0 ){ if( mApplyPhongShading ) mPhongShader.bind(); gl::enableDepthRead(); gl::enableDepthWrite(); gl::disableAlphaBlending(); if( mDrawWireframe ) gl::enableWireframe(); gl::draw( mVboMesh ); if( mDrawWireframe ) gl::disableWireframe(); if( mApplyPhongShading ) mPhongShader.unbind(); } if( mAlpha > 0.0f ){ gl::disableDepthRead(); gl::disableDepthWrite(); gl::enableAlphaBlending(); gl::color( ColorA( 1,1,1, mAlpha ) ); gl::draw( mSurface ); } gl::popModelView(); gl::popMatrices(); if( mTesselator->isRunning() ){ gl::disableDepthRead(); gl::disableDepthWrite(); gl::enableAlphaBlending(); gl::color( ColorA(0.0f, 0.0f, 0.0f, 0.5f ) ); gl::drawSolidRect( Rectf( 0, 0, app::getWindowWidth(), app::getWindowHeight() ) ); gl::pushModelView(); gl::translate( app::getWindowSize()/2 ); double time = getElapsedSeconds(); double fraction = time - (int) time; int numFractions = 12; for(int i=0;i<numFractions;++i) { float a = (float) (fraction + i * (1.0f / (float)numFractions)); a -= (int) a; gl::pushModelView(); gl::rotate( i * ( -360.0f/(float)numFractions ) ); gl::color( ColorA(1,1,1,1-a) ); gl::drawSolidRect( Rectf(-6.0f, -44.0f, +6.0f, -31.0f) ); gl::popModelView(); } gl::popModelView(); } mParams.draw(); }
TriMesh MeshHelper::subdivide( const ci::TriMesh &triMesh, uint32_t division, bool normalize ) { if ( division <= 1 || triMesh.getNumIndices() == 0 || triMesh.getNumVertices() == 0 ) { return triMesh; } vector<uint32_t> indices = triMesh.getIndices(); vector<Vec3f> normals = triMesh.getNormals(); vector<Vec3f> positions = triMesh.getVertices(); vector<Vec2f> texCoords = triMesh.getTexCoords(); vector<uint32_t> indicesBuffer( indices ); indices.clear(); indices.reserve( indicesBuffer.size() * 4 ); uint32_t index0; uint32_t index1; uint32_t index2; uint32_t index3; uint32_t index4; uint32_t index5; for ( vector<uint32_t>::const_iterator iter = indicesBuffer.begin(); iter != indicesBuffer.end(); ) { index0 = *iter; ++iter; index1 = *iter; ++iter; index2 = *iter; ++iter; if ( normalize ) { index3 = positions.size(); positions.push_back( positions.at( index0 ).lerp( 0.5f, positions.at( index1 ) ).normalized() * 0.5f ); index4 = positions.size(); positions.push_back( positions.at( index1 ).lerp( 0.5f, positions.at( index2 ) ).normalized() * 0.5f ); index5 = positions.size(); positions.push_back( positions.at( index2 ).lerp( 0.5f, positions.at( index0 ) ).normalized() * 0.5f ); } else { index3 = positions.size(); positions.push_back( positions.at( index0 ).lerp( 0.5f, positions.at( index1 ) ) ); index4 = positions.size(); positions.push_back( positions.at( index1 ).lerp( 0.5f, positions.at( index2 ) ) ); index5 = positions.size(); positions.push_back( positions.at( index2 ).lerp( 0.5f, positions.at( index0 ) ) ); } if ( !normals.empty() ) { normals.push_back( normals.at( index0 ).lerp( 0.5f, normals.at( index1 ) ) ); normals.push_back( normals.at( index1 ).lerp( 0.5f, normals.at( index2 ) ) ); normals.push_back( normals.at( index2 ).lerp( 0.5f, normals.at( index0 ) ) ); } if ( !texCoords.empty() ) { texCoords.push_back( texCoords.at( index0 ).lerp( 0.5f, texCoords.at( index1 ) ) ); texCoords.push_back( texCoords.at( index1 ).lerp( 0.5f, texCoords.at( index2 ) ) ); texCoords.push_back( texCoords.at( index2 ).lerp( 0.5f, texCoords.at( index0 ) ) ); } indices.push_back( index0 ); indices.push_back( index3 ); indices.push_back( index5 ); indices.push_back( index3 ); indices.push_back( index1 ); indices.push_back( index4 ); indices.push_back( index5 ); indices.push_back( index4 ); indices.push_back( index2 ); indices.push_back( index3 ); indices.push_back( index4 ); indices.push_back( index5 ); } ci::TriMesh mesh = create( indices, positions, normals, texCoords ); indices.clear(); normals.clear(); positions.clear(); texCoords.clear(); return subdivide( mesh, division - 1, normalize ); }
void World::generateMesh(ci::TriMesh & mesh) { using namespace ci; Vec3f offset = Vec3f(m_size * -0.5f, m_size * -0.5f, m_size * -0.5f); for (size_t z = 0; z < m_size; ++z) for (size_t y = 0; y < m_size; ++y) for (size_t x = 0; x < m_size; ++x) { if (cell(x, y, z) == AIR) { for (size_t i = 0; i < 6; ++i) { int index = getNeigbour(x, y, z, i); if (index != -1) { if (cell(index) == DIRT) { Vec3f normal = getNeigbourOffset(i); Vec3f up = std::abs(normal.dot(Vec3f::yAxis())) > 0.9f ? Vec3f::zAxis() : Vec3f::yAxis(); Vec3f side = normal.cross(up) * 0.5f; up = up * 0.5f; Vec3f pos = offset + Vec3f(x, y, z) + (normal * 0.5f); size_t indexStart = mesh.getNumVertices(); // Layout of the quad // // 0 --------------- 3 // | ^ up | // | | | // | side | | // | <-----o pos | // | | // | | // | | // 1 --------------- 2 // Create the vertex data mesh.appendVertex(pos + side + up); mesh.appendVertex(pos + side - up); mesh.appendVertex(pos - side - up); mesh.appendVertex(pos - side + up); mesh.appendNormal(-normal); mesh.appendNormal(-normal); mesh.appendNormal(-normal); mesh.appendNormal(-normal); // Create triangle data mesh.appendTriangle(indexStart + 0, indexStart + 1, indexStart + 2); mesh.appendTriangle(indexStart + 0, indexStart + 2, indexStart + 3); } } } } } }