VR - spinning a globe

Post Reply
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.
Post Reply