// --------------------------------------------------------------------------------- // calculate vertex normals given the triangles void Mesh3D:: calculateVertexNormals() { // create 0-normals m_vertexNormals = std::vector< Vector3 >( getNumberOfVertices(), Vector3(0,0,0) ); for(unsigned int i = 0; i < getNumberOfFaces(); i++) { int v1 = getFaceVertexIndex(i,0); int v2 = getFaceVertexIndex(i,1); int v3 = getFaceVertexIndex(i,2); assert( v1 < getNumberOfVertices() ); assert( v2 < getNumberOfVertices() ); assert( v3 < getNumberOfVertices() ); Vector3 p = getVertexPosition( v1 ); Vector3 q = getVertexPosition( v2 ); Vector3 r = getVertexPosition( v3 ); Vector3 n = (q-p).cross(r-p).normalize(); m_vertexNormals[v1] += n; m_vertexNormals[v2] += n; m_vertexNormals[v3] += n; } for(int i = 0; i < getNumberOfVertices(); i++) { assert( m_vertexNormals[i].length() > 0 ); m_vertexNormals[i] = m_vertexNormals[i].normalize(); } }
Math::Vector3d Path::getWeightedPositionInEdge(uint edgeIndex, float positionInEdge) { float edgeLength = getEdgeLength(edgeIndex); float weightedEdgeLength = getWeightedEdgeLength(edgeIndex); float startWeight = getVertexWeight(edgeIndex); float endWeight = getVertexWeight(edgeIndex + 1); float weightedEdgePosition = ((endWeight - startWeight) / (2 * weightedEdgeLength) * positionInEdge + startWeight) * 0.001 * positionInEdge / edgeLength; Math::Vector3d edgeStart = getVertexPosition(edgeIndex); Math::Vector3d edgeEnd = getVertexPosition(edgeIndex + 1); return edgeEnd * weightedEdgePosition + edgeStart * (1.0 - weightedEdgePosition); }
Triangle Terrain::getTriangle( const QPointF & position ) const { QPoint pos = QPoint( position.x(), position.y() ); if( pos.x() >= mMapSize.width()-1 ) pos.setX( mMapSize.width()-2 ); if( pos.y() >= mMapSize.height()-1 ) pos.setY( mMapSize.height()-2 ); if( pos.x() < 0 ) pos.setX( 0 ); if( pos.y() < 0 ) pos.setY( 0 ); QPointF fraction = QPointF( position.x()-(float)pos.x(), position.y()-(float)pos.y() ); if( fraction.x() + fraction.y() < 1.0f ) { return Triangle( getVertexPosition( pos.x(), pos.y() ), getVertexPosition( pos.x(), pos.y()+1 ), getVertexPosition( pos.x()+1, pos.y() ) ); } return Triangle( getVertexPosition( pos.x()+1, pos.y()+1 ), getVertexPosition( pos.x()+1, pos.y() ), getVertexPosition( pos.x(), pos.y()+1 ) ); }
bool Terrain::getLineQuadIntersection( const QVector3D & origin, const QVector3D & direction, const QPoint & quadMapCoord, float & length ) const { QPoint pos = quadMapCoord; if( pos.x() >= mMapSize.width()-1 ) pos.setX( mMapSize.width()-2 ); if( pos.y() >= mMapSize.height()-1 ) pos.setY( mMapSize.height()-2 ); if( pos.x() < 0 ) pos.setX( 0 ); if( pos.y() < 0 ) pos.setY( 0 ); float intersectionDistance; Triangle t1( getVertexPosition( pos.x(), pos.y() ), getVertexPosition( pos.x(), pos.y()+1 ), getVertexPosition( pos.x()+1, pos.y() ) ); if( t1.intersectRay( origin, direction, &intersectionDistance ) ) { if( intersectionDistance < length && intersectionDistance > 0.0f ) { length = intersectionDistance; return true; } } Triangle t2( getVertexPosition( pos.x()+1, pos.y()+1 ), getVertexPosition( pos.x()+1, pos.y() ), getVertexPosition( pos.x(), pos.y()+1 ) ); if( t2.intersectRay( origin, direction, &intersectionDistance ) ) { if( intersectionDistance < length && intersectionDistance > 0.0f ) { length = intersectionDistance; return true; } } return false; }
bool Terrain::getTriangle( const QPointF & position, Triangle & t ) const { QPoint pos = QPoint( position.x(), position.y() ); if( pos.x() >= mMapSize.width()-1 || pos.y() >= mMapSize.height()-1 || pos.x() < 0 || pos.y() < 0 ) return false; QPointF fraction = QPointF( position.x()-(float)pos.x(), position.y()-(float)pos.y() ); if( fraction.x() + fraction.y() < 1.0f ) { t.setP( getVertexPosition( pos.x(), pos.y() ) ); t.setQ( getVertexPosition( pos.x(), pos.y()+1 ) ); t.setR( getVertexPosition( pos.x()+1, pos.y() ) ); } else { t.setP( getVertexPosition( pos.x()+1, pos.y()+1 ) ); t.setQ( getVertexPosition( pos.x()+1, pos.y() ) ); t.setR( getVertexPosition( pos.x(), pos.y()+1 ) ); } return true; }
float Path::getEdgeLength(uint edgeIndex) const { Math::Vector3d edgeStart = getVertexPosition(edgeIndex); Math::Vector3d edgeEnd = getVertexPosition(edgeIndex + 1); return edgeStart.getDistanceTo(edgeEnd); }
Math::Vector3d Path3D::getEdgeDirection(uint edgeIndex) const { Math::Vector3d direction = getVertexPosition(edgeIndex) - getVertexPosition(edgeIndex + 1); direction.normalize(); return direction; }
inline const QVector3D & Terrain::getVertexPosition( const QPoint & p ) const { return getVertexPosition( p.x(), p.y() ); }
void main(void) { //transform data to simulate camera perspective and position vec3 vertex = getVertexPosition(); vec3 normal = getNormal(); vec3 backNormal = normal * -1.0; int state = int(floor(aState[0] + 0.5)); int restyle = int(floor(aState[1] + 0.5)); //HIDDEN state or first stage of xray rendering and no style state if (state == 254 || (uRenderingMode == 1 && !(state == 253 || state == 252)) || (uRenderingMode == 2 && (state == 253 || state == 252))) { vDiscard = 1.0; return; } else { vDiscard = 0.0; } if (uColorCoding){ vec4 idColor = getIdColor(); vFrontColor = idColor; vBackColor = idColor; } else{ //ulightA[3] represents intensity of the light float lightAIntensity = ulightA[3]; vec3 lightADirection = normalize(ulightA.xyz - vertex); float lightBIntensity = ulightB[3]; vec3 lightBDirection = normalize(ulightB.xyz - vertex); //Light weighting float lightWeightA = max(dot(normal, lightADirection ) * lightAIntensity, 0.0); float lightWeightB = max(dot(normal, lightBDirection ) * lightBIntensity, 0.0); float backLightWeightA = max(dot(backNormal, lightADirection) * lightAIntensity, 0.0); float backLightWeightB = max(dot(backNormal, lightBDirection) * lightBIntensity, 0.0); //minimal constant value is for ambient light float lightWeighting = lightWeightA + lightWeightB + 0.4; float backLightWeighting = backLightWeightA + backLightWeightB + 0.4; //get base color or set highlighted colour vec4 baseColor = state == 253 ? uHighlightColour : getColor(); //offset semitransparent triangles if (baseColor.a < 0.98 && uRenderingMode == 0) { mat4 transpose = mat4(1); vec3 trans = -0.002 * uMeter * normalize(normal); transpose[3] = vec4(trans,1.0); vertex = vec3(transpose * vec4(vertex, 1.0)); } //transform colour to simulate lighting //preserve original alpha channel vFrontColor = vec4(baseColor.rgb * lightWeighting, baseColor.a); vBackColor = vec4(baseColor.rgb * backLightWeighting, baseColor.a); } vPosition = vertex; gl_Position = uPMatrix * uMVMatrix * vec4(vertex, 1.0); }
peano::kernel::spacetreegrid::SingleLevelEnumerator::Vector peano::kernel::spacetreegrid::SingleLevelEnumerator::getCellCenter() const { return getVertexPosition() + _fineGridCellSize/2.0; }
peano::kernel::spacetreegrid::SingleLevelEnumerator::Vector peano::kernel::spacetreegrid::SingleLevelEnumerator::getVertexPosition() const { return getVertexPosition(LocalVertexIntegerIndex(0)); }
Geometry::Triangle_f TriangleAccessor::getTriangle() const { return Geometry::Triangle_f(Geometry::Vec3f(getVertexPosition(0)), Geometry::Vec3f(getVertexPosition(1)), Geometry::Vec3f(getVertexPosition(2))); }
Terrain::Terrain( const QString & heightMapPath, const QVector3D & size, const QVector3D & offset, const int & smoothingPasses ) { QImage heightMap( heightMapPath ); if( heightMap.isNull() ) { qFatal( "\"%s\" not found!", heightMapPath.toLocal8Bit().constData() ); } mMapSize = heightMap.size(); mSize = size; mOffset = offset; mToMapFactor = QSizeF( (float)mMapSize.width()/(float)mSize.x(), (float)mMapSize.height()/(float)mSize.z() ); mVertices.resize( mMapSize.width() * mMapSize.height() ); // prepare positions QVector<QVector3D> rawPositions; for( int h=0; h<mMapSize.height(); h++ ) { for( int w=0; w<mMapSize.width(); w++ ) { rawPositions.push_back( offset + QVector3D( w*(mSize.x()/mMapSize.width()), (float)qRed( heightMap.pixel( w, h ) )*(mSize.y()/256.0), h*(mSize.z()/mMapSize.height()) ) ); } } // smoothed positions for( int i=0; i<smoothingPasses; i++ ) rawPositions = smoothedPositions( rawPositions, mMapSize ); // copy smoothed positions to vertex array for( int i=0; i<mVertices.size(); i++ ) { mVertices[i].position = rawPositions[i]; } // normals for( int h=0; h<mMapSize.height()-1; h++ ) { for( int w=0; w<mMapSize.width()-1; w++ ) { vertex( w, h ).normal = QVector3D::normal( getVertexPosition( w, h ), getVertexPosition( w, h+1 ), getVertexPosition( w+1, h ) ); } vertex( mMapSize.width()-1, h ).normal = QVector3D(0,1,0); // last vertex in row } for( int w=0; w<mMapSize.width(); w++ ) { vertex( w, mMapSize.height()-1 ).normal = QVector3D(0,1,0); // last row } // texture coordinates for( int h=0; h<mMapSize.height(); h++ ) { for( int w=0; w<mMapSize.width(); w++ ) { vertex( w, h ).texCoord = QVector2D( w, h ); } } mVertexBuffer = QGLBuffer( QGLBuffer::VertexBuffer ); mVertexBuffer.create(); mVertexBuffer.bind(); mVertexBuffer.setUsagePattern( QGLBuffer::StaticDraw ); mVertexBuffer.allocate( mVertices.data(), mVertices.size()*VertexP3fN3fT2f::size() ); mVertexBuffer.release(); // indices QVector<unsigned int> indices; for( int h=0; h<mMapSize.height()-1; ++h ) { for( int w=0; w<mMapSize.width(); ++w ) { indices.push_back( w + h*(unsigned int)mMapSize.width() ); indices.push_back( w + (h+1)*(unsigned int)mMapSize.width() ); } } mIndexBuffer = QGLBuffer( QGLBuffer::IndexBuffer ); mIndexBuffer.create(); mIndexBuffer.bind(); mIndexBuffer.setUsagePattern( QGLBuffer::StaticDraw ); mIndexBuffer.allocate( indices.data(), indices.size()*sizeof(unsigned int) ); mIndexBuffer.release(); }
void SurfaceMeshShape::computeVolumeIntegrals() { // Considering a surface mesh with thickness, the goal is to compute the following properties: // 1) volume = integral(over volume) dx dy dz // 2) center = integral(over volume) (x y z)^T dx dy dz / volume // 3) the inertia matrix without the mass density: // I = (Ixx Ixy Ixz) = integral(over volume) (y^2+z^2 -xy -xz ) dx dy dz // (Iyx Iyy Iyz) ( -yx x^2+z^2 -yz ) // (Izx Izy Izz) ( -zx -zy x^2+y^2) // Each term of the matrix I can be evaluated independently and each monome can also be evaluated // independently and summed up after: integral(V) y^2+z^2 dV = integral(V) y^2 dV + integral(V) z^2 dV // // Therefore, we simply need to compute 10 different volume integral: // {1, x, y, z, x^2, y^2, z^2, xy, yz, zx} // // Example for the monome 'xy': // = integral(over volume) x.y dx dy dz = integral(over volume) x.y dV // = integral(over area) x.y dS * thickness // = [sum(over all triangles) integral(over triangle) x.y dS] * thickness // // Change the integration variables from cartesian coordinates to a parametrization of the // triangle ABC = {P | P = A + a.u + b.v} // with // { u=AB the 1st triangle edge supporting the parametrization // { v=AC the 2nd triangle edge supporting the parametrization // { 0<=a<=1 the triangle 1st coordinate in the new coordinate system (parametrized) // { 0<=b<=1-a the triangle 2nd coordinate in the new coordinate system (parametrized) // => dS = |dP/db x dP/da|.db.da = |vxu|.db.da = |uxv|.db.da // => x = Px // => y = Py // // integral(over volume) x.y dx dy dz = // [sum(over all triangles) integral(over triangle) x.y dS] * thickness = // [sum(over all triangles) integral(from 0 to 1) integral(from 0 to 1-a) Px.Py db.da |uxv|] * thickness // // From here, the various integral terms can be found related to A, u and v using any formal integration tool. // Order: 1, x, y, z, x^2, y^2, z^2, xy, yz, zx Eigen::VectorXd integral(10); integral.setZero(); for (auto const& triangle : getTriangles()) { if (!triangle.isValid) { continue; } auto A = getVertexPosition(triangle.verticesId[0]); auto B = getVertexPosition(triangle.verticesId[1]); auto C = getVertexPosition(triangle.verticesId[2]); // Triangle parametrization P(a, b) = A + u.a + v.b with u=AB and v=AC const Vector3d u = B - A; const Vector3d v = C - A; const double area = u.cross(v).norm() / 2.0; // Triangle area integral[0] += area; integral[1] += (A[0] + (u[0] + v[0]) / 3.0) * area; integral[2] += (A[1] + (u[1] + v[1]) / 3.0) * area; integral[3] += (A[2] + (u[2] + v[2]) / 3.0) * area; integral[4] += (A[0] * (A[0] + 2.0 * (u[0] + v[0]) / 3.0) + (u[0] * v[0] + v[0] * v[0] + u[0] * u[0]) / 6.0) * area; integral[5] += (A[1] * (A[1] + 2.0 * (u[1] + v[1]) / 3.0) + (u[1] * v[1] + v[1] * v[1] + u[1] * u[1]) / 6.0) * area; integral[6] += (A[2] * (A[2] + 2.0 * (u[2] + v[2]) / 3.0) + (u[2] * v[2] + v[2] * v[2] + u[2] * u[2]) / 6.0) * area; integral[7] += (A[0] * A[1] + (A[0] * (u[1] + v[1]) + A[1] * (u[0] + v[0])) / 3.0) * area; integral[7] += ((u[0] * u[1] + v[0] * v[1]) / 6.0 + (u[0] * v[1] + u[1] * v[0]) / 12.0) * area; integral[8] += (A[1] * A[2] + (A[1] * (u[2] + v[2]) + A[2] * (u[1] + v[1])) / 3.0) * area; integral[8] += ((u[1] * u[2] + v[1] * v[2]) / 6.0 + (u[1] * v[2] + u[2] * v[1]) / 12.0) * area; integral[9] += (A[2] * A[0] + (A[2] * (u[0] + v[0]) + A[0] * (u[2] + v[2])) / 3.0) * area; integral[9] += ((u[2] * u[0] + v[2] * v[0]) / 6.0 + (u[2] * v[0] + u[0] * v[2]) / 12.0) * area; } // integral[0] is the sum of all triangle's area double area = integral[0]; // Center of mass m_center = integral.segment(1, 3); if (area > epsilon) { m_center /= area; } // second moment of volume relative to center Vector3d centerSquared = m_center.cwiseProduct(m_center); m_secondMomentOfVolume(0, 0) = integral[5] + integral[6] - area * (centerSquared.y() + centerSquared.z()); m_secondMomentOfVolume(1, 1) = integral[4] + integral[6] - area * (centerSquared.z() + centerSquared.x()); m_secondMomentOfVolume(2, 2) = integral[4] + integral[5] - area * (centerSquared.x() + centerSquared.y()); m_secondMomentOfVolume(0, 1) = -(integral[7] - area * m_center.x() * m_center.y()); m_secondMomentOfVolume(1, 0) = m_secondMomentOfVolume(0, 1); m_secondMomentOfVolume(1, 2) = -(integral[8] - area * m_center.y() * m_center.z()); m_secondMomentOfVolume(2, 1) = m_secondMomentOfVolume(1, 2); m_secondMomentOfVolume(0, 2) = -(integral[9] - area * m_center.z() * m_center.x()); m_secondMomentOfVolume(2, 0) = m_secondMomentOfVolume(0, 2); m_secondMomentOfVolume *= m_thickness; m_volume = (area * m_thickness); }