Page 1 of 1

Help with Oculus Rift Rotation

Posted: Sat Jun 22, 2013 3:55 pm
by Brainsaw
Hi there,

once again I realize how much I know about math - close to ... uhm ... not much ;). I got my Oculus Rift DevKit a week ago, and after some simulator sickness from playing Portal and Half Life 2 I decided I want to start Irrlicht integration. Works fine so far, I get the necessary values from the SDK. The orientation is returned as a quaternion. I convert the quaternion to a matrix and then I transform the lookat vector with this matrix. Works fine except for one thing - the rotation is exactly the other direction (turning Rift right -> Irrlicht turns left, turning Rift down -> Irrlicht turns up). Anyone got an idea how to fix this? I tried the CMatrix4.getInverse method, but this screws rotation up quite a bit - if I look 90 degrees to the right and then down the camera rotates. Here is my code (the problem is located in CCameraController::update)

Code: Select all

 
#include <irrlicht.h>
#include <iostream>
#include <OVR.h>
#include <math.h>
 
#ifdef _MSC_VER
#pragma comment(lib, "Irrlicht.lib")
#endif
 
#define M_PI 3.14159265358979323846f
 
using namespace OVR;
 
class CRiftTest : public irr::IEventReceiver {
  private:
    class CCameraController {
      protected:
        irr::scene::ICameraSceneNode *m_pCam;
        irr::gui::ICursorControl *m_pCursor;
        irr::f32 m_fAngleH,
                 m_fAngleV;
 
        Ptr<DeviceManager> m_pRiftManager;
        Ptr<HMDDevice    > m_pRiftHMD;
        Ptr<SensorDevice > m_pRiftSensor;
        SensorFusion       m_cRiftFusion;
 
      public:
        CCameraController(irr::scene::ICameraSceneNode *pCam, irr::gui::ICursorControl *pCursor) {
          m_pCam = pCam;
 
          m_fAngleH = 0.0f;
          m_fAngleV = 0.0f;
 
          m_pCursor = pCursor;
 
          update(0, 0);
 
          System::Init(Log::ConfigureDefaultLog(LogMask_All));
 
          m_pRiftManager = *DeviceManager::Create();
 
          m_pRiftHMD = *m_pRiftManager->EnumerateDevices<HMDDevice>().CreateDevice();
 
          m_pRiftSensor = *m_pRiftHMD->GetSensor();
 
          if (m_pRiftSensor) m_cRiftFusion.AttachToSensor(m_pRiftSensor);
        }
 
        void update(irr::s32 iMove, irr::s32 iStrafe) {
          irr::core::position2di cDiff = m_pCursor->getPosition() - irr::core::vector2di(640, 400);
          m_pCursor->setPosition(640, 400);
          m_fAngleH -= ((irr::f32)cDiff.X) / 15.0f;
          m_fAngleV -= ((irr::f32)cDiff.Y) / 15.0f;
 
          if (m_fAngleV >  90.0f) m_fAngleV =  90.0f;
          if (m_fAngleV < -90.0f) m_fAngleV = -90.0f;
 
          irr::core::vector2df vRotH = irr::core::vector2df(-1.0f, 0.0f).rotateBy(m_fAngleH),
                               vRotV = irr::core::vector2df( 1.0f, 0.0f).rotateBy(m_fAngleV);
 
          irr::core::vector3df vPos  = m_pCam->getPosition(),
                               vTgt  = irr::core::vector3df(0, 0, 1),
                               vUp   = irr::core::vector3df(0, 1, 0),
                               vSide = vTgt.crossProduct(vUp);
 
          Quatf hmdOrient = m_cRiftFusion.GetOrientation();
 
          irr::core::quaternion cQuat(hmdOrient.x, hmdOrient.y, hmdOrient.z, hmdOrient.w);
 
          irr::core::CMatrix4<irr::f32> cMat;
 
          cQuat.getMatrix(cMat);
 
          //cMat.getInverse(cMat2);
 
          cMat.transformVect(vTgt, irr::core::vector3df(0, 0, 1));
          cMat.transformVect(vUp , irr::core::vector3df(0, 1, 0));
 
          vPos += iMove * vTgt / 25.0f + iStrafe * vSide / 25.0f;
 
          m_pCam->setPosition(vPos);
          m_pCam->setTarget  (vPos + vTgt);
          m_pCam->setUpVector(       vUp );
        }
    };
 
    irr::IrrlichtDevice       *m_pDevice;
    irr::scene::ISceneManager *m_pSmgr;
    irr::video::IVideoDriver  *m_pDrv;
    irr::gui::IGUIEnvironment *m_pGui;
 
    irr::s32 m_iMove,
             m_iStrafe;
 
    irr::gui::ICursorControl *m_pCursor;
 
    irr::scene::ICameraSceneNode *m_pCam;
    CCameraController *m_pCamCtrl;
 
    irr::core::position2di m_cMousePos;
 
    bool m_bLeftBtn,
         m_bRghtBtn;
 
  public:
    CRiftTest(irr::IrrlichtDevice *pDevice) {
      m_pDevice = pDevice;
 
      m_pDevice->setWindowCaption(L"Oculus Rift Test");
      m_pDevice->setEventReceiver(this);
 
      m_pDrv  = m_pDevice->getVideoDriver();
      m_pSmgr = m_pDevice->getSceneManager();
      m_pGui  = m_pDevice->getGUIEnvironment();
 
      m_pCursor = m_pDevice->getCursorControl();
      m_pCam    = m_pSmgr->addCameraSceneNode();
      m_pCamCtrl = new CCameraController(m_pCam, m_pCursor);
 
      m_pCam->setTarget(irr::core::vector3df(0, 0, 1));
 
      m_iMove = 0;
      m_iStrafe = 0;
    }
 
    ~CRiftTest() {
    }
 
    void run() {
      m_pDevice->getFileSystem()->addZipFileArchive("../../media/map-20kdm2.pk3");
 
      irr::u32 iFrameCnt = 0;
      irr::u32 iStartTime = m_pDevice->getTimer()->getTime();
      irr::scene::IAnimatedMesh *pMesh = m_pSmgr->getMesh("20kdm2.bsp");
      irr::scene::ISceneNode *pNode = 0;
 
      if (pMesh) {
        pNode = m_pSmgr->addOctreeSceneNode(pMesh->getMesh(0), 0, -1, 1024);
        pNode->setPosition(irr::core::vector3df(-1500.0f, -500.0f, -500.0f));
      }
 
      while(m_pDevice->run()) {
        m_cMousePos = m_pCursor->getPosition();
        if (m_pCamCtrl != NULL) m_pCamCtrl->update(m_iMove, m_iStrafe);
        m_pDrv->beginScene(true, true, irr::video::SColor(0,200,200,200));
 
        m_pSmgr->drawAll();
        m_pGui->drawAll();
 
        m_pDrv->endScene();
      }
 
      printf("Ready.\n");
    }
 
    virtual bool OnEvent(const irr::SEvent &event) {
      if (event.EventType == irr::EET_KEY_INPUT_EVENT) {
        if (event.KeyInput.PressedDown) {
          switch (event.KeyInput.Key) {
            case irr::KEY_KEY_W: m_iMove   =  1; break;
            case irr::KEY_KEY_S: m_iMove   = -1; break;
            case irr::KEY_KEY_A: m_iStrafe =  1; break;
            case irr::KEY_KEY_D: m_iStrafe = -1; break;
          }
        }
        else {
          switch (event.KeyInput.Key) {
            case irr::KEY_KEY_W: if (m_iMove   ==  1) m_iMove   = 0; break;
            case irr::KEY_KEY_S: if (m_iMove   == -1) m_iMove   = 0; break;
            case irr::KEY_KEY_A: if (m_iStrafe ==  1) m_iStrafe = 0; break;
            case irr::KEY_KEY_D: if (m_iStrafe == -1) m_iStrafe = 0; break;
          }
        }
      }
 
      if (event.EventType == irr::EET_MOUSE_INPUT_EVENT) {
        m_bLeftBtn = event.MouseInput.isLeftPressed ();
        m_bRghtBtn = event.MouseInput.isRightPressed();
      }
 
      return false;
    }
};
 
 
int main()
{
    irr::IrrlichtDevice *device = irr::createDevice(irr::video::EDT_DIRECT3D9, irr::core::dimension2d<irr::u32>(1280, 800));
    if (device == 0) return 1; // could not create selected driver.
 
  CRiftTest cRunner(device);
  cRunner.run();
 
    device->drop();
    return 0;
}
 
Apart from that I'm totally blown away by the rift, and it's easy to program with - apart from math. Thanks for the answer.

Re: Help with Oculus Rift Rotation

Posted: Sun Jun 23, 2013 1:08 am
by mongoose7
Replace the 'angle' in the quaternion with its negative?

Re: Help with Oculus Rift Rotation

Posted: Sun Jun 23, 2013 11:16 am
by Brainsaw
Did already try that, it didn't work. When I turn the Rift around the Y-Axis by 90 degrees it converts pitch to roll. I uploaded a video to youtube showing the problem: http://www.youtube.com/watch?v=WyKA-yfW ... e=youtu.be. Still searching for the answer.

Re: Help with Oculus Rift Rotation

Posted: Sun Jun 23, 2013 3:02 pm
by mongoose7
Firstly, you should find out which of Y and Z is "up". Then you will have to see if it is a right-handed or left-handed system. But the first thing is, which way is up.

Re: Help with Oculus Rift Rotation

Posted: Sun Jun 23, 2013 3:52 pm
by CuteAlien
Try multiplying by a scale (1,1,-1) matrix (so it flips one axis).

Re: Help with Oculus Rift Rotation

Posted: Sun Jun 23, 2013 4:32 pm
by devsh
remember that the rift introduces some serious amount of distortion and you need to make your renderer correct for that, either by rendering onto a bigger render target and anti-distorting (i.e. if your rift turns a square into a paraboloid surface {convex sides}, then you need to render a square with 'sunken'/concave sides) or by rendering in non-linear ways (some tessellation of triangles to achieve anti-curved triangle lines)

Re: Help with Oculus Rift Rotation

Posted: Sun Jun 23, 2013 11:22 pm
by hybrid
Well, this is indeed true to some extent, but has nothing to do with the problem mentioned originally. So not really helpful...

Re: Help with Oculus Rift Rotation

Posted: Mon Jun 24, 2013 5:40 am
by Brainsaw
Thanks. I'll try the scaling once I get home after work.

@devsh: I am well aware of the necessary distortion, but I want to take this step by step. First step: get headtracking. There is already a code snippet somewhere here in the forum that distorts the rendering, and, according to the Rift forums, it works quite well.

Re: Help with Oculus Rift Rotation

Posted: Mon Jun 24, 2013 7:56 am
by Suvi
To get the head tracking work with the Rift I simply added empty scenenodes and then just applied the values from the SensorFusion.

Code: Select all

 
headX_ = getSceneManager()->addEmptySceneNode(0, 0);
headY_ = getSceneManager()->addEmptySceneNode(headX_, 0);
headZ_ = getSceneManager()->addEmptySceneNode(headY_, 0);
 
...
 
// Read sensor fusion 
OVR::Quatf qua = m_sensorFusion.GetOrientation();
irr::core::vector3df p;
qua.GetEulerAngles<OVR::Axis_X, OVR::Axis_Y, OVR::Axis_Z>(&p.X, &p.Y, &p.Z);
 
p.X *= -irr::core::RADTODEG;
p.Y *= -irr::core::RADTODEG;
p.Z *= irr::core::RADTODEG;
 
// Set empty node rotations
headY_->setRotation(irr::core::vector3df(0.0f, p.Y, 0.0f));
headX_->setRotation(irr::core::vector3df(p.X, 0.0f, 0.0f));
headZ_->setRotation(irr::core::vector3df(0.0f, 0.0f, p.Z));
 
// Apply to camera
irr::core::matrix4 m;
m.setRotationDegrees(headZ_->getAbsoluteTransformation().getRotationDegrees());
 
// Forward
irr::core::vector3df frv = irr::core::vector3df (0.0f, 0.0f, 1.0f);
m.transformVect(frv);
   
// Up
irr::core::vector3df upv = irr::core::vector3df (0.0f, 1.0f, 0.0f);
m.transformVect(upv);
 
camera->setTarget(camera->getPosition() + frv);
camera->setUpVector(upv); //set up vector of camera
 
I'm sure you can do it with less nodes or simply with math but if you're bad at maths like me then this is one way to do it. I had some other issues messing up the camera positioning (gimbal lock or something) while I was implementing the tracking so it's possible that most of the code here is not needed x)

The script posted here in the forums earlier does pretty good job with the rendering but at least for me it was missing depth in some angles so I had to adjust the eye positions. This screen is taken using the script (with the eye positions fixed): http://www.indiedb.com/games/gekkeiju-o ... d-tracking

Re: Help with Oculus Rift Rotation

Posted: Mon Jun 24, 2013 10:16 am
by hendu
/OT

How come nearly everyone here has one, when the tech makes 30% of people puke? It's like 3d cinema, if it is unusable for a significant proportion of people, it will never be a huge success.

(30% figure comes from a Remedy presentation about two months ago I was at)

Re: Help with Oculus Rift Rotation

Posted: Mon Jun 24, 2013 10:22 am
by Brainsaw
Thanks. I'll try that when I get home after work.
Suvi wrote:To get the head tracking work with the Rift I simply added empty scenenodes and then just applied the values from the SensorFusion.

Code: Select all

 
headX_ = getSceneManager()->addEmptySceneNode(0, 0);
headY_ = getSceneManager()->addEmptySceneNode(headX_, 0);
headZ_ = getSceneManager()->addEmptySceneNode(headY_, 0);
 
...
 
// Read sensor fusion 
OVR::Quatf qua = m_sensorFusion.GetOrientation();
irr::core::vector3df p;
qua.GetEulerAngles<OVR::Axis_X, OVR::Axis_Y, OVR::Axis_Z>(&p.X, &p.Y, &p.Z);
 
p.X *= -irr::core::RADTODEG;
p.Y *= -irr::core::RADTODEG;
p.Z *= irr::core::RADTODEG;
 
// Set empty node rotations
headY_->setRotation(irr::core::vector3df(0.0f, p.Y, 0.0f));
headX_->setRotation(irr::core::vector3df(p.X, 0.0f, 0.0f));
headZ_->setRotation(irr::core::vector3df(0.0f, 0.0f, p.Z));
 
// Apply to camera
irr::core::matrix4 m;
m.setRotationDegrees(headZ_->getAbsoluteTransformation().getRotationDegrees());
 
// Forward
irr::core::vector3df frv = irr::core::vector3df (0.0f, 0.0f, 1.0f);
m.transformVect(frv);
   
// Up
irr::core::vector3df upv = irr::core::vector3df (0.0f, 1.0f, 0.0f);
m.transformVect(upv);
 
camera->setTarget(camera->getPosition() + frv);
camera->setUpVector(upv); //set up vector of camera
 
I'm sure you can do it with less nodes or simply with math but if you're bad at maths like me then this is one way to do it. I had some other issues messing up the camera positioning (gimbal lock or something) while I was implementing the tracking so it's possible that most of the code here is not needed x)

The script posted here in the forums earlier does pretty good job with the rendering but at least for me it was missing depth in some angles so I had to adjust the eye positions. This screen is taken using the script (with the eye positions fixed): http://www.indiedb.com/games/gekkeiju-o ... d-tracking

Re: Help with Oculus Rift Rotation

Posted: Mon Jun 24, 2013 3:28 pm
by Brainsaw
@Suvi: Thanx, this does the job. I'll try to get the code more compact sometime, but for the moment it's OK.