/*-----------------------------------------------*/ 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(); }
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); // use the skyRbt as the eyeRbt const RigTForm eyeRbt = *g_currViewRbt; 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 RigTForm groundRbt = RigTForm(); // identity 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 = rigTFormToMatrix(invEyeRbt * g_objectRbt[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 = rigTFormToMatrix(invEyeRbt * g_objectRbt[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 //============ if(g_showArcBall){ RigTForm arcballEye = inv(*g_currViewRbt); arcballEye = arcballEye * getArcBallRBT(); //if not zooming if (!(g_mouseMClickButton || (g_mouseLClickButton && g_mouseRClickButton))){ double depth = arcballEye.getTranslation()[2]; g_arcBallScale = getScreenToEyeScale(depth, g_frustFovY, g_windowHeight); } double alpha = g_arcBallScale* g_arcBallScreenRadius; //g_objectRbt[2] = RigTForm(g_objectRbt[2].getTranslation(),g_objectRbt[2].getRotation()*alpha); MVM = rigTFormToMatrix( arcballEye) * Matrix4::makeScale(Cvec3(1,1,1)*alpha); NMVM = normalMatrix(MVM); sendModelViewNormalMatrix(curSS, MVM, NMVM); safe_glUniform3f(curSS.h_uColor, g_objectColors[2][0], g_objectColors[2][1], g_objectColors[2][2]); glPolygonMode( GL_FRONT_AND_BACK, GL_LINE); g_arcBall->draw(curSS); glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); } }
//true on intersection, will populate passed Cvec3 pointer with intersection point bool PhysicsSim::intersect_sphere_plane(shared_ptr<HasPhysicsBody> sphere, shared_ptr<HasPhysicsBody> plane, Cvec3* intersectionPoint) { SphericalPhysicsBody *spherePb = dynamic_cast<SphericalPhysicsBody *>(sphere->getPhysicsBody()); shared_ptr<SgTransformNode> sphereNode = dynamic_pointer_cast<SgTransformNode>(sphere); PlanarPhysicsBody *planePb = dynamic_cast<PlanarPhysicsBody *>(plane->getPhysicsBody()); shared_ptr<SgTransformNode> planeNode = dynamic_pointer_cast<SgTransformNode>(plane); //assert sphere and plane! assert(spherePb != NULL && sphereNode != NULL); assert(planePb != NULL && planeNode != NULL); Cvec3 sphereCenter = getPathAccumRbt(rootNode_, sphereNode).getTranslation(); RigTForm planeRtf = getPathAccumRbt(rootNode_, planeNode); Cvec3 planeNormal = planeRtf.getRotation() * planePb->getUnitNormal(); //line is a line perp. to plane passing through sphere center Cvec3 intersection = Cvec3(); bool doesIntersect = intersect_line_plane( sphereCenter, planeNormal, planeRtf.getTranslation(), planeNormal, &intersection ); //constructed to be perp. assert(doesIntersect); Cvec3 perpVecFromCtrToPlane = intersection - sphereCenter; float distFromCtrToPlane = norm(perpVecFromCtrToPlane); //if the closest dist. from the center of the sphere to the plane //is less than radius, then collision. Otherwise, no. if(distFromCtrToPlane <= spherePb->getRadius()) { //TODO: check that intersection lies within bounds of finite plane //first: find quat from x-axis to the normal that has had the RigTForm's quat applied //use this quat to transform the y and z axes //get the intersection point relative to planar center //apply the inverse quat from the first part //check that abs(y) and ans(z) components are less than width/2 and height/2!! Quat fromXAxisToNormal; if(abs(dot(planeNormal, Cvec3(1, 0, 0))) - 1 < CS175_EPS2) { //normal is parallel to x-axis //Case 1: opposite if(dot(planeNormal, Cvec3(1, 0, 0)) < 0) { fromXAxisToNormal = Quat::makeZRotation(2 * M_PI); } else {//Case 2:on the axis fromXAxisToNormal = Quat::makeZRotation(0); } } else { //then it's valid to do general formula //from v1 to v2 Cvec3 a = cross(Cvec3(1, 0, 0), planeNormal); fromXAxisToNormal[0] = a[0]; fromXAxisToNormal[1] = a[1]; fromXAxisToNormal[2] = a[2]; fromXAxisToNormal[3] = sqrt(norm2(planeNormal)) + planeNormal[0]; } Quat fromNormalToXAxis = inv(fromXAxisToNormal); Cvec3 intersectionOnXAxis = fromNormalToXAxis * (intersection - planeRtf.getTranslation()); if(abs(intersectionOnXAxis[1] <= planePb->getWidth()/2 && intersectionOnXAxis[2] <= planePb->getHeight()/2)) { //fix sphere position to be firmly outside of plane! float overlap = spherePb->getRadius() - distFromCtrToPlane; Cvec3 offset = planeNormal * overlap; sphereNode->setRbt(sphereNode->getRbt() * RigTForm(offset)); //intersection within bounds! (*intersectionPoint) = intersection; return true; } else return false; } else return false; }
//called on mouse motion 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 mRbt; if (g_mouseLClickButton && !g_mouseRClickButton && !g_spaceDown) { // left button down? if (g_arcballVisible){ mRbt = RigTForm(arcballRotation(x, y)); } else { mRbt = RigTForm(Quat::makeXRotation(-dy) * Quat::makeYRotation(dx)); } } else if (g_mouseRClickButton && !g_mouseLClickButton) { // right button down? if (g_arcballVisible) { mRbt = RigTForm(Cvec3(dx, dy, 0) * g_arcballScale); } else { mRbt = RigTForm(Cvec3(dx, dy, 0) * 0.01); } } else if (g_mouseMClickButton || (g_mouseLClickButton && g_mouseRClickButton) || (g_mouseLClickButton && !g_mouseRClickButton && g_spaceDown)) { // middle or (left and right, or left + space) button down? if (g_arcballVisible) { mRbt = RigTForm(Cvec3(0, 0, -dy) * g_arcballScale); } else { mRbt = RigTForm(Cvec3(0, 0, -dy) * 0.01); } } buildAFrame(); if (g_mouseClickDown) { RigTForm curRbt = g_currentPickedRbtNode->getRbt(); if(g_currentPickedRbtNode == g_skyNode) { if (g_skyModMode == 0) { Quat rot = mRbt.getRotation(); mRbt = RigTForm(-(mRbt.getTranslation()), Quat(rot[0], -(rot[1]), -(rot[2]), -(rot[3]))); g_skyNode->setRbt(g_aFrame * mRbt * inv(g_aFrame) * curRbt); } else { Quat rot = mRbt.getRotation(); mRbt = RigTForm(mRbt.getTranslation(), Quat(rot[0], -(rot[1]), -(rot[2]), -(rot[3]))); g_skyNode->setRbt(g_aFrame * mRbt * inv(g_aFrame) * curRbt); } }else { //g_arcballRbt = g_aFrame * mRbt * inv(g_aFrame) * g_arcballRbt; RigTForm newAFrame = inv(getPathAccumRbt(g_world, g_currentPickedRbtNode, 1)) * g_aFrame; g_currentPickedRbtNode->setRbt(newAFrame * mRbt * inv(newAFrame) * curRbt); } glutPostRedisplay(); // we always redraw if we changed the scene } g_mouseClickX = x; g_mouseClickY = g_windowHeight - y - 1; }