void ConeRenderer::init(ShaderProgram* prog) { if(_vbo) { _vbo->bind(); _vbo->setPointer(); return; } _vbo = make_resource<VBO>(getResourceManager(), "P"); _vbo->overrideIndex(getResourceManager()->geometryCache()->getIndexForAttribute("P")); _vbo->bind(); prog->bindAttributeLocation(_vbo.get()); VertexList verts; //cone verts.push_back(glm::vec3(0, 1, 0)); for(int i=0; i <= _segments; i++) { float pni = 2 * PI * float(i) / _segments; verts.push_back(glm::vec3(sin(pni), 0, cos(pni))); } //disc verts.push_back(glm::vec3()); for(int i=_segments; i >= 0; i--) { float pni = 2 * PI * float(i) / _segments; verts.push_back(glm::vec3(sin(pni), 0, cos(pni))); } _vbo->data(verts); _vbo->setPointer(); }
void Cylinder::buildTopCap(VertexList& vertices, IndexList& indices) { UINT baseIndex = (UINT)vertices.size(); // Duplicate cap vertices because the texture coordinates and normals differ. float y = 0.5f*mHeight; // vertices of ring float dTheta = 2.0f*PI/mNumSlices; for(UINT i = 0; i <= mNumSlices; ++i) { float x = mTopRadius*cosf(i*dTheta); float z = mTopRadius*sinf(i*dTheta); // Map [-1,1]-->[0,1] for planar texture coordinates. float u = +0.5f*x/mTopRadius + 0.5f; float v = -0.5f*z/mTopRadius + 0.5f; vertices.push_back( Vertex(x, y, z, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, u, v) ); } // cap center vertex vertices.push_back( Vertex(0.0f, y, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f) ); // index of center vertex UINT centerIndex = (UINT)vertices.size()-1; for(UINT i = 0; i < mNumSlices; ++i) { indices.push_back(centerIndex); indices.push_back(baseIndex + i+1); indices.push_back(baseIndex + i); } }
void PolyMesh::findNeighbors( osg::Vec3 p, VertexList& vlist ) { for ( EdgeMap::iterator itr=_edges.begin(); itr!=_edges.end(); ++itr ) { if ( equivalent(itr->first.first,p) ) vlist.push_back( itr->first.second ); else if ( equivalent(itr->first.second,p) ) vlist.push_back( itr->first.first ); } }
//*************************************************************************************** // Name: Subdivide // Desc: Function subdivides every input triangle into four triangles of equal area. //*************************************************************************************** void Subdivide(VertexList& vertices, IndexList& indices) { VertexList vin = vertices; IndexList iin = indices; vertices.resize(0); indices.resize(0); // v1 // * // / \ // / \ // m0*-----*m1 // / \ / \ // / \ / \ // *-----*-----* // v0 m2 v2 UINT numTris = (UINT)iin.size()/3; for(UINT i = 0; i < numTris; ++i) { D3DXVECTOR3 v0 = vin[ iin[i*3+0] ]; D3DXVECTOR3 v1 = vin[ iin[i*3+1] ]; D3DXVECTOR3 v2 = vin[ iin[i*3+2] ]; D3DXVECTOR3 m0 = 0.5f*(v0 + v1); D3DXVECTOR3 m1 = 0.5f*(v1 + v2); D3DXVECTOR3 m2 = 0.5f*(v0 + v2); vertices.push_back(v0); // 0 vertices.push_back(v1); // 1 vertices.push_back(v2); // 2 vertices.push_back(m0); // 3 vertices.push_back(m1); // 4 vertices.push_back(m2); // 5 indices.push_back(i*6+0); indices.push_back(i*6+3); indices.push_back(i*6+5); indices.push_back(i*6+3); indices.push_back(i*6+4); indices.push_back(i*6+5); indices.push_back(i*6+5); indices.push_back(i*6+4); indices.push_back(i*6+2); indices.push_back(i*6+3); indices.push_back(i*6+1); indices.push_back(i*6+4); } }
ListPair KDTree::splitListBy(const size_t& index, const VertexList& sourceList, const VertexPtr& sourceVert){ VertexList left; VertexList right; for(VertexPtr elem : sourceList){ if((*elem)[index] < (*sourceVert)[index]){ left.push_back(elem); }else{ right.push_back(elem); } } return ListPair(left, right); }
void copyPointListToVertexList(const PointList& in,VertexList& out) { out.reserve(in.size()); for(PointList::const_iterator itr=in.begin(); itr!=in.end(); ++itr) { out.push_back(itr->second); } }
bool PLY2Reader::loadPLY2Mesh(std::shared_ptr<Shape> shape, std::string fname) { std::ifstream f_handler(fname); if (!f_handler) { std::cout << "Open file failed.\n"; return false; } std::string line; std::stringstream ss; int num_vertex = 0; int num_face = 0; VertexList vertexList; FaceList faceList; STLVectorf UVList; getline(f_handler, line); ss.str(line); ss >> num_vertex; getline(f_handler, line); ss.str(line); ss >> num_face; for (int i = 0; i < num_vertex; ++i) { float v; for (int j = 0; j < 3; ++j) { getline(f_handler, line); ss.str(line); ss >> v; vertexList.push_back(v); } } for (int i = 0; i < num_face; ++i) { int f; for (int j = 0; j < 3; ++j) { getline(f_handler, line); ss.str(line); ss >> f; faceList.push_back(f); } } shape->init(vertexList, faceList, UVList); return true; }
VertexList KDTree::findKNearestNeighbours(const VertexPtr source, const size_t numNeighbours){ VertexList result; //Stopwatch findS("NKSearch"); LimitedPriorityQueue resultQueue(numNeighbours); findKNearestNeighbours(m_root, resultQueue, source); while(!resultQueue.empty()){ VertexDistPair pair = resultQueue.top(); VertexPtr vrtx = std::get<0>(pair); result.push_back(vrtx); resultQueue.pop(); } //findS.stop(); return result; }
void LineRenderer::init(ShaderProgram* prog) { _vbo = make_resource<VBO>(getResourceManager(), "P"); _vbo->overrideIndex(getResourceManager()->geometryCache()->getIndexForAttribute("P")); _vbo->bind(); prog->bindAttributeLocation(_vbo.get()); VertexList points; for(auto p : _points) { points.push_back(p); } _vbo->data(points); _vbo->setPointer(); }
void KDTree::findInRadius(const NodePtr& src, const HyperSphere& sphere, VertexList& result) const{ if(src->isLeaf()){ for(VertexPtr vrtx : src->getBucket()){ if(sphere.contains(vrtx)){ result.push_back(vrtx); } } } if(src->getLeft() != nullptr){ if(sphere.intersectsRegion(src->getDomain())){ findInRadius(src->getLeft(), sphere, result); } } if(src->getRight() != nullptr){ if(sphere.intersectsRegion(src->getDomain())){ findInRadius(src->getRight(), sphere, result); } } }
void StaticGeometryBuffer::_generateIndices() { _indexList.clear(); VertexList newVertList; //DebugText debugText; for( uint i = 0; i < _vertexList.size(); ++i ) { bool repeated = false; ///FLip uv's for openGL _vertexList[ i ].texCoord.y = 1 - _vertexList[ i ].texCoord.y; for( uint j = 0; j < newVertList.size(); ++j ) { repeated = _isSameVertex( _vertexList[ i ], newVertList[ j ] ); if( repeated ) { _indexList.push_back( j ); break; } } if( !repeated ) { newVertList.push_back( _vertexList[ i ] ); _indexList.push_back( newVertList.size() - 1 ); } } _vertexList = newVertList; }
void Cylinder::buildStacks(VertexList& vertices, IndexList& indices) { float stackHeight = mHeight / mNumStacks; // Amount to increment radius as we move up each stack level from bottom to top. float radiusStep = (mTopRadius - mBottomRadius) / mNumStacks; UINT numRings = mNumStacks+1; // Compute vertices for each stack ring. for(UINT i = 0; i < numRings; ++i) { float y = -0.5f*mHeight + i*stackHeight; float r = mBottomRadius + i*radiusStep; // Height and radius of next ring up. float y_next = -0.5f*mHeight + (i+1)*stackHeight; float r_next = mBottomRadius + (i+1)*radiusStep; // vertices of ring float dTheta = 2.0f*PI/mNumSlices; for(UINT j = 0; j <= mNumSlices; ++j) { float c = cosf(j*dTheta); float s = sinf(j*dTheta); float u = (float)j/mNumSlices; float v = 1.0f - (float)i/mNumStacks; // Partial derivative in theta direction to get tangent vector (this is a unit vector). D3DXVECTOR3 T(-s, 0.0f, c); // Compute tangent vector down the slope of the cone (if the top/bottom // radii differ then we get a cone and not a true cylinder). D3DXVECTOR3 P(r*c, y, r*s); D3DXVECTOR3 P_next(r_next*c, y_next, r_next*s); D3DXVECTOR3 B = P - P_next; D3DXVec3Normalize(&B, &B); D3DXVECTOR3 N; D3DXVec3Cross(&N, &T, &B); D3DXVec3Normalize(&N, &N); vertices.push_back( Vertex(P.x, P.y, P.z, T.x, T.y, T.z, N.x, N.y, N.z, u, v) ); } } UINT numRingVertices = mNumSlices+1; // Compute indices for each stack. for(UINT i = 0; i < mNumStacks; ++i) { for(UINT j = 0; j < mNumSlices; ++j) { indices.push_back(i*numRingVertices + j); indices.push_back((i+1)*numRingVertices + j); indices.push_back((i+1)*numRingVertices + j+1); indices.push_back(i*numRingVertices + j); indices.push_back((i+1)*numRingVertices + j+1); indices.push_back(i*numRingVertices + j+1); } } }
void Sphere::buildStacks(VertexList& vertices, IndexList& indices) { float phiStep = PI/mNumStacks; // do not count the poles as rings UINT numRings = mNumStacks-1; // Compute vertices for each stack ring. for(UINT i = 1; i <= numRings; ++i) { float phi = i*phiStep; // vertices of ring float thetaStep = 2.0f*PI/mNumSlices; for(UINT j = 0; j <= mNumSlices; ++j) { float theta = j*thetaStep; Vertex v; // spherical to cartesian v.pos.x = mRadius*sinf(phi)*cosf(theta); v.pos.y = mRadius*cosf(phi); v.pos.z = mRadius*sinf(phi)*sinf(theta); // partial derivative of P with respect to theta v.tangent.x = -mRadius*sinf(phi)*sinf(theta); v.tangent.y = 0.0f; v.tangent.z = mRadius*sinf(phi)*cosf(theta); D3DXVec3Normalize(&v.normal, &v.pos); v.texC.x = theta / (2.0f*PI); v.texC.y = phi / PI; vertices.push_back( v ); } } // poles: note that there will be texture coordinate distortion vertices.push_back( Vertex(0.0f, -mRadius, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f) ); vertices.push_back( Vertex(0.0f, mRadius, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f) ); UINT northPoleIndex = (UINT)vertices.size()-1; UINT southPoleIndex = (UINT)vertices.size()-2; UINT numRingVertices = mNumSlices+1; // Compute indices for inner stacks (not connected to poles). for(UINT i = 0; i < mNumStacks-2; ++i) { for(UINT j = 0; j < mNumSlices; ++j) { indices.push_back(i*numRingVertices + j); indices.push_back(i*numRingVertices + j+1); indices.push_back((i+1)*numRingVertices + j); indices.push_back((i+1)*numRingVertices + j); indices.push_back(i*numRingVertices + j+1); indices.push_back((i+1)*numRingVertices + j+1); } } // Compute indices for top stack. The top stack was written // first to the vertex buffer. for(UINT i = 0; i < mNumSlices; ++i) { indices.push_back(northPoleIndex); indices.push_back(i+1); indices.push_back(i); } // Compute indices for bottom stack. The bottom stack was written // last to the vertex buffer, so we need to offset to the index // of first vertex in the last ring. UINT baseIndex = (numRings-1)*numRingVertices; for(UINT i = 0; i < mNumSlices; ++i) { indices.push_back(southPoleIndex); indices.push_back(baseIndex+i); indices.push_back(baseIndex+i+1); } }
void Smooth::operator() (const Mesh& in, Mesh& out) const { std::unique_ptr<ProgressBar> progress; if (message.size()) progress.reset (new ProgressBar (message, 8)); out.clear(); const size_t V = in.num_vertices(); if (!V) return; if (in.num_quads()) throw Exception ("For now, mesh smoothing is only supported for triangular meshes"); const size_t T = in.num_triangles(); if (V == 3*T) throw Exception ("Cannot perform smoothing on this mesh: no triangulation information"); // Pre-compute polygon centroids and areas VertexList centroids; vector<default_type> areas; for (TriangleList::const_iterator p = in.triangles.begin(); p != in.triangles.end(); ++p) { centroids.push_back ((in.vertices[(*p)[0]] + in.vertices[(*p)[1]] + in.vertices[(*p)[2]]) * (1.0/3.0)); areas.push_back (area (in, *p)); } if (progress) ++(*progress); // Perform pre-calculation of an appropriate mesh neighbourhood for each vertex // Use knowledge of the connections between vertices provided by the triangles/quads to // perform an iterative search outward from each vertex, selecting a subset of // polygons for each vertex // Extent of window should be approximately the value of spatial_factor, though only an // approximate windowing is likely to be used (i.e. number of iterations) // // Initialisation is different to iterations: Need a single pass to find those // polygons that actually use the vertex vector< std::set<uint32_t> > vert_polys (V, std::set<uint32_t>()); // For each vertex, don't just want to store the polygons within the neighbourhood; // also want to store those that will be expanded from in the next iteration vector< vector<uint32_t> > vert_polys_to_expand (V, vector<uint32_t>()); for (uint32_t t = 0; t != T; ++t) { for (uint32_t i = 0; i != 3; ++i) { vert_polys[(in.triangles[t])[i]].insert (t); vert_polys_to_expand[(in.triangles[t])[i]].push_back (t); } } if (progress) ++(*progress); // Now, we want to expand this selection outwards for each vertex // To do this, also want to produce a list for each polygon: containing those polygons // that share a common edge (i.e. two vertices) vector< vector<uint32_t> > poly_neighbours (T, vector<uint32_t>()); for (uint32_t i = 0; i != T; ++i) { for (uint32_t j = i+1; j != T; ++j) { if (in.triangles[i].shares_edge (in.triangles[j])) { poly_neighbours[i].push_back (j); poly_neighbours[j].push_back (i); } } } if (progress) ++(*progress); // TODO Will want to develop a better heuristic for this for (size_t iter = 0; iter != 8; ++iter) { for (uint32_t v = 0; v != V; ++v) { // Find polygons at the outer edge of this expanding front, and add them to the neighbourhood for this vertex vector<uint32_t> next_front; for (vector<uint32_t>::const_iterator front = vert_polys_to_expand[v].begin(); front != vert_polys_to_expand[v].end(); ++front) { for (vector<uint32_t>::const_iterator expansion = poly_neighbours[*front].begin(); expansion != poly_neighbours[*front].end(); ++expansion) { const std::set<uint32_t>::const_iterator existing = vert_polys[v].find (*expansion); if (existing == vert_polys[v].end()) { vert_polys[v].insert (*expansion); next_front.push_back (*expansion); } } } vert_polys_to_expand[v] = std::move (next_front); } } if (progress) ++(*progress); // Need to perform a first mollification pass, where the polygon normals are // smoothed but the vertices are not perturbed // However, in order to calculate these new normals, we need to calculate new vertex positions! VertexList mollified_vertices; // Use half standard spatial factor for mollification // Denominator = 2(SF/2)^2 const default_type spatial_mollification_power_multiplier = -2.0 / Math::pow2 (spatial); // No need to normalise the Gaussian; have to explicitly normalise afterwards for (uint32_t v = 0; v != V; ++v) { Vertex new_pos (0.0, 0.0, 0.0); default_type sum_weights = 0.0; // For now, just use every polygon as part of the estimate // Eventually, restrict this to some form of mesh neighbourhood //for (size_t i = 0; i != centroids.size(); ++i) { for (std::set<uint32_t>::const_iterator it = vert_polys[v].begin(); it != vert_polys[v].end(); ++it) { const uint32_t i = *it; default_type this_weight = areas[i]; const default_type distance_sq = (centroids[i] - in.vertices[v]).squaredNorm(); this_weight *= std::exp (distance_sq * spatial_mollification_power_multiplier); const Vertex prediction = centroids[i]; new_pos += this_weight * prediction; sum_weights += this_weight; } new_pos *= (1.0 / sum_weights); mollified_vertices.push_back (new_pos); } if (progress) ++(*progress); // Have new vertices; compute polygon normals based on these vertices Mesh mollified_mesh; mollified_mesh.load (mollified_vertices, in.triangles); VertexList tangents; for (TriangleList::const_iterator p = mollified_mesh.triangles.begin(); p != mollified_mesh.triangles.end(); ++p) tangents.push_back (normal (mollified_mesh, *p)); if (progress) ++(*progress); // Now perform the actual smoothing const default_type spatial_power_multiplier = -0.5 / Math::pow2 (spatial); const default_type influence_power_multiplier = -0.5 / Math::pow2 (influence); for (size_t v = 0; v != V; ++v) { Vertex new_pos (0.0, 0.0, 0.0); default_type sum_weights = 0.0; //for (size_t i = 0; i != centroids.size(); ++i) { for (std::set<uint32_t>::const_iterator it = vert_polys[v].begin(); it != vert_polys[v].end(); ++it) { const uint32_t i = *it; default_type this_weight = areas[i]; const default_type distance_sq = (centroids[i] - in.vertices[v]).squaredNorm(); this_weight *= std::exp (distance_sq * spatial_power_multiplier); const default_type prediction_distance = (centroids[i] - in.vertices[v]).dot (tangents[i]); const Vertex prediction = in.vertices[v] + (tangents[i] * prediction_distance); this_weight *= std::exp (Math::pow2 (prediction_distance) * influence_power_multiplier); new_pos += this_weight * prediction; sum_weights += this_weight; } new_pos *= (1.0 / sum_weights); out.vertices.push_back (new_pos); } if (progress) ++(*progress); out.triangles = in.triangles; // If the vertex normals were calculated previously, re-calculate them if (in.have_normals()) out.calculate_normals(); }