Imperfections when Bake displacement map to plane if camera is not in front #48550

Closed
opened 2016-05-30 20:48:45 +02:00 by YAFU · 7 comments

System Information
Kubuntu Linux 64bits, GTX 960

Blender Version
Broken: Perhaps all, I've tried from blender 2.73a until buildbot.

Short description of error
Hi. Sorry if this is not a bug, but I prefer to report just in case. I asked in forum and IRC, but still I could not clear the doubt.
I've been looking for documentation about whether or not it is needed some Camera configuration in Blender internal to bake the displacement map form objets to a plane. Like this answer from Greg Zaal, he does not mention any special camera settings:
https://blender.stackexchange.com/questions/1161/how-to-make-a-displacement-map-from-existing-3d-geometry

I have this concern because with this .blend file:
Displacement map_bi.blend

if I do not set the camera in front and top of the plane, then I get small square/pixels missing in the bake image, like these that another user mentions some years ago:
https://blender.stackexchange.com/questions/18639/small-errors-when-baking-displacement-maps

Exact steps for others to reproduce the error
Open the .blend I shared and bake. Then zoom in the bake image much and you see carefully looking for those little squares.

If you places the camera above (in top view just Ctrl+Alt+NP 0, and no matter if the camera is centered) and bake again, then the imperfections do not appear.

**System Information** Kubuntu Linux 64bits, GTX 960 **Blender Version** Broken: Perhaps all, I've tried from blender 2.73a until buildbot. **Short description of error** Hi. Sorry if this is not a bug, but I prefer to report just in case. I asked in forum and IRC, but still I could not clear the doubt. I've been looking for documentation about whether or not it is needed some Camera configuration in Blender internal to bake the displacement map form objets to a plane. Like this answer from Greg Zaal, he does not mention any special camera settings: https://blender.stackexchange.com/questions/1161/how-to-make-a-displacement-map-from-existing-3d-geometry I have this concern because with this .blend file: [Displacement map_bi.blend](https://archive.blender.org/developer/F315351/Displacement_map_bi.blend) if I do not set the camera in front and top of the plane, then I get small square/pixels missing in the bake image, like these that another user mentions some years ago: https://blender.stackexchange.com/questions/18639/small-errors-when-baking-displacement-maps **Exact steps for others to reproduce the error** Open the .blend I shared and bake. Then zoom in the bake image much and you see carefully looking for those little squares. If you places the camera above (in top view just Ctrl+Alt+NP 0, and no matter if the camera is centered) and bake again, then the imperfections do not appear.
Author

Changed status to: 'Open'

Changed status to: 'Open'
Author

Added subscriber: @YAFU

Added subscriber: @YAFU

Added subscribers: @brecht, @Sergey

Added subscribers: @brecht, @Sergey

Root of the issue here is non-watertight nature of ray-tri intersection in BI, which is very much similar to what we had in Cycles. The reason why artifacts depends on camera angle is because BI considers all objects to be in camera space when rendering or baking.

Have a quick patch to make intersections watertight:

P359: Snippet for #48550

diff --git a/source/blender/render/intern/include/rayintersection.h b/source/blender/render/intern/include/rayintersection.h
index 3607e66..1935e4e 100644
--- a/source/blender/render/intern/include/rayintersection.h
+++ b/source/blender/render/intern/include/rayintersection.h
@@ -38,6 +38,8 @@
 extern "C" {
 #endif
 
+#include "BLI_math_geom.h"
+
 struct RayObject;
 
 /* Ray Hints */
@@ -101,6 +103,9 @@ typedef struct Isect {
 #ifdef RE_RAYCOUNTER
 	RayCounter *raycounter;
 #endif
+
+	/* Precalculated coefficients for watertight intersection check. */
+	struct IsectRayPrecalc isect_precalc;
 } Isect;
 
 /* ray types */
diff --git a/source/blender/render/intern/raytrace/rayobject.cpp b/source/blender/render/intern/raytrace/rayobject.cpp
index de6b913..66653fd 100644
--- a/source/blender/render/intern/raytrace/rayobject.cpp
+++ b/source/blender/render/intern/raytrace/rayobject.cpp
@@ -138,80 +138,29 @@ MALWAYS_INLINE int vlr_check_bake(Isect *is, ObjectInstanceRen *obi, VlakRen *UN
 
 /* Ray Triangle/Quad Intersection */
 
-MALWAYS_INLINE int isec_tri_quad(float start- [x], float dir- [x], RayFace *face, float uv- [x], float *lambda)
+MALWAYS_INLINE int isec_tri_quad(float start- [x], const struct IsectRayPrecalc *isect_precalc, RayFace *face, float r_uv- [x], float *lambda)
 {
-	float co1- [x], co2- [x], co3- [x], co4[3];
-	float t0- [x], t1- [x], x- [x], r- [x], m- [x], u, v, divdet, det1, l;
-	int quad;
-
-	quad = RE_rayface_isQuad(face);
-
-	copy_v3_v3(co1, face->v1);
-	copy_v3_v3(co2, face->v2);
-	copy_v3_v3(co3, face->v3);
-
-	copy_v3_v3(r, dir);
-
-	/* intersect triangle */
-	sub_v3_v3v3(t0, co3, co2);
-	sub_v3_v3v3(t1, co3, co1);
-
-	cross_v3_v3v3(x, r, t1);
-	divdet = dot_v3v3(t0, x);
-
-	sub_v3_v3v3(m, start, co3);
-	det1 = dot_v3v3(m, x);
-	
-	if (divdet != 0.0f) {
-		divdet = 1.0f / divdet;
-		v = det1 * divdet;
-
-		if (v < RE_RAYTRACE_EPSILON && v > -(1.0f + RE_RAYTRACE_EPSILON)) {
-			float cros[3];
-
-			cross_v3_v3v3(cros, m, t0);
-			u = divdet * dot_v3v3(cros, r);
-
-			if (u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f + RE_RAYTRACE_EPSILON)) {
-				l = divdet * dot_v3v3(cros, t1);
-
-				/* check if intersection is within ray length */
-				if (l > -RE_RAYTRACE_EPSILON && l < *lambda) {
-					uv- [x] = u;
-					uv- [x] = v;
-					*lambda = l;
-					return 1;
-				}
-			}
+	float uv- [x], l;
+
+	if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v2, face->v3, &l, uv)) {
+		/* check if intersection is within ray length */
+		if (l > -RE_RAYTRACE_EPSILON && l < *lambda) {
+			r_uv- [x] = uv[0];
+			r_uv- [x] = uv[1];
+			*lambda = l;
+			return 1;
 		}
 	}
 
 	/* intersect second triangle in quad */
-	if (quad) {
-		copy_v3_v3(co4, face->v4);
-		sub_v3_v3v3(t0, co3, co4);
-		divdet = dot_v3v3(t0, x);
-
-		if (divdet != 0.0f) {
-			divdet = 1.0f / divdet;
-			v = det1 * divdet;
-			
-			if (v < RE_RAYTRACE_EPSILON && v > -(1.0f + RE_RAYTRACE_EPSILON)) {
-				float cros[3];
-
-				cross_v3_v3v3(cros, m, t0);
-				u = divdet * dot_v3v3(cros, r);
-	
-				if (u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f + RE_RAYTRACE_EPSILON)) {
-					l = divdet * dot_v3v3(cros, t1);
-					
-					if (l > -RE_RAYTRACE_EPSILON && l < *lambda) {
-						uv- [x] = u;
-						uv- [x] = -(1.0f + v + u);
-						*lambda = l;
-						return 2;
-					}
-				}
+	if (RE_rayface_isQuad(face)) {
+		if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v3, face->v4, &l, uv)) {
+			/* check if intersection is within ray length */
+			if (l > -RE_RAYTRACE_EPSILON && l < *lambda) {
+				r_uv- [x] = uv[0];
+				r_uv- [x] = uv[1];
+				*lambda = l;
+				return 1;
 			}
 		}
 	}
@@ -221,6 +170,7 @@ MALWAYS_INLINE int isec_tri_quad(float start- [x], float dir- [x], RayFace *face, fl
 
 /* Simpler yes/no Ray Triangle/Quad Intersection */
 
+/* TODO(sergey): Can become watertight. */
 MALWAYS_INLINE int isec_tri_quad_neighbour(float start- [x], float dir- [x], RayFace *face)
 {
 	float co1- [x], co2- [x], co3- [x], co4[3];
@@ -317,7 +267,7 @@ MALWAYS_INLINE int intersect_rayface(RayObject *hit_obj, RayFace *face, Isect *i
 	RE_RC_COUNT(is->raycounter->faces.test);
 
 	dist = is->dist;
-	ok = isec_tri_quad(is->start, is->dir, face, uv, &dist);
+	ok = isec_tri_quad(is->start, &is->isect_precalc, face, uv, &dist);
 
 	if (ok) {
 	
@@ -433,6 +383,9 @@ int RE_rayobject_raycast(RayObject *r, Isect *isec)
 
 int RE_rayobject_intersect(RayObject *r, Isect *i)
 {
+	/* Pre-calculate orientation for watertight intersection checks. */
+	isect_ray_tri_watertight_v3_precalc(&i->isect_precalc, i->dir);
+
 	if (RE_rayobject_isRayFace(r)) {
 		return intersect_rayface(r, (RayFace *) RE_rayobject_align(r), i);
 	}

But there are couple of things:

  • Since the triangle intersection is now happening in bf_blenlib it's no longer using same SIMD optimization level as the raycatsobject. Perhaps it's not so bad, because SSE2 is now enabled globally for whole Blender and i'm not sure if higher SSE will actually be applyable to triangle intersection.

  • While it seems to work with this particular file, i'm not sure how to verify it on all other files

  • Neighbor intersection is not watertight yet. It also seems it can't re-use same pre-calculation because direction is inverted, so it'll be somewhat slower.

@brecht, do you have some strong opinion here?

Root of the issue here is non-watertight nature of ray-tri intersection in BI, which is very much similar to what we had in Cycles. The reason why artifacts depends on camera angle is because BI considers all objects to be in camera space when rendering or baking. Have a quick patch to make intersections watertight: [P359: Snippet for #48550](https://archive.blender.org/developer/P359.txt) ``` diff --git a/source/blender/render/intern/include/rayintersection.h b/source/blender/render/intern/include/rayintersection.h index 3607e66..1935e4e 100644 --- a/source/blender/render/intern/include/rayintersection.h +++ b/source/blender/render/intern/include/rayintersection.h @@ -38,6 +38,8 @@ extern "C" { #endif +#include "BLI_math_geom.h" + struct RayObject; /* Ray Hints */ @@ -101,6 +103,9 @@ typedef struct Isect { #ifdef RE_RAYCOUNTER RayCounter *raycounter; #endif + + /* Precalculated coefficients for watertight intersection check. */ + struct IsectRayPrecalc isect_precalc; } Isect; /* ray types */ diff --git a/source/blender/render/intern/raytrace/rayobject.cpp b/source/blender/render/intern/raytrace/rayobject.cpp index de6b913..66653fd 100644 --- a/source/blender/render/intern/raytrace/rayobject.cpp +++ b/source/blender/render/intern/raytrace/rayobject.cpp @@ -138,80 +138,29 @@ MALWAYS_INLINE int vlr_check_bake(Isect *is, ObjectInstanceRen *obi, VlakRen *UN /* Ray Triangle/Quad Intersection */ -MALWAYS_INLINE int isec_tri_quad(float start- [x], float dir- [x], RayFace *face, float uv- [x], float *lambda) +MALWAYS_INLINE int isec_tri_quad(float start- [x], const struct IsectRayPrecalc *isect_precalc, RayFace *face, float r_uv- [x], float *lambda) { - float co1- [x], co2- [x], co3- [x], co4[3]; - float t0- [x], t1- [x], x- [x], r- [x], m- [x], u, v, divdet, det1, l; - int quad; - - quad = RE_rayface_isQuad(face); - - copy_v3_v3(co1, face->v1); - copy_v3_v3(co2, face->v2); - copy_v3_v3(co3, face->v3); - - copy_v3_v3(r, dir); - - /* intersect triangle */ - sub_v3_v3v3(t0, co3, co2); - sub_v3_v3v3(t1, co3, co1); - - cross_v3_v3v3(x, r, t1); - divdet = dot_v3v3(t0, x); - - sub_v3_v3v3(m, start, co3); - det1 = dot_v3v3(m, x); - - if (divdet != 0.0f) { - divdet = 1.0f / divdet; - v = det1 * divdet; - - if (v < RE_RAYTRACE_EPSILON && v > -(1.0f + RE_RAYTRACE_EPSILON)) { - float cros[3]; - - cross_v3_v3v3(cros, m, t0); - u = divdet * dot_v3v3(cros, r); - - if (u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f + RE_RAYTRACE_EPSILON)) { - l = divdet * dot_v3v3(cros, t1); - - /* check if intersection is within ray length */ - if (l > -RE_RAYTRACE_EPSILON && l < *lambda) { - uv- [x] = u; - uv- [x] = v; - *lambda = l; - return 1; - } - } + float uv- [x], l; + + if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v2, face->v3, &l, uv)) { + /* check if intersection is within ray length */ + if (l > -RE_RAYTRACE_EPSILON && l < *lambda) { + r_uv- [x] = uv[0]; + r_uv- [x] = uv[1]; + *lambda = l; + return 1; } } /* intersect second triangle in quad */ - if (quad) { - copy_v3_v3(co4, face->v4); - sub_v3_v3v3(t0, co3, co4); - divdet = dot_v3v3(t0, x); - - if (divdet != 0.0f) { - divdet = 1.0f / divdet; - v = det1 * divdet; - - if (v < RE_RAYTRACE_EPSILON && v > -(1.0f + RE_RAYTRACE_EPSILON)) { - float cros[3]; - - cross_v3_v3v3(cros, m, t0); - u = divdet * dot_v3v3(cros, r); - - if (u < RE_RAYTRACE_EPSILON && (v + u) > -(1.0f + RE_RAYTRACE_EPSILON)) { - l = divdet * dot_v3v3(cros, t1); - - if (l > -RE_RAYTRACE_EPSILON && l < *lambda) { - uv- [x] = u; - uv- [x] = -(1.0f + v + u); - *lambda = l; - return 2; - } - } + if (RE_rayface_isQuad(face)) { + if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v3, face->v4, &l, uv)) { + /* check if intersection is within ray length */ + if (l > -RE_RAYTRACE_EPSILON && l < *lambda) { + r_uv- [x] = uv[0]; + r_uv- [x] = uv[1]; + *lambda = l; + return 1; } } } @@ -221,6 +170,7 @@ MALWAYS_INLINE int isec_tri_quad(float start- [x], float dir- [x], RayFace *face, fl /* Simpler yes/no Ray Triangle/Quad Intersection */ +/* TODO(sergey): Can become watertight. */ MALWAYS_INLINE int isec_tri_quad_neighbour(float start- [x], float dir- [x], RayFace *face) { float co1- [x], co2- [x], co3- [x], co4[3]; @@ -317,7 +267,7 @@ MALWAYS_INLINE int intersect_rayface(RayObject *hit_obj, RayFace *face, Isect *i RE_RC_COUNT(is->raycounter->faces.test); dist = is->dist; - ok = isec_tri_quad(is->start, is->dir, face, uv, &dist); + ok = isec_tri_quad(is->start, &is->isect_precalc, face, uv, &dist); if (ok) { @@ -433,6 +383,9 @@ int RE_rayobject_raycast(RayObject *r, Isect *isec) int RE_rayobject_intersect(RayObject *r, Isect *i) { + /* Pre-calculate orientation for watertight intersection checks. */ + isect_ray_tri_watertight_v3_precalc(&i->isect_precalc, i->dir); + if (RE_rayobject_isRayFace(r)) { return intersect_rayface(r, (RayFace *) RE_rayobject_align(r), i); } ``` But there are couple of things: - Since the triangle intersection is now happening in `bf_blenlib` it's no longer using same SIMD optimization level as the `raycatsobject`. Perhaps it's not so bad, because SSE2 is now enabled globally for whole Blender and i'm not sure if higher SSE will actually be applyable to triangle intersection. - While it seems to work with this particular file, i'm not sure how to verify it on all other files - Neighbor intersection is not watertight yet. It also seems it can't re-use same pre-calculation because direction is inverted, so it'll be somewhat slower. @brecht, do you have some strong opinion here?
Sergey Sharybin self-assigned this 2016-05-31 11:27:30 +02:00

No strong opinion here, watertight intersection is worth a small slowdown in my opinion.

No strong opinion here, watertight intersection is worth a small slowdown in my opinion.

Changed status from 'Open' to: 'Resolved'

Changed status from 'Open' to: 'Resolved'

This issue was referenced by fd7068ee28

This issue was referenced by fd7068ee2879c949b5b6e9356702e00201988481
Sign in to join this conversation.
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
4 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender#48550
No description provided.