Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClément Foucault <foucault.clem@gmail.com>2018-07-20 16:25:20 +0300
committerClément Foucault <foucault.clem@gmail.com>2018-07-20 20:16:48 +0300
commite7d8908f1405bbe54df2b5b51b4c1078200e5020 (patch)
treefc2e4c1ee3dea888fcfa30fdaff317d7a6432426 /source/blender
parent9ad5eafe465e4ab0c9945e234b187dc210ac608a (diff)
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.
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl116
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_image.c31
2 files changed, 78 insertions, 69 deletions
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;
}