77#include < iostream>
88
99Interaction_teleport::Interaction_teleport (vsg::ref_ptr<vsgvr::Instance> xrInstance,
10+ vsg::ref_ptr<vsgvr::SpaceBinding> headPose,
1011 vsg::ref_ptr<vsgvr::ActionPoseBinding> leftHandPose,
1112 vsg::ref_ptr<vsg::Switch> teleportTarget,
1213 vsg::ref_ptr<vsg::Group> ground)
13- : _leftHandPose(leftHandPose)
14+ : _headPose(headPose)
15+ , _leftHandPose(leftHandPose)
1416 , _teleportTarget(teleportTarget)
1517 , _ground(ground)
1618{
@@ -42,6 +44,9 @@ Interaction_teleport::~Interaction_teleport() {}
4244
4345void Interaction_teleport::frame (vsg::ref_ptr<vsg::Group> scene, Game& game, double deltaT)
4446{
47+ auto applyRotation = false ;
48+ auto applyTeleport = false ;
49+
4550 if (_teleportAction->getStateValid ())
4651 {
4752 auto state = _teleportAction->getStateBool ();
@@ -50,6 +55,7 @@ void Interaction_teleport::frame(vsg::ref_ptr<vsg::Group> scene, Game& game, dou
5055 _teleportButtonDown = true ;
5156 }
5257 }
58+
5359 double rotThresh = 0.25 ;
5460 if (_rotateAction->getStateValid ())
5561 {
@@ -62,11 +68,11 @@ void Interaction_teleport::frame(vsg::ref_ptr<vsg::Group> scene, Game& game, dou
6268 if (_rotateActionState != 0 )
6369 {
6470 _playerRotation += (- 15.0 * _rotateActionState);
65- game. userOrigin ()-> orientation = vsg::dquat ( vsg::radians (_playerRotation), { 0.0 , 0.0 , 1.0 }) ;
71+ applyRotation = true ;
6672 }
6773 }
6874 }
69-
75+
7076 if (_teleportButtonDown && _leftHandPose->getTransformValid ())
7177 {
7278 // Raycast from controller aim to world, colliding with anything named "ground"
@@ -79,8 +85,8 @@ void Interaction_teleport::frame(vsg::ref_ptr<vsg::Group> scene, Game& game, dou
7985
8086 auto intersector = vsg::LineSegmentIntersector::create (intersectStart, intersectEnd);
8187 // TODO: Intersect whole scene, or sub-scene matched on tags? For now we can't be anywhere but the ground plane
82- // TODO: Intersections appear to be in reverse-distance order. Should double check this but intersections.back()
83- // seems to always get the ground plane ( and not fences, trees, houses, or the underside of the ground plane .
88+ // TODO: Should sort intersections as well - For now intersections.back() seems to always get the ground plane,
89+ // and not other geometry within the world .
8490 _ground->accept (*intersector);
8591 if (!intersector->intersections .empty ())
8692 {
@@ -93,7 +99,7 @@ void Interaction_teleport::frame(vsg::ref_ptr<vsg::Group> scene, Game& game, dou
9399 {
94100 if (auto m = child.node ->cast <vsg::MatrixTransform>())
95101 {
96- m->matrix = vsg::translate (_teleportPosition) * vsg::rotate ( vsg::radians ( 90.0 ), { 1.0 , 0.0 , 0.0 }) ;
102+ m->matrix = vsg::translate (_teleportPosition);
97103 }
98104 }
99105 }
@@ -112,7 +118,8 @@ void Interaction_teleport::frame(vsg::ref_ptr<vsg::Group> scene, Game& game, dou
112118 if (_teleportTargetValid)
113119 {
114120 // Teleport position within the child scene
115- game.userOrigin ()->position = game.userOrigin ()->userToScene () * _teleportPosition;
121+ // Here the origin is being moved, by the difference between the teleport target, and where the user currently is (left hand)
122+ applyTeleport = true ;
116123 }
117124 _teleportButtonDown = false ;
118125 _teleportTargetValid = false ;
@@ -127,4 +134,34 @@ void Interaction_teleport::frame(vsg::ref_ptr<vsg::Group> scene, Game& game, dou
127134 if ( fabs (state.currentState ) < rotThresh) _rotateActionState = 0 ;
128135 }
129136 }
137+
138+ if ( applyRotation || applyTeleport )
139+ {
140+ // The player's position in vr space, at 'ground' level
141+ // In this case we know the level if the ground from the teleport target
142+ auto playerPosOrigin = _headPose->getTransform () * vsg::dvec3{ 0.0 , 0.0 , 0.0 };
143+ playerPosOrigin.z = _teleportPosition.z ;
144+
145+ vsg::dvec3 newPlayerPosScene;
146+ if (!applyTeleport)
147+ {
148+ // The player hasn't moved
149+ newPlayerPosScene = game.userOrigin ()->userToScene () * playerPosOrigin;
150+ }
151+ else
152+ {
153+ // The player has moved - Center on the teleport target
154+ newPlayerPosScene = game.userOrigin ()->userToScene () * _teleportPosition;
155+ }
156+
157+ // Set the transform from vr origin to position/rotation within scene
158+ // The initial translate is important as the user is rarely positioned
159+ // at the origin of their vr space.
160+ game.userOrigin ()->setUserInScene (
161+ playerPosOrigin,
162+ newPlayerPosScene,
163+ vsg::dquat (vsg::radians (_playerRotation), { 0.0 , 0.0 , 1.0 }),
164+ {1.0 , 1.0 , 1.0 }
165+ );
166+ }
130167}
0 commit comments