[Bf-blender-cvs] [b2dcff4c21a] master: GPUMaterial: Rework/simplify image texture filtering

Clément Foucault noreply at git.blender.org
Wed Jun 3 16:24:14 CEST 2020


Commit: b2dcff4c21a645fa16ca39484d206a38944168d2
Author: Clément Foucault
Date:   Wed Jun 3 16:18:28 2020 +0200
Branches: master
https://developer.blender.org/rBb2dcff4c21a645fa16ca39484d206a38944168d2

GPUMaterial: Rework/simplify image texture filtering

This use the latest GPUTexture change to use the sampler state to avoid
the pole issues instead of using GLSL hacks.

This should fix T73942: Eevee mipmaps not respecting border mode.

Note that this also fix some discrepencies between cycles and eevee (like
boxmapping + clip).

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

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

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

diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl
index 3a9fc49e8b8..878ffefbe45 100644
--- a/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl
+++ b/source/blender/gpu/shaders/material/gpu_shader_material_tex_image.glsl
@@ -218,15 +218,8 @@ void tex_box_sample_smart(
   tex_box_sample_cubic(texco, N, ima, color1, color2, color3);
 }
 
-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)
+void tex_box_blend(
+    vec3 N, vec4 color1, vec4 color2, vec4 color3, float blend, out vec4 color, out float alpha)
 {
   /* project from direction vector to barycentric coordinates in triangles */
   N = abs(N);
@@ -271,70 +264,6 @@ void node_tex_image_box(vec3 texco,
   alpha = color.a;
 }
 
-void tex_clip_linear(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha)
-{
-  vec2 tex_size = vec2(textureSize(ima, 0).xy);
-  vec2 minco = min(co.xy, 1.0 - co.xy);
-  minco = clamp(minco * tex_size + 0.5, 0.0, 1.0);
-  float fac = minco.x * minco.y;
-
-  color = mix(vec4(0.0), icolor, fac);
-  alpha = color.a;
-}
-
-void tex_clip_nearest(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha)
-{
-  vec4 minco = vec4(co.xy, 1.0 - co.xy);
-  color = (any(lessThan(minco, vec4(0.0)))) ? vec4(0.0) : icolor;
-  alpha = color.a;
-}
-
-void tex_clip_cubic(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha)
-{
-  vec2 tex_size = vec2(textureSize(ima, 0).xy);
-
-  co.xy *= tex_size;
-  /* texel center */
-  vec2 tc = floor(co.xy - 0.5) + 0.5;
-  vec2 w0, w1, w2, w3;
-  cubic_bspline_coefs(co.xy - tc, w0, w1, w2, w3);
-
-  /* TODO Optimize this part. I'm sure there is a smarter way to do that.
-   * Could do that when sampling? */
-#define CLIP_CUBIC_SAMPLE(samp, size) \
-  (float(all(greaterThan(samp, vec2(-0.5)))) * float(all(lessThan(ivec2(samp), itex_size))))
-  ivec2 itex_size = textureSize(ima, 0).xy;
-  float fac;
-  fac = CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, -1.0), itex_size) * w0.x * w0.y;
-  fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, -1.0), itex_size) * w1.x * w0.y;
-  fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, -1.0), itex_size) * w2.x * w0.y;
-  fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, -1.0), itex_size) * w3.x * w0.y;
-
-  fac += CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, 0.0), itex_size) * w0.x * w1.y;
-  fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, 0.0), itex_size) * w1.x * w1.y;
-  fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, 0.0), itex_size) * w2.x * w1.y;
-  fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, 0.0), itex_size) * w3.x * w1.y;
-
-  fac += CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, 1.0), itex_size) * w0.x * w2.y;
-  fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, 1.0), itex_size) * w1.x * w2.y;
-  fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, 1.0), itex_size) * w2.x * w2.y;
-  fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, 1.0), itex_size) * w3.x * w2.y;
-
-  fac += CLIP_CUBIC_SAMPLE(tc + vec2(-1.0, 2.0), itex_size) * w0.x * w3.y;
-  fac += CLIP_CUBIC_SAMPLE(tc + vec2(0.0, 2.0), itex_size) * w1.x * w3.y;
-  fac += CLIP_CUBIC_SAMPLE(tc + vec2(1.0, 2.0), itex_size) * w2.x * w3.y;
-  fac += CLIP_CUBIC_SAMPLE(tc + vec2(2.0, 2.0), itex_size) * w3.x * w3.y;
-#undef CLIP_CUBIC_SAMPLE
-
-  color = mix(vec4(0.0), icolor, fac);
-  alpha = color.a;
-}
-
-void tex_clip_smart(vec3 co, sampler2D ima, vec4 icolor, out vec4 color, out float alpha)
-{
-  tex_clip_cubic(co, ima, icolor, color, alpha);
-}
-
 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 87114fe23b5..b349555efe8 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_image.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.c
@@ -19,6 +19,8 @@
 
 #include "../node_shader_util.h"
 
+#include "GPU_draw.h"
+
 /* **************** OUTPUT ******************** */
 
 static bNodeSocketTemplate sh_node_tex_image_in[] = {
@@ -57,31 +59,6 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
                                      GPUNodeStack *in,
                                      GPUNodeStack *out)
 {
-  static const char *names[] = {
-      "node_tex_image_linear",
-      "node_tex_image_nearest",
-      "node_tex_image_cubic",
-      "node_tex_image_smart",
-  };
-  static const char *names_tiled[] = {
-      "node_tex_tile_linear",
-      "node_tex_tile_nearest",
-      "node_tex_tile_cubic",
-      "node_tex_tile_smart",
-  };
-  static const char *names_box[] = {
-      "tex_box_sample_linear",
-      "tex_box_sample_nearest",
-      "tex_box_sample_cubic",
-      "tex_box_sample_smart",
-  };
-  static const char *names_clip[] = {
-      "tex_clip_linear",
-      "tex_clip_nearest",
-      "tex_clip_cubic",
-      "tex_clip_smart",
-  };
-
   Image *ima = (Image *)node->id;
   NodeTexImage *tex = node->storage;
 
@@ -91,26 +68,11 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
   NodeTexImage *tex_original = node_original->storage;
   ImageUser *iuser = &tex_original->iuser;
 
-  const char *gpu_node_name = (tex->projection == SHD_PROJ_BOX) ? names_box[tex->interpolation] :
-                                                                  names[tex->interpolation];
-  bool do_texco_extend = (tex->extension != SHD_IMAGE_EXTENSION_REPEAT);
-  const bool do_texco_clip = (tex->extension == SHD_IMAGE_EXTENSION_CLIP);
-
-  if (do_texco_extend && (tex->projection != SHD_PROJ_BOX) &&
-      ELEM(tex->interpolation, SHD_INTERP_CUBIC, SHD_INTERP_SMART)) {
-    gpu_node_name = "node_tex_image_cubic_extend";
-    /* We do it inside the sampling function */
-    do_texco_extend = false;
-  }
-
-  GPUNodeLink *norm, *col1, *col2, *col3, *input_coords, *gpu_image;
-  GPUNodeLink *vnor, *ob_mat, *blend;
-  GPUNodeLink **texco = &in[0].link;
-
   if (!ima) {
     return GPU_stack_link(mat, node, "node_tex_image_empty", in, out);
   }
 
+  GPUNodeLink **texco = &in[0].link;
   if (!*texco) {
     *texco = GPU_attribute(mat, CD_MTFACE, "");
     node_shader_gpu_bump_tex_coord(mat, node, texco);
@@ -118,108 +80,73 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
 
   node_shader_gpu_tex_mapping(mat, node, in, out);
 
-  eGPUSamplerState sampler_state = GPU_SAMPLER_MAX;
+  eGPUSamplerState sampler_state = 0;
+
+  switch (tex->extension) {
+    case SHD_IMAGE_EXTENSION_REPEAT:
+      sampler_state |= GPU_SAMPLER_REPEAT;
+      break;
+    case SHD_IMAGE_EXTENSION_CLIP:
+      sampler_state |= GPU_SAMPLER_CLAMP_BORDER;
+      break;
+    default:
+      break;
+  }
+
+  if (tex->interpolation != SHD_INTERP_CLOSEST) {
+    sampler_state |= GPU_SAMPLER_ANISO | GPU_SAMPLER_FILTER;
+    sampler_state |= GPU_get_mipmap() ? GPU_SAMPLER_MIPMAP : 0;
+  }
+  const bool use_cubic = ELEM(tex->interpolation, SHD_INTERP_CUBIC, SHD_INTERP_SMART);
 
   if (ima->source == IMA_SRC_TILED) {
+    const char *gpu_node_name = use_cubic ? "node_tex_tile_cubic" : "node_tex_tile_linear";
+    GPUNodeLink *gpu_image = GPU_image(mat, ima, iuser, sampler_state);
+    GPUNodeLink *gpu_image_tile_mapping = GPU_image_tiled_mapping(mat, ima, iuser);
     /* UDIM tiles needs a samper2DArray and sampler1DArray for tile mapping. */
-    GPU_stack_link(mat,
-                   node,
-                   names_tiled[tex->interpolation],
-                   in,
-                   out,
-                   GPU_image_tiled(mat, ima, iuser, sampler_state),
-                   GPU_image_tiled_mapping(mat, ima, iuser));
+    GPU_stack_link(mat, node, gpu_node_name, in, out, gpu_image, gpu_image_tile_mapping);
   }
   else {
+    const char *gpu_node_name = use_cubic ? "node_tex_image_cubic" : "node_tex_image_linear";
+
     switch (tex->projection) {
-      case SHD_PROJ_FLAT:
-        if (do_texco_clip) {
-          /* This seems redundant, but is required to ensure the texco link
-           * is not freed by GPU_link, as it is still needed for GPU_stack_link.
-           * Intermediate links like this can only be used once and are then
-           * freed immediately, but if we make it the output link of a set_rgb
-           * node it will be kept and can be used multiple times. */
-          GPU_link(mat, "set_rgb", *texco, texco);
-          GPU_link(mat, "set_rgb", *texco, &input_coords);
-        }
-        if (do_texco_extend) {
-          GPU_link(
-              mat, "point_texco_clamp", *texco, GPU_image(mat, ima, iuser, sampler_state), texco);
-        }
-        GPU_stack_link(
-            mat, node, gpu_node_name, in, out, GPU_image(mat, ima, iuser, sampler_state));
+      case SHD_PROJ_FLAT: {
+        GPUNodeLink *gpu_image = GPU_image(mat, ima, iuser, sampler_state);
+        GPU_stack_link(mat, node, gpu_node_name, in, out, gpu_image);
         break;
-
-      case SHD_PROJ_BOX:
-        vnor = GPU_builtin(GPU_WORLD_NORMAL);
-        ob_mat = GPU_builtin(GPU_OBJECT_MATRIX);
-        blend = GPU_uniform(&tex->projection_blend);
-        gpu_image = GPU_image(mat, ima, iuser, sampler_state);
-
+      }
+      case SHD_PROJ_BOX: {
+        gpu_node_name = use_cubic ? "tex_box_sample_cubic" : "tex_box_sample_linear";
+        GPUNodeLink *wnor, *col1, *col2, *col3;
+        GPUNodeLink *vnor = GPU_builtin(GPU_WORLD_NORMAL);
+        GPUNodeLink *ob_mat = GPU_builtin(GPU_OBJECT_MATRIX);
+        GPUNodeLink *blend = GPU_uniform(&tex->projection_blend);
+        GPUNodeLink *gpu_image = GPU_image(mat, ima, iuser, sampler_state);
         /* equivalent to normal_world_to_object */
-        GPU_link(mat, "normal_transform_transposed_m4v3", vnor, ob_mat, &norm);
-        {
-          /* See SHD_PROJ_FLAT for explanation. */
-          GPU_link(mat, "set_rgb", *texco, texco);
-          GPU_link(mat, "set_rgb", *texco, &input_coords);
-          in[0].link = input_coords;
-        }
-        GPU_link(mat,
-                 gpu_node_name,
-    

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list