[Bf-blender-cvs] [f4eb493] compositor-2016: Support all Cycles image texture projections in the GLSL viewport

Ralf Hölzemer noreply at git.blender.org
Wed Jun 8 21:51:21 CEST 2016


Commit: f4eb493db65ac368f9f29f86440cd6b416a9a8ea
Author: Ralf Hölzemer
Date:   Mon May 30 10:23:43 2016 +0200
Branches: compositor-2016
https://developer.blender.org/rBf4eb493db65ac368f9f29f86440cd6b416a9a8ea

Support all Cycles image texture projections in the GLSL viewport

This patch enables Tube, Sphere and Box projections in GLSL for the image texture node.

Reviewers: sergey

Projects: #nodes, #opengl_gfx

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

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

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 84806e9..a3b0580 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -218,6 +218,42 @@ void point_transform_m4v3(vec3 vin, mat4 mat, out vec3 vout)
 	vout = (mat * vec4(vin, 1.0)).xyz;
 }
 
+void point_texco_remap_square(vec3 vin, out vec3 vout)
+{
+	vout = vec3(vin - vec3(0.5, 0.5, 0.5)) * 2.0;
+}
+
+void point_map_to_sphere(vec3 vin, out vec3 vout)
+{
+	float len = length(vin);
+	float v, u;
+	if (len > 0.0) {
+		if (vin.x == 0.0 && vin.y == 0.0)
+			u = 0.0;
+		else
+			u = (1.0 - atan(vin.x, vin.y) / M_PI) / 2.0;
+
+		v = 1.0 - acos(vin.z / len) / M_PI;
+	}
+	else
+		v = u = 0.0;
+
+	vout = vec3(u, v, 0.0);
+}
+
+void point_map_to_tube(vec3 vin, out vec3 vout)
+{
+	float u, v;
+	v = (vin.z + 1.0) * 0.5;
+	float len = sqrt(vin.x * vin.x + vin.y * vin[1]);
+	if (len > 0.0)
+		u = (1.0 - (atan(vin.x / len, vin.y / len) / M_PI)) * 0.5;
+	else
+		v = u = 0.0;
+
+	vout = vec3(u, v, 0.0);
+}
+
 void mapping(vec3 vec, mat4 mat, vec3 minvec, vec3 maxvec, float domin, float domax, out vec3 outvec)
 {
 	outvec = (mat * vec4(vec, 1.0)).xyz;
@@ -2872,6 +2908,82 @@ void node_tex_image(vec3 co, sampler2D ima, out vec4 color, out float alpha)
 	alpha = color.a;
 }
 
+void node_tex_image_box(vec3 texco,
+                        vec3 nob,
+                        sampler2D ima,
+                        float blend,
+                        out vec4 color,
+                        out float alpha)
+{
+	/* project from direction vector to barycentric coordinates in triangles */
+	nob = vec3(abs(nob.x), abs(nob.y), abs(nob.z));
+	nob /= (nob.x + nob.y + nob.z);
+
+	/* 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,
+	 * in between we blend between two textures, and in the middle we a blend
+	 * between three textures.
+	 *
+	 * 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 */
+
+	vec3 weight = vec3(0.0, 0.0, 0.0);
+	float limit = 0.5 * (1.0 + blend);
+
+	/* first test for corners with single texture */
+	if (nob.x > limit * (nob.x + nob.y) && nob.x > limit * (nob.x + nob.z)) {
+		weight.x = 1.0;
+	}
+	else if (nob.y > limit * (nob.x + nob.y) && nob.y > limit * (nob.y + nob.z)) {
+		weight.y = 1.0;
+	}
+	else if (nob.z > limit * (nob.x + nob.z) && nob.z > limit * (nob.y + nob.z)) {
+		weight.z = 1.0;
+	}
+	else if (blend > 0.0) {
+		/* in case of blending, test for mixes between two textures */
+		if (nob.z < (1.0 - limit) * (nob.y + nob.x)) {
+			weight.x = nob.x / (nob.x + nob.y);
+			weight.x = clamp((weight.x - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
+			weight.y = 1.0 - weight.x;
+		}
+		else if (nob.x < (1.0 - limit) * (nob.y + nob.z)) {
+			weight.y = nob.y / (nob.y + nob.z);
+			weight.y = clamp((weight.y - 0.5 * (1.0 - blend)) / blend, 0.0, 1.0);
+			weight.z = 1.0 - weight.y;
+		}
+		else if (nob.y < (1.0 - limit) * (nob.x + nob.z)) {
+			weight.x = nob.x / (nob.x + nob.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) * nob.x + (limit - 1.0)) / (2.0 * limit - 1.0);
+			weight.y = ((2.0 - limit) * nob.y + (limit - 1.0)) / (2.0 * limit - 1.0);
+			weight.z = ((2.0 - limit) * nob.z + (limit - 1.0)) / (2.0 * limit - 1.0);
+		}
+	}
+	else {
+		/* Desperate mode, no valid choice anyway, fallback to one side.*/
+		weight.x = 1.0;
+	}
+
+	if (weight.x > 0.0) {
+		color += weight.x * texture2D(ima, texco.yz);
+	}
+	if (weight.y > 0.0) {
+		color += weight.y * texture2D(ima, texco.xz);
+	}
+	if (weight.z > 0.0) {
+		color += weight.z * texture2D(ima, texco.yx);
+	}
+
+	alpha = color.a;
+}
+
 void node_tex_image_empty(vec3 co, out vec4 color, out float alpha)
 {
 	color = vec4(0.0);
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 f0a8cda..71200df 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_image.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
@@ -59,17 +59,49 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, bNode *node, bNodeExecDat
 	Image *ima = (Image *)node->id;
 	ImageUser *iuser = NULL;
 	NodeTexImage *tex = node->storage;
+
+	GPUNodeLink *norm;
+
 	int isdata = tex->color_space == SHD_COLORSPACE_NONE;
+	float blend = tex->projection_blend;
 
 	if (!ima)
 		return GPU_stack_link(mat, "node_tex_image_empty", in, out);
-	
+
 	if (!in[0].link)
 		in[0].link = GPU_attribute(CD_MTFACE, "");
 
 	node_shader_gpu_tex_mapping(mat, node, in, out);
 
-	GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata));
+	switch (tex->projection) {
+		case SHD_PROJ_FLAT:
+			GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata));
+			break;
+		case SHD_PROJ_BOX:
+			GPU_link(mat, "direction_transform_m4v3", GPU_builtin(GPU_VIEW_NORMAL),
+			                                          GPU_builtin(GPU_INVERSE_VIEW_MATRIX),
+			                                          &norm);
+			GPU_link(mat, "direction_transform_m4v3", norm,
+			                                          GPU_builtin(GPU_INVERSE_OBJECT_MATRIX),
+			                                          &norm);
+			GPU_link(mat, "node_tex_image_box", in[0].link,
+			                                    norm,
+			                                    GPU_image(ima, iuser, isdata),
+			                                    GPU_uniform(&blend),
+			                                    &out[0].link,
+			                                    &out[1].link);
+			break;
+		case SHD_PROJ_SPHERE:
+			GPU_link(mat, "point_texco_remap_square", in[0].link, &in[0].link);
+			GPU_link(mat, "point_map_to_sphere", in[0].link, &in[0].link);
+			GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata));
+			break;
+		case SHD_PROJ_TUBE:
+			GPU_link(mat, "point_texco_remap_square", in[0].link, &in[0].link);
+			GPU_link(mat, "point_map_to_tube", in[0].link, &in[0].link);
+			GPU_stack_link(mat, "node_tex_image", in, out, GPU_image(ima, iuser, isdata));
+			break;
+	}
 
 	ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL);
 	if ((tex->color_space == SHD_COLORSPACE_COLOR) &&




More information about the Bf-blender-cvs mailing list