void collectFaceVertices(Mesh& m) { for (int i = 0; i < m.getNumFaces(); ++i) { Mesh::Face f = m.getFace(i); vector<Cvec3> vertices; for (int j = 0; j < f.getNumVertices(); ++j) { vertices.push_back(f.getVertex(j).getPosition()); } m.setNewFaceVertex(f, getFaceVertex(vertices)); } }
static void applySubdivs(Mesh &mesh, int subdivLevel) { for (int i = 0; i < subdivLevel; i++) { // subdivide faces for (int j = 0, n = mesh.getNumFaces(); j < n; j++) { Mesh::Face face = mesh.getFace(j); int verticesAroundFace = face.getNumVertices(); Cvec3 vertexSum = Cvec3(); for (int k = 0; k < verticesAroundFace; k++) { vertexSum += face.getVertex(k).getPosition(); } vertexSum = vertexSum * (1.0 / verticesAroundFace); mesh.setNewFaceVertex(face, vertexSum); } // subdivide edges for (int j = 0, n = mesh.getNumEdges(); j < n; j++) { Mesh::Edge edge = mesh.getEdge(j); Cvec3 vertexSum = (edge.getVertex(0).getPosition() + edge.getVertex(1).getPosition() + mesh.getNewFaceVertex(edge.getFace(0)) + mesh.getNewFaceVertex(edge.getFace(1))) * 0.25; mesh.setNewEdgeVertex(edge, vertexSum); } // subdivide vertices for (int j = 0, n = mesh.getNumVertices(); j < n; j++) { Mesh::Vertex v = mesh.getVertex(j); int numOfVertices = 0; Mesh::VertexIterator vertexIter(v.getIterator()), iterOrigin(vertexIter); Cvec3 accumVertices = Cvec3(); Cvec3 accumFaceVertices = Cvec3(); do { accumVertices += vertexIter.getVertex().getPosition(); accumFaceVertices += mesh.getNewFaceVertex(vertexIter.getFace()); numOfVertices++; } while (++vertexIter != iterOrigin); double factor = 1.0 / (numOfVertices * numOfVertices); Cvec3 vertexVertex = v.getPosition() * ((numOfVertices - 2.0) / numOfVertices) + accumVertices * factor + accumFaceVertices * factor; mesh.setNewVertexVertex(mesh.getVertex(j), vertexVertex); } // subdivide for each level of subdivision we need mesh.subdivide(); } }
static void simpleShadeCube(Mesh& mesh) { Cvec3 normal = Cvec3(0, 1, 0); for (int i = 0; i < mesh.getNumFaces(); ++i) { const Mesh::Face f = mesh.getFace(i); Cvec3 facenorm = f.getNormal(); for (int j = 0; j < f.getNumVertices(); ++j) { const Mesh::Vertex v = f.getVertex(j); v.setNormal(facenorm); } } }
bool Mesh::verify_same_direction(Mesh::Face current_face, Point3D vertices[], Point3D& point, Vector3D& normal) { bool is_same_direction = false; // Make sure the intersect face is pointing to the same direction for (unsigned int i = 0; i < current_face.size(); i++) { is_same_direction = ((vertices[(i + 1) % current_face.size()] - vertices[i]).cross( point - vertices[i]).dot(normal)) >= 0; if (!is_same_direction) { break; } } return is_same_direction; }
static void initCubeMesh() { if (!meshLoaded) { cubeMesh.load("./cube.mesh"); meshLoaded = true; } // set normals shadeCube(cubeMesh); // collect vertices from each face and map quads to triangles vector<VertexPN> verts; for (int i = 0; i < cubeMesh.getNumFaces(); ++i) { const Mesh::Face f = cubeMesh.getFace(i); Cvec3 pos; Cvec3 normal; if (g_flat) normal = f.getNormal(); for (int j = 0; j < f.getNumVertices(); ++j) { const Mesh::Vertex v = f.getVertex(j); pos = v.getPosition(); if (!g_flat) normal = v.getNormal(); verts.push_back(VertexPN(pos, normal)); if (j == 2) { verts.push_back(VertexPN(pos, normal)); } } const Mesh::Vertex v = f.getVertex(0); pos = v.getPosition(); if (!g_flat) normal = v.getNormal(); verts.push_back(VertexPN(pos, normal)); } // add vertices to cube geometry int numVertices = verts.size(); if (!g_cubeGeometryPN) { g_cubeGeometryPN.reset(new SimpleGeometryPN()); } g_cubeGeometryPN->upload(&verts[0], numVertices); }
static vector<VertexPN> getMeshVertices(Mesh &mesh) { vector<VertexPN> vertices; for (int i = 0, n = mesh.getNumFaces(); i < n; i++) { Mesh::Face face = mesh.getFace(i); Cvec3 normals[3]; for (int j = 1; j < face.getNumVertices() - 1; j++) { if (g_smoothShadeOn) { normals[0] = face.getVertex(0).getNormal(); normals[1] = face.getVertex(j).getNormal(); normals[2] = face.getVertex(j+1).getNormal(); } else { normals[0] = normals[1] = normals[2] = face.getNormal(); } vertices.push_back(VertexPN(face.getVertex(0).getPosition(), normals[0])); vertices.push_back(VertexPN(face.getVertex(j).getPosition(), normals[1])); vertices.push_back(VertexPN(face.getVertex(j+1).getPosition(), normals[2])); } } return vertices; }
static void updateShellGeometry() { float xs[] = {0, g_hairyness, 0}; float ys[] = {0, 0, g_hairyness}; vector<Cvec3> prevPos; prevPos.resize(g_bunnyMesh.getNumFaces() * 3); for (int level = 0; level < g_numShells; ++level) { int counter = 0; vector<VertexPNX> verts; for (int i = 0; i < g_bunnyMesh.getNumFaces(); ++i) { const Mesh::Face f = g_bunnyMesh.getFace(i); for (int j = 0; j < f.getNumVertices(); ++j) { const Mesh::Vertex v = f.getVertex(j); int index = v.getIndex(); Cvec3 pos = v.getPosition(); Cvec3 normal = v.getNormal(); Cvec2 c = Cvec2(xs[j], ys[j]); Cvec3 n = normal * g_furHeight / g_numShells; Cvec3 s = pos + (n * g_numShells); Cvec3 t = world2bunny(g_tipPos[index]); Cvec3 d = (t - s) / ((g_numShells + 1) * g_numShells / 2); /* Cvec3 d = (world2bunny(g_tipPos[index]) - (normal * g_furHeight)) / (g_numShells - 1); */ if (level == 0) { prevPos[counter] = pos; verts.push_back(VertexPNX(pos, n, c)); } else { Cvec3 new_position = prevPos[counter] + n + (d * level); verts.push_back(VertexPNX(new_position, new_position - prevPos[counter], c)); prevPos[counter] = new_position; } ++counter; } } int numVertices = verts.size(); g_bunnyShellGeometries[level]->upload(&verts[0], numVertices); verts.clear(); } }
bool Mesh::faceIntersection( const Ray& ray, HitRecord* hitRecord, const Mesh::Face& face) { // Get a point on the plane Vector3D norm; double t; { const auto& p0 = m_verts[face[0]]; const auto& p1 = m_verts[face[1]]; const auto& p2 = m_verts[face[face.size()-1]]; norm = (p1 - p0).cross(p2 - p0); auto rayNorm = ray.dir.dot(norm); // Parallel if (isZero(rayNorm)) return false; t = (p0 - ray.start).dot(norm) / rayNorm; // No intersection if (t < 0 || isZero(t)) { return false; } } // Intersection point auto planePt = ray.at(t); // Now check if planePt is "left" of everything for (size_t i = 0; i < face.size(); ++i) { // Go over points in order const auto& p1 = m_verts[face[i]]; const auto& p2 = m_verts[face[(i + 1) % face.size()]]; // from p1 to p2 const auto side = p2 - p1; // cross from p1 to plane pt and dot against normal auto k = norm.dot(side.cross(planePt - p1)); if (!isZero(k) && k < 0) { // Zero means on the side; negative means opposite dir from norm return false; } } // Update if this is a better t value return hitRecord->update(norm, planePt, t); }
static void initBunnyMeshes() { g_bunnyMesh.load("bunny.mesh"); // TODO: Init the per vertex normal of g_bunnyMesh, using codes from asst7 // ... shadeCube(g_bunnyMesh); // cout << "Finished shading bunny" << endl; // TODO: Initialize g_bunnyGeometry from g_bunnyMesh, similar to vector<VertexPN> verts; for (int i = 0; i < g_bunnyMesh.getNumFaces(); ++i) { const Mesh::Face f = g_bunnyMesh.getFace(i); Cvec3 pos; Cvec3 normal; if (g_flat) normal = f.getNormal(); for (int j = 0; j < f.getNumVertices(); ++j) { const Mesh::Vertex v = f.getVertex(j); pos = v.getPosition(); if (!g_flat) normal = v.getNormal(); verts.push_back(VertexPN(pos, normal)); } } // add vertices to bunny geometry int numVertices = verts.size(); g_bunnyGeometry.reset(new SimpleGeometryPN()); g_bunnyGeometry->upload(&verts[0], numVertices); // Now allocate array of SimpleGeometryPNX to for shells, one per layer g_bunnyShellGeometries.resize(g_numShells); for (int i = 0; i < g_numShells; ++i) { g_bunnyShellGeometries[i].reset(new SimpleGeometryPNX()); } }
static void shadeCube(Mesh& mesh) { Cvec3 normal = Cvec3(0, 0, 0); for (int i = 0; i < mesh.getNumVertices(); ++i) { mesh.getVertex(i).setNormal(normal); } for (int i = 0; i < mesh.getNumFaces(); ++i) { const Mesh::Face f = mesh.getFace(i); Cvec3 facenorm = f.getNormal(); for (int j = 0; j < f.getNumVertices(); ++j) { const Mesh::Vertex v = f.getVertex(j); v.setNormal(facenorm + v.getNormal()); } } for (int i = 0; i < mesh.getNumVertices(); ++i) { const Mesh::Vertex v = mesh.getVertex(i); if (norm2(v.getNormal()) > .001) { v.setNormal(normalize(v.getNormal())); } } }
static void loadMeshGeometry(Mesh& m, GeometryPX& g) { vector<GLfloat> pos, tex; for (int i = 0; i < m.getNumFaces(); ++i) { const Mesh::Face f = m.getFace(i); for (int j = 0; j < f.getNumVertices(); ++j) { const Mesh::Vertex v = f.getVertex(j); pos.push_back((GLfloat)(v.getPosition()[0])); pos.push_back((GLfloat)(v.getPosition()[1])); tex.push_back((GLfloat)v.getTexCoords()[0]); tex.push_back((GLfloat)v.getTexCoords()[1]); } } const unsigned int size = pos.size() * sizeof(GLfloat); glBindBuffer(GL_ARRAY_BUFFER, g.posVbo); glBufferData(GL_ARRAY_BUFFER, size, NULL, GL_DYNAMIC_DRAW); glBufferSubData(GL_ARRAY_BUFFER, 0, size, &pos[0]); checkGlErrors(); glBindBuffer(GL_ARRAY_BUFFER, g.texVbo); glBufferData(GL_ARRAY_BUFFER, size, NULL, GL_DYNAMIC_DRAW); glBufferSubData(GL_ARRAY_BUFFER, 0, size, &tex[0]); checkGlErrors(); }
static void animateCube(int ms) { float t = (float) ms / (float) g_msBetweenKeyFrames; // scale all vertices in cube for (int i = 0; i < cubeMesh.getNumVertices(); ++i) { const Mesh::Vertex v = cubeMesh.getVertex(i); Cvec3 pos = v.getPosition(); double factor = (1 + (float(g_div_level)/10)) * ((-1 * sin((double) (g_horiz_scale * ms) / (1000 * (vertex_speeds[i] + .5))) + 1) / 2 + .5); pos[0] = vertex_signs[i][0] * (factor / sqrt(3)); pos[1] = vertex_signs[i][1] * (factor / sqrt(3)); pos[2] = vertex_signs[i][2] * (factor / sqrt(3)); v.setPosition(pos); } // copy mesh to temporary mesh for rendering Mesh renderMesh = cubeMesh; // subdivision for (int i = 0; i < g_div_level; ++i) { collectFaceVertices(renderMesh); collectEdgeVertices(renderMesh); collectVertexVertices(renderMesh); renderMesh.subdivide(); } // set normals shadeCube(renderMesh); // collect vertices for each face vector<VertexPN> verts; int q = 0; for (int i = 0; i < renderMesh.getNumFaces(); ++i) { const Mesh::Face f = renderMesh.getFace(i); Cvec3 pos; Cvec3 normal; for (int j = 0; j < f.getNumVertices(); ++j) { const Mesh::Vertex v = f.getVertex(j); pos = v.getPosition(); if (!g_flat) normal = v.getNormal(); else normal = f.getNormal(); verts.push_back(VertexPN(pos, normal)); if (j == 2) { verts.push_back(VertexPN(pos, normal)); } } const Mesh::Vertex v = f.getVertex(0); pos = v.getPosition(); if (!g_flat) normal = v.getNormal(); else normal = f.getNormal(); verts.push_back(VertexPN(pos, normal)); } // dump into geometry int numVertices = verts.size(); g_cubeGeometryPN->upload(&verts[0], numVertices); glutPostRedisplay(); glutTimerFunc(1000/g_animateFramesPerSecond, animateCube, ms + 1000/g_animateFramesPerSecond); }