static void lookAtOrigin() { // Set angle to look at the origin Cvec3 eye = g_eyeRbt.getTranslation(); Cvec3 up = Cvec3(0,1,0); g_eyeRbt.setRotation(Quat().makeXRotation(lookAt(eye,up))); }
static void motion(const int x, const int y) { const double dx = x - g_mouseClickX; const double dy = g_windowHeight - y - 1 - g_mouseClickY; //Matrix4 m; RigTForm m; if (g_mouseLClickButton && !g_mouseRClickButton) { // left button down? //m = Matrix4::makeXRotation(-dy) * Matrix4::makeYRotation(dx); m = m.setRotation( Quat::makeXRotation(-dy) * Quat::makeYRotation(dx) ); } else if (g_mouseRClickButton && !g_mouseLClickButton) { // right button down? //m = Matrix4::makeTranslation(Cvec3(dx, dy, 0) * 0.01); m = m.setTranslation(Cvec3(dx, dy, 0) * 0.01); } else if (g_mouseMClickButton || (g_mouseLClickButton && g_mouseRClickButton)) { // middle or (left and right) button down? //m = Matrix4::makeTranslation(Cvec3(0, 0, -dy) * 0.01); m = m.setTranslation(Cvec3(0, 0, -dy) * 0.01); } if (g_mouseClickDown) { //noInterfaceRotation(m); arcBallRotation(m); glutPostRedisplay(); // we always redraw if we changed the scene } g_mouseClickX = x; g_mouseClickY = g_windowHeight - y - 1; }
/*-----------------------------------------------*/ static void initCamera() { Cvec3 eye = Cvec3(0.0, 3.0, 10.0); Cvec3 at = Cvec3(0.0, 0.0, 0.0); Cvec3 up = Cvec3(0.0,1.0,0.0); //g_skyRbt = lookAt(eye, at, up); // Default camera g_skyRbt.setRotation(Quat().makeXRotation(lookAt(eye,up))); g_eyeRbt = g_skyRbt; }
static void readFrameDataFromFile() { ifstream myfile; string line; myfile.open("animation.txt"); getline(myfile, line); int num_frames = atoi(line.c_str()); getline(myfile, line); int num_nodes = atoi(line.c_str()); printf("%d %d\n", num_frames, num_nodes); keyframeList.clear(); for (int i = 0; i < num_frames; i++) { RigTFormVector frame; for (int j = 0; j < num_nodes; j++) { RigTForm node; Cvec3 translation; Quat rotation; std::string line; std::getline(myfile, line); std::stringstream stream(line); for (int k = 0; k < 3; k++) { double cvec_double; stream >> cvec_double; translation[k] = cvec_double; } for (int l = 0; l < 4; l++) { double quat_double; stream >> quat_double; rotation[l] = quat_double; } printf("\n"); node.setTranslation(translation); node.setRotation(rotation); frame.push_back(node); } keyframeList.push_back(frame); } g_currentKeyframe = keyframeList.begin(); copyCurrentKeyframe(); myfile.close(); }
static void motion(const int x, const int y) { const double dx = x - g_mouseClickX; const double dy = g_windowHeight - y - 1 - g_mouseClickY; //initialize the outCenter and outRadius for the screenSpaceCircle Cvec2 outCenter; double outRadius; //initialize the projection matrix for the screenSpaceCircle const Matrix4 projmat = Matrix4::makeProjection( g_frustFovY, g_windowWidth / static_cast <double> (g_windowHeight), g_frustNear, g_frustFar); if(currentView == 0) eyeRbt = g_skyRbt; else if (currentView == 1) eyeRbt = g_objectRbt[0]; else eyeRbt = g_objectRbt[1]; //gets the center for the screenSpaceCircle by passing in the center of the sphere in eye-coordinates Cvec3 center = (inv(eyeRbt) * g_objectRbt[2]).getTranslation(); //getsthe screenSpaceCircle getScreenSpaceCircle(center, 1, projmat, g_frustNear, g_frustFovY, g_windowWidth, g_windowHeight, outCenter, outRadius); //get the two screen space vectors Cvec2 p1((g_mouseClickX+dx)-outCenter(0), (dy + g_mouseClickY)-outCenter(1)); Cvec2 p2(g_mouseClickX-outCenter(0), g_mouseClickY-outCenter(1)); //clamp if we go outside the radius of the sphere double dist1 = sqrt(pow(p1(0),2) + pow(p1(1),2)); if(dist1 > outRadius){ p1 = p1 * outRadius/(dist1+10); //+10 to avoid random rounding errors and stuff } double dist2 = sqrt(pow(p2(0),2) + pow(p2(1),2)); if (dist2 > outRadius){ p2 = p2 * outRadius/(dist2+10); } //Z-components for the projection double currentZ = sqrt(pow(outRadius,2) - pow(p1(0),2) - pow(p1(1),2)); double transZ = sqrt(pow(outRadius,2) - pow(p2(0),2) - pow(p2(1),2)); //create two vectors for each mouse click with the tails at the origin of the sphere Cvec3 currentV(p1, currentZ); Cvec3 transV(p2, transZ); //create two quaternions with normalized vectors Quat qV1(0, normalize(currentV)); Quat qV2(0, normalize(transV)); //calculate the rotation quaternion Quat Q = qV2 * inv(qV1); RigTForm m; if (g_mouseLClickButton && !g_mouseRClickButton){ // left button down? m.setRotation(Q); //set the rotation quaternion } else if (g_mouseRClickButton && !g_mouseLClickButton) { // right button down? if(currentObj==2 && currentAuxFrame==0) m.setTranslation(Cvec3(dx, dy, 0) * -0.01); else m.setTranslation(Cvec3(dx, dy, 0) * 0.01); } else if (g_mouseMClickButton || (g_mouseLClickButton && g_mouseRClickButton)) { // middle or (left and right) button down? m.setTranslation(Cvec3(0, 0, -dy) * 0.01); } RigTForm auxFrame; //initialize the auxillary frame if (g_mouseClickDown) { if(currentObj != 2){ m.setRotation(inv(m.getRotation())); auxFrame.setTranslation(g_objectRbt[currentObj].getTranslation()); auxFrame.setRotation(eyeRbt.getRotation()); g_objectRbt[currentObj] = auxFrame * m * inv(auxFrame) * g_objectRbt[currentObj];//rotate around the object frame, translate around the sky frame } else if (currentObj == 2 && currentAuxFrame == 0){ auxFrame.setRotation(eyeRbt.getRotation()); g_skyRbt = auxFrame * m * inv(auxFrame) * g_skyRbt; //world-sky aux frame } else if (currentObj == 2 && currentAuxFrame == 1){ auxFrame.setTranslation(eyeRbt.getTranslation()); auxFrame.setRotation(eyeRbt.getRotation()); g_skyRbt = auxFrame * m * inv(auxFrame) * g_skyRbt; //sky-sky aux frame } glutPostRedisplay(); // we always redraw if we change the scene } g_mouseClickX = x; g_mouseClickY = g_windowHeight - y - 1; }
static void drawStuff() { // short hand for current shader state const ShaderState& curSS = *g_shaderStates[g_activeShader]; // build & send proj. matrix to vshader const Matrix4 projmat = makeProjectionMatrix(); sendProjectionMatrix(curSS, projmat); // assign eye rigid body matrix; //Matrix4 eyeRbt; RigTForm eyeRbt; switch(viewState){ case 0: eyeRbt = g_skyRbt; break; case 1: eyeRbt = g_objRbt[0]; break; case 2: eyeRbt = g_objRbt[1]; break; } const RigTForm invEyeRbt = inv(eyeRbt); const Cvec3 eyeLight1 = Cvec3(invEyeRbt * Cvec4(g_light1, 1)); // g_light1 position in eye coordinates const Cvec3 eyeLight2 = Cvec3(invEyeRbt * Cvec4(g_light2, 1)); // g_light2 position in eye coordinates safe_glUniform3f(curSS.h_uLight, eyeLight1[0], eyeLight1[1], eyeLight1[2]); safe_glUniform3f(curSS.h_uLight2, eyeLight2[0], eyeLight2[1], eyeLight2[2]); // draw ground // =========== // //const Matrix4 groundRbt = Matrix4(); // identity const RigTForm groundRbt; Matrix4 MVM = rigTFormToMatrix(invEyeRbt * groundRbt); Matrix4 NMVM = normalMatrix(MVM); sendModelViewNormalMatrix(curSS, MVM, NMVM); safe_glUniform3f(curSS.h_uColor, 0.1, 0.95, 0.1); // set color g_ground->draw(curSS); // draw cubes // ========== //MVM = invEyeRbt * g_objectRbt[0]; MVM = rigTFormToMatrix(inv(eyeRbt) * g_objRbt[0]); NMVM = normalMatrix(MVM); sendModelViewNormalMatrix(curSS, MVM, NMVM); safe_glUniform3f(curSS.h_uColor, g_objectColors[0][0], g_objectColors[0][1], g_objectColors[0][2]); g_cube->draw(curSS); //MVM = invEyeRbt * g_objectRbt[1]; MVM = rigTFormToMatrix(inv(eyeRbt) * g_objRbt[1]); NMVM = normalMatrix(MVM); sendModelViewNormalMatrix(curSS, MVM, NMVM); safe_glUniform3f(curSS.h_uColor, g_objectColors[1][0], g_objectColors[1][1], g_objectColors[1][2]); g_cube->draw(curSS); // draw arcball // ============ // fix scale and you're good to go //g_arcballScale = getScreenToEyeScale(0, g_frustFovY, g_windowHeight); g_arcballScale = 1; switch(manipState){ case 0: g_sphereRbt.setTranslation(Cvec3(0,0,0)); break; case 1: g_sphereRbt.setTranslation(g_objRbt[0].getTranslation()); g_sphereRbt.setRotation(g_objRbt[0].getRotation()); break; case 2: g_sphereRbt.setTranslation(g_objRbt[1].getTranslation()); g_sphereRbt.setRotation(g_objRbt[1].getRotation()); break; } glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); // draw wireframe // compute MVM, taking into account the dynamic radius float scale = g_arcballScale * g_arcballScreenRadius; MVM = rigTFormToMatrix(inv(eyeRbt) * g_sphereRbt) * g_arcballScale; NMVM = normalMatrix(MVM); // send MVM and NMVM and colors sendModelViewNormalMatrix(curSS, MVM, NMVM); safe_glUniform3f(curSS.h_uColor, g_objectColors[2][0], g_objectColors[2][1], g_objectColors[2][2]); g_sphere->draw(curSS); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); }
/*-----------------------------------------------*/ static void animateCamera(int value) { static float stopwatch = 0; float msecsPerFrame = 1/(g_framesPerSecond / 1000); static int animationPart = 0; static bool isAnimating = true; const static float stepsPerSecond = 10.0/2.0; // Time Allowed / Steps taken static float totalTime = stepsPerSecond * 1 * 1000; static float elapsedTime = 0; static float x; static float z; static float radius = g_eyeRbt.getTranslation()[2]; static float helperDegrees = 0; static float offsetDegrees = 90; static bool isFirstEntry = true; static RigTForm start = g_eyeRbt; static RigTForm end = RigTForm(g_eyeRbt.getTranslation(), Quat::makeYRotation(-180) * start.getRotation()); //static RigTForm end = RigTForm(); // Used to reset variables every time animation is run if (isFirstEntry) { start = g_eyeRbt; radius = g_eyeRbt.getTranslation()[2]; end = RigTForm(g_eyeRbt.getTranslation(), Quat::makeYRotation(-180) * start.getRotation()); isFirstEntry = false; //lookAtOrigin(); } //Handles which part of animation is currently running if (elapsedTime >= totalTime) { g_eyeRbt.setRotation(end.getRotation()); if (animationPart == 0) { start = end; end = RigTForm(g_eyeRbt.getTranslation(), Quat::makeYRotation(-180) * start.getRotation()); helperDegrees = 180; } else { glutPostRedisplay(); isAnimating = false; } //Reset values to default totalTime = stepsPerSecond * 1 * 1000; elapsedTime = 0; animationPart++; } if (isAnimating) { float alpha = elapsedTime / totalTime; ///* //Handle Translation Interpolation Cvec3 startVec = g_eyeRbt.getTranslation(); float degree = ((alpha * 180) + helperDegrees) + offsetDegrees; float toRadians = CS175_PI / 180.0; x = cos(degree * toRadians) * radius; z = sin(degree * toRadians) * radius; g_eyeRbt.setTranslation(Cvec3(x,g_eyeRbt.getTranslation()[1],z)); //*/ // Initial rotations Quat startQ = start.getRotation(); // Final rotations Quat endQ = end.getRotation(); // Handle Rotational Interpolation if (g_interpolationType == I_POWER) // Quaternion Powering { if (endQ - startQ != Quat(0,0,0,0)) // Check for actual rotation { Quat currentQ = Quat::pow(endQ, alpha); g_eyeRbt.setRotation(startQ * currentQ); // Apply rotation with respect to starting Position //Double rotates } } else if (g_interpolationType == I_SLERP) //Spherical linear interpolation { //startQ = inv(Quat()) * startQ;// * Quat(); //endQ = inv(Quat()) * endQ;// * Quat(); g_eyeRbt.setRotation(Quat::slerp(startQ, endQ, alpha) * startQ); } else if (g_interpolationType == I_LERP) { //Normalize quaternions Quat q = normalize(Quat::lerp(startQ, endQ, alpha)); g_eyeRbt.setRotation(q); } elapsedTime += msecsPerFrame; glutPostRedisplay(); //Time total animation stopwatch += msecsPerFrame; glutTimerFunc(msecsPerFrame, animateCamera, 0); } else { isAnimating = true; //cout << "Stopwatch Camera = " << (stopwatch - msecsPerFrame * 2) / 1000 << "\n"; // Display final time not counting first and last frame stopwatch = 0; animationPart = 0; helperDegrees = 0; isFirstEntry = true; glutPostRedisplay(); } }
/*-----------------------------------------------*/ static void animateLegs(int value) { static float stopwatch = 0; float msecsPerFrame = 1/(g_framesPerSecond / 1000); static int animationPart = 0; static bool isAnimating = true; const static float degreesPerStep = 30; const static float stepsPerSecond = 20.0/34.0; // Time Allowed / Steps taken RigTForm *leftLeg = &g_rigidBodies[0].children[0]->children[2]->children[2]->rtf; RigTForm *rightLeg = &g_rigidBodies[0].children[0]->children[2]->children[3]->rtf; static RigTForm startLeftLeg = *leftLeg; static RigTForm endLeftLeg = startLeftLeg; static RigTForm startRightLeg = *rightLeg; static RigTForm endRightLeg = startRightLeg; static float totalTime = stepsPerSecond * 1 * 1000; static float elapsedTime = totalTime; //Handles which part of animation is currently running if (elapsedTime >= totalTime) { leftLeg->setRotation(endLeftLeg.getRotation()); rightLeg->setRotation(endRightLeg.getRotation()); // Initialize with first step if (animationPart == 0) { startLeftLeg = endLeftLeg; startRightLeg = endRightLeg; endLeftLeg = RigTForm(Quat::makeXRotation(-degreesPerStep) * startLeftLeg.getRotation()); endRightLeg = RigTForm(Quat::makeXRotation(degreesPerStep) * startRightLeg.getRotation()); //cout << "endLeftLeg Angle = " << endLeftLeg.getRotation().getAngle() << "\n"; //cout << "endRightLeg Angle = " << endRightLeg.getRotation().getAngle() << "\n"; totalTime = stepsPerSecond * 0.5 * 1000; } else if (animationPart < 34) { startLeftLeg = endLeftLeg; startRightLeg = endRightLeg; if (animationPart %2 == 0) { endLeftLeg = RigTForm(Quat::makeXRotation(-degreesPerStep * 2) * startLeftLeg.getRotation()); endRightLeg = RigTForm(Quat::makeXRotation(degreesPerStep * 2) * startRightLeg.getRotation()); } else { endLeftLeg = RigTForm(Quat::makeXRotation(degreesPerStep * 2) * startLeftLeg.getRotation()); endRightLeg = RigTForm(Quat::makeXRotation(-degreesPerStep * 2) * startRightLeg.getRotation()); } //cout << "Degrees = " << degreesPerStep << "\n"; //cout << "endLeftLeg Angle = " << endLeftLeg.getRotation().getAngle() << "\n"; //cout << "endRightLeg Angle = " << endRightLeg.getRotation().getAngle() << "\n"; totalTime = stepsPerSecond * 1 * 1000; } else if (animationPart == 34) { startLeftLeg = endLeftLeg; startRightLeg = endRightLeg; endLeftLeg = RigTForm(Quat()); endRightLeg = RigTForm(Quat()); totalTime = stepsPerSecond * 0.5 * 1000; } else { glutPostRedisplay(); isAnimating = false; //Reset values to default startLeftLeg = *leftLeg; startRightLeg = *rightLeg; totalTime = stepsPerSecond * 1 * 1000; } animationPart++; elapsedTime = 0; } if (isAnimating) { float alpha = elapsedTime / totalTime; // Initial rotations Quat startLeftLegQ = leftLeg->getRotation(); Quat startRightLegQ = rightLeg->getRotation(); // Final rotations Quat endLeftLegQ = endLeftLeg.getRotation(); Quat endRightLegQ = endRightLeg.getRotation(); // Handle Rotational Interpolation if (g_interpolationType == I_POWER) // Quaternion Powering { if (endLeftLegQ - startLeftLegQ != Quat(0,0,0,0)) // Check for actual rotation { Quat currentLeftLegQ = Quat::pow(endLeftLegQ, alpha); leftLeg->setRotation(startLeftLegQ * currentLeftLegQ); // Apply rotation with respect to starting Position //Double rotates } if (endRightLegQ - startRightLegQ != Quat(0,0,0,0)) // Check for actual rotation { Quat currentRightLegQ = Quat::pow(endRightLegQ, alpha); rightLeg->setRotation(startRightLegQ * currentRightLegQ); // Apply rotation with respect to starting Position //Double rotates } } else if (g_interpolationType == I_SLERP) //Spherical linear interpolation { leftLeg->setRotation(Quat::slerp(startLeftLegQ, endLeftLegQ, alpha) * startLeftLegQ); rightLeg->setRotation(Quat::slerp(startRightLegQ, endRightLegQ, alpha) * startRightLegQ); } else if (g_interpolationType == I_LERP) { //Normalize quaternions Quat leftLegQ = normalize(Quat::lerp(startLeftLegQ, endLeftLegQ, alpha)); Quat rightLegQ = normalize(Quat::lerp(startRightLegQ, endRightLegQ, alpha)); leftLeg->setRotation(leftLegQ); rightLeg->setRotation(rightLegQ); } elapsedTime += msecsPerFrame; glutPostRedisplay(); //Time total animation stopwatch += msecsPerFrame; glutTimerFunc(msecsPerFrame, animateLegs, 0); } else { isAnimating = true; //cout << "Stopwatch Legs = " << (stopwatch - msecsPerFrame * 2) / 1000 << "\n"; // Display final time not counting first and last frame stopwatch = 0; animationPart = 0; elapsedTime = totalTime; } }
/*-----------------------------------------------*/ static void keyboard(const unsigned char key, const int x, const int y) { /* PURPOSE: OpenGL Callback for Keyboard presses RECEIVES: unsigned char key - Key pressed int x - Mouse x_position when key pressed int y - Mouse y_position when key pressed REMARKS: Handles robot modifications based on key presses and then requests a redisplay */ if (isKeyboardActive) { switch (key) { case 27: exit(0); // ESC case 'i': cout << " ============== H E L P ==============\n\n" << "i\t\thelp menu\n" << "s\t\tsave screenshot\n" << "f\t\tToggle flat shading on/off.\n" << "o\t\tCycle object to edit\n" << "v\t\tCycle view\n" << "drag left mouse to rotate\n" << endl; break; case 's': glFlush(); writePpmScreenshot(g_windowWidth, g_windowHeight, "out.ppm"); break; case 'f': g_activeShader ^= 1; break; } if (key == '1') { g_framesPerSecond = 32; } else if (key == '2') { g_framesPerSecond = 16; } else if (key == '3') { g_framesPerSecond = 8; } else if (key == '4') { g_framesPerSecond = 4; } else if (key == '5') { g_framesPerSecond = 2; } else if (key == '6') { g_framesPerSecond = 1; } else if (key == '7') { g_framesPerSecond = 0.5; } else if (key == '8') { g_framesPerSecond = 0.25; } else if (key == '9') { g_framesPerSecond = 0.125; } if (key == 'q') { Quat q = g_rigidBodies[0].rtf.getRotation(); g_rigidBodies[0].rtf.setRotation(q * Quat::makeYRotation(15)); } else if (key == 'p') { g_interpolationType = I_POWER; } else if (key == 's') { g_interpolationType = I_SLERP; } else if (key == 'l') { g_interpolationType = I_LERP; } else if (key == 'r') { float msecs = 0 * 1000; glutTimerFunc(msecs, timer, PAUSE); glutTimerFunc(msecs, animateCamera,0); } else if (key == 'a') { float msecs = 0 * 1000; glutTimerFunc(msecs, animateRobot, 0); glutTimerFunc(msecs, animateLegs, 0); } else if (key == ',') { g_eyeRbt.setRotation(g_eyeRbt.getRotation() * Quat().makeZRotation(15)); } else if (key == '.') { g_eyeRbt.setRotation(g_eyeRbt.getRotation() * Quat().makeZRotation(-15)); } else if (key == '-') { float max = 20; Cvec3 cameraTrans = g_eyeRbt.getTranslation(); g_eyeRbt.setTranslation(cameraTrans + Cvec3(0,0,1)); if (cameraTrans[2] >= max) g_eyeRbt.setTranslation(Cvec3(cameraTrans[0], cameraTrans[1], max)); lookAtOrigin(); //cout << "( " << g_eyeRbt.getTranslation()[0] << ", " << g_eyeRbt.getTranslation()[1] << ", " << g_eyeRbt.getTranslation()[2] << "\n"; } else if (key == '=') { float min = 5; Cvec3 cameraTrans = g_eyeRbt.getTranslation(); g_eyeRbt.setTranslation(cameraTrans - Cvec3(0,0,1)); if (cameraTrans[2] <= min) g_eyeRbt.setTranslation(Cvec3(cameraTrans[0], cameraTrans[1], min)); lookAtOrigin(); //cout << "( " << g_eyeRbt.getTranslation()[0] << ", " << g_eyeRbt.getTranslation()[1] << ", " << g_eyeRbt.getTranslation()[2] << "\n"; } } glutPostRedisplay(); }