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:
@@ -952,6 +952,9 @@ void CUDADevice::tex_alloc(device_texture &mem)
|
|||||||
case EXTENSION_CLIP:
|
case EXTENSION_CLIP:
|
||||||
address_mode = CU_TR_ADDRESS_MODE_BORDER;
|
address_mode = CU_TR_ADDRESS_MODE_BORDER;
|
||||||
break;
|
break;
|
||||||
|
case EXTENSION_MIRROR:
|
||||||
|
address_mode = CU_TR_ADDRESS_MODE_MIRROR;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert(0);
|
assert(0);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -909,6 +909,9 @@ void HIPDevice::tex_alloc(device_texture &mem)
|
|||||||
* because it's unsupported in HIP. */
|
* because it's unsupported in HIP. */
|
||||||
address_mode = hipAddressModeClamp;
|
address_mode = hipAddressModeClamp;
|
||||||
break;
|
break;
|
||||||
|
case EXTENSION_MIRROR:
|
||||||
|
address_mode = hipAddressModeMirror;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert(0);
|
assert(0);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -856,7 +856,7 @@ void MetalDevice::tex_alloc(device_texture &mem)
|
|||||||
/* sampler_index maps into the GPU's constant 'metal_samplers' array */
|
/* sampler_index maps into the GPU's constant 'metal_samplers' array */
|
||||||
uint64_t sampler_index = mem.info.extension;
|
uint64_t sampler_index = mem.info.extension;
|
||||||
if (mem.info.interpolation != INTERPOLATION_CLOSEST) {
|
if (mem.info.interpolation != INTERPOLATION_CLOSEST) {
|
||||||
sampler_index += 3;
|
sampler_index += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Image Texture Storage */
|
/* Image Texture Storage */
|
||||||
|
|||||||
@@ -202,6 +202,14 @@ template<typename TexT, typename OutT = float4> struct TextureInterpolator {
|
|||||||
return clamp(x, 0, width - 1);
|
return clamp(x, 0, width - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ccl_always_inline int wrap_mirror(int x, int width)
|
||||||
|
{
|
||||||
|
const int m = abs(x + (x < 0)) % (2 * width);
|
||||||
|
if (m >= width)
|
||||||
|
return 2 * width - m - 1;
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
/* ******** 2D interpolation ******** */
|
/* ******** 2D interpolation ******** */
|
||||||
|
|
||||||
static ccl_always_inline OutT interp_closest(const TextureInfo &info, float x, float y)
|
static ccl_always_inline OutT interp_closest(const TextureInfo &info, float x, float y)
|
||||||
@@ -226,6 +234,10 @@ template<typename TexT, typename OutT = float4> struct TextureInterpolator {
|
|||||||
ix = wrap_clamp(ix, width);
|
ix = wrap_clamp(ix, width);
|
||||||
iy = wrap_clamp(iy, height);
|
iy = wrap_clamp(iy, height);
|
||||||
break;
|
break;
|
||||||
|
case EXTENSION_MIRROR:
|
||||||
|
ix = wrap_mirror(ix, width);
|
||||||
|
iy = wrap_mirror(iy, height);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
kernel_assert(0);
|
kernel_assert(0);
|
||||||
return zero();
|
return zero();
|
||||||
@@ -268,6 +280,12 @@ template<typename TexT, typename OutT = float4> struct TextureInterpolator {
|
|||||||
niy = wrap_clamp(iy + 1, height);
|
niy = wrap_clamp(iy + 1, height);
|
||||||
iy = wrap_clamp(iy, height);
|
iy = wrap_clamp(iy, height);
|
||||||
break;
|
break;
|
||||||
|
case EXTENSION_MIRROR:
|
||||||
|
nix = wrap_mirror(ix + 1, width);
|
||||||
|
ix = wrap_mirror(ix, width);
|
||||||
|
niy = wrap_mirror(iy + 1, height);
|
||||||
|
iy = wrap_mirror(iy, height);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
kernel_assert(0);
|
kernel_assert(0);
|
||||||
return zero();
|
return zero();
|
||||||
@@ -331,6 +349,17 @@ template<typename TexT, typename OutT = float4> struct TextureInterpolator {
|
|||||||
nniy = wrap_clamp(iy + 2, height);
|
nniy = wrap_clamp(iy + 2, height);
|
||||||
iy = wrap_clamp(iy, height);
|
iy = wrap_clamp(iy, height);
|
||||||
break;
|
break;
|
||||||
|
case EXTENSION_MIRROR:
|
||||||
|
pix = wrap_mirror(ix - 1, width);
|
||||||
|
nix = wrap_mirror(ix + 1, width);
|
||||||
|
nnix = wrap_mirror(ix + 2, width);
|
||||||
|
ix = wrap_mirror(ix, width);
|
||||||
|
|
||||||
|
piy = wrap_mirror(iy - 1, height);
|
||||||
|
niy = wrap_mirror(iy + 1, height);
|
||||||
|
nniy = wrap_mirror(iy + 2, height);
|
||||||
|
iy = wrap_mirror(iy, height);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
kernel_assert(0);
|
kernel_assert(0);
|
||||||
return zero();
|
return zero();
|
||||||
@@ -403,6 +432,11 @@ template<typename TexT, typename OutT = float4> struct TextureInterpolator {
|
|||||||
iy = wrap_clamp(iy, height);
|
iy = wrap_clamp(iy, height);
|
||||||
iz = wrap_clamp(iz, depth);
|
iz = wrap_clamp(iz, depth);
|
||||||
break;
|
break;
|
||||||
|
case EXTENSION_MIRROR:
|
||||||
|
ix = wrap_mirror(ix, width);
|
||||||
|
iy = wrap_mirror(iy, height);
|
||||||
|
iz = wrap_mirror(iz, depth);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
kernel_assert(0);
|
kernel_assert(0);
|
||||||
return zero();
|
return zero();
|
||||||
@@ -480,6 +514,16 @@ template<typename TexT, typename OutT = float4> struct TextureInterpolator {
|
|||||||
niz = wrap_clamp(iz + 1, depth);
|
niz = wrap_clamp(iz + 1, depth);
|
||||||
iz = wrap_clamp(iz, depth);
|
iz = wrap_clamp(iz, depth);
|
||||||
break;
|
break;
|
||||||
|
case EXTENSION_MIRROR:
|
||||||
|
nix = wrap_mirror(ix + 1, width);
|
||||||
|
ix = wrap_mirror(ix, width);
|
||||||
|
|
||||||
|
niy = wrap_mirror(iy + 1, height);
|
||||||
|
iy = wrap_mirror(iy, height);
|
||||||
|
|
||||||
|
niz = wrap_mirror(iz + 1, depth);
|
||||||
|
iz = wrap_mirror(iz, depth);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
kernel_assert(0);
|
kernel_assert(0);
|
||||||
return zero();
|
return zero();
|
||||||
@@ -595,6 +639,22 @@ template<typename TexT, typename OutT = float4> struct TextureInterpolator {
|
|||||||
nniz = wrap_clamp(iz + 2, depth);
|
nniz = wrap_clamp(iz + 2, depth);
|
||||||
iz = wrap_clamp(iz, depth);
|
iz = wrap_clamp(iz, depth);
|
||||||
break;
|
break;
|
||||||
|
case EXTENSION_MIRROR:
|
||||||
|
pix = wrap_mirror(ix - 1, width);
|
||||||
|
nix = wrap_mirror(ix + 1, width);
|
||||||
|
nnix = wrap_mirror(ix + 2, width);
|
||||||
|
ix = wrap_mirror(ix, width);
|
||||||
|
|
||||||
|
piy = wrap_mirror(iy - 1, height);
|
||||||
|
niy = wrap_mirror(iy + 1, height);
|
||||||
|
nniy = wrap_mirror(iy + 2, height);
|
||||||
|
iy = wrap_mirror(iy, height);
|
||||||
|
|
||||||
|
piz = wrap_mirror(iz - 1, depth);
|
||||||
|
niz = wrap_mirror(iz + 1, depth);
|
||||||
|
nniz = wrap_mirror(iz + 2, depth);
|
||||||
|
iz = wrap_mirror(iz, depth);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
kernel_assert(0);
|
kernel_assert(0);
|
||||||
return zero();
|
return zero();
|
||||||
|
|||||||
@@ -301,10 +301,12 @@ enum SamplerType {
|
|||||||
SamplerFilterNearest_AddressRepeat,
|
SamplerFilterNearest_AddressRepeat,
|
||||||
SamplerFilterNearest_AddressClampEdge,
|
SamplerFilterNearest_AddressClampEdge,
|
||||||
SamplerFilterNearest_AddressClampZero,
|
SamplerFilterNearest_AddressClampZero,
|
||||||
|
SamplerFilterNearest_AddressMirroredRepeat,
|
||||||
|
|
||||||
SamplerFilterLinear_AddressRepeat,
|
SamplerFilterLinear_AddressRepeat,
|
||||||
SamplerFilterLinear_AddressClampEdge,
|
SamplerFilterLinear_AddressClampEdge,
|
||||||
SamplerFilterLinear_AddressClampZero,
|
SamplerFilterLinear_AddressClampZero,
|
||||||
|
SamplerFilterLinear_AddressMirroredRepeat,
|
||||||
|
|
||||||
SamplerCount
|
SamplerCount
|
||||||
};
|
};
|
||||||
@@ -313,7 +315,9 @@ constant constexpr array<sampler, SamplerCount> metal_samplers = {
|
|||||||
sampler(address::repeat, filter::nearest),
|
sampler(address::repeat, filter::nearest),
|
||||||
sampler(address::clamp_to_edge, filter::nearest),
|
sampler(address::clamp_to_edge, filter::nearest),
|
||||||
sampler(address::clamp_to_zero, filter::nearest),
|
sampler(address::clamp_to_zero, filter::nearest),
|
||||||
|
sampler(address::mirrored_repeat, filter::nearest),
|
||||||
sampler(address::repeat, filter::linear),
|
sampler(address::repeat, filter::linear),
|
||||||
sampler(address::clamp_to_edge, filter::linear),
|
sampler(address::clamp_to_edge, filter::linear),
|
||||||
sampler(address::clamp_to_zero, filter::linear),
|
sampler(address::clamp_to_zero, filter::linear),
|
||||||
|
sampler(address::mirrored_repeat, filter::linear),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -47,9 +47,11 @@ class MetalKernelContext {
|
|||||||
case 0: return texture_array[tid].tex.sample(sampler(address::repeat, filter::nearest), coords);
|
case 0: return texture_array[tid].tex.sample(sampler(address::repeat, filter::nearest), coords);
|
||||||
case 1: return texture_array[tid].tex.sample(sampler(address::clamp_to_edge, filter::nearest), coords);
|
case 1: return texture_array[tid].tex.sample(sampler(address::clamp_to_edge, filter::nearest), coords);
|
||||||
case 2: return texture_array[tid].tex.sample(sampler(address::clamp_to_zero, filter::nearest), coords);
|
case 2: return texture_array[tid].tex.sample(sampler(address::clamp_to_zero, filter::nearest), coords);
|
||||||
case 3: return texture_array[tid].tex.sample(sampler(address::repeat, filter::linear), coords);
|
case 3: return texture_array[tid].tex.sample(sampler(address::mirrored_repeat, filter::nearest), coords);
|
||||||
case 4: return texture_array[tid].tex.sample(sampler(address::clamp_to_edge, filter::linear), coords);
|
case 4: return texture_array[tid].tex.sample(sampler(address::repeat, filter::linear), coords);
|
||||||
case 5: return texture_array[tid].tex.sample(sampler(address::clamp_to_zero, filter::linear), coords);
|
case 5: return texture_array[tid].tex.sample(sampler(address::clamp_to_edge, filter::linear), coords);
|
||||||
|
case 6: return texture_array[tid].tex.sample(sampler(address::clamp_to_zero, filter::linear), coords);
|
||||||
|
case 7: return texture_array[tid].tex.sample(sampler(address::mirrored_repeat, filter::linear), coords);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -24,6 +24,14 @@ ccl_device_inline int svm_image_texture_wrap_clamp(int x, int width)
|
|||||||
return clamp(x, 0, width - 1);
|
return clamp(x, 0, width - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ccl_device_inline int svm_image_texture_wrap_mirror(int x, int width)
|
||||||
|
{
|
||||||
|
const int m = abs(x + (x < 0)) % (2 * width);
|
||||||
|
if (m >= width)
|
||||||
|
return 2 * width - m - 1;
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
ccl_device_inline float4 svm_image_texture_read(const TextureInfo &info, int x, int y, int z)
|
ccl_device_inline float4 svm_image_texture_read(const TextureInfo &info, int x, int y, int z)
|
||||||
{
|
{
|
||||||
const int data_offset = x + info.width * y + info.width * info.height * z;
|
const int data_offset = x + info.width * y + info.width * info.height * z;
|
||||||
@@ -85,6 +93,10 @@ ccl_device_inline float4 svm_image_texture_read_2d(int id, int x, int y)
|
|||||||
x = svm_image_texture_wrap_clamp(x, info.width);
|
x = svm_image_texture_wrap_clamp(x, info.width);
|
||||||
y = svm_image_texture_wrap_clamp(y, info.height);
|
y = svm_image_texture_wrap_clamp(y, info.height);
|
||||||
}
|
}
|
||||||
|
else if (info.extension == EXTENSION_MIRROR) {
|
||||||
|
x = svm_image_texture_wrap_mirror(x, info.width);
|
||||||
|
y = svm_image_texture_wrap_mirror(y, info.height);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
if (x < 0 || x >= info.width || y < 0 || y >= info.height) {
|
if (x < 0 || x >= info.width || y < 0 || y >= info.height) {
|
||||||
return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
|
return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
@@ -109,6 +121,11 @@ ccl_device_inline float4 svm_image_texture_read_3d(int id, int x, int y, int z)
|
|||||||
y = svm_image_texture_wrap_clamp(y, info.height);
|
y = svm_image_texture_wrap_clamp(y, info.height);
|
||||||
z = svm_image_texture_wrap_clamp(z, info.depth);
|
z = svm_image_texture_wrap_clamp(z, info.depth);
|
||||||
}
|
}
|
||||||
|
else if (info.extension == EXTENSION_MIRROR) {
|
||||||
|
x = svm_image_texture_wrap_mirror(x, info.width);
|
||||||
|
y = svm_image_texture_wrap_mirror(y, info.height);
|
||||||
|
z = svm_image_texture_wrap_mirror(z, info.depth);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
if (x < 0 || x >= info.width || y < 0 || y >= info.height || z < 0 || z >= info.depth) {
|
if (x < 0 || x >= info.width || y < 0 || y >= info.height || z < 0 || z >= info.depth) {
|
||||||
return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
|
return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
|||||||
@@ -226,6 +226,7 @@ NODE_DEFINE(ImageTextureNode)
|
|||||||
extension_enum.insert("periodic", EXTENSION_REPEAT);
|
extension_enum.insert("periodic", EXTENSION_REPEAT);
|
||||||
extension_enum.insert("clamp", EXTENSION_EXTEND);
|
extension_enum.insert("clamp", EXTENSION_EXTEND);
|
||||||
extension_enum.insert("black", EXTENSION_CLIP);
|
extension_enum.insert("black", EXTENSION_CLIP);
|
||||||
|
extension_enum.insert("mirror", EXTENSION_MIRROR);
|
||||||
SOCKET_ENUM(extension, "Extension", extension_enum, EXTENSION_REPEAT);
|
SOCKET_ENUM(extension, "Extension", extension_enum, EXTENSION_REPEAT);
|
||||||
|
|
||||||
static NodeEnum projection_enum;
|
static NodeEnum projection_enum;
|
||||||
|
|||||||
@@ -65,6 +65,8 @@ typedef enum ExtensionType {
|
|||||||
EXTENSION_EXTEND = 1,
|
EXTENSION_EXTEND = 1,
|
||||||
/* Clip to image size and set exterior pixels as transparent. */
|
/* Clip to image size and set exterior pixels as transparent. */
|
||||||
EXTENSION_CLIP = 2,
|
EXTENSION_CLIP = 2,
|
||||||
|
/* Repeatedly flip the image horizontally and vertically. */
|
||||||
|
EXTENSION_MIRROR = 3,
|
||||||
|
|
||||||
EXTENSION_NUM_TYPES,
|
EXTENSION_NUM_TYPES,
|
||||||
} ExtensionType;
|
} ExtensionType;
|
||||||
|
|||||||
@@ -97,11 +97,13 @@ BLI_INLINE void workbench_material_get_image(
|
|||||||
case SH_NODE_TEX_IMAGE: {
|
case SH_NODE_TEX_IMAGE: {
|
||||||
const NodeTexImage *storage = static_cast<NodeTexImage *>(node->storage);
|
const NodeTexImage *storage = static_cast<NodeTexImage *>(node->storage);
|
||||||
const bool use_filter = (storage->interpolation != SHD_INTERP_CLOSEST);
|
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);
|
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_filter, GPU_SAMPLER_FILTER);
|
||||||
SET_FLAG_FROM_TEST(*r_sampler, use_repeat, GPU_SAMPLER_REPEAT);
|
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_clip, GPU_SAMPLER_CLAMP_BORDER);
|
||||||
|
SET_FLAG_FROM_TEST(*r_sampler, use_mirror, GPU_SAMPLER_MIRROR_REPEAT);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SH_NODE_TEX_ENVIRONMENT: {
|
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_CLAMP_BORDER = (1 << 5), /* Clamp to border color instead of border texel. */
|
||||||
GPU_SAMPLER_COMPARE = (1 << 6),
|
GPU_SAMPLER_COMPARE = (1 << 6),
|
||||||
GPU_SAMPLER_ANISO = (1 << 7),
|
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),
|
GPU_SAMPLER_REPEAT = (GPU_SAMPLER_REPEAT_S | GPU_SAMPLER_REPEAT_T | GPU_SAMPLER_REPEAT_R),
|
||||||
} eGPUSamplerState;
|
} eGPUSamplerState;
|
||||||
|
|||||||
@@ -1595,14 +1595,17 @@ id<MTLSamplerState> MTLContext::generate_sampler_from_state(MTLSamplerState samp
|
|||||||
MTLSamplerAddressMode clamp_type = (sampler_state.state & GPU_SAMPLER_CLAMP_BORDER) ?
|
MTLSamplerAddressMode clamp_type = (sampler_state.state & GPU_SAMPLER_CLAMP_BORDER) ?
|
||||||
MTLSamplerAddressModeClampToBorderColor :
|
MTLSamplerAddressModeClampToBorderColor :
|
||||||
MTLSamplerAddressModeClampToEdge;
|
MTLSamplerAddressModeClampToEdge;
|
||||||
|
MTLSamplerAddressMode repeat_type = (sampler_state.state & GPU_SAMPLER_MIRROR_REPEAT) ?
|
||||||
|
MTLSamplerAddressModeMirrorRepeat :
|
||||||
|
MTLSamplerAddressModeRepeat;
|
||||||
descriptor.rAddressMode = (sampler_state.state & GPU_SAMPLER_REPEAT_R) ?
|
descriptor.rAddressMode = (sampler_state.state & GPU_SAMPLER_REPEAT_R) ?
|
||||||
MTLSamplerAddressModeRepeat :
|
repeat_type :
|
||||||
clamp_type;
|
clamp_type;
|
||||||
descriptor.sAddressMode = (sampler_state.state & GPU_SAMPLER_REPEAT_S) ?
|
descriptor.sAddressMode = (sampler_state.state & GPU_SAMPLER_REPEAT_S) ?
|
||||||
MTLSamplerAddressModeRepeat :
|
repeat_type :
|
||||||
clamp_type;
|
clamp_type;
|
||||||
descriptor.tAddressMode = (sampler_state.state & GPU_SAMPLER_REPEAT_T) ?
|
descriptor.tAddressMode = (sampler_state.state & GPU_SAMPLER_REPEAT_T) ?
|
||||||
MTLSamplerAddressModeRepeat :
|
repeat_type :
|
||||||
clamp_type;
|
clamp_type;
|
||||||
descriptor.borderColor = MTLSamplerBorderColorTransparentBlack;
|
descriptor.borderColor = MTLSamplerBorderColorTransparentBlack;
|
||||||
descriptor.minFilter = (sampler_state.state & GPU_SAMPLER_FILTER) ?
|
descriptor.minFilter = (sampler_state.state & GPU_SAMPLER_FILTER) ?
|
||||||
|
|||||||
@@ -548,12 +548,13 @@ GLuint GLTexture::samplers_[GPU_SAMPLER_MAX] = {0};
|
|||||||
void GLTexture::samplers_init()
|
void GLTexture::samplers_init()
|
||||||
{
|
{
|
||||||
glGenSamplers(GPU_SAMPLER_MAX, samplers_);
|
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);
|
eGPUSamplerState state = static_cast<eGPUSamplerState>(i);
|
||||||
GLenum clamp_type = (state & GPU_SAMPLER_CLAMP_BORDER) ? GL_CLAMP_TO_BORDER : GL_CLAMP_TO_EDGE;
|
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 repeat_type = (state & GPU_SAMPLER_MIRROR_REPEAT) ? GL_MIRRORED_REPEAT : GL_REPEAT;
|
||||||
GLenum wrap_t = (state & GPU_SAMPLER_REPEAT_T) ? GL_REPEAT : clamp_type;
|
GLenum wrap_s = (state & GPU_SAMPLER_REPEAT_S) ? repeat_type : clamp_type;
|
||||||
GLenum wrap_r = (state & GPU_SAMPLER_REPEAT_R) ? GL_REPEAT : 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 mag_filter = (state & GPU_SAMPLER_FILTER) ? GL_LINEAR : GL_NEAREST;
|
||||||
GLenum min_filter = (state & GPU_SAMPLER_FILTER) ?
|
GLenum min_filter = (state & GPU_SAMPLER_FILTER) ?
|
||||||
((state & GPU_SAMPLER_MIPMAP) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR) :
|
((state & GPU_SAMPLER_MIPMAP) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR) :
|
||||||
@@ -577,7 +578,7 @@ void GLTexture::samplers_init()
|
|||||||
|
|
||||||
char sampler_name[128] = "\0\0";
|
char sampler_name[128] = "\0\0";
|
||||||
SNPRINTF(sampler_name,
|
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_DEFAULT) ? "_default" : "",
|
||||||
(state & GPU_SAMPLER_FILTER) ? "_filter" : "",
|
(state & GPU_SAMPLER_FILTER) ? "_filter" : "",
|
||||||
(state & GPU_SAMPLER_MIPMAP) ? "_mipmap" : "",
|
(state & GPU_SAMPLER_MIPMAP) ? "_mipmap" : "",
|
||||||
@@ -585,6 +586,7 @@ void GLTexture::samplers_init()
|
|||||||
(state & GPU_SAMPLER_REPEAT_S) ? "S" : "",
|
(state & GPU_SAMPLER_REPEAT_S) ? "S" : "",
|
||||||
(state & GPU_SAMPLER_REPEAT_T) ? "T" : "",
|
(state & GPU_SAMPLER_REPEAT_T) ? "T" : "",
|
||||||
(state & GPU_SAMPLER_REPEAT_R) ? "R" : "",
|
(state & GPU_SAMPLER_REPEAT_R) ? "R" : "",
|
||||||
|
(state & GPU_SAMPLER_MIRROR_REPEAT) ? "-mirror" : "",
|
||||||
(state & GPU_SAMPLER_CLAMP_BORDER) ? "_clamp_border" : "",
|
(state & GPU_SAMPLER_CLAMP_BORDER) ? "_clamp_border" : "",
|
||||||
(state & GPU_SAMPLER_COMPARE) ? "_compare" : "",
|
(state & GPU_SAMPLER_COMPARE) ? "_compare" : "",
|
||||||
(state & GPU_SAMPLER_ANISO) ? "_aniso" : "");
|
(state & GPU_SAMPLER_ANISO) ? "_aniso" : "");
|
||||||
@@ -612,7 +614,7 @@ void GLTexture::samplers_update()
|
|||||||
|
|
||||||
float aniso_filter = min_ff(max_anisotropy, U.anisotropic_filter);
|
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);
|
eGPUSamplerState state = static_cast<eGPUSamplerState>(i);
|
||||||
if ((state & GPU_SAMPLER_ANISO) && (state & GPU_SAMPLER_MIPMAP)) {
|
if ((state & GPU_SAMPLER_ANISO) && (state & GPU_SAMPLER_MIPMAP)) {
|
||||||
glSamplerParameterf(samplers_[i], GL_TEXTURE_MAX_ANISOTROPY_EXT, aniso_filter);
|
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_REPEAT 0
|
||||||
#define SHD_IMAGE_EXTENSION_EXTEND 1
|
#define SHD_IMAGE_EXTENSION_EXTEND 1
|
||||||
#define SHD_IMAGE_EXTENSION_CLIP 2
|
#define SHD_IMAGE_EXTENSION_CLIP 2
|
||||||
|
#define SHD_IMAGE_EXTENSION_MIRROR 3
|
||||||
|
|
||||||
/* image texture */
|
/* image texture */
|
||||||
#define SHD_PROJ_FLAT 0
|
#define SHD_PROJ_FLAT 0
|
||||||
|
|||||||
@@ -4690,6 +4690,30 @@ static const EnumPropertyItem node_subsurface_method_items[] = {
|
|||||||
"automatically adjusted to match color textures"},
|
"automatically adjusted to match color textures"},
|
||||||
{0, NULL, 0, NULL, NULL}};
|
{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 ---------------------------------------------------------- */
|
/* -- Common nodes ---------------------------------------------------------- */
|
||||||
|
|
||||||
static void def_group_input(StructRNA *UNUSED(srna))
|
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},
|
{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;
|
PropertyRNA *prop;
|
||||||
|
|
||||||
prop = RNA_def_property(srna, "image", PROP_POINTER, PROP_NONE);
|
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},
|
{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;
|
PropertyRNA *prop;
|
||||||
|
|
||||||
RNA_def_struct_sdna_from(srna, "NodeGeometryImageTexture", "storage");
|
RNA_def_struct_sdna_from(srna, "NodeGeometryImageTexture", "storage");
|
||||||
|
|||||||
@@ -114,6 +114,15 @@ class ImageFieldsFunction : public fn::MultiFunction {
|
|||||||
return std::clamp(x, 0, width - 1);
|
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)
|
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) {
|
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);
|
piy = wrap_clamp(piy, height);
|
||||||
break;
|
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:
|
default:
|
||||||
return float4(0.0f, 0.0f, 0.0f, 0.0f);
|
return float4(0.0f, 0.0f, 0.0f, 0.0f);
|
||||||
}
|
}
|
||||||
@@ -233,6 +253,12 @@ class ImageFieldsFunction : public fn::MultiFunction {
|
|||||||
piy = wrap_clamp(piy, height);
|
piy = wrap_clamp(piy, height);
|
||||||
break;
|
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:
|
default:
|
||||||
case SHD_IMAGE_EXTENSION_REPEAT:
|
case SHD_IMAGE_EXTENSION_REPEAT:
|
||||||
pix = wrap_periodic(pix, width);
|
pix = wrap_periodic(pix, width);
|
||||||
@@ -282,6 +308,11 @@ class ImageFieldsFunction : public fn::MultiFunction {
|
|||||||
iy = wrap_clamp(iy, height);
|
iy = wrap_clamp(iy, height);
|
||||||
return image_pixel_lookup(ibuf, ix, iy);
|
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:
|
default:
|
||||||
return float4(0.0f, 0.0f, 0.0f, 0.0f);
|
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:
|
case SHD_IMAGE_EXTENSION_CLIP:
|
||||||
sampler_state |= GPU_SAMPLER_CLAMP_BORDER;
|
sampler_state |= GPU_SAMPLER_CLAMP_BORDER;
|
||||||
break;
|
break;
|
||||||
|
case SHD_IMAGE_EXTENSION_MIRROR:
|
||||||
|
sampler_state |= GPU_SAMPLER_REPEAT | GPU_SAMPLER_MIRROR_REPEAT;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user