[Bf-blender-cvs] [e7d8908f140] blender2.8: GPUMaterial: Optimize and fix blending in box mapping

Clément Foucault noreply at git.blender.org
Fri Jul 20 19:17:27 CEST 2018


Commit: e7d8908f1405bbe54df2b5b51b4c1078200e5020
Author: Clément Foucault
Date:   Fri Jul 20 15:25:20 2018 +0200
Branches: blender2.8
https://developer.blender.org/rBe7d8908f1405bbe54df2b5b51b4c1078200e5020

GPUMaterial: Optimize and fix blending in box mapping

Blending was done in srgb space and was not matching cycles.

Optimized by using less branches and more vector operations.

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

M	source/blender/gpu/shaders/gpu_shader_material.glsl
M	source/blender/nodes/shader/nodes/node_shader_tex_image.c

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

diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index d1183c792f5..4b376160105 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -1804,18 +1804,46 @@ void node_tex_image(vec3 co, sampler2D ima, out vec4 color, out float alpha)
 	alpha = color.a;
 }
 
+void tex_box_sample(vec3 texco,
+                    vec3 N,
+                    sampler2D ima,
+                    out vec4 color1,
+                    out vec4 color2,
+                    out vec4 color3)
+{
+	/* X projection */
+	vec2 uv = texco.yz;
+	if (N.x < 0.0) {
+		uv.x = 1.0 - uv.x;
+	}
+	color1 = texture(ima, uv);
+	/* Y projection */
+	uv = texco.xz;
+	if (N.y > 0.0) {
+		uv.x = 1.0 - uv.x;
+	}
+	color2 = texture(ima, uv);
+	/* Z projection */
+	uv = texco.yx;
+	if (N.z > 0.0) {
+		uv.x = 1.0 - uv.x;
+	}
+	color3 = texture(ima, uv);
+}
+
 void node_tex_image_box(vec3 texco,
                         vec3 N,
+                        vec4 color1,
+                        vec4 color2,
+                        vec4 color3,
                         sampler2D ima,
                         float blend,
                         out vec4 color,
                         out float alpha)
 {
-	vec3 signed_N = N;
-
 	/* project from direction vector to barycentric coordinates in triangles */
-	N = vec3(abs(N.x), abs(N.y), abs(N.z));
-	N /= (N.x + N.y + N.z);
+	N = abs(N);
+	N /= dot(N, vec3(1.0));
 
 	/* basic idea is to think of this as a triangle, each corner representing
 	 * one of the 3 faces of the cube. in the corners we have single textures,
@@ -1825,72 +1853,36 @@ void node_tex_image_box(vec3 texco,
 	 * the Nxyz values are the barycentric coordinates in an equilateral
 	 * triangle, which in case of blending, in the middle has a smaller
 	 * equilateral triangle where 3 textures blend. this divides things into
-	 * 7 zones, with an if () test for each zone */
+	 * 7 zones, with an if () test for each zone
+	 * EDIT: Now there is only 4 if's. */
 
-	vec3 weight = vec3(0.0, 0.0, 0.0);
-	float limit = 0.5 * (1.0 + blend);
+	float limit = 0.5 + 0.5 * blend;
 
-	/* first test for corners with single texture */
-	if (N.x > limit * (N.x + N.y) && N.x > limit * (N.x + N.z)) {
-		weight.x = 1.0;
-	}
-	else if (N.y > limit * (N.x + N.y) && N.y > limit * (N.y + N.z)) {
-		weight.y = 1.0;
+	vec3 weight;
+	weight.x = N.x / (N.x + N.y);
+	weight.y = N.y / (N.y + N.z);
+	weight.z = N.z / (N.x + N.z);
+	weight = clamp((weight - 0.5 * (1.0 - blend)) / max(1e-8, blend), 0.0, 1.0);
+
+	/* test for mixes between two textures */
+	if (N.z < (1.0 - limit) * (N.y + N.x)) {
+		weight.z = 0.0;
+		weight.y = 1.0 - weight.x;
 	}
-	else if (N.z > limit * (N.x + N.z) && N.z > limit * (N.y + N.z)) {
-		weight.z = 1.0;
+	else if (N.x < (1.0 - limit) * (N.y + N.z)) {
+		weight.x = 0.0;
+		weight.z = 1.0 - weight.y;
 	}
-	else if (blend > 0.0) {
-		/* in case of blending, test for mixes between two textures */
-		if (N.z < (1.0 - limit) * (N.y + N.x)) {
-			weight.x = N.x / (N.x + N.y);
-			weight.x = clamp((weight.x - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
-			weight.y = 1.0 - weight.x;
-		}
-		else if (N.x < (1.0 - limit) * (N.y + N.z)) {
-			weight.y = N.y / (N.y + N.z);
-			weight.y = clamp((weight.y - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
-			weight.z = 1.0 - weight.y;
-		}
-		else if (N.y < (1.0 - limit) * (N.x + N.z)) {
-			weight.x = N.x / (N.x + N.z);
-			weight.x = clamp((weight.x - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
-			weight.z = 1.0 - weight.x;
-		}
-		else {
-			/* last case, we have a mix between three */
-			weight.x = ((2.0 - limit) * N.x + (limit - 1.0)) / (2.0 * limit - 1.0);
-			weight.y = ((2.0 - limit) * N.y + (limit - 1.0)) / (2.0 * limit - 1.0);
-			weight.z = ((2.0 - limit) * N.z + (limit - 1.0)) / (2.0 * limit - 1.0);
-		}
+	else if (N.y < (1.0 - limit) * (N.x + N.z)) {
+		weight.y = 0.0;
+		weight.x = 1.0 - weight.z;
 	}
 	else {
-		/* Desperate mode, no valid choice anyway, fallback to one side.*/
-		weight.x = 1.0;
-	}
-	color = vec4(0);
-	if (weight.x > 0.0) {
-		vec2 uv = texco.yz;
-		if(signed_N.x < 0.0) {
-			uv.x = 1.0 - uv.x;
-		}
-		color += weight.x * texture(ima, uv);
-	}
-	if (weight.y > 0.0) {
-		vec2 uv = texco.xz;
-		if(signed_N.y > 0.0) {
-			uv.x = 1.0 - uv.x;
-		}
-		color += weight.y * texture(ima, uv);
-	}
-	if (weight.z > 0.0) {
-		vec2 uv = texco.yx;
-		if(signed_N.z > 0.0) {
-			uv.x = 1.0 - uv.x;
-		}
-		color += weight.z * texture(ima, uv);
+		/* last case, we have a mix between three */
+		weight = ((2.0 - limit) * N + (limit - 1.0)) / max(1e-8, 2.0 * limit - 1.0);
 	}
 
+	color = weight.x * color1 + weight.y * color2 + weight.z * color3;
 	alpha = color.a;
 }
 
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.c b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
index 2bbe3617bee..20753445aa6 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_image.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
@@ -58,8 +58,9 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, bNode *node, bNodeExecDat
 	Image *ima = (Image *)node->id;
 	ImageUser *iuser = NULL;
 	NodeTexImage *tex = node->storage;
+	bool do_color_correction = false;
 
-	GPUNodeLink *norm;
+	GPUNodeLink *norm, *col1, *col2, *col3;
 
 	int isdata = tex->color_space == SHD_COLORSPACE_NONE;
 	float blend = tex->projection_blend;
@@ -67,6 +68,15 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, bNode *node, bNodeExecDat
 	if (!ima)
 		return GPU_stack_link(mat, node, "node_tex_image_empty", in, out);
 
+	ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
+	if ((tex->color_space == SHD_COLORSPACE_COLOR) &&
+	    ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 &&
+	    GPU_material_do_color_management(mat))
+	{
+		do_color_correction = true;
+	}
+	BKE_image_release_ibuf(ima, ibuf, NULL);
+
 	if (!in[0].link)
 		in[0].link = GPU_attribute(CD_MTFACE, "");
 
@@ -83,8 +93,20 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, bNode *node, bNodeExecDat
 			GPU_link(mat, "direction_transform_m4v3", norm,
 			                                          GPU_builtin(GPU_INVERSE_OBJECT_MATRIX),
 			                                          &norm);
+			GPU_link(mat, "tex_box_sample", in[0].link,
+			                                norm,
+			                                GPU_image(ima, iuser, isdata),
+			                                &col1,
+			                                &col2,
+			                                &col3);
+			if (do_color_correction) {
+				GPU_link(mat, "srgb_to_linearrgb", col1, &col1);
+				GPU_link(mat, "srgb_to_linearrgb", col2, &col2);
+				GPU_link(mat, "srgb_to_linearrgb", col3, &col3);
+			}
 			GPU_link(mat, "node_tex_image_box", in[0].link,
 			                                    norm,
+			                                    col1, col2, col3,
 			                                    GPU_image(ima, iuser, isdata),
 			                                    GPU_uniform(&blend),
 			                                    &out[0].link,
@@ -102,14 +124,9 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, bNode *node, bNodeExecDat
 			break;
 	}
 
-	ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
-	if ((tex->color_space == SHD_COLORSPACE_COLOR) &&
-	    ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 &&
-	    GPU_material_do_color_management(mat))
-	{
+	if (do_color_correction && (tex->projection != SHD_PROJ_BOX)) {
 		GPU_link(mat, "srgb_to_linearrgb", out[0].link, &out[0].link);
 	}
-	BKE_image_release_ibuf(ima, ibuf, NULL);
 
 	return true;
 }



More information about the Bf-blender-cvs mailing list