void SkeletonModel::updateAttitude(const glm::quat& orientation) { setTranslation(_owningAvatar->getSkeletonPosition()); setRotation(orientation * Quaternions::Y_180); setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningAvatar->getModelScale()); }
void ConstraintsNode::applyConstrainedTranslation(osg::Vec3 v) { osg::Vec3 localPos = this->getTranslation(); osg::ref_ptr<ReferencedNode> hitNode; ReferencedNode *testNode; // with really big velocities (or small enclosures), and if the surface // doesn't damp the velocity, it's possible to get see an infinite recursion // occur. So, we keep a recursionCounter, and stop prevent this occurrence: if (++recursionCounter > 10) return; /* std::cout << std::endl << "checking for collisions" << std::endl; std::cout << "start = " << localPos.x()<<","<<localPos.y()<<","<<localPos.z() << std::endl; std::cout << "v = " << v.x()<<","<<v.y()<<","<<v.z() << std::endl; */ osg::ref_ptr<ReferencedNode> targetNode = dynamic_cast<ReferencedNode*>(_target->s_thing); if (targetNode.valid()) { // get current position (including offset from previous bounces) osg::Matrix thisMatrix = osg::computeLocalToWorld(this->currentNodePath); osg::Vec3 worldPos = thisMatrix.getTrans(); // set up intersector: osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector = new osgUtil::LineSegmentIntersector(worldPos, worldPos + v); osgUtil::IntersectionVisitor iv(intersector.get()); // apply intersector: targetNode->accept(iv); if (intersector->containsIntersections()) { osgUtil::LineSegmentIntersector::Intersections intersections; osgUtil::LineSegmentIntersector::Intersections::iterator itr; intersections = intersector->getIntersections(); for (itr = intersections.begin(); itr != intersections.end(); ++itr) { //std::cout << "testing intersection with " << (*itr).nodePath[0]->getName() << std::endl; // first check if the hit is with our target (should be first in // the nodepath): testNode = dynamic_cast<ReferencedNode*>((*itr).nodePath[0]); if (testNode!=targetNode) continue; // The intersection has a nodepath that we have to walk down to // see which exact node has been hit. It's possible that there // are other SPIN nodes in the targetNode's subgraph that are // the real source of intersection: hitNode = 0; testNode = 0; for (unsigned int i=0; i<(*itr).nodePath.size(); i++) { testNode = dynamic_cast<ReferencedNode*>((*itr).nodePath[i]); if (testNode) hitNode = testNode; } if (hitNode.valid()) { //std::cout << id->s_name << " collision!!! with " << (*itr).drawable->getName() << "[" << (*itr).primitiveIndex << "] @ " << std::endl; //std::cout << "localHitPoint:\t" << localHitPoint.x()<<","<<localHitPoint.y()<<","<<localHitPoint.z() << std::endl; //std::cout << "localHitNormal:\t" << localHitNormal.x()<<","<<localHitNormal.y()<<","<<localHitNormal.z() << std::endl; // For BOUNCE mode, we need to check if we've intersected // with the same primitive again. This may occur since we // do recursive translations after repositioning the node at // the bounce point (and there may be numerical imprecision) // If so, we skip this intersection: if ((_mode==BOUNCE) && (lastDrawable.get()==(*itr).drawable.get()) && (lastPrimitiveIndex==(int)(*itr).primitiveIndex)) { //std::cout << "... skipping" << std::endl; continue; } else { lastDrawable=(*itr).drawable; lastPrimitiveIndex=(*itr).primitiveIndex; } osg::Vec3 localHitPoint = (*itr).getWorldIntersectPoint(); osg::Vec3 localHitNormal = (*itr).getWorldIntersectNormal(); localHitNormal.normalize(); // current direction vector: osg::Vec3 dirVec = v; dirVec.normalize(); // Find the rotation between the direction vector and the // surface normal at the hit point: osg::Quat rot; rot.makeRotate(dirVec, localHitNormal); //std::cout << "rot = " << rot.x()<<","<<rot.y()<<","<<rot.z()<<","<<rot.w() << " ... angle=" << acos(rot.w())*2 << ", indegrees=" << osg::RadiansToDegrees(acos(rot.w()))*2 << std::endl; // the surface normal may be in the opposite direction // from us. If so, we need to flip it: if (acos(rot.w()) * 2 > osg::PI_2) { localHitNormal *= -1; rot.makeRotate(dirVec, localHitNormal); //std::cout << "flipped = " << rot.x()<<","<<rot.y()<<","<<rot.z()<<","<<rot.w() << " ... angle=" << acos(rot.w())*2 << ", indegrees=" << osg::RadiansToDegrees(acos(rot.w()))*2 << std::endl; } osg::Vec3 rotEulers = QuatToEuler(rot); //std::cout << "newHitNormal:\t" << localHitNormal.x()<<","<<localHitNormal.y()<<","<<localHitNormal.z() << std::endl; if ((_mode==COLLIDE)||(_mode==COLLIDE_THRU)||(_mode==STICK)) { // Let the collisionPoint be just a bit before the real // hitpoint (to avoid numerical imprecision placing the // node behind the plane): osg::Vec3 collisionPoint = localHitPoint - (localHitNormal * 0.01); // place the node at the collision point setTranslation(collisionPoint.x(), collisionPoint.y(), collisionPoint.z()); BROADCAST(this, "ssfff", "collide", hitNode->id->s_name, osg::RadiansToDegrees(rotEulers.x()), osg::RadiansToDegrees(rotEulers.y()), osg::RadiansToDegrees(rotEulers.z())); if (_mode==COLLIDE) { // SLIDE along the hit plane with the left over energy: // ie, project the remaining vector onto the surface we // just intersected with. // // using: // cos(theta) = distToSurface / remainderVector length // double cosTheta = (dirVec * -localHitNormal) ; // dot product osg::Vec3 remainderVector = (localPos + v) - localHitPoint; double distToSurface = cosTheta * remainderVector.length(); osg::Vec3 slideVector = remainderVector + (localHitNormal * distToSurface); // pseudo-recursively apply remainder of bounce: applyConstrainedTranslation( slideVector ); } else if (_mode==COLLIDE_THRU) { // allow the node to pass thru (ie, just apply the // translation): //setTranslation(v.x(), v.y(), v.z()); osg::Vec3 newPos = localPos + v; setTranslation(newPos.x(), newPos.y(), newPos.z()); } return; } else if (_mode==BOUNCE) { // bounce returns a translation mirrored about the hit // normal to the surface // the new direction vector is a rotated version // of the original, about the localHitNormal: //osg::Vec3 newDir = (rot * 2.0) * -dirVec; osg::Vec3 newDir = (rot * (rot * -dirVec)); newDir.normalize(); //std::cout << "newDir = " << newDir.x()<<","<<newDir.y()<<","<<newDir.z() << std::endl; // amount of distance still to travel after bounce: double dist = v.length() - (localHitPoint-localPos).length(); //std::cout << "dist = " << dist << std::endl; // in node is translating (ie, changing position // independently from it's orientatino), then we need to // flip the velocity vector. if (_velocityMode == GroupNode::TRANSLATE) { osg::Vec3 newVel = newDir * _velocity.length(); setVelocity(newVel.x(), newVel.y(), newVel.z()); } // if the node is moving along it's orientation vector, // we need to update the orientation of so that it // points in 'bounced' direction else if (_velocityMode == GroupNode::MOVE) { osg::Quat newQuat; newQuat.makeRotate(osg::Vec3(0,1,0), newDir); osg::Vec3 newRot = Vec3inDegrees(QuatToEuler(newQuat)); //std::cout << "newrot = " << newRot.x()<<","<<newRot.y()<<","<<newRot.z() << std::endl; setOrientation(newRot.x(), newRot.y(), newRot.z()); } // the new position will be just a hair before hitpoint // (because numerical imprecision may place the hitpoint // slightly beyond the surface, and when we bounce the // node, we don't want to intersect with the same // surface again) double HAIR = 0.0000001; setTranslation(localHitPoint.x()-dirVec.x()*HAIR, localHitPoint.y()-dirVec.y()*HAIR, localHitPoint.z()-dirVec.z()*HAIR); //setTranslation(localHitPoint.x(), localHitPoint.y(), localHitPoint.z()); //std::cout << "rotEulers = " << osg::RadiansToDegrees(rotEulers.x())<<","<<osg::RadiansToDegrees(rotEulers.y())<<","<<osg::RadiansToDegrees(rotEulers.z()) << std::endl; BROADCAST(this, "ssfff", "bounce", hitNode->id->s_name, osg::RadiansToDegrees(rotEulers.x()), osg::RadiansToDegrees(rotEulers.y()), osg::RadiansToDegrees(rotEulers.z())); // pseudo-recursively apply remainder of bounce: applyConstrainedTranslation(newDir*dist); return; } } } } //else std::cout << "no intersections" << std::endl; } // no intersections, so just do regular translation: osg::Vec3 newPos = localPos + v; setTranslation(newPos.x(), newPos.y(), newPos.z()); }
void Matrix44F::setTranslation(const Vector3F& p) { setTranslation( p.x, p.y, p.z); }
void TangramPieces::setPos(float px, float py, float pz, glm::quat q){ setRotation(q); setTranslation(px, py, pz); }
void TangramPieces::resetPos(float x, float y, float z, glm::quat q) { setTranslation(x, y, z); setRotation(q); }
void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { setTranslation(_owningAvatar->getSkeletonPosition()); static const glm::quat refOrientation = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); setRotation(_owningAvatar->getOrientation() * refOrientation); setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningAvatar->getScale()); setBlendshapeCoefficients(_owningAvatar->getHead()->getBlendshapeCoefficients()); Model::simulate(deltaTime, fullUpdate); if (!isActive() || !_owningAvatar->isMyAvatar()) { return; // only simulate for own avatar } MyAvatar* myAvatar = static_cast<MyAvatar*>(_owningAvatar); if (myAvatar->isPlaying()) { // Don't take inputs if playing back a recording. return; } const FBXGeometry& geometry = _geometry->getFBXGeometry(); PrioVR* prioVR = Application::getInstance()->getPrioVR(); if (prioVR->isActive()) { for (int i = 0; i < prioVR->getJointRotations().size(); i++) { int humanIKJointIndex = prioVR->getHumanIKJointIndices().at(i); if (humanIKJointIndex == -1) { continue; } int jointIndex = geometry.humanIKJointIndices.at(humanIKJointIndex); if (jointIndex != -1) { JointState& state = _jointStates[jointIndex]; state.setRotationInBindFrame(prioVR->getJointRotations().at(i), PALM_PRIORITY); } } return; } // find the left and rightmost active palms int leftPalmIndex, rightPalmIndex; Hand* hand = _owningAvatar->getHand(); hand->getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex); const float HAND_RESTORATION_RATE = 0.25f; if (leftPalmIndex == -1 || rightPalmIndex == -1) { // palms are not yet set, use mouse if (_owningAvatar->getHandState() == HAND_STATE_NULL) { restoreRightHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY); } else { // transform into model-frame glm::vec3 handPosition = glm::inverse(_rotation) * (_owningAvatar->getHandPosition() - _translation); applyHandPosition(geometry.rightHandJointIndex, handPosition); } restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY); } else if (leftPalmIndex == rightPalmIndex) { // right hand only applyPalmData(geometry.rightHandJointIndex, hand->getPalms()[leftPalmIndex]); restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY); } else { applyPalmData(geometry.leftHandJointIndex, hand->getPalms()[leftPalmIndex]); applyPalmData(geometry.rightHandJointIndex, hand->getPalms()[rightPalmIndex]); } _boundingShape.setTranslation(_translation + _rotation * _boundingShapeLocalOffset); _boundingShape.setRotation(_rotation); }
//=========================================== // Entity::assignData //=========================================== void Entity::assignData(const XmlNode data) { if (data.isNull() || data.name() != "Entity") return; AssetManager assetManager; ShapeFactory shapeFactory; try { bool silent = isSilent(); setSilent(true); XmlAttribute attr = data.firstAttribute(); if (!attr.isNull() && attr.name() == "type") { m_type = internString(attr.getString()); attr = attr.nextAttribute(); } if (!attr.isNull() && attr.name() == "name") { m_name = internString(attr.getString()); attr = attr.nextAttribute(); } Vec2f transl = m_transl; if (!attr.isNull() && attr.name() == "x") { transl.x = attr.getFloat(); attr = attr.nextAttribute(); } if (!attr.isNull() && attr.name() == "y") { transl.y = attr.getFloat(); attr = attr.nextAttribute(); } setTranslation(transl); if (!attr.isNull() && attr.name() == "z") { m_z = attr.getFloat(); // So that no Z values are 'exactly' equal m_z += 0.1f * static_cast<float32_t>(rand()) / static_cast<float32_t>(RAND_MAX); attr = attr.nextAttribute(); } XmlNode node = data.firstChild(); if (!node.isNull() && node.name() == "shape") { m_shape = unique_ptr<Shape>(shapeFactory.create(node.firstChild())); node = node.nextSibling(); } if (!node.isNull() && node.name() == "scale") { setScale(Vec2f(node.firstChild())); node = node.nextSibling(); } if (!attr.isNull() && attr.name() == "rot") { setRotation(attr.getFloat()); } if (!node.isNull() && node.name() == "fillColour") { m_fillColour = Colour(node.firstChild()); node = node.nextSibling(); } if (!node.isNull() && node.name() == "lineColour") { m_lineColour = Colour(node.firstChild()); node = node.nextSibling(); } if (!node.isNull() && node.name() == "lineWidth") { m_lineWidth = node.getInt(); node = node.nextSibling(); } if (!node.isNull() && node.name() == "children") { XmlNode node_ = node.firstChild(); while (!node_.isNull() && node_.name() == "child") { XmlAttribute attr = node_.firstAttribute(); if (!attr.isNull() && attr.name() == "ptr") { long id = attr.getLong(); pEntity_t child = boost::dynamic_pointer_cast<Entity>(assetManager.getAssetPointer(id)); if (!child) throw XmlException("Bad entity asset id", __FILE__, __LINE__); addChild(child); } node_ = node_.nextSibling(); } } setSilent(silent); } catch (XmlException& e) { e.prepend("Error parsing XML for instance of class Entity; "); throw; } recomputeBoundary(); }
/** * @brief Overloaded setTranslation function. * @see Camera3D::setTranslation( const QVector3D& t ) * * @param[in] x The new x-axis location. * @param[in] y The new y-axis location. * @param[in] z The new z-axis location. */ void Camera3D::setTranslation( float x, float y, float z ) { setTranslation( QVector3D( x, y, z ) ); }
void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { setTranslation(_owningAvatar->getSkeletonPosition()); static const glm::quat refOrientation = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); setRotation(_owningAvatar->getOrientation() * refOrientation); setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningAvatar->getScale()); setBlendshapeCoefficients(_owningAvatar->getHead()->getBlendshapeCoefficients()); Model::simulate(deltaTime, fullUpdate); if (!isActive() || !_owningAvatar->isMyAvatar()) { return; // only simulate for own avatar } MyAvatar* myAvatar = static_cast<MyAvatar*>(_owningAvatar); if (myAvatar->isPlaying()) { // Don't take inputs if playing back a recording. return; } const FBXGeometry& geometry = _geometry->getFBXGeometry(); // find the left and rightmost active palms int leftPalmIndex, rightPalmIndex; Hand* hand = _owningAvatar->getHand(); hand->getLeftRightPalmIndices(leftPalmIndex, rightPalmIndex); const float HAND_RESTORATION_RATE = 0.25f; if (leftPalmIndex == -1 && rightPalmIndex == -1) { // palms are not yet set, use mouse if (_owningAvatar->getHandState() == HAND_STATE_NULL) { restoreRightHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY); } else { // transform into model-frame glm::vec3 handPosition = glm::inverse(_rotation) * (_owningAvatar->getHandPosition() - _translation); applyHandPosition(geometry.rightHandJointIndex, handPosition); } restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY); } else if (leftPalmIndex == rightPalmIndex) { // right hand only applyPalmData(geometry.rightHandJointIndex, hand->getPalms()[leftPalmIndex]); restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY); } else { if (leftPalmIndex != -1) { applyPalmData(geometry.leftHandJointIndex, hand->getPalms()[leftPalmIndex]); } else { restoreLeftHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY); } if (rightPalmIndex != -1) { applyPalmData(geometry.rightHandJointIndex, hand->getPalms()[rightPalmIndex]); } else { restoreRightHandPosition(HAND_RESTORATION_RATE, PALM_PRIORITY); } } if (_isFirstPerson) { cauterizeHead(); updateClusterMatrices(); } _boundingShape.setTranslation(_translation + _rotation * _boundingShapeLocalOffset); _boundingShape.setRotation(_rotation); }
void gTranslate(GContext *context, const float vector[2]) { setTranslation(context, vector[0],vector[1]); }
void Scene::setTranslation(double x, double y, double z) { setTranslation(Translation(x, y, z)); }
void Transform::setAnimationPropertyValue(int propertyId, AnimationValue* value, float blendWeight) { GP_ASSERT(value); GP_ASSERT(blendWeight >= 0.0f && blendWeight <= 1.0f); switch (propertyId) { case ANIMATE_SCALE_UNIT: { float scale = Curve::lerp(blendWeight, _scale.x, value->getFloat(0)); setScale(scale); break; } case ANIMATE_SCALE: { setScale(Curve::lerp(blendWeight, _scale.x, value->getFloat(0)), Curve::lerp(blendWeight, _scale.y, value->getFloat(1)), Curve::lerp(blendWeight, _scale.z, value->getFloat(2))); break; } case ANIMATE_SCALE_X: { setScaleX(Curve::lerp(blendWeight, _scale.x, value->getFloat(0))); break; } case ANIMATE_SCALE_Y: { setScaleY(Curve::lerp(blendWeight, _scale.y, value->getFloat(0))); break; } case ANIMATE_SCALE_Z: { setScaleZ(Curve::lerp(blendWeight, _scale.z, value->getFloat(0))); break; } case ANIMATE_ROTATE: { applyAnimationValueRotation(value, 0, blendWeight); break; } case ANIMATE_TRANSLATE: { setTranslation(Curve::lerp(blendWeight, _translation.x, value->getFloat(0)), Curve::lerp(blendWeight, _translation.y, value->getFloat(1)), Curve::lerp(blendWeight, _translation.z, value->getFloat(2))); break; } case ANIMATE_TRANSLATE_X: { setTranslationX(Curve::lerp(blendWeight, _translation.x, value->getFloat(0))); break; } case ANIMATE_TRANSLATE_Y: { setTranslationY(Curve::lerp(blendWeight, _translation.y, value->getFloat(0))); break; } case ANIMATE_TRANSLATE_Z: { setTranslationZ(Curve::lerp(blendWeight, _translation.z, value->getFloat(0))); break; } case ANIMATE_ROTATE_TRANSLATE: { applyAnimationValueRotation(value, 0, blendWeight); setTranslation(Curve::lerp(blendWeight, _translation.x, value->getFloat(4)), Curve::lerp(blendWeight, _translation.y, value->getFloat(5)), Curve::lerp(blendWeight, _translation.z, value->getFloat(6))); break; } case ANIMATE_SCALE_ROTATE: { setScale(Curve::lerp(blendWeight, _scale.x, value->getFloat(0)), Curve::lerp(blendWeight, _scale.y, value->getFloat(1)), Curve::lerp(blendWeight, _scale.z, value->getFloat(2))); applyAnimationValueRotation(value, 3, blendWeight); break; } case ANIMATE_SCALE_TRANSLATE: { setScale(Curve::lerp(blendWeight, _scale.x, value->getFloat(0)), Curve::lerp(blendWeight, _scale.y, value->getFloat(1)), Curve::lerp(blendWeight, _scale.z, value->getFloat(2))); setTranslation(Curve::lerp(blendWeight, _translation.x, value->getFloat(3)), Curve::lerp(blendWeight, _translation.y, value->getFloat(4)), Curve::lerp(blendWeight, _translation.z, value->getFloat(5))); break; } case ANIMATE_SCALE_ROTATE_TRANSLATE: { setScale(Curve::lerp(blendWeight, _scale.x, value->getFloat(0)), Curve::lerp(blendWeight, _scale.y, value->getFloat(1)), Curve::lerp(blendWeight, _scale.z, value->getFloat(2))); applyAnimationValueRotation(value, 3, blendWeight); setTranslation(Curve::lerp(blendWeight, _translation.x, value->getFloat(7)), Curve::lerp(blendWeight, _translation.y, value->getFloat(8)), Curve::lerp(blendWeight, _translation.z, value->getFloat(9))); break; } default: break; } }
void cEntity::initialize(sVector3 const& pos, float radian, bool isSceneObject, bool isSyncHeight) { m_isSceneObject = isSceneObject; setTranslation(pos, radian, isSyncHeight); }
void InputMoveComponent::update( float dt ) { auto comp = parent->getComponent<TransformComponent>(); comp->setTranslation( comp->getTranslation() + glm::vec3( 0, (GetAsyncKeyState('W')?1:0) - (GetAsyncKeyState('S')?1:0), (GetAsyncKeyState('D')?1:0) - (GetAsyncKeyState('A')?1:0) )*4.0f*dt ); }
void MayaCamera::Update(float timestep) { (void)timestep; // Track mouse motion int2 mousePos; GetCursorPos((POINT *)&mousePos); int2 mouseMove = mousePos - m_mousePosPrev; m_mousePosPrev = mousePos; // Handle mouse rotation if (m_mbuttonCur == MBUTTON_Left) { m_yaw -= m_rotateSpeed * mouseMove.x; m_yaw = modPositive(m_yaw, 2.0f*pi); m_pitch -= m_rotateSpeed * mouseMove.y; m_pitch = clamp(m_pitch, -0.5f*pi, 0.5f*pi); } // Retrieve controller state XINPUT_STATE controllerState = {}; float2 controllerLeftStick(0.0f), controllerRightStick(0.0f); float controllerLeftTrigger = 0.0f, controllerRightTrigger = 0.0f; if (m_controllerPresent) { // Look out for disconnection if (XInputGetState(0, &controllerState) == ERROR_SUCCESS) { // Decode axes and apply dead zones controllerLeftTrigger = float(max(0, controllerState.Gamepad.bLeftTrigger - XINPUT_GAMEPAD_TRIGGER_THRESHOLD)) / float(255 - XINPUT_GAMEPAD_TRIGGER_THRESHOLD); controllerRightTrigger = float(max(0, controllerState.Gamepad.bRightTrigger - XINPUT_GAMEPAD_TRIGGER_THRESHOLD)) / float(255 - XINPUT_GAMEPAD_TRIGGER_THRESHOLD); controllerLeftStick = float2(controllerState.Gamepad.sThumbLX, controllerState.Gamepad.sThumbLY); float lengthLeft = length(controllerLeftStick); if (lengthLeft > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) controllerLeftStick = (controllerLeftStick / lengthLeft) * (lengthLeft - XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) / float(32768 - XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); else controllerLeftStick = float2(0.0f); controllerRightStick = float2(controllerState.Gamepad.sThumbRX, controllerState.Gamepad.sThumbRY); float lengthRight = length(controllerRightStick); if (lengthRight > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) controllerRightStick = (controllerRightStick / lengthRight) * (lengthRight - XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) / float(32768 - XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE); else controllerRightStick = float2(0.0f); } else { m_controllerPresent = false; } } // Handle controller rotation if (m_controllerPresent) { m_yaw -= m_controllerRotateSpeed * controllerRightStick.x * abs(controllerRightStick.x) * timestep; m_yaw = modPositive(m_yaw, 2.0f*pi); m_pitch += m_controllerRotateSpeed * controllerRightStick.y * abs(controllerRightStick.y) * timestep; m_pitch = clamp(m_pitch, -0.5f*pi, 0.5f*pi); } UpdateOrientation(); // Handle zoom if (m_mbuttonCur == MBUTTON_Right) { m_radius *= expf(mouseMove.y * m_zoomSpeed); } m_radius *= expf(-m_wheelDelta * m_zoomWheelSpeed); m_wheelDelta = 0; // Handle controller zoom if (m_controllerPresent && !(controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER)) { m_radius *= expf(-controllerLeftStick.y * abs(controllerLeftStick.y) * m_controllerZoomSpeed * timestep); } // Handle motion of target point if (m_mbuttonCur == MBUTTON_Middle) { m_posTarget -= m_rotateSpeed * mouseMove.x * m_radius * m_viewToWorld[0].xyz; m_posTarget += m_rotateSpeed * mouseMove.y * m_radius * m_viewToWorld[1].xyz; } // Handle controller motion of target point if (m_controllerPresent && (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER)) { float3 localVelocity(0.0f); localVelocity.x = controllerLeftStick.x * abs(controllerLeftStick.x); localVelocity.y = square(controllerRightTrigger) - square(controllerLeftTrigger); localVelocity.z = -controllerLeftStick.y * abs(controllerLeftStick.y); m_posTarget += xfmVector(localVelocity, m_viewToWorld) * (m_radius * m_controllerMoveSpeed * timestep); } // Calculate remaining matrices m_pos = m_posTarget + m_radius * m_viewToWorld[2].xyz; setTranslation(&m_viewToWorld, m_pos); UpdateWorldToClip(); }
void FPSCamera::Update(float timestep) { // Track mouse motion int2 mousePos; GetCursorPos((POINT *)&mousePos); int2 mouseMove = mousePos - m_mousePosPrev; m_mousePosPrev = mousePos; // Handle mouse rotation if (m_mbuttonActivate == MBUTTON_None || m_mbuttonCur == m_mbuttonActivate) { m_yaw -= m_rotateSpeed * mouseMove.x; m_yaw = modPositive(m_yaw, 2.0f*pi); m_pitch -= m_rotateSpeed * mouseMove.y; m_pitch = clamp(m_pitch, -0.5f*pi, 0.5f*pi); } // Retrieve controller state XINPUT_STATE controllerState = {}; float2 controllerLeftStick(0.0f), controllerRightStick(0.0f); float controllerLeftTrigger = 0.0f, controllerRightTrigger = 0.0f; if (m_controllerPresent) { // Look out for disconnection if (XInputGetState(0, &controllerState) == ERROR_SUCCESS) { // Decode axes and apply dead zones controllerLeftTrigger = float(max(0, controllerState.Gamepad.bLeftTrigger - XINPUT_GAMEPAD_TRIGGER_THRESHOLD)) / float(255 - XINPUT_GAMEPAD_TRIGGER_THRESHOLD); controllerRightTrigger = float(max(0, controllerState.Gamepad.bRightTrigger - XINPUT_GAMEPAD_TRIGGER_THRESHOLD)) / float(255 - XINPUT_GAMEPAD_TRIGGER_THRESHOLD); controllerLeftStick = float2(controllerState.Gamepad.sThumbLX, controllerState.Gamepad.sThumbLY); float lengthLeft = length(controllerLeftStick); if (lengthLeft > XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) controllerLeftStick = (controllerLeftStick / lengthLeft) * (lengthLeft - XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE) / float(32768 - XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE); else controllerLeftStick = float2(0.0f); controllerRightStick = float2(controllerState.Gamepad.sThumbRX, controllerState.Gamepad.sThumbRY); float lengthRight = length(controllerRightStick); if (lengthRight > XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) controllerRightStick = (controllerRightStick / lengthRight) * (lengthRight - XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE) / float(32768 - XINPUT_GAMEPAD_RIGHT_THUMB_DEADZONE); else controllerRightStick = float2(0.0f); } else { m_controllerPresent = false; } } // Handle controller rotation if (m_controllerPresent) { m_yaw -= m_controllerRotateSpeed * controllerRightStick.x * abs(controllerRightStick.x) * timestep; m_yaw = modPositive(m_yaw, 2.0f*pi); m_pitch += m_controllerRotateSpeed * controllerRightStick.y * abs(controllerRightStick.y) * timestep; m_pitch = clamp(m_pitch, -0.5f*pi, 0.5f*pi); } UpdateOrientation(); // Handle translation // !!!UNDONE: acceleration based on how long you've been holding the button, // to make fine motions easier? float moveStep = timestep * m_moveSpeed; // !!!UNDONE: move keyboard tracking into an input system that respects focus, etc. if (GetAsyncKeyState(VK_SHIFT) || (controllerState.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER)) moveStep *= 3.0f; if (GetAsyncKeyState('W')) m_pos -= m_viewToWorld[2].xyz * moveStep; if (GetAsyncKeyState('S')) m_pos += m_viewToWorld[2].xyz * moveStep; if (GetAsyncKeyState('A')) m_pos -= m_viewToWorld[0].xyz * moveStep; if (GetAsyncKeyState('D')) m_pos += m_viewToWorld[0].xyz * moveStep; if (GetAsyncKeyState('E')) m_pos += m_viewToWorld[1].xyz * moveStep; if (GetAsyncKeyState('C')) m_pos -= m_viewToWorld[1].xyz * moveStep; if (m_controllerPresent) { float3 localVelocity(0.0f); localVelocity.x = controllerLeftStick.x * abs(controllerLeftStick.x); localVelocity.y = square(controllerRightTrigger) - square(controllerLeftTrigger); localVelocity.z = -controllerLeftStick.y * abs(controllerLeftStick.y); m_pos += xfmVector(localVelocity, m_viewToWorld) * (moveStep * m_controllerMoveSpeed); } // Calculate remaining matrices setTranslation(&m_viewToWorld, m_pos); UpdateWorldToClip(); }