Images: add mirror extension type
This adds a new mirror image extension type for shaders and geometry nodes (next to the existing repeat, extend and clip options). See D16432 for a more detailed explanation of `wrap_mirror`. This also adds a new sampler flag `GPU_SAMPLER_MIRROR_REPEAT`. It acts as a modifier to `GPU_SAMPLER_REPEAT`, so any `REPEAT` flag must be set for the `MIRROR` flag to have an effect. Differential Revision: https://developer.blender.org/D16432
This commit is contained in:
@@ -97,11 +97,13 @@ BLI_INLINE void workbench_material_get_image(
|
||||
case SH_NODE_TEX_IMAGE: {
|
||||
const NodeTexImage *storage = static_cast<NodeTexImage *>(node->storage);
|
||||
const bool use_filter = (storage->interpolation != SHD_INTERP_CLOSEST);
|
||||
const bool use_repeat = (storage->extension == SHD_IMAGE_EXTENSION_REPEAT);
|
||||
const bool use_mirror = (storage->extension == SHD_IMAGE_EXTENSION_MIRROR);
|
||||
const bool use_repeat = use_mirror || (storage->extension == SHD_IMAGE_EXTENSION_REPEAT);
|
||||
const bool use_clip = (storage->extension == SHD_IMAGE_EXTENSION_CLIP);
|
||||
SET_FLAG_FROM_TEST(*r_sampler, use_filter, GPU_SAMPLER_FILTER);
|
||||
SET_FLAG_FROM_TEST(*r_sampler, use_repeat, GPU_SAMPLER_REPEAT);
|
||||
SET_FLAG_FROM_TEST(*r_sampler, use_clip, GPU_SAMPLER_CLAMP_BORDER);
|
||||
SET_FLAG_FROM_TEST(*r_sampler, use_mirror, GPU_SAMPLER_MIRROR_REPEAT);
|
||||
break;
|
||||
}
|
||||
case SH_NODE_TEX_ENVIRONMENT: {
|
||||
|
||||
@@ -35,7 +35,8 @@ typedef enum eGPUSamplerState {
|
||||
GPU_SAMPLER_CLAMP_BORDER = (1 << 5), /* Clamp to border color instead of border texel. */
|
||||
GPU_SAMPLER_COMPARE = (1 << 6),
|
||||
GPU_SAMPLER_ANISO = (1 << 7),
|
||||
GPU_SAMPLER_ICON = (1 << 8),
|
||||
GPU_SAMPLER_MIRROR_REPEAT = (1 << 8), /* Requires any REPEAT flag to be set. */
|
||||
GPU_SAMPLER_ICON = (1 << 9),
|
||||
|
||||
GPU_SAMPLER_REPEAT = (GPU_SAMPLER_REPEAT_S | GPU_SAMPLER_REPEAT_T | GPU_SAMPLER_REPEAT_R),
|
||||
} eGPUSamplerState;
|
||||
|
||||
@@ -1595,14 +1595,17 @@ id<MTLSamplerState> MTLContext::generate_sampler_from_state(MTLSamplerState samp
|
||||
MTLSamplerAddressMode clamp_type = (sampler_state.state & GPU_SAMPLER_CLAMP_BORDER) ?
|
||||
MTLSamplerAddressModeClampToBorderColor :
|
||||
MTLSamplerAddressModeClampToEdge;
|
||||
MTLSamplerAddressMode repeat_type = (sampler_state.state & GPU_SAMPLER_MIRROR_REPEAT) ?
|
||||
MTLSamplerAddressModeMirrorRepeat :
|
||||
MTLSamplerAddressModeRepeat;
|
||||
descriptor.rAddressMode = (sampler_state.state & GPU_SAMPLER_REPEAT_R) ?
|
||||
MTLSamplerAddressModeRepeat :
|
||||
repeat_type :
|
||||
clamp_type;
|
||||
descriptor.sAddressMode = (sampler_state.state & GPU_SAMPLER_REPEAT_S) ?
|
||||
MTLSamplerAddressModeRepeat :
|
||||
repeat_type :
|
||||
clamp_type;
|
||||
descriptor.tAddressMode = (sampler_state.state & GPU_SAMPLER_REPEAT_T) ?
|
||||
MTLSamplerAddressModeRepeat :
|
||||
repeat_type :
|
||||
clamp_type;
|
||||
descriptor.borderColor = MTLSamplerBorderColorTransparentBlack;
|
||||
descriptor.minFilter = (sampler_state.state & GPU_SAMPLER_FILTER) ?
|
||||
|
||||
@@ -548,12 +548,13 @@ GLuint GLTexture::samplers_[GPU_SAMPLER_MAX] = {0};
|
||||
void GLTexture::samplers_init()
|
||||
{
|
||||
glGenSamplers(GPU_SAMPLER_MAX, samplers_);
|
||||
for (int i = 0; i <= GPU_SAMPLER_ICON - 1; i++) {
|
||||
for (int i = 0; i < GPU_SAMPLER_ICON; i++) {
|
||||
eGPUSamplerState state = static_cast<eGPUSamplerState>(i);
|
||||
GLenum clamp_type = (state & GPU_SAMPLER_CLAMP_BORDER) ? GL_CLAMP_TO_BORDER : GL_CLAMP_TO_EDGE;
|
||||
GLenum wrap_s = (state & GPU_SAMPLER_REPEAT_S) ? GL_REPEAT : clamp_type;
|
||||
GLenum wrap_t = (state & GPU_SAMPLER_REPEAT_T) ? GL_REPEAT : clamp_type;
|
||||
GLenum wrap_r = (state & GPU_SAMPLER_REPEAT_R) ? GL_REPEAT : clamp_type;
|
||||
GLenum repeat_type = (state & GPU_SAMPLER_MIRROR_REPEAT) ? GL_MIRRORED_REPEAT : GL_REPEAT;
|
||||
GLenum wrap_s = (state & GPU_SAMPLER_REPEAT_S) ? repeat_type : clamp_type;
|
||||
GLenum wrap_t = (state & GPU_SAMPLER_REPEAT_T) ? repeat_type : clamp_type;
|
||||
GLenum wrap_r = (state & GPU_SAMPLER_REPEAT_R) ? repeat_type : clamp_type;
|
||||
GLenum mag_filter = (state & GPU_SAMPLER_FILTER) ? GL_LINEAR : GL_NEAREST;
|
||||
GLenum min_filter = (state & GPU_SAMPLER_FILTER) ?
|
||||
((state & GPU_SAMPLER_MIPMAP) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR) :
|
||||
@@ -577,7 +578,7 @@ void GLTexture::samplers_init()
|
||||
|
||||
char sampler_name[128] = "\0\0";
|
||||
SNPRINTF(sampler_name,
|
||||
"%s%s%s%s%s%s%s%s%s%s",
|
||||
"%s%s%s%s%s%s%s%s%s%s%s",
|
||||
(state == GPU_SAMPLER_DEFAULT) ? "_default" : "",
|
||||
(state & GPU_SAMPLER_FILTER) ? "_filter" : "",
|
||||
(state & GPU_SAMPLER_MIPMAP) ? "_mipmap" : "",
|
||||
@@ -585,6 +586,7 @@ void GLTexture::samplers_init()
|
||||
(state & GPU_SAMPLER_REPEAT_S) ? "S" : "",
|
||||
(state & GPU_SAMPLER_REPEAT_T) ? "T" : "",
|
||||
(state & GPU_SAMPLER_REPEAT_R) ? "R" : "",
|
||||
(state & GPU_SAMPLER_MIRROR_REPEAT) ? "-mirror" : "",
|
||||
(state & GPU_SAMPLER_CLAMP_BORDER) ? "_clamp_border" : "",
|
||||
(state & GPU_SAMPLER_COMPARE) ? "_compare" : "",
|
||||
(state & GPU_SAMPLER_ANISO) ? "_aniso" : "");
|
||||
@@ -612,7 +614,7 @@ void GLTexture::samplers_update()
|
||||
|
||||
float aniso_filter = min_ff(max_anisotropy, U.anisotropic_filter);
|
||||
|
||||
for (int i = 0; i <= GPU_SAMPLER_ICON - 1; i++) {
|
||||
for (int i = 0; i < GPU_SAMPLER_ICON; i++) {
|
||||
eGPUSamplerState state = static_cast<eGPUSamplerState>(i);
|
||||
if ((state & GPU_SAMPLER_ANISO) && (state & GPU_SAMPLER_MIPMAP)) {
|
||||
glSamplerParameterf(samplers_[i], GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso_filter);
|
||||
|
||||
@@ -1754,6 +1754,7 @@ enum {
|
||||
#define SHD_IMAGE_EXTENSION_REPEAT 0
|
||||
#define SHD_IMAGE_EXTENSION_EXTEND 1
|
||||
#define SHD_IMAGE_EXTENSION_CLIP 2
|
||||
#define SHD_IMAGE_EXTENSION_MIRROR 3
|
||||
|
||||
/* image texture */
|
||||
#define SHD_PROJ_FLAT 0
|
||||
|
||||
@@ -4690,6 +4690,30 @@ static const EnumPropertyItem node_subsurface_method_items[] = {
|
||||
"automatically adjusted to match color textures"},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
static const EnumPropertyItem prop_image_extension[] = {
|
||||
{SHD_IMAGE_EXTENSION_REPEAT,
|
||||
"REPEAT",
|
||||
0,
|
||||
"Repeat",
|
||||
"Cause the image to repeat horizontally and vertically"},
|
||||
{SHD_IMAGE_EXTENSION_EXTEND,
|
||||
"EXTEND",
|
||||
0,
|
||||
"Extend",
|
||||
"Extend by repeating edge pixels of the image"},
|
||||
{SHD_IMAGE_EXTENSION_CLIP,
|
||||
"CLIP",
|
||||
0,
|
||||
"Clip",
|
||||
"Clip to image size and set exterior pixels as transparent"},
|
||||
{SHD_IMAGE_EXTENSION_MIRROR,
|
||||
"MIRROR",
|
||||
0,
|
||||
"Mirror",
|
||||
"Repeatedly flip the image horizontally and vertically"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
/* -- Common nodes ---------------------------------------------------------- */
|
||||
|
||||
static void def_group_input(StructRNA *UNUSED(srna))
|
||||
@@ -5431,25 +5455,6 @@ static void def_sh_tex_image(StructRNA *srna)
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
static const EnumPropertyItem prop_image_extension[] = {
|
||||
{SHD_IMAGE_EXTENSION_REPEAT,
|
||||
"REPEAT",
|
||||
0,
|
||||
"Repeat",
|
||||
"Cause the image to repeat horizontally and vertically"},
|
||||
{SHD_IMAGE_EXTENSION_EXTEND,
|
||||
"EXTEND",
|
||||
0,
|
||||
"Extend",
|
||||
"Extend by repeating edge pixels of the image"},
|
||||
{SHD_IMAGE_EXTENSION_CLIP,
|
||||
"CLIP",
|
||||
0,
|
||||
"Clip",
|
||||
"Clip to image size and set exterior pixels as transparent"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
PropertyRNA *prop;
|
||||
|
||||
prop = RNA_def_property(srna, "image", PROP_POINTER, PROP_NONE);
|
||||
@@ -5516,25 +5521,6 @@ static void def_geo_image_texture(StructRNA *srna)
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
static const EnumPropertyItem prop_image_extension[] = {
|
||||
{SHD_IMAGE_EXTENSION_REPEAT,
|
||||
"REPEAT",
|
||||
0,
|
||||
"Repeat",
|
||||
"Cause the image to repeat horizontally and vertically"},
|
||||
{SHD_IMAGE_EXTENSION_EXTEND,
|
||||
"EXTEND",
|
||||
0,
|
||||
"Extend",
|
||||
"Extend by repeating edge pixels of the image"},
|
||||
{SHD_IMAGE_EXTENSION_CLIP,
|
||||
"CLIP",
|
||||
0,
|
||||
"Clip",
|
||||
"Clip to image size and set exterior pixels as transparent"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
PropertyRNA *prop;
|
||||
|
||||
RNA_def_struct_sdna_from(srna, "NodeGeometryImageTexture", "storage");
|
||||
|
||||
@@ -114,6 +114,15 @@ class ImageFieldsFunction : public fn::MultiFunction {
|
||||
return std::clamp(x, 0, width - 1);
|
||||
}
|
||||
|
||||
static int wrap_mirror(const int x, const int width)
|
||||
{
|
||||
const int m = std::abs(x + (x < 0)) % (2 * width);
|
||||
if (m >= width) {
|
||||
return 2 * width - m - 1;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
static float4 image_pixel_lookup(const ImBuf &ibuf, const int px, const int py)
|
||||
{
|
||||
if (px < 0 || py < 0 || px >= ibuf.x || py >= ibuf.y) {
|
||||
@@ -173,6 +182,17 @@ class ImageFieldsFunction : public fn::MultiFunction {
|
||||
piy = wrap_clamp(piy, height);
|
||||
break;
|
||||
}
|
||||
case SHD_IMAGE_EXTENSION_MIRROR: {
|
||||
ppix = wrap_mirror(pix - 1, width);
|
||||
ppiy = wrap_mirror(piy - 1, height);
|
||||
nix = wrap_mirror(pix + 1, width);
|
||||
niy = wrap_mirror(piy + 1, height);
|
||||
nnix = wrap_mirror(pix + 2, width);
|
||||
nniy = wrap_mirror(piy + 2, height);
|
||||
pix = wrap_mirror(pix, width);
|
||||
piy = wrap_mirror(piy, height);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
@@ -233,6 +253,12 @@ class ImageFieldsFunction : public fn::MultiFunction {
|
||||
piy = wrap_clamp(piy, height);
|
||||
break;
|
||||
}
|
||||
case SHD_IMAGE_EXTENSION_MIRROR:
|
||||
nix = wrap_mirror(pix + 1, width);
|
||||
niy = wrap_mirror(piy + 1, height);
|
||||
pix = wrap_mirror(pix, width);
|
||||
piy = wrap_mirror(piy, height);
|
||||
break;
|
||||
default:
|
||||
case SHD_IMAGE_EXTENSION_REPEAT:
|
||||
pix = wrap_periodic(pix, width);
|
||||
@@ -282,6 +308,11 @@ class ImageFieldsFunction : public fn::MultiFunction {
|
||||
iy = wrap_clamp(iy, height);
|
||||
return image_pixel_lookup(ibuf, ix, iy);
|
||||
}
|
||||
case SHD_IMAGE_EXTENSION_MIRROR: {
|
||||
ix = wrap_mirror(ix, width);
|
||||
iy = wrap_mirror(iy, height);
|
||||
return image_pixel_lookup(ibuf, ix, iy);
|
||||
}
|
||||
default:
|
||||
return float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
}
|
||||
|
||||
@@ -61,6 +61,9 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat,
|
||||
case SHD_IMAGE_EXTENSION_CLIP:
|
||||
sampler_state |= GPU_SAMPLER_CLAMP_BORDER;
|
||||
break;
|
||||
case SHD_IMAGE_EXTENSION_MIRROR:
|
||||
sampler_state |= GPU_SAMPLER_REPEAT | GPU_SAMPLER_MIRROR_REPEAT;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user