// Specifying shell geometries based on g_tipPos, g_furHeight, and g_numShells. // You need to call this function whenver the shell needs to be updated static void updateShellGeometry() { // TASK 1 and 3 TODO: finish this function as part of Task 1 and Task 3 int numVertices = g_bunnyMesh.getNumVertices(); g_bunnyMeshCopy = Mesh(g_bunnyMesh); createSmoothNormals(g_bunnyMeshCopy); RigTForm path = getPathAccumRbt(g_world, g_bunnyNode); for(int i = 0; i < g_numShells; i++) { // iterate through each vertex in the mesh for(int j = 0; j < numVertices; j++) { Cvec3 normal = g_bunnyMesh.getVertex(j).getNormal(); Cvec3 n = normal * (((double) g_furHeight) / g_numShells); Cvec3 s = (path * RigTForm(g_tipAtRest[j])).getTranslation(); Cvec3 d = (g_tipPos[j] - s) * (2.0 / (g_numShells * (g_numShells - 1))); Mesh::Vertex v = g_bunnyMeshCopy.getVertex(j); Cvec3 vPos = v.getPosition(); Cvec3 newPos = vPos + (n + (d * (i+1))); v.setPosition(newPos); v.setNormal(newPos - vPos); } uploadMeshToSimpleGeometryPNX(g_bunnyMeshCopy, *(g_bunnyShellGeometries[i]), g_hairyness); } }
//animation timer for mesh static void animateMeshCallback(int whocares) { g_meshObject = Mesh(g_meshObjectCopy); //update animation data, geometry for(int i = 0; i < 8; ++i){ float ang = g_meshAnimationAngle[i]; ang += (g_meshAnimationSpeed * g_meshAngleSpeed[i]); //between 0 and PI if(ang >= M_PI) ang = 0; g_meshAnimationAngle[i] = ang; //between 0 and 1 float scale = sin(ang); //between 0.5 and 3 float lowerBound = 0.5, upperBound = 3.0; scale = lowerBound + (scale * (upperBound - lowerBound)); //update geometry Mesh::Vertex v = g_meshObject.getVertex(i); Cvec3 vPos = v.getPosition(); //multiply by scale v.setPosition(vPos * scale); } //subdivide modified g_meshObject subdivideMesh(g_meshObject, g_meshSubdivisionLvl); //upload geometry uploadMeshGeometry(); //redraw! glutPostRedisplay(); glutTimerFunc(1000/g_animateFramesPerSecond, animateMeshCallback, 0); }
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); }