Commit: 8939787bfb4b9068408f5fb931354d0fe68faf86
Author: Campbell Barton
Date:   Wed Jul 13 14:42:00 2016 +1000
Branches: master
https://developer.blender.org/rB8939787bfb4b9068408f5fb931354d0fe68faf86

Use BLI_bvhtree_walk_dfs for snapping

The snapping functions when performed in the perspective view,
have some problems in the threshold (a distortion) and in the clip plane (the 
normal is incorrect).
These problems can be only observed when making the snap to edges or to 
vertices (nearest to ray function).

This patch propose a totally different solution.
The idea is to project the edges of bvh nodes and test the 2d projection of the 
snap element.

For this it used the BLI_bvhtree_walk_dfs function.

It is important to pay particular attention also to the changes in 
`ED_transform_snap_object_project_view3d_ex`

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

M       source/blender/editors/include/ED_view3d.h
M       source/blender/editors/space_view3d/view3d_project.c
M       source/blender/editors/transform/transform_snap_object.c

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

diff --git a/source/blender/editors/include/ED_view3d.h 
b/source/blender/editors/include/ED_view3d.h
index b09284a..48c1e2d 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -208,6 +208,7 @@ eV3DProjStatus ED_view3d_project_float_global(const struct 
ARegion *ar, const fl
 eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *ar, const 
float co[3], float r_co[2], const eV3DProjTest flag);
 
 float ED_view3d_calc_zfac(const struct RegionView3D *rv3d, const float co[3], 
bool *r_flip);
+bool ED_view3d_clip_segment(const struct RegionView3D *rv3d, float 
ray_start[3], float ray_end[3]);
 bool ED_view3d_win_to_ray(
         const struct ARegion *ar, const struct View3D *v3d, const float 
mval[2],
         float ray_start[3], float ray_normal[3], const bool do_clip);
@@ -218,6 +219,7 @@ void ED_view3d_global_to_vector(const struct RegionView3D 
*rv3d, const float coo
 void ED_view3d_win_to_3d(const struct ARegion *ar, const float depth_pt[3], 
const float mval[2], float out[3]);
 void ED_view3d_win_to_3d_int(const struct ARegion *ar, const float 
depth_pt[3], const int mval[2], float out[3]);
 void ED_view3d_win_to_delta(const struct ARegion *ar, const float mval[2], 
float out[3], const float zfac);
+void ED_view3d_win_to_origin(const struct ARegion *ar, const float mval[2], 
float out[3]);
 void ED_view3d_win_to_vector(const struct ARegion *ar, const float mval[2], 
float out[3]);
 bool ED_view3d_win_to_segment(const struct ARegion *ar, struct View3D *v3d, 
const float mval[2],
                               float r_ray_start[3], float r_ray_end[3], const 
bool do_clip);
diff --git a/source/blender/editors/space_view3d/view3d_project.c 
b/source/blender/editors/space_view3d/view3d_project.c
index ac05853..e6d8bdc 100644
--- a/source/blender/editors/space_view3d/view3d_project.c
+++ b/source/blender/editors/space_view3d/view3d_project.c
@@ -312,25 +312,9 @@ static void view3d_win_to_ray_segment(
        if (!r_ray_co) r_ray_co = _ray_co;
        if (!r_ray_dir) r_ray_dir = _ray_dir;
 
+       ED_view3d_win_to_origin(ar, mval, r_ray_co);
        ED_view3d_win_to_vector(ar, mval, r_ray_dir);
 
-       if (rv3d->is_persp) {
-               copy_v3_v3(r_ray_co, rv3d->viewinv[3]);
-       }
-       else {
-               r_ray_co[0] = 2.0f * mval[0] / ar->winx - 1.0f;
-               r_ray_co[1] = 2.0f * mval[1] / ar->winy - 1.0f;
-
-               if (rv3d->persp == RV3D_CAMOB) {
-                       r_ray_co[2] = -1.0f;
-               }
-               else {
-                       r_ray_co[2] = 0.0f;
-               }
-
-               mul_project_m4_v3(rv3d->persinv, r_ray_co);
-       }
-
        if ((rv3d->is_persp == false) && (rv3d->persp != RV3D_CAMOB)) {
                end_offset = v3d->far / 2.0f;
                start_offset = -end_offset;
@@ -347,7 +331,7 @@ static void view3d_win_to_ray_segment(
        }
 }
 
-BLI_INLINE bool view3d_clip_segment(const RegionView3D *rv3d, float 
ray_start[3], float ray_end[3])
+bool ED_view3d_clip_segment(const RegionView3D *rv3d, float ray_start[3], 
float ray_end[3])
 {
        if ((rv3d->rflag & RV3D_CLIPPING) &&
            (clip_segment_v3_plane_n(ray_start, ray_end, rv3d->clip, 6,
@@ -384,7 +368,7 @@ bool ED_view3d_win_to_ray_ex(
 
        /* bounds clipping */
        if (do_clip) {
-               return view3d_clip_segment(ar->regiondata, r_ray_start, 
ray_end);
+               return ED_view3d_clip_segment(ar->regiondata, r_ray_start, 
ray_end);
        }
 
        return true;
@@ -549,6 +533,37 @@ void ED_view3d_win_to_delta(const ARegion *ar, const float 
mval[2], float out[3]
 }
 
 /**
+ * Calculate a 3d origin from 2d window coordinates.
+ * \note Orthographic views have a less obvious origin,
+ * Since far clip can be a very large value resulting in numeric precision 
issues,
+ * the origin in this case is close to zero coordinate.
+
+ * \param ar The region (used for the window width and height).
+ * \param mval The area relative 2d location (such as event->mval converted to 
floats).
+ * \param out The resulting normalized world-space direction vector.
+ */
+void ED_view3d_win_to_origin(const ARegion *ar, const float mval[2], float 
out[3])
+{
+       RegionView3D *rv3d = ar->regiondata;
+       if (rv3d->is_persp) {
+               copy_v3_v3(out, rv3d->viewinv[3]);
+       }
+       else {
+               out[0] = 2.0f * mval[0] / ar->winx - 1.0f;
+               out[1] = 2.0f * mval[1] / ar->winy - 1.0f;
+
+               if (rv3d->persp == RV3D_CAMOB) {
+                       out[2] = -1.0f;
+               }
+               else {
+                       out[2] = 0.0f;
+               }
+
+               mul_project_m4_v3(rv3d->persinv, out);
+       }
+}
+
+/**
  * Calculate a 3d direction vector from 2d window coordinates.
  * This direction vector starts and the view in the direction of the 2d window 
coordinates.
  * In orthographic view all window coordinates yield the same vector.
@@ -599,7 +614,7 @@ bool ED_view3d_win_to_segment(const ARegion *ar, View3D 
*v3d, const float mval[2
 
        /* bounds clipping */
        if (do_clip) {
-               return view3d_clip_segment((RegionView3D *)ar->regiondata, 
r_ray_start, r_ray_end);
+               return ED_view3d_clip_segment((RegionView3D *)ar->regiondata, 
r_ray_start, r_ray_end);
        }
 
        return true;
diff --git a/source/blender/editors/transform/transform_snap_object.c 
b/source/blender/editors/transform/transform_snap_object.c
index 59dfe18..2e7e9e0 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -218,37 +218,122 @@ static void raycast_all_cb(void *userdata, int index, 
const BVHTreeRay *ray, BVH
 
 /* -------------------------------------------------------------------- */
 
-/** \name Internal Object Snapping API
- * \{ */
+/** \Common utilities
+* \{ */
+
+
+/**
+* struct that kepts basic information about a BVHTree build from a editmesh
+*/
+typedef struct BVHTreeFromMeshType {
+       void *userdata;
+       char type;
+} BVHTreeFromMeshType;
+
+/**
+* From a threshold (maximum distance to snap in pixels) returns:
+*
+* - The *real* distance (3D) if you are in orthographic-view.
+* - The *tangent* (view cone radius at distance 1.0) if you are in 
perspective-view.
+*/
+static float dist_px_to_dist3d_or_tangent(const ARegion *ar, const float 
dist_px)
+{
+       const RegionView3D *rv3d = ar->regiondata;
+       if (ar->winx >= ar->winy)
+               return 2 * (dist_px / ar->winx) / rv3d->winmat[0][0];
+       else
+               return 2 * (dist_px / ar->winy) / rv3d->winmat[1][1];
+}
+
+static const float *get_vert_co(const BVHTreeFromMeshType *meshdata, const int 
index) {
+       switch (meshdata->type) {
+               case SNAP_MESH:
+               {
+                       BVHTreeFromMesh *data = meshdata->userdata;
+                       const MVert *vert = data->vert;
+                       return vert[index].co;
+               }
+               case SNAP_EDIT_MESH:
+               {
+                       BVHTreeFromEditMesh *data = meshdata->userdata;
+                       BMVert *eve = BM_vert_at_index(data->em->bm, index);
+                       return eve->co;
+               }
+       }
+       return NULL;
+}
+
+static void copy_vert_no(const BVHTreeFromMeshType *meshdata, const int index, 
float r_no[3]) {
+       switch (meshdata->type) {
+               case SNAP_MESH:
+               {
+                       BVHTreeFromMesh *data = meshdata->userdata;
+                       const MVert *vert = data->vert;
+                       normal_short_to_float_v3(r_no, vert->no);
+                       break;
+               }
+               case SNAP_EDIT_MESH:
+               {
+                       BVHTreeFromEditMesh *data = meshdata->userdata;
+                       BMVert *eve = BM_vert_at_index(data->em->bm, index);
+                       copy_v3_v3(r_no, eve->no);
+                       break;
+               }
+       }
+}
+
+static void get_edge_verts(
+        const BVHTreeFromMeshType *meshdata, const int index,
+        const float *v_pair[2])
+{
+       switch (meshdata->type) {
+               case SNAP_MESH:
+               {
+                       BVHTreeFromMesh *data = meshdata->userdata;
+
+                       const MVert *vert = data->vert;
+                       const MEdge *edge = data->edge + index;
+
+                       v_pair[0] = vert[edge->v1].co;
+                       v_pair[1] = vert[edge->v2].co;
+                       break;
+               }
+               case SNAP_EDIT_MESH:
+               {
+                       BVHTreeFromEditMesh *data = meshdata->userdata;
+                       BMEdge *eed = BM_edge_at_index(data->em->bm, index);
+
+                       v_pair[0] = eed->v1->co;
+                       v_pair[1] = eed->v2->co;
+                       break;
+               }
+       }
+}
 
 #define V3_MUL_ELEM(a, b) \
        (a)[0] * (b)[0], \
        (a)[1] * (b)[1], \
        (a)[2] * (b)[2]
 
-static bool test_vert(
+static bool test_vert_dist(
         const float vco[3], const float vno[3], const float ray_co[3], const 
float ray_dir[3],
-        const float ray_depth_range[2], const float scale[3], const bool 
is_persp,
+        const float ray_depth_range[2], const float scale[3],
         /* read/write args */
         float *ray_depth, float *dist_to_ray_sq,
         /* return args */
         float r_co[3], float r_no[3])
 {
        const float vco_sc[3]   = {V3_MUL_ELEM(vco, scale)};
-       const float co_sc[3]    = {V3_MUL_ELEM(ray_co, scale)};
+       const float origin_sc[3]    = {V3_MUL_ELEM(ray_co, scale)};
        const float dir_sc[3]   = {V3_MUL_ELEM(ray_dir, scale)};
 
-       float depth;
-       float dist_sq = dist_squared_to_ray_v3(co_sc, dir_sc, vco_sc, &depth);
+       float depth, dist_sq;
+       dist_sq = dist_squared_to_ray_v3(origin_sc, dir_sc, vco_sc, &depth);
 
        if (depth < ray_depth_range[0]) {
                return false;
        }
 
-       if (is_persp) {
-               dist_sq /= SQUARE(depth);
-       }
-
        if ((dist_sq < *dist_to_ray_sq) && (depth < *ray_depth)) {
                *dist_to_ray_sq = dist_sq;
 
@@ -264,9 +349,9 @@ static bool test_vert(
        return false;
 }
 
-static bool test_edge(
+static bool test_edge_dist(
         const float v1[3], const float v2[3], const float ray_co[3], const 
float ray_dir[3],
-        const float ray_depth_range[2], const float scale[3], const bool 
is_persp,
+        const float ray_depth_range[2], const float scale[3],
         /* read/write args */
         float *ray_depth, float *dist_to_ray_sq,
         /* return args */
@@ -277,17 +362,13 @@ static bool test_edge(
        const float co_sc[3]    = {V3_MUL_ELEM(ray_co, scale)};
        const float dir_sc[3]   = {V3_MUL_ELEM(ray_dir, scale)};
 
-       float tmp_co[3], depth;
-       float dist_sq = dist_squared_ray_to_seg_v3(co_sc, dir_sc, v1_sc, v2_sc, 
tmp_co, &depth);
+       float tmp_co[3], depth, dist_sq;
+       dist_sq = dist_squared_ray_to_seg_v3(co_sc, dir_sc, v1_sc, v2_sc, 
tmp_co, &depth);
 
        if (depth < ray_depth_range[0]) {
                return false;
        }
 
-       if (is_persp) {
-               dist_sq /= SQUARE(depth);
-       }
-
        if ((dist_sq < *dist_to_ray_sq) && (depth < *ray_depth)) {
                *dist_to_ray_sq = dist_sq;
 
@@ -309,50 +390,430 @@ static bool test_edge(
 
 #undef V3_MUL_ELEM
 
+static bool test_projected_vert_dist(
+        float pmat_local[4][4], const float co[3], const bool is_persp,
+        const float mval[2], const float depth_range[2], const float 
win_half[2], float *dist_px_sq,
+        float r_co[3])
+{
+       float depth;
+       i

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
https://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to