diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2018-11-07 21:40:24 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2018-11-08 00:16:13 +0300 |
commit | e0edac4cb27ddacc22bcbf7a628d58bb0eb9e9bf (patch) | |
tree | a3cf814cc7c51bb0c8b16423490d8c38a1f77fdb | |
parent | 0b837a49861c4d4a413ba282124ecd8a6a2efd79 (diff) |
Eevee: Support for extension type in the Node Image Texture
This does not work with the box projection mode. Implementing for box
projection mode would be difficult, slow, and produce a lot of code
duplication. Also i'm not sure this is worth it, as it's not a common use
case.
-rw-r--r-- | source/blender/gpu/shaders/gpu_shader_material.glsl | 122 | ||||
-rw-r--r-- | source/blender/nodes/shader/nodes/node_shader_tex_image.c | 42 |
2 files changed, 146 insertions, 18 deletions
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index eebc19328b2..3983a8c3f32 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -207,6 +207,12 @@ void point_texco_remap_square(vec3 vin, out vec3 vout) vout = vec3(vin - vec3(0.5, 0.5, 0.5)) * 2.0; } +void point_texco_clamp(vec3 vin, sampler2D ima, out vec3 vout) +{ + vec2 half_texel_size = 0.5 / vec2(textureSize(ima, 0).xy); + vout = clamp(vin, half_texel_size.xyy, 1.0 - half_texel_size.xyy); +} + void point_map_to_sphere(vec3 vin, out vec3 vout) { float len = length(vin); @@ -2020,21 +2026,27 @@ void node_tex_image_nearest(vec3 co, sampler2D ima, out vec4 color, out float al alpha = color.a; } -void node_tex_image_cubic(vec3 co, sampler2D ima, out vec4 color, out float alpha) +/* @arg f: signed distance to texel center. */ +void cubic_bspline_coefs(vec2 f, out vec2 w0, out vec2 w1, out vec2 w2, out vec2 w3) +{ + vec2 f2 = f * f; + vec2 f3 = f2 * f; + /* Bspline coefs (optimized) */ + w3 = f3 / 6.0; + w0 = -w3 + f2 * 0.5 - f * 0.5 + 1.0 / 6.0; + w1 = f3 * 0.5 - f2 * 1.0 + 2.0 / 3.0; + w2 = 1.0 - w0 - w1 - w3; +} + +void node_tex_image_cubic_ex(vec3 co, sampler2D ima, float do_extend, 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 f = co.xy - tc; - vec2 f2 = f * f; - vec2 f3 = f2 * f; - /* Bspline coefs (optimized) */ - vec2 w3 = f3 / 6.0; - vec2 w0 = -w3 + f2 * 0.5 - f * 0.5 + 1.0 / 6.0; - vec2 w1 = f3 * 0.5 - f2 * 1.0 + 2.0 / 3.0; - vec2 w2 = 1.0 - w0 - w1 - w3; + vec2 w0, w1, w2, w3; + cubic_bspline_coefs(co.xy - tc, w0, w1, w2, w3); #if 1 /* Optimized version using 4 filtered tap. */ vec2 s0 = w0 + w1; @@ -2047,12 +2059,15 @@ void node_tex_image_cubic(vec3 co, sampler2D ima, out vec4 color, out float alph final_co.xy = tc - 1.0 + f0; final_co.zw = tc + 1.0 + f1; + if (do_extend == 1.0) { + final_co = clamp(final_co, vec4(0.5), tex_size.xyxy - 0.5); + } final_co /= tex_size.xyxy; - color = texture(ima, final_co.xy) * s0.x * s0.y; - color += texture(ima, final_co.zy) * s1.x * s0.y; - color += texture(ima, final_co.xw) * s0.x * s1.y; - color += texture(ima, final_co.zw) * s1.x * s1.y; + color = textureLod(ima, final_co.xy, 0.0) * s0.x * s0.y; + color += textureLod(ima, final_co.zy, 0.0) * s1.x * s0.y; + color += textureLod(ima, final_co.xw, 0.0) * s0.x * s1.y; + color += textureLod(ima, final_co.zw, 0.0) * s1.x * s1.y; #else /* Reference bruteforce 16 tap. */ color = texelFetch(ima, ivec2(tc + vec2(-1.0, -1.0)), 0) * w0.x * w0.y; @@ -2079,10 +2094,20 @@ void node_tex_image_cubic(vec3 co, sampler2D ima, out vec4 color, out float alph alpha = color.a; } +void node_tex_image_cubic(vec3 co, sampler2D ima, out vec4 color, out float alpha) +{ + node_tex_image_cubic_ex(co, ima, 0.0, color, alpha); +} + +void node_tex_image_cubic_extend(vec3 co, sampler2D ima, out vec4 color, out float alpha) +{ + node_tex_image_cubic_ex(co, ima, 1.0, color, alpha); +} + void node_tex_image_smart(vec3 co, sampler2D ima, out vec4 color, out float alpha) { /* use cubic for now */ - node_tex_image_cubic(co, ima, color, alpha); + node_tex_image_cubic_ex(co, ima, 0.0, color, alpha); } void tex_box_sample_linear(vec3 texco, @@ -2155,19 +2180,19 @@ void tex_box_sample_cubic(vec3 texco, if (N.x < 0.0) { uv.x = 1.0 - uv.x; } - node_tex_image_cubic(uv.xyy, ima, color1, alpha); + node_tex_image_cubic_ex(uv.xyy, ima, 0.0, color1, alpha); /* Y projection */ uv = texco.xz; if (N.y > 0.0) { uv.x = 1.0 - uv.x; } - node_tex_image_cubic(uv.xyy, ima, color2, alpha); + node_tex_image_cubic_ex(uv.xyy, ima, 0.0, color2, alpha); /* Z projection */ uv = texco.yx; if (N.z > 0.0) { uv.x = 1.0 - uv.x; } - node_tex_image_cubic(uv.xyy, ima, color3, alpha); + node_tex_image_cubic_ex(uv.xyy, ima, 0.0, color3, alpha); } void tex_box_sample_smart(vec3 texco, @@ -2235,6 +2260,69 @@ 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 9782df2638f..24ad28289c1 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_image.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.c @@ -67,6 +67,12 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, bNode *node, bNodeExecDat "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; ImageUser *iuser = NULL; @@ -75,8 +81,18 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, bNode *node, bNodeExecDat ? names_box[tex->interpolation] : names[tex->interpolation]; bool do_color_correction = false; + 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; + GPUNodeLink *norm, *col1, *col2, *col3, *input_coords; int isdata = tex->color_space == SHD_COLORSPACE_NONE; float blend = tex->projection_blend; @@ -100,6 +116,12 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, bNode *node, bNodeExecDat switch (tex->projection) { case SHD_PROJ_FLAT: + if (do_texco_clip) { + GPU_link(mat, "set_rgb", in[0].link, &input_coords); + } + if (do_texco_extend) { + GPU_link(mat, "point_texco_clamp", in[0].link, GPU_image(ima, iuser, isdata), &in[0].link); + } GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser, isdata)); break; case SHD_PROJ_BOX: @@ -131,15 +153,33 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, bNode *node, bNodeExecDat 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); + if (do_texco_clip) { + GPU_link(mat, "set_rgb", in[0].link, &input_coords); + } + if (do_texco_extend) { + GPU_link(mat, "point_texco_clamp", in[0].link, GPU_image(ima, iuser, isdata), &in[0].link); + } GPU_stack_link(mat, node, gpu_node_name, 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); + if (do_texco_clip) { + GPU_link(mat, "set_rgb", in[0].link, &input_coords); + } + if (do_texco_extend) { + GPU_link(mat, "point_texco_clamp", in[0].link, GPU_image(ima, iuser, isdata), &in[0].link); + } GPU_stack_link(mat, node, gpu_node_name, in, out, GPU_image(ima, iuser, isdata)); break; } + if (do_texco_clip && (tex->projection != SHD_PROJ_BOX)) { + GPU_link(mat, names_clip[tex->interpolation], + input_coords, GPU_image(ima, iuser, isdata), out[0].link, + &out[0].link, &out[1].link); + } + if (do_color_correction && (tex->projection != SHD_PROJ_BOX)) { GPU_link(mat, "srgb_to_linearrgb", out[0].link, &out[0].link); } |