From 2642ba13b4639fc524bc77e30c112942cd3f5355 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Sat, 22 Jun 2019 13:19:11 +1000 Subject: GPU_matrix: Add GPU_matrix_unproject_precalc Pre-calculates values needed for unprojecting to avoid a matrix invert and extracting projection matrix dimensions for every call to GPU_matrix_unproject. Use for gizmo selection drawing. --- source/blender/gpu/GPU_matrix.h | 31 +++++++-- source/blender/gpu/intern/gpu_matrix.c | 79 +++++++++++++--------- .../windowmanager/gizmo/intern/wm_gizmo_map.c | 9 ++- 3 files changed, 77 insertions(+), 42 deletions(-) (limited to 'source') diff --git a/source/blender/gpu/GPU_matrix.h b/source/blender/gpu/GPU_matrix.h index 6f7d25dafa7..61622c40ff0 100644 --- a/source/blender/gpu/GPU_matrix.h +++ b/source/blender/gpu/GPU_matrix.h @@ -96,21 +96,38 @@ void GPU_matrix_perspective_set(float fovy, float aspect, float near, float far) /* 3D Projection between Window and World Space */ +struct GPUMatrixUnproject_Precalc { + float model_inverted[4][4]; + float view[4]; + bool is_persp; + /** Result of 'projmat_dimensions'. */ + struct { + float xmin, xmax; + float ymin, ymax; + float zmin, zmax; + } dims; +}; + +bool GPU_matrix_unproject_precalc(struct GPUMatrixUnproject_Precalc *unproj_precalc, + const float model[4][4], + const float proj[4][4], + const int view[4]); + void GPU_matrix_project(const float world[3], const float model[4][4], const float proj[4][4], const int view[4], - float win[3]); + float r_win[3]); + bool GPU_matrix_unproject(const float win[3], const float model[4][4], const float proj[4][4], const int view[4], - float world[3]); -void GPU_matrix_unproject_model_inverted(const float win[3], - const float model_inverted[4][4], - const float proj[4][4], - const int view[4], - float world[3]); + float r_world[3]); + +void GPU_matrix_unproject_with_precalc(const struct GPUMatrixUnproject_Precalc *unproj_precalc, + const float win[3], + float r_world[3]); /* 2D Projection Matrix */ diff --git a/source/blender/gpu/intern/gpu_matrix.c b/source/blender/gpu/intern/gpu_matrix.c index cc89da19705..858afdc534e 100644 --- a/source/blender/gpu/intern/gpu_matrix.c +++ b/source/blender/gpu/intern/gpu_matrix.c @@ -481,58 +481,73 @@ void GPU_matrix_project(const float world[3], * But that solution loses much precision. * Therefore, get the same result without inverting the matrix. */ -static void gpu_mul_invert_projmat_m4_unmapped_v3(const float projmat[4][4], float co[3]) +static void gpu_mul_invert_projmat_m4_unmapped_v3_with_precalc( + const struct GPUMatrixUnproject_Precalc *precalc, float co[3]) { - float left, right, bottom, top, near, far; - bool is_persp = projmat[3][3] == 0.0f; + /* 'precalc->dims' is the result of 'projmat_dimensions(proj, ...)'. */ + co[0] = precalc->dims.xmin + co[0] * (precalc->dims.xmax - precalc->dims.xmin); + co[1] = precalc->dims.ymin + co[1] * (precalc->dims.ymax - precalc->dims.ymin); - projmat_dimensions(projmat, &left, &right, &bottom, &top, &near, &far); - - co[0] = left + co[0] * (right - left); - co[1] = bottom + co[1] * (top - bottom); - - if (is_persp) { - co[2] = far * near / (far + co[2] * (near - far)); + if (precalc->is_persp) { + co[2] = precalc->dims.zmax * precalc->dims.zmin / + (precalc->dims.zmax + co[2] * (precalc->dims.zmin - precalc->dims.zmax)); co[0] *= co[2]; co[1] *= co[2]; } else { - co[2] = near + co[2] * (far - near); + co[2] = precalc->dims.zmin + co[2] * (precalc->dims.zmax - precalc->dims.zmin); } co[2] *= -1; } -void GPU_matrix_unproject_model_inverted(const float win[3], - const float model_inverted[4][4], - const float proj[4][4], - const int view[4], - float world[3]) -{ - float in[3]; - - copy_v3_v3(in, win); - - /* Map x and y from window coordinates */ - in[0] = (in[0] - view[0]) / view[2]; - in[1] = (in[1] - view[1]) / view[3]; +bool GPU_matrix_unproject_precalc(struct GPUMatrixUnproject_Precalc *precalc, + const float model[4][4], + const float proj[4][4], + const int view[4]) +{ + precalc->is_persp = proj[3][3] == 0.0f; + projmat_dimensions(proj, + &precalc->dims.xmin, + &precalc->dims.xmax, + &precalc->dims.ymin, + &precalc->dims.ymax, + &precalc->dims.zmin, + &precalc->dims.zmax); + for (int i = 0; i < 4; i++) { + precalc->view[i] = (float)view[i]; + } + if (!invert_m4_m4(precalc->model_inverted, model)) { + unit_m4(precalc->model_inverted); + return false; + } + return true; +} - gpu_mul_invert_projmat_m4_unmapped_v3(proj, in); - mul_v3_m4v3(world, model_inverted, in); +void GPU_matrix_unproject_with_precalc(const struct GPUMatrixUnproject_Precalc *precalc, + const float win[3], + float r_world[3]) +{ + float in[3] = { + (win[0] - precalc->view[0]) / precalc->view[2], + (win[1] - precalc->view[1]) / precalc->view[3], + win[2], + }; + gpu_mul_invert_projmat_m4_unmapped_v3_with_precalc(precalc, in); + mul_v3_m4v3(r_world, precalc->model_inverted, in); } bool GPU_matrix_unproject(const float win[3], const float model[4][4], const float proj[4][4], const int view[4], - float world[3]) + float r_world[3]) { - float model_inverted[4][4]; - - if (!invert_m4_m4(model_inverted, model)) { - zero_v3(world); + struct GPUMatrixUnproject_Precalc precalc; + if (!GPU_matrix_unproject_precalc(&precalc, model, proj, view)) { + zero_v3(r_world); return false; } - GPU_matrix_unproject_model_inverted(win, model_inverted, proj, view, world); + GPU_matrix_unproject_with_precalc(&precalc, win, r_world); return true; } diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c index 6915ea91c8e..f57760cdc2b 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c @@ -571,8 +571,11 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos, const int viewport[4] = {0, 0, ar->winx, ar->winy}; float co_3d_origin[3]; - GPU_matrix_unproject_model_inverted( - co_screen, rv3d->viewinv, rv3d->winmat, viewport, co_3d_origin); + /* Avoid multiple calculations. */ + struct GPUMatrixUnproject_Precalc unproj_precalc; + GPU_matrix_unproject_precalc(&unproj_precalc, rv3d->viewmat, rv3d->winmat, viewport); + + GPU_matrix_unproject_with_precalc(&unproj_precalc, co_screen, co_3d_origin); GLuint *buf_iter = buffer; int hit_found = -1; @@ -583,7 +586,7 @@ static int gizmo_find_intersected_3d_intern(wmGizmo **visible_gizmos, wmGizmo *gz = visible_gizmos[buf_iter[3] >> 8]; float co_3d[3]; co_screen[2] = int_as_float(buf_iter[1]); - GPU_matrix_unproject_model_inverted(co_screen, rv3d->viewinv, rv3d->winmat, viewport, co_3d); + GPU_matrix_unproject_with_precalc(&unproj_precalc, co_screen, co_3d); float select_bias = gz->select_bias; if ((gz->flag & WM_GIZMO_DRAW_NO_SCALE) == 0) { select_bias *= gz->scale_final; -- cgit v1.2.3