Reputation: 97
I have this little toy graphics library in rust I tinker with to learn OpenGL. I initially intended it to do only low-res 2D stuff on it, so I set up the coordinate system for pixel-space orthographic rendering, a system with (0, 0) at the top-left corner of the screen that allows sprites to be "snapped" to pixels for an 8/16-bit style.
Now I'm thinking it would be fun to add a perspective camera to render the sprites in perspective as a sort of paper-doll theater thing, sort of inverse 2.5D, world is 3D but characters are 2D.
So I use the excellent tutorial here: https://learnopengl.com/Getting-started/Camera
Great stuff, but the algorithm calls for deriving from the up-vector [0, 1, 0], so my world renders upside down (since my "up" is [0, -1, 0]). If I do set the "up" as [0, -1, 0] I instead get the X-axis extending from right to left, as if negating "up" rotates 180° around the Z-axis, which again isn't what I want.
Is it at all possible to do a perspective camera view matrix with a typical orthographic world Y-down coordinate system, and how would that be done practically using e.g. glm?
Upvotes: 0
Views: 1071
Reputation: 26
I do not recommend changing the camera matrix.
Instead, try to use glClipControl(GL_UPPRER_LEFT,GL_ZERO_TO_ONE)
; in this situation, the front face will be CW.
Or simply multiply the projection matrix P[1][1]
by -1.
Upvotes: 0
Reputation: 97
The trick with the reflection matrix works; The orientation and position of all objects on screen works out and camera movement produces the expected results.
This page is what tipped me off on the fact that the only difference between left and right-hand view matrixes is the direction of the X-axis, and that mirroring/reflections changes the handedness: https://www.realtimerendering.com/blog/left-handed-vs-right-handed-viewing/
That should make sense, if you compare your hands they only differ in what side the thumb is on, not in what direction the fingers are pointing.
The solution:
[-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0 0, 0, 0, 1]
reflection_matrix * view_matrix;
This works in OpenGL, but allegedly DirectX works with row-major matrices, so you have to take that into account when multiplying.
This is the code I use to produce the view matrix:
let eye: glm::Vec3 = glm::vec3(160.0, 90.0, 300.0);
let target: glm::Vec3 = glm::vec3(160.0, 90.0, 0.0);
let cam_forward = glm::normalize(&(&eye - &target));
let up = glm::Vec3::new(0.0, -1.0, 0.0);
let cam_right = glm::normalize(&glm::cross(&up, &cam_forward));
let cam_up = glm::normalize(&glm::cross(&cam_forward, &cam_right));
let mut mx_view = glm::look_at(&eye, &target, &cam_up);
let mut mirr: glm::Mat4 = glm::Mat4::identity();
mirr[0] = -1.0;
mx_view = mirr * mx_view;
The camera looks down the Z-axis of my 320 by 180 pixel world.
This is of-course in rust, but, based on the excellent nalgebra-glm crate which pretty closely replicates what glm does for C++, so I think anyone using C++ should also be able to follow.
Upvotes: 0