diff options
author | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2019-05-19 03:56:12 +0300 |
---|---|---|
committer | Brecht Van Lommel <brechtvanlommel@gmail.com> | 2019-05-19 15:36:42 +0300 |
commit | 3b23b5c638feae0ad6319440771b83a64a1f9ebe (patch) | |
tree | 16fbedd83ffa6a02904d3f93576c1de1674a0584 | |
parent | 7c78c20b6bf6f7dd00397c456fb9e2116febfca7 (diff) |
Images: don't (un)premultipy non-color data
The previous behavior here was wrong for some specific combinations of
settings, non-color RGB channels should never be affected by the alpha
channel.
-rw-r--r-- | intern/cycles/render/colorspace.cpp | 25 | ||||
-rw-r--r-- | intern/cycles/render/colorspace.h | 3 | ||||
-rw-r--r-- | intern/cycles/render/image.cpp | 8 | ||||
-rw-r--r-- | intern/cycles/render/nodes.cpp | 12 | ||||
-rw-r--r-- | source/blender/imbuf/intern/readimage.c | 10 | ||||
-rw-r--r-- | source/blender/nodes/shader/nodes/node_shader_tex_image.c | 3 |
6 files changed, 55 insertions, 6 deletions
diff --git a/intern/cycles/render/colorspace.cpp b/intern/cycles/render/colorspace.cpp index 7b57478ff51..f4c217bc9fb 100644 --- a/intern/cycles/render/colorspace.cpp +++ b/intern/cycles/render/colorspace.cpp @@ -82,6 +82,31 @@ ColorSpaceProcessor *ColorSpaceManager::get_processor(ustring colorspace) #endif } +bool ColorSpaceManager::colorspace_is_data(ustring colorspace) +{ + if (colorspace == u_colorspace_auto || colorspace == u_colorspace_raw || + colorspace == u_colorspace_srgb) { + return false; + } + +#ifdef WITH_OCIO + OCIO::ConstConfigRcPtr config = OCIO::GetCurrentConfig(); + if (!config) { + return false; + } + + try { + OCIO::ConstColorSpaceRcPtr space = config->getColorSpace(colorspace.c_str()); + return space && space->isData(); + } + catch (OCIO::Exception &exception) { + return false; + } +#else + return false; +#endif +} + ustring ColorSpaceManager::detect_known_colorspace(ustring colorspace, const char *file_format, bool is_float) diff --git a/intern/cycles/render/colorspace.h b/intern/cycles/render/colorspace.h index e7c7f943c2d..9fea2d6efc6 100644 --- a/intern/cycles/render/colorspace.h +++ b/intern/cycles/render/colorspace.h @@ -37,6 +37,9 @@ class ColorSpaceManager { const char *file_format, bool is_float); + /* Test if colorspace is for non-color data. */ + static bool colorspace_is_data(ustring colorspace); + /* Convert pixels in the specified colorspace to scene linear color for * rendering. Must be a colorspace returned from detect_known_colorspace. */ template<typename T> diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index 431e9230cb4..6301b416724 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -513,8 +513,14 @@ bool ImageManager::file_load_image_generic(Image *img, unique_ptr<ImageInput> *i ImageSpec spec = ImageSpec(); ImageSpec config = ImageSpec(); - if (img->use_alpha == false) + /* For typical RGBA images we let OIIO convert to associated alpha, + * but some types we want to leave the RGB channels untouched. */ + const bool associate_alpha = !(ColorSpaceManager::colorspace_is_data(img->colorspace) || + img->use_alpha == false); + + if (!associate_alpha) { config.attribute("oiio:UnassociatedAlpha", 1); + } if (!(*in)->open(img->filename, spec, config)) { return false; diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 27e6309ab2d..3905189c8b0 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -316,7 +316,12 @@ void ImageTextureNode::compile(SVMCompiler &compiler) flags |= NODE_IMAGE_COMPRESS_AS_SRGB; } if (!alpha_out->links.empty()) { - flags |= NODE_IMAGE_ALPHA_UNASSOCIATE; + const bool unassociate_alpha = !(ColorSpaceManager::colorspace_is_data(colorspace) || + use_alpha == false); + + if (unassociate_alpha) { + flags |= NODE_IMAGE_ALPHA_UNASSOCIATE; + } } if (projection != NODE_IMAGE_PROJ_BOX) { @@ -389,11 +394,14 @@ void ImageTextureNode::compile(OSLCompiler &compiler) compiler.parameter_texture("filename", slot); } + const bool unassociate_alpha = !(ColorSpaceManager::colorspace_is_data(colorspace) || + use_alpha == false); + compiler.parameter(this, "projection"); compiler.parameter(this, "projection_blend"); compiler.parameter("convert_from_srgb", compress_as_srgb); compiler.parameter("ignore_alpha", !use_alpha); - compiler.parameter("unassociate_alpha", !alpha_out->links.empty()); + compiler.parameter("unassociate_alpha", !alpha_out->links.empty() && unassociate_alpha); compiler.parameter("is_float", is_float); compiler.parameter(this, "interpolation"); compiler.parameter(this, "extension"); diff --git a/source/blender/imbuf/intern/readimage.c b/source/blender/imbuf/intern/readimage.c index e1df5c63093..9297227bc87 100644 --- a/source/blender/imbuf/intern/readimage.c +++ b/source/blender/imbuf/intern/readimage.c @@ -49,8 +49,6 @@ static void imb_handle_alpha(ImBuf *ibuf, char colorspace[IM_MAX_SPACE], char effective_colorspace[IM_MAX_SPACE]) { - int alpha_flags; - if (colorspace) { if (ibuf->rect != NULL && ibuf->rect_float == NULL) { /* byte buffer is never internally converted to some standard space, @@ -62,6 +60,9 @@ static void imb_handle_alpha(ImBuf *ibuf, BLI_strncpy(colorspace, effective_colorspace, IM_MAX_SPACE); } + bool is_data = (colorspace && IMB_colormanagement_space_name_is_data(colorspace)); + int alpha_flags; + if (flags & IB_alphamode_detect) { alpha_flags = ibuf->flags & IB_alphamode_premul; } @@ -69,7 +70,10 @@ static void imb_handle_alpha(ImBuf *ibuf, alpha_flags = flags & IB_alphamode_premul; } - if (flags & IB_ignore_alpha) { + if (is_data) { + /* Don't touch alpha. */ + } + else if (flags & IB_ignore_alpha) { IMB_rectfill_alpha(ibuf, 1.0f); } else { 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 a9183cd10ef..8086bb2e15d 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_image.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.c @@ -180,6 +180,9 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, } if (out[0].hasoutput) { + /* When the alpha socket is used, unpremultiply alpha. This makes it so + * that if we blend the color with a transparent shader using alpha as + * a factor, we don't multiply alpha into the color twice. */ if (out[1].hasoutput && !IMB_colormanagement_space_name_is_data(ima->colorspace_settings.name)) { GPU_link(mat, "tex_color_alpha_unpremultiply", out[0].link, &out[0].link); |