From 922bb24865f451aabb1a3112ab8ffb592e3ff875 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Fri, 13 May 2011 14:32:08 +0000 Subject: [PATCH] Cycles: color space control for image/environment texture nodes. Ideally would be automated but need to think about how to do this, not so simply in a node system. But guideline for now is, for color textures set to sRGB, for things like bump or roughness map, set to Linear. --- intern/cycles/blender/blender_shader.cpp | 6 ++- .../osl/nodes/node_environment_texture.osl | 4 ++ .../kernel/osl/nodes/node_image_texture.osl | 4 ++ intern/cycles/kernel/svm/svm.h | 4 +- intern/cycles/kernel/svm/svm_image.h | 26 +++++++++-- intern/cycles/render/nodes.cpp | 32 ++++++++++++- intern/cycles/render/nodes.h | 6 +++ source/blender/editors/space_node/drawnode.c | 1 + source/blender/makesdna/DNA_node_types.h | 8 +++- source/blender/makesrna/intern/rna_nodetree.c | 46 +++++++++++++------ .../intern/SHD_nodes/SHD_tex_environment.c | 1 + .../nodes/intern/SHD_nodes/SHD_tex_image.c | 1 + 12 files changed, 114 insertions(+), 25 deletions(-) diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index c6dbfc630ab..c23f9a4cd95 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -282,15 +282,17 @@ static ShaderNode *add_node(BL::BlendData b_data, ShaderGraph *graph, BL::Node * /* todo: handle generated/builtin images */ if(b_image) image->filename = blender_absolute_path(b_data, b_image, b_image.filepath()); + image->color_space = ImageTextureNode::color_space_enum[(int)b_image_node.color_space()]; node = image; break; } case BL::ShaderNode::type_TEX_ENVIRONMENT: { - BL::ShaderNodeTexEnvironment b_environment_node(b_node); - BL::Image b_image(b_environment_node.image()); + BL::ShaderNodeTexEnvironment b_env_node(b_node); + BL::Image b_image(b_env_node.image()); EnvironmentTextureNode *env = new EnvironmentTextureNode(); if(b_image) env->filename = blender_absolute_path(b_data, b_image, b_image.filepath()); + env->color_space = EnvironmentTextureNode::color_space_enum[(int)b_env_node.color_space()]; node = env; break; } diff --git a/intern/cycles/kernel/osl/nodes/node_environment_texture.osl b/intern/cycles/kernel/osl/nodes/node_environment_texture.osl index 569b22d53ec..ee3fc44f0f8 100644 --- a/intern/cycles/kernel/osl/nodes/node_environment_texture.osl +++ b/intern/cycles/kernel/osl/nodes/node_environment_texture.osl @@ -21,8 +21,12 @@ shader node_environment_texture( vector Vector = P, string filename = "", + string color_space = "sRGB", output color Color = color(0.0, 0.0, 0.0)) { Color = (color)environment(filename, Vector); + + if(color_space == "sRGB") + Color = color_srgb_to_scene_linear(Color); } diff --git a/intern/cycles/kernel/osl/nodes/node_image_texture.osl b/intern/cycles/kernel/osl/nodes/node_image_texture.osl index 0dbcc122deb..e1efb787655 100644 --- a/intern/cycles/kernel/osl/nodes/node_image_texture.osl +++ b/intern/cycles/kernel/osl/nodes/node_image_texture.osl @@ -21,8 +21,12 @@ shader node_image_texture( point Vector = P, string filename = "", + string color_space = "sRGB", output color Color = color(0.0, 0.0, 0.0)) { Color = (color)texture(filename, Vector[0], 1.0-Vector[1], "wrap", "periodic"); + + if(color_space == "sRGB") + Color = color_srgb_to_scene_linear(Color); } diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h index 51445aece6c..68e54d9752e 100644 --- a/intern/cycles/kernel/svm/svm.h +++ b/intern/cycles/kernel/svm/svm.h @@ -190,9 +190,9 @@ __device void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ShaderType type, else if(node.x == NODE_TEX_NOISE_V) svm_node_tex_noise_v(sd, stack, node.y, node.z); else if(node.x == NODE_TEX_IMAGE) - svm_node_tex_image(kg, sd, stack, node.y, node.z, node.w); + svm_node_tex_image(kg, sd, stack, node); else if(node.x == NODE_TEX_ENVIRONMENT) - svm_node_tex_environment(kg, sd, stack, node.y, node.z, node.w); + svm_node_tex_environment(kg, sd, stack, node); else if(node.x == NODE_TEX_SKY) svm_node_tex_sky(kg, sd, stack, node.y, node.z); else if(node.x == NODE_TEX_BLEND) diff --git a/intern/cycles/kernel/svm/svm_image.h b/intern/cycles/kernel/svm/svm_image.h index c2020b1f69c..88f0b582442 100644 --- a/intern/cycles/kernel/svm/svm_image.h +++ b/intern/cycles/kernel/svm/svm_image.h @@ -140,22 +140,40 @@ __device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y) return r; } -__device void svm_node_tex_image(KernelGlobals *kg, ShaderData *sd, float *stack, uint id, uint co_offset, uint out_offset) +__device void svm_node_tex_image(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node) { + uint id = node.y; + uint co_offset, out_offset, srgb; + + decode_node_uchar4(node.z, &co_offset, &out_offset, &srgb, NULL); + float3 co = stack_load_float3(stack, co_offset); float4 f = svm_image_texture(kg, id, co.x, co.y); + float3 r = make_float3(f.x, f.y, f.z); - stack_store_float3(stack, out_offset, make_float3(f.x, f.y, f.z)); + if(srgb) + r = color_srgb_to_scene_linear(r); + + stack_store_float3(stack, out_offset, r); } -__device void svm_node_tex_environment(KernelGlobals *kg, ShaderData *sd, float *stack, uint id, uint co_offset, uint out_offset) +__device void svm_node_tex_environment(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node) { + uint id = node.y; + uint co_offset, out_offset, srgb; + + decode_node_uchar4(node.z, &co_offset, &out_offset, &srgb, NULL); + float3 co = stack_load_float3(stack, co_offset); float u = (atan2f(co.y, co.x) + M_PI_F)/(2*M_PI_F); float v = atan2f(co.z, hypotf(co.x, co.y))/M_PI_F + 0.5f; float4 f = svm_image_texture(kg, id, u, v); + float3 r = make_float3(f.x, f.y, f.z); - stack_store_float3(stack, out_offset, make_float3(f.x, f.y, f.z)); + if(srgb) + r = color_srgb_to_scene_linear(r); + + stack_store_float3(stack, out_offset, r); } CCL_NAMESPACE_END diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index bcce6db6171..0e14deac98f 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -27,12 +27,25 @@ CCL_NAMESPACE_BEGIN /* Image Texture */ +static ShaderEnum color_space_init() +{ + ShaderEnum enm; + + enm.insert("Linear", 0); + enm.insert("sRGB", 1); + + return enm; +} + +ShaderEnum ImageTextureNode::color_space_enum = color_space_init(); + ImageTextureNode::ImageTextureNode() : ShaderNode("image_texture") { image_manager = NULL; slot = -1; filename = ""; + color_space = ustring("sRGB"); add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_COORDINATE); add_output("Color", SHADER_SOCKET_COLOR); @@ -65,7 +78,12 @@ void ImageTextureNode::compile(SVMCompiler& compiler) if(slot != -1) { compiler.stack_assign(vector_in); - compiler.add_node(NODE_TEX_IMAGE, slot, vector_in->stack_offset, color_out->stack_offset); + compiler.add_node(NODE_TEX_IMAGE, + slot, + compiler.encode_uchar4( + vector_in->stack_offset, + color_out->stack_offset, + color_space_enum[color_space])); } else { /* image not found */ @@ -77,17 +95,21 @@ void ImageTextureNode::compile(SVMCompiler& compiler) void ImageTextureNode::compile(OSLCompiler& compiler) { compiler.parameter("filename", filename.c_str()); + compiler.parameter("color_space", color_space.c_str()); compiler.add(this, "node_image_texture"); } /* Environment Texture */ +ShaderEnum EnvironmentTextureNode::color_space_enum = color_space_init(); + EnvironmentTextureNode::EnvironmentTextureNode() : ShaderNode("environment_texture") { image_manager = NULL; slot = -1; filename = ""; + color_space = ustring("sRGB"); add_input("Vector", SHADER_SOCKET_VECTOR, ShaderInput::POSITION); add_output("Color", SHADER_SOCKET_COLOR); @@ -120,7 +142,12 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler) if(slot != -1) { compiler.stack_assign(vector_in); - compiler.add_node(NODE_TEX_ENVIRONMENT, slot, vector_in->stack_offset, color_out->stack_offset); + compiler.add_node(NODE_TEX_ENVIRONMENT, + slot, + compiler.encode_uchar4( + vector_in->stack_offset, + color_out->stack_offset, + color_space_enum[color_space])); } else { /* image not found */ @@ -132,6 +159,7 @@ void EnvironmentTextureNode::compile(SVMCompiler& compiler) void EnvironmentTextureNode::compile(OSLCompiler& compiler) { compiler.parameter("filename", filename.c_str()); + compiler.parameter("color_space", color_space.c_str()); compiler.add(this, "node_environment_texture"); } diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index f59a775b658..da3b743e79b 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -39,6 +39,9 @@ public: ImageManager *image_manager; int slot; string filename; + ustring color_space; + + static ShaderEnum color_space_enum; }; class EnvironmentTextureNode : public ShaderNode { @@ -50,6 +53,9 @@ public: ImageManager *image_manager; int slot; string filename; + ustring color_space; + + static ShaderEnum color_space_enum; }; class SkyTextureNode : public ShaderNode { diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index a98235722e5..11d822607d7 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -400,6 +400,7 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA { //uiItemR(layout, ptr, "image", 0, "", ICON_NONE); uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL); + uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE); } static void node_shader_buts_tex_sky(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index f3540e5fcc7..896f809a97e 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -355,11 +355,11 @@ typedef struct NodeTexSky { } NodeTexSky; typedef struct NodeTexImage { - int pad; + int color_space; } NodeTexImage; typedef struct NodeTexEnvironment { - int pad; + int color_space; } NodeTexEnvironment; typedef struct NodeTexBlend { @@ -499,6 +499,10 @@ typedef struct TexNodeOutput { #define SHD_WOOD_BAND_NOISE 2 #define SHD_WOOD_RING_NOISE 3 +/* image/environment texture */ +#define SHD_COLORSPACE_LINEAR 0 +#define SHD_COLORSPACE_SRGB 1 + /* blur node */ #define CMP_NODE_BLUR_ASPECT_NONE 0 #define CMP_NODE_BLUR_ASPECT_Y 1 diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 8601a986c3f..63241c339f6 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -1044,20 +1044,11 @@ static void def_sh_tex_sky(StructRNA *srna) static void def_sh_tex_environment(StructRNA *srna) { - PropertyRNA *prop; + static const EnumPropertyItem prop_color_space_items[]= { + {SHD_COLORSPACE_SRGB, "SRGB", 0, "sRGB", "Image is in sRGB color space"}, + {SHD_COLORSPACE_LINEAR, "LINEAR", 0, "Linear", "Image is in scene linear color space"}, + {0, NULL, 0, NULL, NULL}}; - prop = RNA_def_property(srna, "image", PROP_POINTER, PROP_NONE); - RNA_def_property_pointer_sdna(prop, NULL, "id"); - RNA_def_property_struct_type(prop, "Image"); - RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text(prop, "Image", ""); - RNA_def_property_update(prop, NC_NODE|NA_EDITED, "rna_Node_update"); - - RNA_def_struct_sdna_from(srna, "NodeTexEnvironment", "storage"); -} - -static void def_sh_tex_image(StructRNA *srna) -{ PropertyRNA *prop; prop = RNA_def_property(srna, "image", PROP_POINTER, PROP_NONE); @@ -1068,6 +1059,35 @@ static void def_sh_tex_image(StructRNA *srna) RNA_def_property_update(prop, NC_NODE|NA_EDITED, "rna_Node_update"); RNA_def_struct_sdna_from(srna, "NodeTexImage", "storage"); + + prop= RNA_def_property(srna, "color_space", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, prop_color_space_items); + RNA_def_property_ui_text(prop, "Color Space", "Image file color space"); + RNA_def_property_update(prop, 0, "rna_Node_update"); +} + +static void def_sh_tex_image(StructRNA *srna) +{ + static const EnumPropertyItem prop_color_space_items[]= { + {SHD_COLORSPACE_LINEAR, "LINEAR", 0, "Linear", "Image is in scene linear color space"}, + {SHD_COLORSPACE_SRGB, "SRGB", 0, "sRGB", "Image is in sRGB color space"}, + {0, NULL, 0, NULL, NULL}}; + + PropertyRNA *prop; + + prop = RNA_def_property(srna, "image", PROP_POINTER, PROP_NONE); + RNA_def_property_pointer_sdna(prop, NULL, "id"); + RNA_def_property_struct_type(prop, "Image"); + RNA_def_property_flag(prop, PROP_EDITABLE); + RNA_def_property_ui_text(prop, "Image", ""); + RNA_def_property_update(prop, NC_NODE|NA_EDITED, "rna_Node_update"); + + RNA_def_struct_sdna_from(srna, "NodeTexImage", "storage"); + + prop= RNA_def_property(srna, "color_space", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, prop_color_space_items); + RNA_def_property_ui_text(prop, "Color Space", "Image file color space"); + RNA_def_property_update(prop, 0, "rna_Node_update"); } static void def_sh_tex_blend(StructRNA *srna) diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_tex_environment.c b/source/blender/nodes/intern/SHD_nodes/SHD_tex_environment.c index d9050ae8c43..c1b18e17d26 100644 --- a/source/blender/nodes/intern/SHD_nodes/SHD_tex_environment.c +++ b/source/blender/nodes/intern/SHD_nodes/SHD_tex_environment.c @@ -44,6 +44,7 @@ static bNodeSocketType sh_node_tex_environment_out[]= { static void node_shader_init_tex_environment(bNode *node) { NodeTexEnvironment *tex = MEM_callocN(sizeof(NodeTexEnvironment), "NodeTexEnvironment"); + tex->color_space = SHD_COLORSPACE_SRGB; node->storage = tex; } diff --git a/source/blender/nodes/intern/SHD_nodes/SHD_tex_image.c b/source/blender/nodes/intern/SHD_nodes/SHD_tex_image.c index 69f93ab1903..c08ba2ca86d 100644 --- a/source/blender/nodes/intern/SHD_nodes/SHD_tex_image.c +++ b/source/blender/nodes/intern/SHD_nodes/SHD_tex_image.c @@ -44,6 +44,7 @@ static bNodeSocketType sh_node_tex_image_out[]= { static void node_shader_init_tex_image(bNode *node) { NodeTexImage *tex = MEM_callocN(sizeof(NodeTexImage), "NodeTexImage"); + tex->color_space = SHD_COLORSPACE_SRGB; node->storage = tex; }