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).
This commit is contained in:
parent
054923c860
commit
b2dcff4c21
Notes:
blender-bot
2023-02-13 23:27:23 +01:00
Referenced by issue #73942, Eevee mipmaps not respecting border mode
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue