[Bf-blender-cvs] [77089a3] master: Fix T38358: Face snapping fails on Orthographic view

Bastien Montagne noreply at git.blender.org
Wed Jan 29 20:13:55 CET 2014


Commit: 77089a3bf20319be87a434750656206449c04dbc
Author: Bastien Montagne
Date:   Wed Jan 29 20:10:03 2014 +0100
https://developer.blender.org/rB77089a3bf20319be87a434750656206449c04dbc

Fix T38358: Face snapping fails on Orthographic view

Issue is caused by start point of ray used to detect faces under the mouse is set rather far away in ortho 3dviews.
The loss of precision on the ray location induced by this can lead to face snapping failures.

Solution is to do the raycasting with a temp start point, much closer to the object we check, and add back
to the found distance the diff to the real start point once detection is done (as we need all hit distances
from all tested objects to be relative to a common point!).

Note this commit only addresses the "face snapping on mesh" case, other kind of snapping do not seem to suffer
from this issue.

Reviewers: brecht, campbellbarton

Differential Revision: https://developer.blender.org/D268

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

M	source/blender/blenkernel/BKE_object.h
M	source/blender/blenkernel/intern/object.c
M	source/blender/editors/include/ED_view3d.h
M	source/blender/editors/space_view3d/view3d_project.c
M	source/blender/editors/transform/transform_snap.c

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

diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 33c9583..38055dd 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -124,7 +124,8 @@ void BKE_object_where_is_calc_mat4(struct Scene *scene, struct Object *ob, float
 /* possibly belong in own moduke? */
 struct BoundBox *BKE_boundbox_alloc_unit(void);
 void BKE_boundbox_init_from_minmax(struct BoundBox *bb, const float min[3], const float max[3]);
-bool BKE_boundbox_ray_hit_check(struct BoundBox *bb, const float ray_start[3], const float ray_normal[3]);
+bool BKE_boundbox_ray_hit_check(struct BoundBox *bb, const float ray_start[3], const float ray_normal[3],
+                                float *r_lambda);
 
 struct BoundBox *BKE_object_boundbox_get(struct Object *ob);
 void BKE_object_dimensions_get(struct Object *ob, float vec[3]);
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index dc20629..019885d 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -3131,7 +3131,8 @@ int BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc,
  * Test a bounding box for ray intersection
  * assumes the ray is already local to the boundbox space
  */
-bool BKE_boundbox_ray_hit_check(struct BoundBox *bb, const float ray_start[3], const float ray_normal[3])
+bool BKE_boundbox_ray_hit_check(struct BoundBox *bb, const float ray_start[3], const float ray_normal[3],
+                                float *r_lambda)
 {
 	const int triangle_indexes[12][3] = {
 	    {0, 1, 2}, {0, 2, 3},
@@ -3144,13 +3145,18 @@ bool BKE_boundbox_ray_hit_check(struct BoundBox *bb, const float ray_start[3], c
 	bool result = false;
 	int i;
 	
-	for (i = 0; i < 12 && result == 0; i++) {
+	for (i = 0; i < 12 && (!result || r_lambda); i++) {
 		float lambda;
 		int v1, v2, v3;
 		v1 = triangle_indexes[i][0];
 		v2 = triangle_indexes[i][1];
 		v3 = triangle_indexes[i][2];
-		result = isect_ray_tri_v3(ray_start, ray_normal, bb->vec[v1], bb->vec[v2], bb->vec[v3], &lambda, NULL);
+		if (isect_ray_tri_v3(ray_start, ray_normal, bb->vec[v1], bb->vec[v2], bb->vec[v3], &lambda, NULL) &&
+		    (!r_lambda || *r_lambda > lambda))
+		{
+			result = true;
+			*r_lambda = lambda;
+		}
 	}
 	
 	return result;
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index f155247..a76c904 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -200,6 +200,8 @@ eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *ar, const fl
 float ED_view3d_calc_zfac(const struct RegionView3D *rv3d, const float co[3], bool *r_flip);
 bool ED_view3d_win_to_ray(const struct ARegion *ar, struct View3D *v3d, const float mval[2],
                           float ray_start[3], float ray_normal[3], const bool do_clip);
+bool ED_view3d_win_to_ray_ex(const struct ARegion *ar, struct View3D *v3d, const float mval[2],
+                             float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip);
 void ED_view3d_global_to_vector(const struct RegionView3D *rv3d, const float coord[3], float vec[3]);
 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]);
diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c
index 0954563..0c35398 100644
--- a/source/blender/editors/space_view3d/view3d_project.c
+++ b/source/blender/editors/space_view3d/view3d_project.c
@@ -302,29 +302,102 @@ float ED_view3d_calc_zfac(const RegionView3D *rv3d, const float co[3], bool *r_f
 	return zfac;
 }
 
+static void view3d_win_to_ray_segment(const ARegion *ar, View3D *v3d, const float mval[2],
+                                      float r_ray_co[3], float r_ray_dir[3], float r_ray_start[3], float r_ray_end[3])
+{
+	RegionView3D *rv3d = ar->regiondata;
+	float _ray_co[3], _ray_dir[3], start_offset, end_offset;
+
+	if (!r_ray_co) r_ray_co = _ray_co;
+	if (!r_ray_dir) r_ray_dir = _ray_dir;
+
+	ED_view3d_win_to_vector(ar, mval, r_ray_dir);
+	negate_v3(r_ray_dir);
+
+	if (rv3d->is_persp) {
+		copy_v3_v3(r_ray_co, rv3d->viewinv[3]);
+
+		start_offset = -v3d->near;
+		end_offset = -v3d->far;
+	}
+	else {
+		float vec[4];
+		vec[0] = 2.0f * mval[0] / ar->winx - 1;
+		vec[1] = 2.0f * mval[1] / ar->winy - 1;
+		vec[2] = 0.0f;
+		vec[3] = 1.0f;
+
+		mul_m4_v4(rv3d->persinv, vec);
+		copy_v3_v3(r_ray_co, vec);
+
+		start_offset = -1000.0f;
+		end_offset = 1000.0f;
+	}
+
+	if (r_ray_start) {
+		madd_v3_v3v3fl(r_ray_start, r_ray_co, r_ray_dir, start_offset);
+	}
+	if (r_ray_end) {
+		madd_v3_v3v3fl(r_ray_end, r_ray_co, r_ray_dir, end_offset);
+	}
+}
+
+BLI_INLINE bool view3d_clip_segment(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)) {
+		return false;
+	}
+	return true;
+}
+
 /**
  * Calculate a 3d viewpoint and direction vector from 2d window coordinates.
  * This ray_start is located at the viewpoint, ray_normal is the direction towards mval.
  * ray_start is clipped by the view near limit so points in front of it are always in view.
  * In orthographic view the resulting ray_normal will match the view vector.
+ * This version also returns the ray_co point of the ray on window plane, useful to fix precision
+ * issues esp. with ortho view, where default ray_start is set rather far away.
  * \param ar The region (used for the window width and height).
  * \param v3d The 3d viewport (used for near clipping value).
  * \param mval The area relative 2d location (such as event->mval, converted into float[2]).
- * \param r_ray_start The world-space starting point of the segment.
+ * \param r_ray_co The world-space point where the ray intersects the window plane.
  * \param r_ray_normal The normalized world-space direction of towards mval.
- * \param do_clip Optionally clip the ray by the view clipping planes.
- * \return success, false if the segment is totally clipped.
+ * \param r_ray_start The world-space starting point of the ray.
+ * \param do_clip Optionally clip the start of the ray by the view clipping planes.
+ * \return success, false if the ray is totally clipped.
+ */
+bool ED_view3d_win_to_ray_ex(const ARegion *ar, View3D *v3d, const float mval[2],
+                             float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip)
+{
+	float ray_end[3];
+
+	view3d_win_to_ray_segment(ar, v3d, mval, r_ray_co, r_ray_normal, r_ray_start, ray_end);
+
+	/* bounds clipping */
+	if (do_clip) {
+		return view3d_clip_segment((RegionView3D *)ar->regiondata, r_ray_start, ray_end);
+	}
+
+	return true;
+}
+
+/**
+ * Calculate a 3d viewpoint and direction vector from 2d window coordinates.
+ * This ray_start is located at the viewpoint, ray_normal is the direction towards mval.
+ * ray_start is clipped by the view near limit so points in front of it are always in view.
+ * In orthographic view the resulting ray_normal will match the view vector.
+ * \param ar The region (used for the window width and height).
+ * \param v3d The 3d viewport (used for near clipping value).
+ * \param mval The area relative 2d location (such as event->mval, converted into float[2]).
+ * \param r_ray_co The world-space point where the ray intersects the window plane.
+ * \param r_ray_normal The normalized world-space direction of towards mval.
+ * \param do_clip Optionally clip the start of the ray by the view clipping planes.
+ * \return success, false if the ray is totally clipped.
  */
 bool ED_view3d_win_to_ray(const ARegion *ar, View3D *v3d, const float mval[2],
                           float r_ray_start[3], float r_ray_normal[3], const bool do_clip)
 {
-	float ray_end[3];
-	bool is_clip;
-	
-	is_clip = ED_view3d_win_to_segment(ar, v3d, mval, r_ray_start, ray_end, do_clip);
-	sub_v3_v3v3(r_ray_normal, ray_end, r_ray_start);
-	normalize_v3(r_ray_normal);
-	return is_clip;
+	return ED_view3d_win_to_ray_ex(ar, v3d, mval, NULL, r_ray_normal, r_ray_start, do_clip);
 }
 
 /**
@@ -507,34 +580,11 @@ void ED_view3d_win_to_vector(const ARegion *ar, const float mval[2], float out[3
 bool ED_view3d_win_to_segment(const ARegion *ar, View3D *v3d, const float mval[2],
                               float r_ray_start[3], float r_ray_end[3], const bool do_clip)
 {
-	RegionView3D *rv3d = ar->regiondata;
-
-	if (rv3d->is_persp) {
-		float vec[3];
-		ED_view3d_win_to_vector(ar, mval, vec);
-
-		copy_v3_v3(r_ray_start, rv3d->viewinv[3]);
-		madd_v3_v3v3fl(r_ray_start, rv3d->viewinv[3], vec, v3d->near);
-		madd_v3_v3v3fl(r_ray_end, rv3d->viewinv[3], vec, v3d->far);
-	}
-	else {
-		float vec[4];
-		vec[0] = 2.0f * mval[0] / ar->winx - 1;
-		vec[1] = 2.0f * mval[1] / ar->winy - 1;
-		vec[2] = 0.0f;
-		vec[3] = 1.0f;
-
-		mul_m4_v4(rv3d->persinv, vec);
-
-		madd_v3_v3v3fl(r_ray_start, vec, rv3d->viewinv[2],  1000.0f);
-		madd_v3_v3v3fl(r_ray_end, vec, rv3d->viewinv[2], -1000.0f);
-	}
+	view3d_win_to_ray_segment(ar, v3d, mval, NULL, NULL, r_ray_start, r_ray_end);
 
 	/* bounds clipping */
-	if (do_clip && (rv3d->rflag & RV3D_CLIPPING)) {
-		if (clip_segment_v3_plane_n(r_ray_start, r_ray_end, rv3d->clip, 6) == false) {
-			return false;
-		}
+	if (do_clip) {
+		return view3d_clip_segment((RegionView3D *)ar->regiondata, r_ray_start, r_ray_end);
 	}
 
 	return true;
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 7df5c5f..694b293 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -1504,21 +1504,19 @@ static bool snapCurve(short snap_mode, ARegion *ar, Object *ob, Curve *cu, float
 }
 
 static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, BMEditMesh *em, float obmat[4][4],
-                            const float ray_start[3], const float ray_normal[3], const float 

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list