I switched to quaternion rotation for topocentric horizon frame, but it still resulted the same. Here is initialization route (setGroundMode() call)
// Clear all ground velocity controls
go.av = { 0, 0, 0 };
go.tv = { 0, 0, 0 };
double rad = cbody->getRadius() + go.alt;
cam.rpos = cbody->convertEquatorialToLocal(go.lat, go.lng, rad);
go.R = glm::lookAt(cam.rpos, {0, 0, 0}, {0, 1, 0});
go.Q = go.R;
Here is update call each frame.
// rotate camera in local coordinate
glm::dvec3 wv = go.av * 0.5;
glm::dquat dr = glm::dquat(1.0, wv.x, wv.y, wv.z) * cam.rqrot;
cam.rqrot = glm::normalize(cam.rqrot + dr);
cam.rrot = glm::mat3_cast(cam.rqrot);
// convert to local planetocentric coordinate
gqrot = go.Q * cam.rqrot;
grot = glm::mat3_cast(gqrot);
It correctly points down to the runway 15 at right angle as default. I rotated camera up but it tilted off course. I had the same problem with matrix rotation before. It aligns with global XYZ axis instead of horizon ref frame. I am still figuring out elsewhere…
In planetocentric frame (orbit area), It functions correctly.
// rotate camera in local coordinate
glm::dvec3 wv = av * 0.5;
glm::dquat dr = glm::dquat(1.0, wv.x, wv.y, wv.z) * cam.rqrot;
cam.rqrot = glm::normalize(cam.rqrot + dr);
cam.rrot = glm::mat3_cast(cam.rqrot);
// move camera in global frame
cam.rpos -= glm::conjugate(cam.rqrot) * tv;
// convert to global coordinate from local planetocentric coordinate
gspos = tgtObject->getuOrientation(0) * cam.rpos;
gpos = tgtObject->getoPosition() + gspos;
grot = tgtObject->getuOrientation(0) * cam.rrot;
gqrot = grot;
In local planetocentric coordinate (orbtal space area), I tried rotate camera up and aligns with horizon level correctly. I am figuring why it did not work with topocentric horizon frame (ground space area).