From 440ff4916e7598f356612c0f93cc27354040af3f Mon Sep 17 00:00:00 2001 From: Lukas Stockner Date: Sun, 1 May 2016 21:52:49 +0200 Subject: [PATCH 1/4] Render API: Add an interface for renderers to allow a color-managed workflow This commit adds three functions to the Render API: - Returning a conversion matrix from the CIE XYZ color space to the scene_linear space, which is needed by physically based renderers to accurately model e.g. blackbody temperatures or determine luminance. - Converting colors from an arbitrary color space into the scene_linear space, which is needed to e.g. convert textures to the working color space. - Returning the default color spaces for float or byte textures, which is needed for automatic fallback color space detection. --- intern/opencolorio/ocio_capi.h | 2 + source/blender/imbuf/IMB_colormanagement.h | 5 +++ source/blender/imbuf/intern/colormanagement.c | 50 +++++++++++++++++++++- source/blender/makesrna/intern/rna_render.c | 17 ++++++++ source/blender/render/extern/include/RE_engine.h | 3 ++ .../blender/render/intern/source/external_engine.c | 24 +++++++++++ 6 files changed, 99 insertions(+), 2 deletions(-) diff --git a/intern/opencolorio/ocio_capi.h b/intern/opencolorio/ocio_capi.h index 52a8672..5211da9 100644 --- a/intern/opencolorio/ocio_capi.h +++ b/intern/opencolorio/ocio_capi.h @@ -37,11 +37,13 @@ struct OCIO_GLSLDrawState; #define OCIO_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name #define OCIO_ROLE_SCENE_LINEAR "scene_linear" +#define OCIO_ROLE_XYZ "xyz" #define OCIO_ROLE_COLOR_PICKING "color_picking" #define OCIO_ROLE_TEXTURE_PAINT "texture_paint" #define OCIO_ROLE_DEFAULT_BYTE "default_byte" #define OCIO_ROLE_DEFAULT_FLOAT "default_float" #define OCIO_ROLE_DEFAULT_SEQUENCER "default_sequencer" +#define OCIO_ROLE_RAW "raw" OCIO_DECLARE_HANDLE(OCIO_ConstConfigRcPtr); OCIO_DECLARE_HANDLE(OCIO_ConstColorSpaceRcPtr); diff --git a/source/blender/imbuf/IMB_colormanagement.h b/source/blender/imbuf/IMB_colormanagement.h index ab822f1..1fb2288 100644 --- a/source/blender/imbuf/IMB_colormanagement.h +++ b/source/blender/imbuf/IMB_colormanagement.h @@ -79,9 +79,12 @@ void IMB_colormanagement_transform_threaded(float *buffer, int width, int height const char *from_colorspace, const char *to_colorspace, bool predivide); void IMB_colormanagement_transform_v4(float pixel[4], const char *from_colorspace, const char *to_colorspace); +void IMB_colormanagement_named_colorspace_to_scene_linear_v3(float pixel[3], const char *name); void IMB_colormanagement_colorspace_to_scene_linear_v3(float pixel[3], struct ColorSpace *colorspace); void IMB_colormanagement_colorspace_to_scene_linear_v4(float pixel[4], bool predivide, struct ColorSpace *colorspace); +void IMB_colormanagement_xyz_to_scene_linear_m3(float matrix[3][3]); + void IMB_colormanagement_scene_linear_to_colorspace_v3(float pixel[3], struct ColorSpace *colorspace); void IMB_colormanagement_colorspace_to_scene_linear(float *buffer, int width, int height, int channels, struct ColorSpace *colorspace, bool predivide); @@ -201,11 +204,13 @@ void IMB_colormanagement_finish_glsl_draw(void); /* Roles */ enum { COLOR_ROLE_SCENE_LINEAR = 0, + COLOR_ROLE_XYZ, COLOR_ROLE_COLOR_PICKING, COLOR_ROLE_TEXTURE_PAINTING, COLOR_ROLE_DEFAULT_SEQUENCER, COLOR_ROLE_DEFAULT_BYTE, COLOR_ROLE_DEFAULT_FLOAT, + COLOR_ROLE_RAW, }; #include "intern/colormanagement_inline.c" diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c index e4e93d3..82513a0 100644 --- a/source/blender/imbuf/intern/colormanagement.c +++ b/source/blender/imbuf/intern/colormanagement.c @@ -74,11 +74,13 @@ /* ** list of all supported color spaces, displays and views */ static char global_role_scene_linear[MAX_COLORSPACE_NAME]; +static char global_role_xyz[MAX_COLORSPACE_NAME]; static char global_role_color_picking[MAX_COLORSPACE_NAME]; static char global_role_texture_painting[MAX_COLORSPACE_NAME]; static char global_role_default_byte[MAX_COLORSPACE_NAME]; static char global_role_default_float[MAX_COLORSPACE_NAME]; static char global_role_default_sequencer[MAX_COLORSPACE_NAME]; +static char global_role_raw[MAX_COLORSPACE_NAME]; static ListBase global_colorspaces = {NULL, NULL}; static ListBase global_displays = {NULL, NULL}; @@ -475,11 +477,13 @@ static void colormanage_load_config(OCIO_ConstConfigRcPtr *config) /* get roles */ colormanage_role_color_space_name_get(config, global_role_scene_linear, OCIO_ROLE_SCENE_LINEAR, NULL); + colormanage_role_color_space_name_get(config, global_role_xyz, OCIO_ROLE_XYZ, NULL); colormanage_role_color_space_name_get(config, global_role_color_picking, OCIO_ROLE_COLOR_PICKING, NULL); colormanage_role_color_space_name_get(config, global_role_texture_painting, OCIO_ROLE_TEXTURE_PAINT, NULL); colormanage_role_color_space_name_get(config, global_role_default_sequencer, OCIO_ROLE_DEFAULT_SEQUENCER, OCIO_ROLE_SCENE_LINEAR); colormanage_role_color_space_name_get(config, global_role_default_byte, OCIO_ROLE_DEFAULT_BYTE, OCIO_ROLE_TEXTURE_PAINT); colormanage_role_color_space_name_get(config, global_role_default_float, OCIO_ROLE_DEFAULT_FLOAT, OCIO_ROLE_SCENE_LINEAR); + colormanage_role_color_space_name_get(config, global_role_raw, OCIO_ROLE_RAW, OCIO_ROLE_SCENE_LINEAR); /* load colorspaces */ tot_colorspace = OCIO_configGetNumColorSpaces(config); @@ -1162,6 +1166,8 @@ const char *IMB_colormanagement_role_colorspace_name_get(int role) switch (role) { case COLOR_ROLE_SCENE_LINEAR: return global_role_scene_linear; + case COLOR_ROLE_XYZ: + return global_role_xyz; case COLOR_ROLE_COLOR_PICKING: return global_role_color_picking; case COLOR_ROLE_TEXTURE_PAINTING: @@ -1172,6 +1178,8 @@ const char *IMB_colormanagement_role_colorspace_name_get(int role) return global_role_default_float; case COLOR_ROLE_DEFAULT_BYTE: return global_role_default_byte; + case COLOR_ROLE_RAW: + return global_role_raw; default: printf("Unknown role was passed to %s\n", __func__); BLI_assert(0); @@ -1690,6 +1698,18 @@ void IMB_colormanagement_transform_v4(float pixel[4], const char *from_colorspac IMB_colormanagement_processor_free(cm_processor); } +/* convert pixel from specified color space to scene linear */ + +void IMB_colormanagement_named_colorspace_to_scene_linear_v3(float pixel[3], const char *name) +{ + OCIO_ConstProcessorRcPtr *processor; + + processor = create_colorspace_transform_processor(name, global_role_scene_linear); + + if (processor) + OCIO_processorApplyRGB(processor, pixel); +} + /* convert pixel from specified by descriptor color space to scene linear * used by performance-critical areas such as renderer and baker */ @@ -1842,6 +1862,32 @@ void IMB_colormanagement_imbuf_make_display_space(ImBuf *ibuf, const ColorManage colormanagement_imbuf_make_display_space(ibuf, view_settings, display_settings, false); } +void IMB_colormanagement_xyz_to_scene_linear_m3(float matrix[3][3]) +{ + if (global_role_xyz[0]) + { + /* we assume that both spaces are linear and so that the transformation + * must always be a 3x3 matrix which we can extract by converting + * the (1, 0, 0), (0, 1, 0), (0, 0, 1) basis vectors */ + ColormanageProcessor *cm_processor; + cm_processor = IMB_colormanagement_colorspace_processor_new(global_role_xyz, global_role_scene_linear); + + unit_m3(matrix); + IMB_colormanagement_processor_apply_v3(cm_processor, matrix[0]); + IMB_colormanagement_processor_apply_v3(cm_processor, matrix[1]); + IMB_colormanagement_processor_apply_v3(cm_processor, matrix[2]); + + IMB_colormanagement_processor_free(cm_processor); + } + else + { + /* default XYZ to Rec.709 if the configuration contains no XYZ role */ + matrix[0][0] = 3.240479f; matrix[1][0] = -1.537150f; matrix[2][0] = -0.498535f; + matrix[0][1] = -0.969256f; matrix[1][1] = 1.875991f; matrix[2][1] = 0.041556f; + matrix[0][2] = 0.055648f; matrix[1][2] = -0.204043f; matrix[2][2] = 1.057311f; + } +} + /* prepare image buffer to be saved on disk, applying color management if needed * color management would be applied if image is saving as render result and if * file format is not expecting float buffer to be in linear space (currently @@ -2343,7 +2389,7 @@ static void colormanage_description_strip(char *description) ColorSpace *colormanage_colorspace_add(const char *name, const char *description, bool is_invertible, bool is_data) { ColorSpace *colorspace, *prev_space; - int counter = 1; + int counter = COLORSPACE_NUM; colorspace = MEM_callocN(sizeof(ColorSpace), "ColorSpace"); @@ -2402,7 +2448,7 @@ ColorSpace *colormanage_colorspace_get_roled(int role) ColorSpace *colormanage_colorspace_get_indexed(int index) { /* color space indices are 1-based */ - return BLI_findlink(&global_colorspaces, index - 1); + return BLI_findlink(&global_colorspaces, index - COLORSPACE_NUM); } int IMB_colormanagement_colorspace_get_named_index(const char *name) diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c index 8438270..1432c56 100644 --- a/source/blender/makesrna/intern/rna_render.c +++ b/source/blender/makesrna/intern/rna_render.c @@ -544,6 +544,23 @@ static void rna_def_render_engine(BlenderRNA *brna) prop = RNA_def_float_matrix(func, "r_model_matrix", 4, 4, NULL, 0.0f, 0.0f, "Model Matrix", "Normalized camera model matrix", 0.0f, 0.0f); RNA_def_property_flag(prop, PROP_REQUIRED); + func = RNA_def_function(srna, "xyz_to_scene_linear_matrix", "RE_engine_get_xyz_to_scene_linear_matrix"); + prop = RNA_def_float_matrix(func, "matrix", 3, 3, NULL, 0.0f, 0.0f, "Matrix", "CIE XYZ to scene linear color space matrix, depending on the OpenColorIO configuration", 0.0f, 0.0f); + RNA_def_property_flag(prop, PROP_REQUIRED); + + func = RNA_def_function(srna, "color_to_scene_linear", "RE_engine_color_to_scene_linear"); + prop = RNA_def_int(func, "colorspace", 0, 0, INT_MAX, "Color Space", "The color space in which the color is given", 0, INT_MAX); + RNA_def_property_flag(prop, PROP_REQUIRED); + prop = RNA_def_float_vector(func, "color", 3, NULL, 0.0f, 0.0f, "Color", "The color that's transformed to scene linear colorspace", 0.0f, 0.0f); + RNA_def_property_flag(prop, PROP_REQUIRED); + RNA_def_function_output(func, prop); + + func = RNA_def_function(srna, "default_colorspace", "RE_engine_default_colorspace"); + prop = RNA_def_boolean(func, "float_texture", 0, "Get the default colorspace for float textures (instead of byte textures)", ""); + RNA_def_property_flag(prop, PROP_REQUIRED); + prop = RNA_def_int(func, "colorspace", 0, 0, INT_MAX, "Color Space", "The default color space for the specified texture type", 0, INT_MAX); + RNA_def_function_return(func, prop); + func = RNA_def_function(srna, "use_spherical_stereo", "RE_engine_get_spherical_stereo"); prop = RNA_def_pointer(func, "camera", "Object", "", ""); RNA_def_property_flag(prop, PROP_REQUIRED); diff --git a/source/blender/render/extern/include/RE_engine.h b/source/blender/render/extern/include/RE_engine.h index f83a210..d9c731e 100644 --- a/source/blender/render/extern/include/RE_engine.h +++ b/source/blender/render/extern/include/RE_engine.h @@ -146,6 +146,9 @@ void RE_engine_active_view_set(RenderEngine *engine, const char *viewname); float RE_engine_get_camera_shift_x(RenderEngine *engine, struct Object *camera, int use_spherical_stereo); void RE_engine_get_camera_model_matrix(RenderEngine *engine, struct Object *camera, int use_spherical_stereo, float *r_modelmat); int RE_engine_get_spherical_stereo(RenderEngine *engine, struct Object *camera); +void RE_engine_get_xyz_to_scene_linear_matrix(RenderEngine *engine, float *r_matrix); +void RE_engine_color_to_scene_linear(RenderEngine *engine, int colorspace, float color[3]); +int RE_engine_default_colorspace(RenderEngine *engine, int float_texture); int RE_engine_test_break(RenderEngine *engine); void RE_engine_update_stats(RenderEngine *engine, const char *stats, const char *info); diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c index fd9d95c..9d9977e 100644 --- a/source/blender/render/intern/source/external_engine.c +++ b/source/blender/render/intern/source/external_engine.c @@ -54,6 +54,8 @@ #include "BPY_extern.h" #endif +#include "IMB_colormanagement.h" + #include "RE_engine.h" #include "RE_pipeline.h" #include "RE_bake.h" @@ -406,6 +408,28 @@ void RE_engine_get_camera_model_matrix(RenderEngine *engine, Object *camera, int BKE_camera_multiview_model_matrix(re ? &re->r : NULL, camera, re->viewname, (float (*)[4])r_modelmat); } +void RE_engine_get_xyz_to_scene_linear_matrix(RenderEngine *UNUSED(engine), float *r_matrix) +{ + IMB_colormanagement_xyz_to_scene_linear_m3((float (*)[3])r_matrix); +} + +void RE_engine_color_to_scene_linear(RenderEngine *UNUSED(engine), int colorspace, float color[3]) +{ + const char* name = IMB_colormanagement_colorspace_get_indexed_name(colorspace); + + /* If an invalid index is given, return the color untransformed. */ + if (name == NULL || name[0] == '\0') + return; + + IMB_colormanagement_named_colorspace_to_scene_linear_v3(color, name); +} + +int RE_engine_default_colorspace(RenderEngine *UNUSED(engine), int float_texture) +{ + const char* name = IMB_colormanagement_role_colorspace_name_get(float_texture? COLOR_ROLE_DEFAULT_FLOAT: COLOR_ROLE_DEFAULT_BYTE); + return IMB_colormanagement_colorspace_get_named_index(name); +} + int RE_engine_get_spherical_stereo(RenderEngine *engine, Object *camera) { Render *re = engine->re; -- 1.9.1