[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [53820] trunk/blender/intern/cycles: Fix #33830: cycles normal mapping was not quite correct, was not correctly

Brecht Van Lommel brechtvanlommel at pandora.be
Tue Jan 15 17:35:10 CET 2013


Revision: 53820
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=53820
Author:   blendix
Date:     2013-01-15 16:35:05 +0000 (Tue, 15 Jan 2013)
Log Message:
-----------
Fix #33830: cycles normal mapping was not quite correct, was not correctly
respecting the assumption that normal and tangent are interpolated without
normalization.

Modified Paths:
--------------
    trunk/blender/intern/cycles/kernel/shaders/node_normal_map.osl
    trunk/blender/intern/cycles/kernel/svm/svm_tex_coord.h
    trunk/blender/intern/cycles/render/mesh.cpp
    trunk/blender/intern/cycles/render/mesh.h
    trunk/blender/intern/cycles/render/nodes.cpp
    trunk/blender/intern/cycles/render/object.cpp

Modified: trunk/blender/intern/cycles/kernel/shaders/node_normal_map.osl
===================================================================
--- trunk/blender/intern/cycles/kernel/shaders/node_normal_map.osl	2013-01-15 16:07:43 UTC (rev 53819)
+++ trunk/blender/intern/cycles/kernel/shaders/node_normal_map.osl	2013-01-15 16:35:05 UTC (rev 53820)
@@ -31,15 +31,23 @@
 
 	if (space == "Tangent") {
 		vector tangent;
+		vector ninterp;
 		float tangent_sign;
 
-		getattribute(attr_name, tangent);
-		getattribute(attr_sign_name, tangent_sign);
+		// get _unnormalized_ interpolated normal and tangent
+		if(!getattribute(attr_name, tangent) ||
+		   !getattribute(attr_sign_name, tangent_sign) ||
+		   !getattribute("geom:N", ninterp)) {
+			Normal = normal(0, 0, 0);
+		}
+		else {
+			// apply normal map
+			vector B = tangent_sign * cross(ninterp, tangent);
+			Normal = normalize(mcolor[0] * tangent + mcolor[1] * B + mcolor[2] * ninterp);
 
-		tangent = transform("object", "world", tangent);
-
-		vector B = tangent_sign * cross(NormalIn, tangent);
-		Normal = normalize(mcolor[0] * tangent + mcolor[1] * B + mcolor[2] * NormalIn);
+			// transform to world space
+			Normal = normalize(transform("object", "world", Normal));
+		}
 	}
 	else if (space == "Object")
 		Normal = normalize(transform("object", "world", vector(mcolor)));

Modified: trunk/blender/intern/cycles/kernel/svm/svm_tex_coord.h
===================================================================
--- trunk/blender/intern/cycles/kernel/svm/svm_tex_coord.h	2013-01-15 16:07:43 UTC (rev 53819)
+++ trunk/blender/intern/cycles/kernel/svm/svm_tex_coord.h	2013-01-15 16:35:05 UTC (rev 53820)
@@ -248,24 +248,27 @@
 		}
 
 		/* first try to get tangent attribute */
-		AttributeElement attr_elem, attr_sign_elem;
+		AttributeElement attr_elem, attr_sign_elem, attr_normal_elem;
 		int attr_offset = find_attribute(kg, sd, node.z, &attr_elem);
 		int attr_sign_offset = find_attribute(kg, sd, node.w, &attr_sign_elem);
+		int attr_normal_offset = find_attribute(kg, sd, ATTR_STD_VERTEX_NORMAL, &attr_normal_elem);
 
-		if(attr_offset == ATTR_STD_NOT_FOUND || attr_sign_offset == ATTR_STD_NOT_FOUND) {
+		if(attr_offset == ATTR_STD_NOT_FOUND || attr_sign_offset == ATTR_STD_NOT_FOUND || attr_normal_offset == ATTR_STD_NOT_FOUND) {
 			stack_store_float3(stack, normal_offset, make_float3(0.0f, 0.0f, 0.0f));
 			return;
 		}
 
-		/* ensure orthogonal and normalized (interpolation breaks it) */
+		/* get _unnormalized_ interpolated normal and tangent */
 		float3 tangent = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL);
 		float sign = primitive_attribute_float(kg, sd, attr_sign_elem, attr_sign_offset, NULL, NULL);
+		float3 normal = primitive_attribute_float3(kg, sd, attr_normal_elem, attr_normal_offset, NULL, NULL);
 
-		object_normal_transform(kg, sd, &tangent);
-		tangent = cross(sd->N, normalize(cross(tangent, sd->N)));;
+		/* apply normal map */
+		float3 B = sign * cross(normal, tangent);
+		N = normalize(color.x * tangent + color.y * B + color.z * normal);
 
-		float3 B = sign * cross(sd->N, tangent);
-		N = normalize(color.x * tangent + color.y * B + color.z * sd->N);
+		/* transform to world space */
+		object_normal_transform(kg, sd, &N);
 	}
 	else {
 		/* object, world space */

Modified: trunk/blender/intern/cycles/render/mesh.cpp
===================================================================
--- trunk/blender/intern/cycles/render/mesh.cpp	2013-01-15 16:07:43 UTC (rev 53819)
+++ trunk/blender/intern/cycles/render/mesh.cpp	2013-01-15 16:35:05 UTC (rev 53820)
@@ -43,6 +43,7 @@
 	need_update = true;
 	transform_applied = false;
 	transform_negative_scaled = false;
+	transform_normal = transform_identity();
 	displacement_method = DISPLACE_BUMP;
 	bounds = BoundBox::empty;
 
@@ -94,6 +95,7 @@
 
 	transform_applied = false;
 	transform_negative_scaled = false;
+	transform_normal = transform_identity();
 }
 
 void Mesh::add_triangle(int v0, int v1, int v2, int shader_, bool smooth_)
@@ -151,7 +153,7 @@
 	/* don't compute if already there */
 	if(attributes.find(ATTR_STD_FACE_NORMAL))
 		return;
-
+	
 	/* get attributes */
 	Attribute *attr_fN = attributes.add(ATTR_STD_FACE_NORMAL);
 	float3 *fN = attr_fN->data_float3();
@@ -181,6 +183,14 @@
 				fN[i] = -fN[i];
 		}
 	}
+
+	/* expected to be in local space */
+	if(transform_applied) {
+		Transform ntfm = transform_inverse(transform_normal);
+
+		for(size_t i = 0; i < triangles_size; i++)
+			fN[i] = normalize(transform_direction(&ntfm, fN[i]));
+	}
 }
 
 void Mesh::add_vertex_normals()
@@ -188,7 +198,7 @@
 	/* don't compute if already there */
 	if(attributes.find(ATTR_STD_VERTEX_NORMAL))
 		return;
-
+	
 	/* get attributes */
 	Attribute *attr_fN = attributes.find(ATTR_STD_FACE_NORMAL);
 	Attribute *attr_vN = attributes.add(ATTR_STD_VERTEX_NORMAL);
@@ -232,11 +242,19 @@
 	size_t triangles_size = triangles.size();
 	uint *shader_ptr = (shader.size())? &shader[0]: NULL;
 
+	bool do_transform = transform_applied;
+	Transform ntfm = transform_normal;
+
 	for(size_t i = 0; i < triangles_size; i++) {
-		normal[i].x = fN[i].x;
-		normal[i].y = fN[i].y;
-		normal[i].z = fN[i].z;
+		float3 fNi = fN[i];
 
+		if(do_transform)
+			fNi = normalize(transform_direction(&ntfm, fNi));
+
+		normal[i].x = fNi.x;
+		normal[i].y = fNi.y;
+		normal[i].z = fNi.z;
+
 		/* stuff shader id in here too */
 		if(shader_ptr[i] != last_shader || last_smooth != smooth[i]) {
 			last_shader = shader_ptr[i];
@@ -249,8 +267,14 @@
 
 	size_t verts_size = verts.size();
 
-	for(size_t i = 0; i < verts_size; i++)
-		vnormal[i] = make_float4(vN[i].x, vN[i].y, vN[i].z, 0.0f);
+	for(size_t i = 0; i < verts_size; i++) {
+		float3 vNi = vN[i];
+
+		if(do_transform)
+			vNi = normalize(transform_direction(&ntfm, vNi));
+
+		vnormal[i] = make_float4(vNi.x, vNi.y, vNi.z, 0.0f);
+	}
 }
 
 void Mesh::pack_verts(float4 *tri_verts, float4 *tri_vindex, size_t vert_offset)

Modified: trunk/blender/intern/cycles/render/mesh.h
===================================================================
--- trunk/blender/intern/cycles/render/mesh.h	2013-01-15 16:07:43 UTC (rev 53819)
+++ trunk/blender/intern/cycles/render/mesh.h	2013-01-15 16:35:05 UTC (rev 53820)
@@ -90,6 +90,7 @@
 	BoundBox bounds;
 	bool transform_applied;
 	bool transform_negative_scaled;
+	Transform transform_normal;
 	DisplacementMethod displacement_method;
 
 	/* Update Flags */

Modified: trunk/blender/intern/cycles/render/nodes.cpp
===================================================================
--- trunk/blender/intern/cycles/render/nodes.cpp	2013-01-15 16:07:43 UTC (rev 53819)
+++ trunk/blender/intern/cycles/render/nodes.cpp	2013-01-15 16:35:05 UTC (rev 53820)
@@ -3257,6 +3257,8 @@
 			attributes->add(ustring((string(attribute.c_str()) + ".tangent").c_str()));
 			attributes->add(ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
 		}
+
+		attributes->add(ATTR_STD_VERTEX_NORMAL);
 	}
 	
 	ShaderNode::attributes(attributes);

Modified: trunk/blender/intern/cycles/render/object.cpp
===================================================================
--- trunk/blender/intern/cycles/render/object.cpp	2013-01-15 16:07:43 UTC (rev 53819)
+++ trunk/blender/intern/cycles/render/object.cpp	2013-01-15 16:35:05 UTC (rev 53820)
@@ -91,38 +91,16 @@
 	for(size_t i = 0; i < mesh->curve_keys.size(); i++)
 		mesh->curve_keys[i].co = transform_point(&tfm, mesh->curve_keys[i].co);
 
-	Attribute *attr_tangent = mesh->curve_attributes.find(ATTR_STD_CURVE_TANGENT);
-	Attribute *attr_fN = mesh->attributes.find(ATTR_STD_FACE_NORMAL);
-	Attribute *attr_vN = mesh->attributes.find(ATTR_STD_VERTEX_NORMAL);
+	/* store matrix to transform later. when accessing these as attributes we
+	 * do not want the transform to be applied for consistency between static
+	 * and dynamic BVH, so we do it on packing. */
+	mesh->transform_normal = transform_transpose(transform_inverse(tfm));
 
-	Transform ntfm = transform_transpose(transform_inverse(tfm));
-
 	/* we keep normals pointing in same direction on negative scale, notify
 	 * mesh about this in it (re)calculates normals */
 	if(transform_negative_scale(tfm))
 		mesh->transform_negative_scaled = true;
 
-	if(attr_fN) {
-		float3 *fN = attr_fN->data_float3();
-
-		for(size_t i = 0; i < mesh->triangles.size(); i++)
-			fN[i] = transform_direction(&ntfm, fN[i]);
-	}
-
-	if(attr_vN) {
-		float3 *vN = attr_vN->data_float3();
-
-		for(size_t i = 0; i < mesh->verts.size(); i++)
-			vN[i] = transform_direction(&ntfm, vN[i]);
-	}
-
-	if(attr_tangent) {
-		float3 *tangent = attr_tangent->data_float3();
-
-		for(size_t i = 0; i < mesh->curve_keys.size(); i++)
-			tangent[i] = transform_direction(&tfm, tangent[i]);
-	}
-
 	if(bounds.valid()) {
 		mesh->compute_bounds();
 		compute_bounds(false, 0.0f);




More information about the Bf-blender-cvs mailing list