bool SimpleRenderer::get_inverse_matrix (Matrix44 &result, ustring to, float time) { if (to == u_camera || to == u_screen || to == u_NDC || to == u_raster) { Matrix44 M = m_world_to_camera; if (to == u_screen || to == u_NDC || to == u_raster) { // arbitrary clip planes because renderer doesn't do any clipping float yon = 0.01f; float hither = 1e5f; float depthrange = yon - hither; float tanhalffov = tanf (m_fov * float(M_PI/360.0)); Matrix44 camera_to_screen (1/tanhalffov, 0, 0, 0, 0, 1/tanhalffov, 0, 0, 0, 0, yon/depthrange, 1, 0, 0, -yon*hither/depthrange, 0); M = M * camera_to_screen; if (to == u_NDC || to == u_raster) { Matrix44 screen_to_ndc (0.5f, 0, 0, 0, 0, 0.5f, 0, 0, 0, 0, 1.0f, 0, -0.5f, -0.5f, 0, 1); M = M * screen_to_ndc; if (to == u_raster) { Matrix44 ndc_to_raster (m_xres, 0, 0, 0, 0, m_yres, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); M = M * ndc_to_raster; } } } result = M; return true; } TransformMap::const_iterator found = m_named_xforms.find (to); if (found == m_named_xforms.end()) return false; result = found->second; result.invert(); return true; }
void test_d_camera_to_screen() { auto pos = Vector3f{0, 0, 0}; auto look = Vector3f{0, 0, 1}; auto up = Vector3f{0, 1, 0}; Matrix3x3f n2c = Matrix3x3f::identity(); Matrix3x3f c2n = Matrix3x3f::identity(); Camera camera{1, 1, &pos[0], &look[0], &up[0], &n2c.data[0][0], &c2n.data[0][0], 1e-2f, false}; auto pt = Vector3{0.5, 0.5, 1.0}; auto dx = Real(1); auto dy = Real(1); auto d_camera = DCameraInst{}; auto d_pt = Vector3{0, 0, 0}; d_camera_to_screen(camera, pt, dx, dy, d_camera, d_pt); // Compare with central difference auto finite_delta = Real(1e-6); for (int i = 0; i < 3; i++) { auto delta_pos = pos; delta_pos[i] += finite_delta; auto delta_camera = Camera{ 1, 1, &delta_pos[0], &look[0], &up[0], &n2c.data[0][0], &c2n.data[0][0], 1e-2f, false}; auto pxy = camera_to_screen(delta_camera, pt); delta_pos[i] -= 2 * finite_delta; delta_camera = Camera{ 1, 1, &delta_pos[0], &look[0], &up[0], &n2c.data[0][0], &c2n.data[0][0], 1e-2f, false}; auto nxy = camera_to_screen(delta_camera, pt); auto diff = (sum(pxy - nxy)) / (2 * finite_delta); equal_or_error(__FILE__, __LINE__, (Real)diff, (Real)d_camera.position[i]); } for (int i = 0; i < 3; i++) { auto delta_look = look; delta_look[i] += finite_delta; auto delta_camera = Camera{ 1, 1, &pos[0], &delta_look[0], &up[0], &n2c.data[0][0], &c2n.data[0][0], 1e-2f, false}; auto pxy = camera_to_screen(delta_camera, pt); delta_look[i] -= 2 * finite_delta; delta_camera = Camera{ 1, 1, &pos[0], &delta_look[0], &up[0], &n2c.data[0][0], &c2n.data[0][0], 1e-2f, false}; auto nxy = camera_to_screen(delta_camera, pt); auto diff = (sum(pxy - nxy)) / (2 * finite_delta); equal_or_error(__FILE__, __LINE__, (Real)diff, (Real)d_camera.look[i]); } for (int i = 0; i < 3; i++) { auto delta_up = up; delta_up[i] += finite_delta; auto delta_camera = Camera{ 1, 1, &pos[0], &look[0], &delta_up[0], &n2c.data[0][0], &c2n.data[0][0], 1e-2f, false}; auto pxy = camera_to_screen(delta_camera, pt); delta_up[i] -= 2 * finite_delta; delta_camera = Camera{ 1, 1, &pos[0], &look[0], &delta_up[0], &n2c.data[0][0], &c2n.data[0][0], 1e-2f, false}; auto nxy = camera_to_screen(delta_camera, pt); auto diff = (sum(pxy - nxy)) / (2 * finite_delta); equal_or_error(__FILE__, __LINE__, (Real)diff, (Real)d_camera.up[i]); } for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { auto delta_camera = camera; delta_camera.cam_to_ndc(i, j) += finite_delta; auto pxy = camera_to_screen(delta_camera, pt); delta_camera.cam_to_ndc(i, j) -= 2 * finite_delta; auto nxy = camera_to_screen(delta_camera, pt); auto diff = sum(pxy - nxy) / (2 * finite_delta); equal_or_error(__FILE__, __LINE__, (Real)diff, (Real)d_camera.cam_to_ndc(i, j)); } } }