[Bf-blender-cvs] [d9cc3ea] master: Cycles: Fix rays parallel to the surface in the triangle refine and MultiGGX code

Lukas Stockner noreply at git.blender.org
Mon Jul 25 16:15:59 CEST 2016


Commit: d9cc3ea2c6e8cfd17612c35a82050cb01d8070ec
Author: Lukas Stockner
Date:   Mon Jul 25 16:02:25 2016 +0200
Branches: master
https://developer.blender.org/rBd9cc3ea2c6e8cfd17612c35a82050cb01d8070ec

Cycles: Fix rays parallel to the surface in the triangle refine and MultiGGX code

In the triangle intersection refinement code, rays that are parallel to the triangle caused a divide by zero.
These rays might initially hit the triangle due to the watertight intersection test, but are very rare - therefore, just skipping the refinement for them works fine.

Also, a few remaining issues in the MultiGGX code are fixed that were caused by rays parallel to the surface (which happened more often there due to smooth shading).

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

M	intern/cycles/kernel/closure/bsdf_microfacet_multi.h
M	intern/cycles/kernel/geom/geom_triangle_intersect.h

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

diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h
index deb3d24..acb50ce 100644
--- a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h
+++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h
@@ -42,7 +42,7 @@ ccl_device_inline float D_ggx_aniso(const float3 wm, const float2 alpha)
 /* Sample slope distribution (based on page 14 of the supplemental implementation). */
 ccl_device_inline float2 mf_sampleP22_11(const float cosI, const float2 randU)
 {
-	if(cosI > 0.9999f) {
+	if(cosI > 0.9999f || cosI < 1e-6f) {
 		const float r = sqrtf(randU.x / (1.0f - randU.x));
 		const float phi = M_2PI_F * randU.y;
 		return make_float2(r*cosf(phi), r*sinf(phi));
@@ -117,7 +117,7 @@ ccl_device_inline float3 mf_eval_phase_glossy(const float3 w, const float lambda
 	if(dotW_WH < 0.0f)
 		return make_float3(0.0f, 0.0f, 0.0f);
 
-	float phase = max(0.0f, dotW_WH) * 0.25f / (pArea * dotW_WH);
+	float phase = max(0.0f, dotW_WH) * 0.25f / max(pArea * dotW_WH, 1e-7f);
 	if(alpha.x == alpha.y)
 		phase *= D_ggx(wh, alpha.x);
 	else
@@ -200,9 +200,9 @@ ccl_device_inline float mf_lambda(const float3 w, const float2 alpha)
 	if(w.z > 0.9999f)
 		return 0.0f;
 	else if(w.z < -0.9999f)
-		return -1.0f;
+		return -0.9999f;
 
-	const float inv_wz2 = 1.0f / (w.z*w.z);
+	const float inv_wz2 = 1.0f / max(w.z*w.z, 1e-7f);
 	const float2 wa = make_float2(w.x, w.y)*alpha;
 	float v = sqrtf(1.0f + dot(wa, wa) * inv_wz2);
 	if(w.z <= 0.0f)
@@ -271,7 +271,10 @@ ccl_device_inline float mf_ggx_albedo(float r)
 
 ccl_device_inline float mf_ggx_pdf(const float3 wi, const float3 wo, const float alpha)
 {
-	return 0.25f * D_ggx(normalize(wi+wo), alpha) / ((1.0f + mf_lambda(wi, make_float2(alpha, alpha))) * wi.z) + (1.0f - mf_ggx_albedo(alpha)) * wo.z;
+	float D = D_ggx(normalize(wi+wo), alpha);
+	float lambda = mf_lambda(wi, make_float2(alpha, alpha));
+	float albedo = mf_ggx_albedo(alpha);
+	return 0.25f * D / max((1.0f + lambda) * wi.z, 1e-7f) + (1.0f - albedo) * wo.z;
 }
 
 ccl_device_inline float mf_ggx_aniso_pdf(const float3 wi, const float3 wo, const float2 alpha)
diff --git a/intern/cycles/kernel/geom/geom_triangle_intersect.h b/intern/cycles/kernel/geom/geom_triangle_intersect.h
index caa6c9d..eb0decc 100644
--- a/intern/cycles/kernel/geom/geom_triangle_intersect.h
+++ b/intern/cycles/kernel/geom/geom_triangle_intersect.h
@@ -342,9 +342,16 @@ ccl_device_inline float3 triangle_refine(KernelGlobals *kg,
 	float3 tvec = make_float3(P.x - tri_c.x, P.y - tri_c.y, P.z - tri_c.z);
 	float3 qvec = cross(tvec, edge1);
 	float3 pvec = cross(D, edge2);
-	float rt = dot(edge2, qvec) / dot(edge1, pvec);
-
-	P = P + D*rt;
+	float det = dot(edge1, pvec);
+	if(det != 0.0f) {
+		/* If determinant is zero it means ray lies in the plane of
+		 * the triangle. It is possible in theory due to watertight
+		 * nature of triangle intersection. For suc hcases we simply
+		 * don't refine intersection hoping it'll go all fine.
+		 */
+		float rt = dot(edge2, qvec) / det;
+		P = P + D*rt;
+	}
 
 	if(isect->object != OBJECT_NONE) {
 #  ifdef __OBJECT_MOTION__
@@ -400,9 +407,16 @@ ccl_device_inline float3 triangle_refine_subsurface(KernelGlobals *kg,
 	float3 tvec = make_float3(P.x - tri_c.x, P.y - tri_c.y, P.z - tri_c.z);
 	float3 qvec = cross(tvec, edge1);
 	float3 pvec = cross(D, edge2);
-	float rt = dot(edge2, qvec) / dot(edge1, pvec);
-
-	P = P + D*rt;
+	float det = dot(edge1, pvec);
+	if(det != 0.0f) {
+		/* If determinant is zero it means ray lies in the plane of
+		 * the triangle. It is possible in theory due to watertight
+		 * nature of triangle intersection. For such cases we simply
+		 * don't refine intersection hoping it'll go all fine.
+		 */
+		float rt = dot(edge2, qvec) / det;
+		P = P + D*rt;
+	}
 #endif  /* __INTERSECTION_REFINE__ */
 
 	if(isect->object != OBJECT_NONE) {




More information about the Bf-blender-cvs mailing list