diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2020-06-03 17:18:28 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2020-06-03 17:18:50 +0300 |
commit | b2dcff4c21a645fa16ca39484d206a38944168d2 (patch) | |
tree | da30f1d9208033668478fa872029d1f7743c0a6d /source/blender/nodes/shader | |
parent | 054923c8607c804a717cb5bb8ef15c0d4b151df3 (diff) |
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).
Diffstat (limited to 'source/blender/nodes/shader')
-rw-r--r-- | source/blender/nodes/shader/nodes/node_shader_tex_image.c | 183 |
1 files changed, 55 insertions, 128 deletions
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, - *texco, - norm, - GPU_image(mat, ima, iuser, sampler_state), - &col1, - &col2, - &col3); - GPU_stack_link( - mat, node, "node_tex_image_box", in, out, norm, col1, col2, col3, gpu_image, blend); + GPU_link(mat, "normal_transform_transposed_m4v3", vnor, ob_mat, &wnor); + GPU_link(mat, gpu_node_name, in[0].link, wnor, gpu_image, &col1, &col2, &col3); + GPU_link(mat, "tex_box_blend", wnor, col1, col2, col3, blend, &out[0].link, &out[1].link); break; - - case SHD_PROJ_SPHERE: + } + case SHD_PROJ_SPHERE: { + /* This projection is known to have a derivative discontinuity. + * Hide it by turning off mipmapping. */ + sampler_state &= ~GPU_SAMPLER_MIPMAP; + GPUNodeLink *gpu_image = GPU_image(mat, ima, iuser, sampler_state); GPU_link(mat, "point_texco_remap_square", *texco, texco); GPU_link(mat, "point_map_to_sphere", *texco, texco); - if (do_texco_clip) { - /* See SHD_PROJ_FLAT for explanation. */ - 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)); + GPU_stack_link(mat, node, gpu_node_name, in, out, gpu_image); break; - - case SHD_PROJ_TUBE: + } + case SHD_PROJ_TUBE: { + /* This projection is known to have a derivative discontinuity. + * Hide it by turning off mipmapping. */ + sampler_state &= ~GPU_SAMPLER_MIPMAP; + GPUNodeLink *gpu_image = GPU_image(mat, ima, iuser, sampler_state); GPU_link(mat, "point_texco_remap_square", *texco, texco); GPU_link(mat, "point_map_to_tube", *texco, texco); - if (do_texco_clip) { - /* See SHD_PROJ_FLAT for explanation. */ - 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)); + GPU_stack_link(mat, node, gpu_node_name, in, out, gpu_image); break; - } - - if (tex->projection != SHD_PROJ_BOX) { - if (do_texco_clip) { - gpu_node_name = names_clip[tex->interpolation]; - in[0].link = input_coords; - GPU_stack_link(mat, - node, - gpu_node_name, - in, - out, - GPU_image(mat, ima, iuser, sampler_state), - out[0].link); } } } |