[Bf-blender-cvs] [2642ba13b46] master: GPU_matrix: Add GPU_matrix_unproject_precalc

Campbell Barton noreply at git.blender.org
Sat Jun 22 05:22:55 CEST 2019


Commit: 2642ba13b4639fc524bc77e30c112942cd3f5355
Author: Campbell Barton
Date:   Sat Jun 22 13:19:11 2019 +1000
Branches: master
https://developer.blender.org/rB2642ba13b4639fc524bc77e30c112942cd3f5355

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.

===================================================================

M	source/blender/gpu/GPU_matrix.h
M	source/blender/gpu/intern/gpu_matrix.c
M	source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c

===================================================================

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;



More information about the Bf-blender-cvs mailing list