diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index d88ebb854d2..e81170ac411 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -242,8 +242,16 @@ static void create_mesh_volume_attribute(BL::Object b_ob, Mesh *mesh, ImageManag bool animated = false; volume_data->manager = image_manager; - volume_data->slot = image_manager->add_image(Attribute::standard_name(std), - b_ob.ptr.data, animated, frame, is_float, is_linear, INTERPOLATION_LINEAR, true); + volume_data->slot = image_manager->add_image( + Attribute::standard_name(std), + b_ob.ptr.data, + animated, + frame, + is_float, + is_linear, + INTERPOLATION_LINEAR, + EXTENSION_REPEAT, + true); } static void create_mesh_volume_attributes(Scene *scene, BL::Object b_ob, Mesh *mesh, float frame) diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 6c54149164d..fe7bd76d6b4 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -590,14 +590,17 @@ static ShaderNode *add_node(Scene *scene, /* TODO(sergey): Does not work properly when we change builtin type. */ if(b_image.is_updated()) { - scene->image_manager->tag_reload_image(image->filename, - image->builtin_data, - (InterpolationType)b_image_node.interpolation()); + scene->image_manager->tag_reload_image( + image->filename, + image->builtin_data, + (InterpolationType)b_image_node.interpolation(), + EXTENSION_REPEAT); } } image->color_space = ImageTextureNode::color_space_enum[(int)b_image_node.color_space()]; image->projection = ImageTextureNode::projection_enum[(int)b_image_node.projection()]; image->interpolation = (InterpolationType)b_image_node.interpolation(); + image->extension = EXTENSION_REPEAT; image->projection_blend = b_image_node.projection_blend(); get_tex_mapping(&image->tex_mapping, b_image_node.texture_mapping()); node = image; @@ -630,7 +633,8 @@ static ShaderNode *add_node(Scene *scene, if(b_image.is_updated()) { scene->image_manager->tag_reload_image(env->filename, env->builtin_data, - INTERPOLATION_LINEAR); + INTERPOLATION_LINEAR, + EXTENSION_REPEAT); } } env->color_space = EnvironmentTextureNode::color_space_enum[(int)b_env_node.color_space()]; @@ -759,9 +763,11 @@ static ShaderNode *add_node(Scene *scene, /* TODO(sergey): Use more proper update flag. */ if(true) { - scene->image_manager->tag_reload_image(point_density->filename, - point_density->builtin_data, - point_density->interpolation); + scene->image_manager->tag_reload_image( + point_density->filename, + point_density->builtin_data, + point_density->interpolation, + EXTENSION_CLIP); } node = point_density; } diff --git a/intern/cycles/device/device_cpu.cpp b/intern/cycles/device/device_cpu.cpp index 013f656e31c..ec82b3805c4 100644 --- a/intern/cycles/device/device_cpu.cpp +++ b/intern/cycles/device/device_cpu.cpp @@ -123,10 +123,20 @@ public: kernel_const_copy(&kernel_globals, name, host, size); } - void tex_alloc(const char *name, device_memory& mem, InterpolationType interpolation, bool /*periodic*/) + void tex_alloc(const char *name, + device_memory& mem, + InterpolationType interpolation, + bool periodic) { VLOG(1) << "Texture allocate: " << name << ", " << mem.memory_size() << " bytes."; - kernel_tex_copy(&kernel_globals, name, mem.data_pointer, mem.data_width, mem.data_height, mem.data_depth, interpolation); + kernel_tex_copy(&kernel_globals, + name, + mem.data_pointer, + mem.data_width, + mem.data_height, + mem.data_depth, + interpolation, + periodic); mem.device_pointer = mem.data_pointer; mem.device_size = mem.memory_size(); stats.mem_alloc(mem.device_size); diff --git a/intern/cycles/kernel/kernel.h b/intern/cycles/kernel/kernel.h index 0996e51b7a0..5c34ddcfbcb 100644 --- a/intern/cycles/kernel/kernel.h +++ b/intern/cycles/kernel/kernel.h @@ -32,7 +32,14 @@ void *kernel_osl_memory(KernelGlobals *kg); bool kernel_osl_use(KernelGlobals *kg); void kernel_const_copy(KernelGlobals *kg, const char *name, void *host, size_t size); -void kernel_tex_copy(KernelGlobals *kg, const char *name, device_ptr mem, size_t width, size_t height, size_t depth, InterpolationType interpolation=INTERPOLATION_LINEAR); +void kernel_tex_copy(KernelGlobals *kg, + const char *name, + device_ptr mem, + size_t width, + size_t height, + size_t depth, + InterpolationType interpolation=INTERPOLATION_LINEAR, + bool periodic = true); void kernel_cpu_path_trace(KernelGlobals *kg, float *buffer, unsigned int *rng_state, int sample, int x, int y, int offset, int stride); diff --git a/intern/cycles/kernel/kernel_compat_cpu.h b/intern/cycles/kernel/kernel_compat_cpu.h index 0bf1ed36d1e..a780c356a18 100644 --- a/intern/cycles/kernel/kernel_compat_cpu.h +++ b/intern/cycles/kernel/kernel_compat_cpu.h @@ -128,7 +128,7 @@ template struct texture_image { return x - (float)i; } - ccl_always_inline float4 interp(float x, float y, bool periodic = true) + ccl_always_inline float4 interp(float x, float y) { if(UNLIKELY(!data)) return make_float4(0.0f, 0.0f, 0.0f, 0.0f); @@ -233,14 +233,13 @@ template struct texture_image { } } - ccl_always_inline float4 interp_3d(float x, float y, float z, bool periodic = false) + ccl_always_inline float4 interp_3d(float x, float y, float z) { - return interp_3d_ex(x, y, z, interpolation, periodic); + return interp_3d_ex(x, y, z, interpolation); } ccl_always_inline float4 interp_3d_ex(float x, float y, float z, - int interpolation = INTERPOLATION_LINEAR, - bool periodic = false) + int interpolation = INTERPOLATION_LINEAR) { if(UNLIKELY(!data)) return make_float4(0.0f, 0.0f, 0.0f, 0.0f); @@ -393,6 +392,7 @@ template struct texture_image { T *data; int interpolation; + bool periodic; int width, height, depth; #undef SET_CUBIC_SPLINE_WEIGHTS }; diff --git a/intern/cycles/kernel/kernels/cpu/kernel.cpp b/intern/cycles/kernel/kernels/cpu/kernel.cpp index 37a73ab2f04..2dbd9e62ee7 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel.cpp +++ b/intern/cycles/kernel/kernels/cpu/kernel.cpp @@ -38,7 +38,14 @@ void kernel_const_copy(KernelGlobals *kg, const char *name, void *host, size_t s assert(0); } -void kernel_tex_copy(KernelGlobals *kg, const char *name, device_ptr mem, size_t width, size_t height, size_t depth, InterpolationType interpolation) +void kernel_tex_copy(KernelGlobals *kg, + const char *name, + device_ptr mem, + size_t width, + size_t height, + size_t depth, + InterpolationType interpolation, + bool periodic) { if(0) { } @@ -64,6 +71,7 @@ void kernel_tex_copy(KernelGlobals *kg, const char *name, device_ptr mem, size_t tex->data = (float4*)mem; tex->dimensions_set(width, height, depth); tex->interpolation = interpolation; + tex->periodic = periodic; } } else if(strstr(name, "__tex_image")) { @@ -79,6 +87,7 @@ void kernel_tex_copy(KernelGlobals *kg, const char *name, device_ptr mem, size_t tex->data = (uchar4*)mem; tex->dimensions_set(width, height, depth); tex->interpolation = interpolation; + tex->periodic = periodic; } } else diff --git a/intern/cycles/kernel/shaders/node_image_texture.osl b/intern/cycles/kernel/shaders/node_image_texture.osl index 46a02cab32e..d3a347b70db 100644 --- a/intern/cycles/kernel/shaders/node_image_texture.osl +++ b/intern/cycles/kernel/shaders/node_image_texture.osl @@ -55,9 +55,16 @@ point map_to_sphere(vector dir) return point(u, v, 0.0); } -color image_texture_lookup(string filename, string color_space, float u, float v, output float Alpha, int use_alpha, int is_float, string interpolation) +color image_texture_lookup(string filename, + string color_space, + float u, float v, + output float Alpha, + int use_alpha, + int is_float, + string interpolation, + string wrap) { - color rgb = (color)texture(filename, u, 1.0 - v, "wrap", "periodic", "interp", interpolation, "alpha", Alpha); + color rgb = (color)texture(filename, u, 1.0 - v, "wrap", wrap, "interp", interpolation, "alpha", Alpha); if (use_alpha) { rgb = color_unpremultiply(rgb, Alpha); @@ -81,6 +88,7 @@ shader node_image_texture( string color_space = "sRGB", string projection = "Flat", string interpolation = "smartcubic", + string wrap = "periodic", float projection_blend = 0.0, int is_float = 1, int use_alpha = 1, @@ -93,7 +101,14 @@ shader node_image_texture( p = transform(mapping, p); if (projection == "Flat") { - Color = image_texture_lookup(filename, color_space, p[0], p[1], Alpha, use_alpha, is_float, interpolation); + Color = image_texture_lookup(filename, + color_space, + p[0], p[1], + Alpha, + use_alpha, + is_float, + interpolation, + wrap); } else if (projection == "Box") { /* object space normal */ @@ -162,28 +177,59 @@ shader node_image_texture( float tmp_alpha; if (weight[0] > 0.0) { - Color += weight[0] * image_texture_lookup(filename, color_space, p[1], p[2], tmp_alpha, use_alpha, is_float, interpolation); + Color += weight[0] * image_texture_lookup(filename, + color_space, + p[1], p[2], + tmp_alpha, + use_alpha, + is_float, + interpolation, + wrap); Alpha += weight[0] * tmp_alpha; } if (weight[1] > 0.0) { - Color += weight[1] * image_texture_lookup(filename, color_space, p[0], p[2], tmp_alpha, use_alpha, is_float, interpolation); + Color += weight[1] * image_texture_lookup(filename, + color_space, + p[0], p[2], + tmp_alpha, + use_alpha, + is_float, + interpolation, + wrap); Alpha += weight[1] * tmp_alpha; } if (weight[2] > 0.0) { - Color += weight[2] * image_texture_lookup(filename, color_space, p[1], p[0], tmp_alpha, use_alpha, is_float, interpolation); + Color += weight[2] * image_texture_lookup(filename, + color_space, + p[1], p[0], + tmp_alpha, + use_alpha, + is_float, + interpolation, + wrap); Alpha += weight[2] * tmp_alpha; } } else if (projection == "Sphere") { point projected = map_to_sphere(texco_remap_square(p)); - Color = image_texture_lookup(filename, color_space, + Color = image_texture_lookup(filename, + color_space, projected[0], projected[1], - Alpha, use_alpha, is_float, interpolation); + Alpha, + use_alpha, + is_float, + interpolation, + wrap); } else if (projection == "Tube") { point projected = map_to_tube(texco_remap_square(p)); - Color = image_texture_lookup(filename, color_space, + Color = image_texture_lookup(filename, + color_space, projected[0], projected[1], - Alpha, use_alpha, is_float, interpolation); + Alpha, + use_alpha, + is_float, + interpolation, + wrap); } } diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index c62afcd7719..dc9aeeefc6d 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -151,15 +151,27 @@ bool ImageManager::is_float_image(const string& filename, void *builtin_data, bo return is_float; } -static bool image_equals(ImageManager::Image *image, const string& filename, void *builtin_data, InterpolationType interpolation) +static bool image_equals(ImageManager::Image *image, + const string& filename, + void *builtin_data, + InterpolationType interpolation, + ExtensionType extension) { return image->filename == filename && image->builtin_data == builtin_data && - image->interpolation == interpolation; + image->interpolation == interpolation && + image->extension == extension; } -int ImageManager::add_image(const string& filename, void *builtin_data, bool animated, float frame, - bool& is_float, bool& is_linear, InterpolationType interpolation, bool use_alpha) +int ImageManager::add_image(const string& filename, + void *builtin_data, + bool animated, + float frame, + bool& is_float, + bool& is_linear, + InterpolationType interpolation, + ExtensionType extension, + bool use_alpha) { Image *img; size_t slot; @@ -171,7 +183,12 @@ int ImageManager::add_image(const string& filename, void *builtin_data, bool ani /* find existing image */ for(slot = 0; slot < float_images.size(); slot++) { img = float_images[slot]; - if(img && image_equals(img, filename, builtin_data, interpolation)) { + if(img && image_equals(img, + filename, + builtin_data, + interpolation, + extension)) + { if(img->frame != frame) { img->frame = frame; img->need_load = true; @@ -210,6 +227,7 @@ int ImageManager::add_image(const string& filename, void *builtin_data, bool ani img->animated = animated; img->frame = frame; img->interpolation = interpolation; + img->extension = extension; img->users = 1; img->use_alpha = use_alpha; @@ -218,7 +236,12 @@ int ImageManager::add_image(const string& filename, void *builtin_data, bool ani else { for(slot = 0; slot < images.size(); slot++) { img = images[slot]; - if(img && image_equals(img, filename, builtin_data, interpolation)) { + if(img && image_equals(img, + filename, + builtin_data, + interpolation, + extension)) + { if(img->frame != frame) { img->frame = frame; img->need_load = true; @@ -257,6 +280,7 @@ int ImageManager::add_image(const string& filename, void *builtin_data, bool ani img->animated = animated; img->frame = frame; img->interpolation = interpolation; + img->extension = extension; img->users = 1; img->use_alpha = use_alpha; @@ -300,12 +324,20 @@ void ImageManager::remove_image(int slot) } } -void ImageManager::remove_image(const string& filename, void *builtin_data, InterpolationType interpolation) +void ImageManager::remove_image(const string& filename, + void *builtin_data, + InterpolationType interpolation, + ExtensionType extension) { size_t slot; for(slot = 0; slot < images.size(); slot++) { - if(images[slot] && image_equals(images[slot], filename, builtin_data, interpolation)) { + if(images[slot] && image_equals(images[slot], + filename, + builtin_data, + interpolation, + extension)) + { remove_image(slot+tex_image_byte_start); break; } @@ -314,7 +346,11 @@ void ImageManager::remove_image(const string& filename, void *builtin_data, Inte if(slot == images.size()) { /* see if it's in a float texture slot */ for(slot = 0; slot < float_images.size(); slot++) { - if(float_images[slot] && image_equals(float_images[slot], filename, builtin_data, interpolation)) { + if(float_images[slot] && image_equals(float_images[slot], + filename, + builtin_data, + interpolation, + extension)) { remove_image(slot); break; } @@ -326,12 +362,19 @@ void ImageManager::remove_image(const string& filename, void *builtin_data, Inte * without bunch of arguments passing around making code readability even * more cluttered. */ -void ImageManager::tag_reload_image(const string& filename, void *builtin_data, InterpolationType interpolation) +void ImageManager::tag_reload_image(const string& filename, + void *builtin_data, + InterpolationType interpolation, + ExtensionType extension) { size_t slot; for(slot = 0; slot < images.size(); slot++) { - if(images[slot] && image_equals(images[slot], filename, builtin_data, interpolation)) { + if(images[slot] && image_equals(images[slot], + filename, + builtin_data, + interpolation, + extension)) { images[slot]->need_load = true; break; } @@ -340,7 +383,11 @@ void ImageManager::tag_reload_image(const string& filename, void *builtin_data, if(slot == images.size()) { /* see if it's in a float texture slot */ for(slot = 0; slot < float_images.size(); slot++) { - if(float_images[slot] && image_equals(float_images[slot], filename, builtin_data, interpolation)) { + if(float_images[slot] && image_equals(float_images[slot], + filename, + builtin_data, + interpolation, + extension)) { float_images[slot]->need_load = true; break; } @@ -664,7 +711,10 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, int sl if(!pack_images) { thread_scoped_lock device_lock(device_mutex); - device->tex_alloc(name.c_str(), tex_img, img->interpolation, true); + device->tex_alloc(name.c_str(), + tex_img, + img->interpolation, + img->extension == EXTENSION_REPEAT); } } else { @@ -696,7 +746,10 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, int sl if(!pack_images) { thread_scoped_lock device_lock(device_mutex); - device->tex_alloc(name.c_str(), tex_img, img->interpolation, true); + device->tex_alloc(name.c_str(), + tex_img, + img->interpolation, + img->extension == EXTENSION_REPEAT); } } diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h index 70cc4935daa..bcc58ae951b 100644 --- a/intern/cycles/render/image.h +++ b/intern/cycles/render/image.h @@ -55,11 +55,24 @@ public: ImageManager(); ~ImageManager(); - int add_image(const string& filename, void *builtin_data, bool animated, float frame, - bool& is_float, bool& is_linear, InterpolationType interpolation, bool use_alpha); + int add_image(const string& filename, + void *builtin_data, + bool animated, + float frame, + bool& is_float, + bool& is_linear, + InterpolationType interpolation, + ExtensionType extension, + bool use_alpha); void remove_image(int slot); - void remove_image(const string& filename, void *builtin_data, InterpolationType interpolation); - void tag_reload_image(const string& filename, void *builtin_data, InterpolationType interpolation); + void remove_image(const string& filename, + void *builtin_data, + InterpolationType interpolation, + ExtensionType extension); + void tag_reload_image(const string& filename, + void *builtin_data, + InterpolationType interpolation, + ExtensionType extension); bool is_float_image(const string& filename, void *builtin_data, bool& is_linear); void device_update(Device *device, DeviceScene *dscene, Progress& progress); @@ -87,6 +100,7 @@ public: bool animated; float frame; InterpolationType interpolation; + ExtensionType extension; int users; }; diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 46d5b3c3684..1150c63a65a 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -198,6 +198,7 @@ ImageTextureNode::ImageTextureNode() color_space = ustring("Color"); projection = ustring("Flat"); interpolation = INTERPOLATION_LINEAR; + extension = EXTENSION_REPEAT; projection_blend = 0.0f; animated = false; @@ -208,8 +209,12 @@ ImageTextureNode::ImageTextureNode() ImageTextureNode::~ImageTextureNode() { - if(image_manager) - image_manager->remove_image(filename, builtin_data, interpolation); + if(image_manager) { + image_manager->remove_image(filename, + builtin_data, + interpolation, + extension); + } } ShaderNode *ImageTextureNode::clone() const @@ -246,9 +251,15 @@ void ImageTextureNode::compile(SVMCompiler& compiler) image_manager = compiler.image_manager; if(is_float == -1) { bool is_float_bool; - slot = image_manager->add_image(filename, builtin_data, - animated, 0, is_float_bool, is_linear, - interpolation, use_alpha); + slot = image_manager->add_image(filename, + builtin_data, + animated, + 0, + is_float_bool, + is_linear, + interpolation, + extension, + use_alpha); is_float = (int)is_float_bool; } @@ -318,9 +329,15 @@ void ImageTextureNode::compile(OSLCompiler& compiler) } else { bool is_float_bool; - slot = image_manager->add_image(filename, builtin_data, - animated, 0, is_float_bool, is_linear, - interpolation, use_alpha); + slot = image_manager->add_image(filename, + builtin_data, + animated, + 0, + is_float_bool, + is_linear, + interpolation, + extension, + use_alpha); is_float = (int)is_float_bool; } } @@ -361,6 +378,14 @@ void ImageTextureNode::compile(OSLCompiler& compiler) compiler.parameter("interpolation", "linear"); break; } + + if (extension == EXTENSION_REPEAT) { + compiler.parameter("wrap", "periodic"); + } + else { + compiler.parameter("wrap", "clamp"); + } + compiler.add(this, "node_image_texture"); } @@ -400,8 +425,12 @@ EnvironmentTextureNode::EnvironmentTextureNode() EnvironmentTextureNode::~EnvironmentTextureNode() { - if(image_manager) - image_manager->remove_image(filename, builtin_data, INTERPOLATION_LINEAR); + if(image_manager) { + image_manager->remove_image(filename, + builtin_data, + INTERPOLATION_LINEAR, + EXTENSION_REPEAT); + } } ShaderNode *EnvironmentTextureNode::clone() const @@ -436,9 +465,15 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler) image_manager = compiler.image_manager; if(slot == -1) { bool is_float_bool; - slot = image_manager->add_image(filename, builtin_data, - animated, 0, is_float_bool, is_linear, - INTERPOLATION_LINEAR, use_alpha); + slot = image_manager->add_image(filename, + builtin_data, + animated, + 0, + is_float_bool, + is_linear, + INTERPOLATION_LINEAR, + EXTENSION_REPEAT, + use_alpha); is_float = (int)is_float_bool; } @@ -499,9 +534,15 @@ void EnvironmentTextureNode::compile(OSLCompiler& compiler) } else { bool is_float_bool; - slot = image_manager->add_image(filename, builtin_data, - animated, 0, is_float_bool, is_linear, - INTERPOLATION_LINEAR, use_alpha); + slot = image_manager->add_image(filename, + builtin_data, + animated, + 0, + is_float_bool, + is_linear, + INTERPOLATION_LINEAR, + EXTENSION_REPEAT, + use_alpha); is_float = (int)is_float_bool; } } @@ -1330,8 +1371,12 @@ PointDensityTextureNode::PointDensityTextureNode() PointDensityTextureNode::~PointDensityTextureNode() { - if(image_manager) - image_manager->remove_image(filename, builtin_data, interpolation); + if(image_manager) { + image_manager->remove_image(filename, + builtin_data, + interpolation, + EXTENSION_CLIP); + } } ShaderNode *PointDensityTextureNode::clone() const @@ -1374,6 +1419,7 @@ void PointDensityTextureNode::compile(SVMCompiler& compiler) false, 0, is_float, is_linear, interpolation, + EXTENSION_CLIP, true); } @@ -1421,6 +1467,7 @@ void PointDensityTextureNode::compile(OSLCompiler& compiler) false, 0, is_float, is_linear, interpolation, + EXTENSION_CLIP, true); } diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 5a412916e85..5065e68345a 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -92,6 +92,7 @@ public: ustring color_space; ustring projection; InterpolationType interpolation; + ExtensionType extension; float projection_blend; bool animated; diff --git a/intern/cycles/util/util_types.h b/intern/cycles/util/util_types.h index 187675e74bf..411f2d803f8 100644 --- a/intern/cycles/util/util_types.h +++ b/intern/cycles/util/util_types.h @@ -470,6 +470,17 @@ enum InterpolationType { INTERPOLATION_SMART = 3, }; +/* Extension types for textures. + * + * Defines how the image is extrapolated past its original bounds. + */ +enum ExtensionType { + /* Cause the image to repeat horizontally and vertically. */ + EXTENSION_REPEAT = 0, + /* Clip to image size and set exterior pixels as transparent. */ + EXTENSION_CLIP = 1, +}; + /* macros */ /* hints for branch prediction, only use in code that runs a _lot_ */