2

There is a camera represented by a quaternion [w, x, y, z] associated with a position [x, y, z]. The camera is looking at a mirror (plane) defined as a normal and a point residing on the mirror. This mirror may also be represented as the plane equation AX + BY + CZ + D = 0.

Using the information above, how would the reflected/virtual camera be found?

The quaternion roll should be preserved, ie if you are looking directly into a mirror, the quaternion looking back at you should have the same roll and not be upside down. Ray vs plane can be used to find the virtual camera position, the reflected vector origin and 3D direction, but I'm not sure that helps in finding the quaternion. Finding the virtual camera position was easy enough as shown below (I prefer this over the ray vs. plane tracing method due to parallel or looking away case):

//plane equation ax + by + cz + d = 0
        float plane_equation[4];//a, b, c, d
        plane_equation[0] = mirror_normal[0];
        plane_equation[1] = mirror_normal[1];
        plane_equation[2] = mirror_normal[2];

        float mults[3];
        mults[0] = plane_equation[0] * mirror_position[0];
        mults[1] = plane_equation[1] * mirror_position[1];
        mults[2] = plane_equation[2] * mirror_position[2];
        plane_equation[3] = -1 * (mults[0] + mults[1] + mults[2]);

        //find the virtual camera position for reflection using the plane equation
        //a(p0 + aT) + b(p1 + bT) + c(p2 + cT) + d = 0
        //ap0 + bp1 + cp2 + T(a^2 + b^2 + c^2) + d = 0
        //U + TV + d = 0
        //T = (-d - U) / V
        float t_parts[2];
        //U
        t_parts[0] = plane_equation[0] * cam_pos[0] + plane_equation[1] * cam_pos[1] + plane_equation[2] * cam_pos[2];
        //V
        t_parts[1] = plane_equation[0] * plane_equation[0] + plane_equation[1] * plane_equation[1] + plane_equation[2] * plane_equation[2];

        float t = (-plane_equation[3] - t_parts[0]) / t_parts[1];

        //t gets us to the intersection point. 2t gets us to the virtual point
        virtual_cam_pos[0] = 2 * t * plane_equation[0] + cam_pos[0];
        virtual_cam_pos[1] = 2 * t * plane_equation[1] + cam_pos[1];
        virtual_cam_pos[2] = 2 * t * plane_equation[2] + cam_pos[2];
ddxm
  • 103
  • 6
  • 1
    In general, you can't, because you can only use unimodular quaternions to model rotations/orientations and not reflections *(a mathematician would say the manifold of unimodular 4d quaternions is a double cover of SO(3))* https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation?wprov=sfla1. The best you can do is to find the position of the reflected camera, rotate so that it looks in the opposite direction and then use some other kind of transform for the reflection, e.g. a homogeneous coordinate transform. – joergbrech Dec 21 '22 at 00:56
  • Just found this: https://www.euclideanspace.com/maths/geometry/affine/reflection/quaternion/index.htm. As mentioned in the link, use it carefully and expect things to go sour! *"Since this only works in 3D and since it can't be combined with other types of transform it is more of a curiosity than a useful technique."* – joergbrech Dec 21 '22 at 01:09
  • So then it's not possible to represent a reflection as a rotation? I was able to derive the y_angle = 2 * asin(camera_quat[2]), then 180 + a_sign * 2 * y_angle for a yaw quaternion global quaternion multiplication. This works so long as you face the mirror on plane xy without roll and with angles less than 90. I suppose this was cheating though as I derived the angle from the quaternion. – ddxm Dec 21 '22 at 01:10
  • No, reflections and rotations are different things. You would have to use some other technique. Homogeneous transforms are common in computer graphics afaik. I can't quite follow the rationale behind your calculations for your special case... – joergbrech Dec 21 '22 at 01:14
  • Some more reading material for you, with some good explanantions and use of the dirty trick from the previous link: https://stackoverflow.com/a/39519536/12173376 – joergbrech Dec 21 '22 at 01:21
  • Okay, that's unfortunate, I guess a conversion to Euler / matrix is inevitable then. I was able to get it to work so long as the camera didn't roll or look more than 90 degrees away from the mirror, was hopeful I was just missing some part of an equation. edit: followed the link "Matrices that are not pure rotations (ones that have determinant -1, for example matrices that flip a single axis) are also called "improper rotations", and cannot be converted to a unit quaternion and back" hmm... I'll just have to study this a bit more. I feel like it's possible but what do I know – ddxm Dec 21 '22 at 01:22
  • 1
    It is possible with an "improper quaternion product", see the two links providing this "trick". It is just not an SO(3) transform and this could be problematic in other parts of your code, since this is typically expected of quaternions. One final comment: If your "camera" has a symmetry plane and it's only about visuals, you could cheat differently: You can skip the left-right mirroring of the camera as it doesn't have a visual effect. – joergbrech Dec 21 '22 at 01:29

1 Answers1

0

One solution, it could probably be simplified but this works:

  1. Do ray vs plane. There are 3 cases that need to be taken into account. First is looking towards the mirror so that there is an intersection. Second is looking parallel to the mirror. Third is looking away from the mirror (the mirror may still be visible by the camera, do flipped ray vs plane)
  2. Find the reflected vector
  3. Use the distance from the camera position to the mirror intersection point, intersection point, and reflected vector to find the virtual camera position
  4. Use the vector from the virtual camera to the mirror intersection point to create a quaternion
  5. Apply a local roll to the quaternion. An exact equation to find the appropriate amount of roll for all possible cases is a little unclear to me, but this gets most of the way there
ddxm
  • 103
  • 6