VR - spinning a globe

hexland
Posts: 1
Joined: Fri Jul 28, 2017 5:27 am

VR - spinning a globe

Post by hexland »

I'm mucking around in VR right now. In my world, I have a btRigidBody collision box representing my hand, and under kinematic control from the VR Device (setting position and rotation).
I also have a world globe (like those table top globes of the earth) that I want to be able to touch and spin.
The globe is constructed as a btRigidBody collision sphere, and is not kinematic. I also have the LinearFactor set to 0,0,0 to prevent it from moving. Angular factor is still 1,1,1.

I want to reach out and 'grab' the globe (using the controller, and check the button state to see if we're 'grabbing') - and *do something* to make the globe turn as I drag the controller across the surface.

I am unsure what that *do something* looks like. It's not an impulse or a force... it's almost as if I want to take the linear velocity of the controller and somehow apply that to the rotation of the globe -- but I don't know how to do that, or if that's the right approach. I did consider setting up a 6-dof constraint between the controller and the globe, but I don't think that will have the effect that I want (like if I try and flick/spin across the surface of the globe)

Any suggestions?
User avatar
drleviathan
Posts: 849
Joined: Tue Sep 30, 2014 6:03 pm
Location: San Francisco

Re: VR - spinning a globe

Post by drleviathan »

At the moment you make contact with the globe you do the following:

Code: Select all

// caputure globe transform and normalized direction from globe to hand:
btTransform globeTransform = globeBody->getTransform();
btVector3 oldHandDirection = (handBody->getTransform().getOrigin() - globeTransform.getOrigin()).normalize();
Then each frame where the hand moves the globe you do the following:

Code: Select all

// measure new normalied hand direction
btVector3 newHandDirection = (handBody->getTransform().getOrigin() - globeTransform.getOrigin()).normalize();

// compute the dot-product between the two directions:
//   a value of 1.0 means they are parallel and nothing needs to be done
//   anything less than 1.0 means there is a non-zero angle between them
btScalar cosAngle = newHandDirection.dot(oldHandDirection);
if (cosAngle < 1.0f) {
    // compute the shortest rotation from oldHandDirection to newHandDirection
    btVector3 axis = oldHandDirection.cross(newHandDirection).normalize();
    btScalar angle = acosf(cosAngle);
    btQuaternion deltaRotation(axis, angle);
    
    // the new rotation of the globe has an extra deltaRotation applied to it
    btTransform newGlobeTransform = globeBody->getTransform();
    btQuaternion globeRotation = deltaRotation * newGlobeTransform.getRotation(); // operate from the left by deltaRotation
    newGlobeTransform.setRotation(globeRotation);
    globeBody->setTransform(newGlobeTransform);
    
    // update oldHandDirection for next frame:
    oldHandDirection = newHandDirection;
}   
I dunno if that code compiles but it should be close. Beware of division by zero when you put the hand at the very center of the globe. Good luck.