Changes to Color Management

After testing and feedback, I've decided to slightly modify the way color 
management works internally. While the previous method worked well for 
rendering, was a smaller transition and had some advantages over this
new method, it was a bit more ambiguous, and was making things difficult 
for other areas such as compositing.

This implementation now considers all color data (with only a couple of 
exceptions such as brush colors) to be stored in linear RGB color space, 
rather than sRGB as previously. This brings it in line with Nuke, which also 
operates this way, quite successfully. Color swatches, pickers, color ramp 
display are now gamma corrected to display gamma so you can see what 
you're doing, but the numbers themselves are considered linear. This 
makes understanding blending modes more clear (a 0.5 value on overlay 
will not change the result now) as well as making color swatches act more 
predictably in the compositor, however bringing over color values from 
applications like photoshop or gimp, that operate in a gamma space, 
will give identical results.

This commit will convert over existing files saved by earlier 2.5 versions to 
work generally the same, though there may be some slight differences with 
things like textures. Now that we're set on changing other areas of shading, 
this won't be too disruptive overall.

I've made a diagram explaining the pipeline here:
http://mke3.net/blender/devel/2.5/25_linear_workflow_pipeline.png

and some docs here:
http://www.blender.org/development/release-logs/blender-250/color-management/
This commit is contained in:
Matt Ebb
2009-12-02 07:56:34 +00:00
parent c758f6589e
commit b89138564e
30 changed files with 273 additions and 159 deletions

View File

@@ -495,7 +495,7 @@ class MATERIAL_PT_sss(MaterialButtonsPanel):
col.prop(sss, "ior")
col.prop(sss, "scale")
col.prop(sss, "color", text="")
col.prop(sss, "radius", text="RGB Radius")
col.prop(sss, "radius", text="RGB Radius", expand=True)
if wide_ui:
col = split.column()

View File

@@ -43,7 +43,7 @@ struct bContext;
struct ReportList;
#define BLENDER_VERSION 250
#define BLENDER_SUBVERSION 7
#define BLENDER_SUBVERSION 8
#define BLENDER_MINVERSION 250
#define BLENDER_MINSUBVERSION 0

View File

@@ -34,12 +34,6 @@ struct CurveMap;
struct ImBuf;
struct rctf;
void gamma_correct_rec709(float *c, float gamma);
void gamma_correct(float *c, float gamma);
float srgb_to_linearrgb(float c);
float linearrgb_to_srgb(float c);
void color_manage_linearize(float *col_to, float *col_from);
void floatbuf_to_srgb_byte(float *rectf, unsigned char *rectc, int x1, int x2, int y1, int y2, int w);
void floatbuf_to_byte(float *rectf, unsigned char *rectc, int x1, int x2, int y1, int y2, int w);

View File

@@ -58,52 +58,6 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
/* ********************************* color transforms ********************************* */
/*Transform linear RGB values to nonlinear RGB values. Rec.
709 is ITU-R Recommendation BT. 709 (1990) ``Basic
Parameter Values for the HDTV Standard for the Studio and
for International Programme Exchange'', formerly CCIR Rec.
709.*/
void gamma_correct_rec709(float *c, float gamma)
{
/* Rec. 709 gamma correction. */
const float cc = 0.018f;
if (*c < cc)
*c *= ((1.099f * (float)powf(cc, gamma)) - 0.099f) * (1.0f/cc);
else
*c = (1.099f * (float)powf(*c, gamma)) - 0.099f;
}
void gamma_correct(float *c, float gamma)
{
*c = powf((*c), gamma);
}
float srgb_to_linearrgb(float c)
{
if (c < 0.04045f)
return (c < 0.0f)? 0.0f: c*(1.0f/12.92f);
else
return powf((c + 0.055f)*(1.0f/1.055f), 2.4f);
}
float linearrgb_to_srgb(float c)
{
if (c < 0.0031308f)
return (c < 0.0f)? 0.0f: c * 12.92f;
else
return 1.055f * powf(c, 1.0f/2.4f) - 0.055f;
}
/* utility function convert an RGB triplet from sRGB to linear RGB color space */
void color_manage_linearize(float *col_to, float *col_from)
{
col_to[0] = srgb_to_linearrgb(col_from[0]);
col_to[1] = srgb_to_linearrgb(col_from[1]);
col_to[2] = srgb_to_linearrgb(col_from[2]);
}
void floatbuf_to_srgb_byte(float *rectf, unsigned char *rectc, int x1, int x2, int y1, int y2, int w)
{

View File

@@ -795,7 +795,7 @@ void *add_lamp(char *name)
la->sun_intensity = 1.0f;
la->skyblendtype= MA_RAMP_ADD;
la->skyblendfac= 1.0f;
la->sky_colorspace= BLI_CS_CIE;
la->sky_colorspace= BLI_XYZ_CIE;
la->sky_exposure= 1.0f;
curvemapping_initialize(la->curfalloff);

View File

@@ -32,10 +32,16 @@
extern "C" {
#endif
#define BLI_CS_SMPTE 0
#define BLI_CS_REC709 1
#define BLI_CS_CIE 2
/* primaries */
#define BLI_XYZ_SMPTE 0
#define BLI_XYZ_REC709_SRGB 1
#define BLI_XYZ_CIE 2
/* built-in profiles */
#define BLI_PR_NONE 0
#define BLI_PR_SRGB 1
#define BLI_PR_REC709 2
/******************* Conversion to RGB ********************/
void hsv_to_rgb(float h, float s, float v, float *r, float *g, float *b);
@@ -53,6 +59,16 @@ void rgb_to_hsv(float r, float g, float b, float *lh, float *ls, float *lv);
unsigned int rgb_to_cpack(float r, float g, float b);
unsigned int hsv_to_cpack(float h, float s, float v);
/***************** Profile Transformations ********************/
void gamma_correct(float *c, float gamma);
float rec709_to_linearrgb(float c);
float linearrgb_to_rec709(float c);
float srgb_to_linearrgb(float c);
float linearrgb_to_srgb(float c);
void srgb_to_linearrgb_v3_v3(float *col_to, float *col_from);
void linearrgb_to_srgb_v3_v3(float *col_to, float *col_from);
/************************** Other *************************/
int constrain_rgb(float *r, float *g, float *b);

View File

@@ -208,17 +208,17 @@ void rgb_to_hsv(float r, float g, float b, float *lh, float *ls, float *lv)
void xyz_to_rgb(float xc, float yc, float zc, float *r, float *g, float *b, int colorspace)
{
switch (colorspace) {
case BLI_CS_SMPTE:
case BLI_XYZ_SMPTE:
*r = (3.50570f * xc) + (-1.73964f * yc) + (-0.544011f * zc);
*g = (-1.06906f * xc) + (1.97781f * yc) + (0.0351720f * zc);
*b = (0.0563117f * xc) + (-0.196994f * yc) + (1.05005f * zc);
break;
case BLI_CS_REC709:
case BLI_XYZ_REC709_SRGB:
*r = (3.240476f * xc) + (-1.537150f * yc) + (-0.498535f * zc);
*g = (-0.969256f * xc) + (1.875992f * yc) + (0.041556f * zc);
*b = (0.055648f * xc) + (-0.204043f * yc) + (1.057311f * zc);
break;
case BLI_CS_CIE:
case BLI_XYZ_CIE:
*r = (2.28783848734076f * xc) + (-0.833367677835217f * yc) + (-0.454470795871421f * zc);
*g = (-0.511651380743862f * xc) + (1.42275837632178f * yc) + (0.0888930017552939f * zc);
*b = (0.00572040983140966f * xc) + (-0.0159068485104036f * yc) + (1.0101864083734f * zc);
@@ -274,6 +274,61 @@ void cpack_to_rgb(unsigned int col, float *r, float *g, float *b)
*b /= 255.0f;
}
/* ********************************* color transforms ********************************* */
void gamma_correct(float *c, float gamma)
{
*c = powf((*c), gamma);
}
float rec709_to_linearrgb(float c)
{
if (c < 0.081f)
return (c < 0.0f)? 0.0f: c * (1.0f/4.5f);
else
return powf((c + 0.099f)*(1.0f/1.099f), (1.0f/0.45f));
}
float linearrgb_to_rec709(float c)
{
if (c < 0.018f)
return (c < 0.0f)? 0.0f: c * 4.5f;
else
return 1.099f * powf(c, 0.45f) - 0.099f;
}
float srgb_to_linearrgb(float c)
{
if (c < 0.04045f)
return (c < 0.0f)? 0.0f: c * (1.0f/12.92f);
else
return powf((c + 0.055f)*(1.0f/1.055f), 2.4f);
}
float linearrgb_to_srgb(float c)
{
if (c < 0.0031308f)
return (c < 0.0f)? 0.0f: c * 12.92f;
else
return 1.055f * powf(c, 1.0f/2.4f) - 0.055f;
}
void srgb_to_linearrgb_v3_v3(float *col_to, float *col_from)
{
col_to[0] = srgb_to_linearrgb(col_from[0]);
col_to[1] = srgb_to_linearrgb(col_from[1]);
col_to[2] = srgb_to_linearrgb(col_from[2]);
}
void linearrgb_to_srgb_v3_v3(float *col_to, float *col_from)
{
col_to[0] = linearrgb_to_srgb(col_from[0]);
col_to[1] = linearrgb_to_srgb(col_from[1]);
col_to[2] = linearrgb_to_srgb(col_from[2]);
}
void minmax_rgb(short c[])
{
if(c[0]>255) c[0]=255;

View File

@@ -10064,7 +10064,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
}
}
/* put 2.50 compatibility code here until next subversion bump */
if (main->versionfile < 250 || (main->versionfile == 250 && main->subversionfile < 8))
{
{
Scene *sce= main->scene.first;
@@ -10108,7 +10108,47 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
ob=ob->id.next;
}
}
/* only convert old 2.50 files with color management */
if (main->versionfile == 250) {
Scene *sce=main->scene.first;
Material *ma=main->mat.first;
World *wo=main->world.first;
int convert=0;
/* convert to new color management system:
while previously colors were stored as srgb,
now they are stored as linear internally,
with screen gamma correction in certain places in the UI. */
/* don't know what scene is active, so we'll convert if any scene has it enabled... */
while (sce) {
if(sce->r.color_mgt_flag & R_COLOR_MANAGEMENT)
convert=1;
sce=sce->id.next;
}
if (convert) {
while(ma) {
srgb_to_linearrgb_v3_v3(&ma->r, &ma->r);
srgb_to_linearrgb_v3_v3(&ma->specr, &ma->specr);
srgb_to_linearrgb_v3_v3(&ma->mirr, &ma->mirr);
srgb_to_linearrgb_v3_v3(ma->sss_col, ma->sss_col);
ma=ma->id.next;
}
while(wo) {
srgb_to_linearrgb_v3_v3(&wo->ambr, &wo->ambr);
srgb_to_linearrgb_v3_v3(&wo->horr, &wo->horr);
srgb_to_linearrgb_v3_v3(&wo->zenr, &wo->zenr);
wo=wo->id.next;
}
}
}
}
/* put 2.50 compatibility code here until next subversion bump */
/* WATCH IT!!!: pointers from libdata have not been converted yet here! */
/* WATCH IT 2!: Userdef struct init has to be in src/usiblender.c! */

View File

@@ -1790,14 +1790,17 @@ uiBlock *uiBeginBlock(const bContext *C, ARegion *region, const char *name, shor
{
uiBlock *block;
wmWindow *window;
Scene *scn;
int getsizex, getsizey;
window= CTX_wm_window(C);
scn = CTX_data_scene(C);
block= MEM_callocN(sizeof(uiBlock), "uiBlock");
block->active= 1;
block->dt= dt;
block->evil_C= (void*)C; // XXX
if (scn) block->color_profile= (scn->r.color_mgt_flag & R_COLOR_MANAGEMENT);
BLI_strncpy(block->name, name, sizeof(block->name));
if(region)
@@ -2295,6 +2298,7 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, char *str, short
if(ELEM(but->type, HSVCUBE, HSVCIRCLE)) { /* hsv buttons temp storage */
float rgb[3];
ui_get_but_vectorf(but, rgb);
rgb_to_hsv(rgb[0], rgb[1], rgb[2], but->hsv, but->hsv+1, but->hsv+2);
}

View File

@@ -736,6 +736,8 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *wcol, rcti *rect)
for( a = 1; a < sizex; a++ ) {
pos = ((float)a) / (sizex-1);
do_colorband( coba, pos, colf );
if (but->block->color_profile != BLI_PR_NONE)
linearrgb_to_srgb_v3_v3(colf, colf);
v1[0]=v2[0]= x1 + a;

View File

@@ -2697,7 +2697,13 @@ static int ui_numedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data, int mx,
{
float x, y;
int changed= 1;
int color_profile = but->block->color_profile;
if (but->rnaprop) {
if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
color_profile = BLI_PR_NONE;
}
/* relative position within box */
x= ((float)mx-but->x1)/(but->x2-but->x1);
y= ((float)my-but->y1)/(but->y2-but->y1);
@@ -2719,8 +2725,12 @@ static int ui_numedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data, int mx,
else if(but->a1==3) {
but->hsv[0]= x;
}
else
else {
/* vertical 'value' strip */
but->hsv[2]= y;
if (color_profile)
but->hsv[2] = srgb_to_linearrgb(but->hsv[2]);
}
ui_set_but_hsv(but); // converts to rgb

View File

@@ -303,6 +303,8 @@ struct uiBlock {
int active; // to keep blocks while drawing and free them afterwards
int puphash; // popup menu hash for memory
int color_profile; // color profile for correcting linear colors for display
void *evil_C; // XXX hack for dynamic operator enums
};

View File

@@ -409,10 +409,10 @@ static void ui_item_array(uiLayout *layout, uiBlock *block, char *name, int icon
}
}
else {
if(ELEM(subtype, PROP_COLOR, PROP_RGB))
if(ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA))
uiDefAutoButR(block, ptr, prop, -1, "", 0, 0, 0, w, UI_UNIT_Y);
if(!ELEM(subtype, PROP_COLOR, PROP_RGB) || expand) {
if(!ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA) || expand) {
/* layout for known array subtypes */
char str[3];
@@ -439,7 +439,7 @@ static void ui_item_array(uiLayout *layout, uiBlock *block, char *name, int icon
but->type= TOG;
}
}
else if(ELEM(subtype, PROP_COLOR, PROP_RGB) && len == 4) {
else if(ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA) && len == 4) {
but= uiDefAutoButR(block, ptr, prop, 3, "A:", 0, 0, 0, w, UI_UNIT_Y);
if(slider && but->type==NUM)
but->type= NUMSLI;

View File

@@ -1902,9 +1902,16 @@ static void uiBlockPickerNew(uiBlock *block, float *col, float *hsv, float *old,
static short colormode= 0; /* temp? 0=rgb, 1=hsv, 2=hex */
uiBut *bt;
int width;
static char tip[50];
VECCOPY(old, col); // old color stored there, for palette_cb to work
/* existence of profile means storage is in linear colour space, with display correction */
if (block->color_profile == BLI_PR_NONE)
sprintf(tip, "Value in Display Color Space");
else
sprintf(tip, "Value in Linear RGB Color Space");
/* HS circle */
bt= uiDefButF(block, HSVCIRCLE, retval, "", 0, 0,SPICK1,SPICK1, col, 0.0, 0.0, 0, 0, "");
uiButSetFunc(bt, do_picker_small_cb, bt, hsv);
@@ -1930,11 +1937,11 @@ static void uiBlockPickerNew(uiBlock *block, float *col, float *hsv, float *old,
sprintf(hexcol, "%02X%02X%02X", (unsigned int)(col[0]*255.0), (unsigned int)(col[1]*255.0), (unsigned int)(col[2]*255.0));
uiBlockBeginAlign(block);
bt= uiDefButF(block, NUMSLI, 0, "R ", 0, -60, width, 19, col, 0.0, 1.0, 10, 3, "");
bt= uiDefButF(block, NUMSLI, 0, "R ", 0, -60, width, 19, col, 0.0, 1.0, 10, 3, tip);
uiButSetFunc(bt, do_palette1_cb, bt, hsv);
bt= uiDefButF(block, NUMSLI, 0, "G ", 0, -80, width, 19, col+1, 0.0, 1.0, 10, 3, "");
bt= uiDefButF(block, NUMSLI, 0, "G ", 0, -80, width, 19, col+1, 0.0, 1.0, 10, 3, tip);
uiButSetFunc(bt, do_palette1_cb, bt, hsv);
bt= uiDefButF(block, NUMSLI, 0, "B ", 0, -100, width, 19, col+2, 0.0, 1.0, 10, 3, "");
bt= uiDefButF(block, NUMSLI, 0, "B ", 0, -100, width, 19, col+2, 0.0, 1.0, 10, 3, tip);
uiButSetFunc(bt, do_palette1_cb, bt, hsv);
uiBlockEndAlign(block);
@@ -2000,6 +2007,13 @@ uiBlock *ui_block_func_COL(bContext *C, uiPopupBlockHandle *handle, void *arg_bu
block= uiBeginBlock(C, handle->region, "colorpicker", UI_EMBOSS);
/* XXX ideally the colour picker buttons would reference the rna property itself */
if (but->rnaprop) {
if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
block->color_profile = BLI_PR_NONE;
}
}
uiBlockSetFlag(block, UI_BLOCK_MOVEMOUSE_QUIT);
VECCOPY(handle->retvec, but->editvec);

View File

@@ -80,7 +80,7 @@ uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int ind
case PROP_INT:
case PROP_FLOAT:
if(arraylen && index == -1) {
if(RNA_property_subtype(prop) == PROP_COLOR)
if(ELEM(RNA_property_subtype(prop), PROP_COLOR, PROP_COLOR_GAMMA))
but= uiDefButR(block, COL, 0, name, x1, y1, x2, y2, ptr, propname, 0, 0, 0, -1, -1, NULL);
}
else if(RNA_property_subtype(prop) == PROP_PERCENTAGE || RNA_property_subtype(prop) == PROP_FACTOR)

View File

@@ -44,6 +44,8 @@
#include "BKE_global.h"
#include "BKE_utildefines.h"
#include "RNA_access.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
@@ -1693,6 +1695,17 @@ static void ui_draw_but_HSV_v(uiBut *but, rcti *rect)
uiWidgetBase wtb;
float rad= 0.5f*(rect->xmax - rect->xmin);
float x, y;
float v = but->hsv[2];
int color_profile = but->block->color_profile;
if (but->rnaprop) {
if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
color_profile = BLI_PR_NONE;
}
}
if (color_profile)
v = linearrgb_to_srgb(v);
widget_init(&wtb);
@@ -1709,8 +1722,8 @@ static void ui_draw_but_HSV_v(uiBut *but, rcti *rect)
widgetbase_draw(&wtb, &wcol_tmp);
/* cursor */
x= rect->xmin + 0.5f*(rect->xmax-rect->xmin);
y= rect->ymin + but->hsv[2]*(rect->ymax-rect->ymin);
x= rect->xmin + 0.5f * (rect->xmax-rect->xmin);
y= rect->ymin + v * (rect->ymax-rect->ymin);
CLAMP(y, rect->ymin+3.0, rect->ymax-3.0);
ui_hsv_cursor(x, y);
@@ -2005,6 +2018,12 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat
{
uiWidgetBase wtb;
float col[4];
int color_profile = but->block->color_profile;
if (but->rnaprop) {
if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA)
color_profile = BLI_PR_NONE;
}
widget_init(&wtb);
@@ -2012,6 +2031,10 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat
round_box_edges(&wtb, roundboxalign, rect, 5.0f);
ui_get_but_vectorf(but, col);
if (color_profile)
linearrgb_to_srgb_v3_v3(col, col);
wcol->inner[0]= FTOCHAR(col[0]);
wcol->inner[1]= FTOCHAR(col[1]);
wcol->inner[2]= FTOCHAR(col[2]);

View File

@@ -341,8 +341,9 @@ static int set_draw_settings_cached(int clearcache, int textured, MTFace *texfac
struct TextureDrawState {
Object *ob;
int islit, istex;
int color_profile;
unsigned char obcol[4];
} Gtexdraw = {NULL, 0, 0, {0, 0, 0, 0}};
} Gtexdraw = {NULL, 0, 0, 0, {0, 0, 0, 0}};
static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob)
{
@@ -371,6 +372,7 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O
Gtexdraw.ob = ob;
Gtexdraw.istex = istex;
Gtexdraw.color_profile = scene->r.color_mgt_flag & R_COLOR_MANAGEMENT;
memcpy(Gtexdraw.obcol, obcol, sizeof(obcol));
set_draw_settings_cached(1, 0, 0, Gtexdraw.islit, 0, 0, 0);
glShadeModel(GL_SMOOTH);
@@ -413,7 +415,13 @@ static int draw_tface__set_draw_legacy(MTFace *tface, MCol *mcol, int matnr)
if (tface) glColor3f(1.0, 1.0, 1.0);
else {
Material *ma= give_current_material(Gtexdraw.ob, matnr+1);
if(ma) glColor3f(ma->r, ma->g, ma->b);
if(ma) {
float col[3];
if(Gtexdraw.color_profile) linearrgb_to_srgb_v3_v3(col, &ma->r);
else copy_v3_v3(col, &ma->r);
glColor3fv(col);
}
else glColor3f(1.0, 1.0, 1.0);
}
return 2; /* Don't set color */
@@ -478,13 +486,19 @@ static void add_tface_color_layer(DerivedMesh *dm)
}
}
else {
float col[3];
Material *ma= give_current_material(Gtexdraw.ob, mface[i].mat_nr+1);
if(ma)
if(ma) {
if(Gtexdraw.color_profile) linearrgb_to_srgb_v3_v3(col, &ma->r);
else copy_v3_v3(col, &ma->r);
for(j=0;j<4;j++) {
finalCol[i*4+j].b = ma->b;
finalCol[i*4+j].g = ma->g;
finalCol[i*4+j].r = ma->r;
finalCol[i*4+j].b = col[2];
finalCol[i*4+j].g = col[1];
finalCol[i*4+j].r = col[0];
}
}
else
for(j=0;j<4;j++) {
finalCol[i*4+j].b = 255;

View File

@@ -34,6 +34,8 @@
#include "GL/glew.h"
#include "BLI_math.h"
#include "DNA_image_types.h"
#include "DNA_lamp_types.h"
#include "DNA_material_types.h"
@@ -856,6 +858,7 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O
GPUMaterial *gpumat;
GPUBlendMode blendmode;
int a;
int gamma = scene->r.color_mgt_flag & R_COLOR_MANAGEMENT;
/* initialize state */
memset(&GMS, 0, sizeof(GMS));
@@ -930,6 +933,7 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O
GMS.matbuf[a][0][0]= ma->r;
GMS.matbuf[a][0][1]= ma->g;
GMS.matbuf[a][0][2]= ma->b;
if(gamma) linearrgb_to_srgb_v3_v3(&GMS.matbuf[a][0][0], &GMS.matbuf[a][0][0]);
} else {
GMS.matbuf[a][0][0]= (ma->ref+ma->emit)*ma->r;
GMS.matbuf[a][0][1]= (ma->ref+ma->emit)*ma->g;
@@ -939,6 +943,11 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O
GMS.matbuf[a][1][1]= ma->spec*ma->specg;
GMS.matbuf[a][1][2]= ma->spec*ma->specb;
GMS.matbuf[a][1][3]= 1.0;
if(gamma) {
linearrgb_to_srgb_v3_v3(&GMS.matbuf[a][0][0], &GMS.matbuf[a][0][0]);
linearrgb_to_srgb_v3_v3(&GMS.matbuf[a][1][0], &GMS.matbuf[a][1][0]);
}
}
blendmode = (ma->alpha == 1.0f)? GPU_BLEND_SOLID: GPU_BLEND_ALPHA;

View File

@@ -115,7 +115,7 @@ typedef enum PropertySubType {
PROP_QUATERNION = 27,
PROP_AXISANGLE = 28,
PROP_XYZ = 29,
PROP_RGB = 30,
PROP_COLOR_GAMMA = 30,
/* booleans */
PROP_LAYER = 40,

View File

@@ -1430,7 +1430,7 @@ static const char *rna_property_subtypename(PropertyType type)
case PROP_VELOCITY: return "PROP_VELOCITY";
case PROP_ACCELERATION: return "PROP_ACCELERATION";
case PROP_XYZ: return "PROP_XYZ";
case PROP_RGB: return "PROP_RGB";
case PROP_COLOR_GAMMA: return "PROP_COLOR_GAMMA";
case PROP_LAYER: return "PROP_LAYER";
case PROP_LAYER_MEMBER: return "PROP_LAYER_MEMBER";
default: {

View File

@@ -693,7 +693,7 @@ char RNA_property_array_item_char(PropertyRNA *prop, int index)
return quatitem[index];
else if((index < 4) && ELEM6(subtype, PROP_TRANSLATION, PROP_DIRECTION, PROP_XYZ, PROP_EULER, PROP_VELOCITY, PROP_ACCELERATION))
return vectoritem[index];
else if ((index < 4) && ELEM(subtype, PROP_COLOR, PROP_RGB))
else if ((index < 4) && ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA))
return coloritem[index];
return '\0';
@@ -731,7 +731,7 @@ int RNA_property_array_item_index(PropertyRNA *prop, char name)
return 3;
}
}
else if (ELEM(subtype, PROP_COLOR, PROP_RGB)) {
else if (ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA)) {
switch (name) {
case 'R':
return 0;

View File

@@ -203,7 +203,7 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Rate", "Number of paints per second for Airbrush.");
RNA_def_property_update(prop, 0, "rna_Brush_update");
prop= RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR);
prop= RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "rgb");
RNA_def_property_ui_text(prop, "Color", "");
RNA_def_property_update(prop, 0, "rna_Brush_update");

View File

@@ -216,13 +216,13 @@ static void rna_def_curvemapping(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "CurveMap");
RNA_def_property_ui_text(prop, "Curves", "");
prop= RNA_def_property(srna, "black_level", PROP_FLOAT, PROP_RGB);
prop= RNA_def_property(srna, "black_level", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "black");
RNA_def_property_range(prop, -1000.0f, 1000.0f);
RNA_def_property_ui_text(prop, "Black Level", "For RGB curves, the color that black is mapped to");
RNA_def_property_float_funcs(prop, NULL, "rna_CurveMapping_black_level_set", NULL);
prop= RNA_def_property(srna, "white_level", PROP_FLOAT, PROP_RGB);
prop= RNA_def_property(srna, "white_level", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "white");
RNA_def_property_range(prop, -1000.0f, 1000.0f);
RNA_def_property_ui_text(prop, "White Level", "For RGB curves, the color that white is mapped to");

View File

@@ -1239,7 +1239,7 @@ static void rna_def_material_sss(BlenderRNA *brna)
RNA_def_struct_nested(brna, srna, "Material");
RNA_def_struct_ui_text(srna, "Material Subsurface Scattering", "Diffuse subsurface scattering settings for a Material datablock.");
prop= RNA_def_property(srna, "radius", PROP_FLOAT, PROP_RGB|PROP_UNIT_LENGTH);
prop= RNA_def_property(srna, "radius", PROP_FLOAT, PROP_COLOR|PROP_UNIT_LENGTH);
RNA_def_property_float_sdna(prop, NULL, "sss_radius");
RNA_def_property_range(prop, 0.001, FLT_MAX);
RNA_def_property_ui_range(prop, 0.001, 10000, 1, 3);

View File

@@ -869,7 +869,7 @@ static void rna_def_property(BlenderRNA *brna)
{PROP_EULER, "EULER", 0, "Euler", ""},
{PROP_QUATERNION, "QUATERNION", 0, "Quaternion", ""},
{PROP_XYZ, "XYZ", 0, "XYZ", ""},
{PROP_RGB, "RGB", 0, "RGB", ""},
{PROP_COLOR_GAMMA, "COLOR_GAMMA", 0, "Gamma Corrected Color", ""},
{PROP_LAYER, "LAYER", 0, "Layer", ""},
{PROP_LAYER_MEMBER, "LAYER_MEMBERSHIP", 0, "Layer Membership", ""},
{0, NULL, 0, NULL, NULL}};

View File

@@ -4848,8 +4848,7 @@ void RE_Database_FromScene(Render *re, Scene *scene, int use_camera_view)
/* still bad... doing all */
init_render_textures(re);
if (re->r.color_mgt_flag & R_COLOR_MANAGEMENT) color_manage_linearize(amb, &re->wrld.ambr);
else VECCOPY(amb, &re->wrld.ambr);
VECCOPY(amb, &re->wrld.ambr);
init_render_materials(re->r.mode, amb);
set_node_shader_lamp_loop(shade_material_loop);
@@ -5538,8 +5537,7 @@ void RE_Database_Baking(Render *re, Scene *scene, int type, Object *actob)
/* still bad... doing all */
init_render_textures(re);
if (re->r.color_mgt_flag & R_COLOR_MANAGEMENT) color_manage_linearize(amb, &re->wrld.ambr);
else VECCOPY(amb, &re->wrld.ambr);
VECCOPY(amb, &re->wrld.ambr);
init_render_materials(re->r.mode, amb);
set_node_shader_lamp_loop(shade_material_loop);

View File

@@ -537,15 +537,9 @@ void shadeSkyView(float *colf, float *rco, float *view, float *dxyview, short th
/* the fraction of how far we are above the bottom of the screen */
blend= fabs(0.5+ view[1]);
}
if (R.r.color_mgt_flag & R_COLOR_MANAGEMENT) {
color_manage_linearize(hor, &R.wrld.horr);
color_manage_linearize(zen, &R.wrld.zenr);
}
else {
VECCOPY(hor, &R.wrld.horr);
VECCOPY(zen, &R.wrld.zenr);
}
VECCOPY(hor, &R.wrld.horr);
VECCOPY(zen, &R.wrld.zenr);
/* Careful: SKYTEX and SKYBLEND are NOT mutually exclusive! If */
/* SKYBLEND is active, the texture and color blend are added. */
@@ -633,10 +627,7 @@ void shadeSkyPixel(float *collector, float fx, float fy, short thread)
}
else if((R.wrld.skytype & (WO_SKYBLEND+WO_SKYTEX))==0) {
/* 2. solid color */
if(R.r.color_mgt_flag & R_COLOR_MANAGEMENT)
color_manage_linearize(collector, &R.wrld.horr);
else
VECCOPY(collector, &R.wrld.horr);
VECCOPY(collector, &R.wrld.horr);
collector[3] = 0.0f;
}

View File

@@ -91,42 +91,16 @@ extern struct Render R;
* doing inverse gamma correction where applicable */
void shade_input_init_material(ShadeInput *shi)
{
if (R.r.color_mgt_flag & R_COLOR_MANAGEMENT) {
color_manage_linearize(&shi->r, &shi->mat->r);
color_manage_linearize(&shi->specr, &shi->mat->specr);
color_manage_linearize(&shi->mirr, &shi->mat->mirr);
/* material ambr / ambg / ambb is overwritten from world
color_manage_linearize(shi->ambr, shi->mat->ambr);
*/
/* note, keep this synced with render_types.h */
memcpy(&shi->amb, &shi->mat->amb, 11*sizeof(float));
shi->har= shi->mat->har;
} else {
/* note, keep this synced with render_types.h */
memcpy(&shi->r, &shi->mat->r, 23*sizeof(float));
shi->har= shi->mat->har;
}
}
static void shadeinput_colors_linearize(ShadeInput *shi)
{
color_manage_linearize(&shi->r, &shi->r);
color_manage_linearize(&shi->specr, &shi->specr);
color_manage_linearize(&shi->mirr, &shi->mirr);
/* note, keep this synced with render_types.h */
memcpy(&shi->r, &shi->mat->r, 23*sizeof(float));
shi->har= shi->mat->har;
}
/* also used as callback for nodes */
/* delivers a fully filled in ShadeResult, for all passes */
void shade_material_loop(ShadeInput *shi, ShadeResult *shr)
{
/* because node materials don't have access to rendering context,
* inverse gamma correction must happen here. evil. */
if (R.r.color_mgt_flag & R_COLOR_MANAGEMENT && shi->nodes == 1)
shadeinput_colors_linearize(shi);
shade_lamp_loop(shi, shr); /* clears shr */
if(shi->translucency!=0.0f) {
@@ -626,7 +600,7 @@ void shade_input_set_strand_texco(ShadeInput *shi, StrandRen *strand, StrandVert
if (R.r.color_mgt_flag & R_COLOR_MANAGEMENT) {
if(mode & (MA_VERTEXCOL|MA_VERTEXCOLP|MA_FACETEXTURE)) {
color_manage_linearize(shi->vcol, shi->vcol);
srgb_to_linearrgb_v3_v3(shi->vcol, shi->vcol);
}
}
@@ -1291,7 +1265,7 @@ void shade_input_set_shade_texco(ShadeInput *shi)
*/
if (R.r.color_mgt_flag & R_COLOR_MANAGEMENT) {
if(mode & (MA_VERTEXCOL|MA_VERTEXCOLP|MA_FACETEXTURE)) {
color_manage_linearize(shi->vcol, shi->vcol);
srgb_to_linearrgb_v3_v3(shi->vcol, shi->vcol);
}
}

View File

@@ -926,20 +926,17 @@ static void sss_create_tree_mat(Render *re, Material *mat)
if(!re->test_break(re->tbh)) {
SSSData *sss= MEM_callocN(sizeof(*sss), "SSSData");
float ior= mat->sss_ior, cfac= mat->sss_colfac;
float col[3], *radius= mat->sss_radius;
float *radius= mat->sss_radius;
float fw= mat->sss_front, bw= mat->sss_back;
float error = mat->sss_error;
error= get_render_aosss_error(&re->r, error);
if((re->r.scemode & R_PREVIEWBUTS) && error < 0.5f)
error= 0.5f;
if (re->r.color_mgt_flag & R_COLOR_MANAGEMENT) color_manage_linearize(col, mat->sss_col);
else VECCOPY(col, mat->sss_col);
sss->ss[0]= scatter_settings_new(col[0], radius[0], ior, cfac, fw, bw);
sss->ss[1]= scatter_settings_new(col[1], radius[1], ior, cfac, fw, bw);
sss->ss[2]= scatter_settings_new(col[2], radius[2], ior, cfac, fw, bw);
sss->ss[0]= scatter_settings_new(mat->sss_col[0], radius[0], ior, cfac, fw, bw);
sss->ss[1]= scatter_settings_new(mat->sss_col[1], radius[1], ior, cfac, fw, bw);
sss->ss[2]= scatter_settings_new(mat->sss_col[2], radius[2], ior, cfac, fw, bw);
sss->tree= scatter_tree_new(sss->ss, mat->sss_scale, error,
co, color, area, totpoint);

View File

@@ -2051,8 +2051,13 @@ void do_material_tex(ShadeInput *shi)
else texres.tin= texres.ta;
/* inverse gamma correction */
if (R.r.color_mgt_flag & R_COLOR_MANAGEMENT) {
color_manage_linearize(tcol, tcol);
if (tex->type==TEX_IMAGE) {
Image *ima = tex->ima;
ImBuf *ibuf = BKE_image_get_ibuf(ima, &tex->iuser);
/* don't linearize float buffers, assumed to be linear */
if (ibuf && !(ibuf->rect_float) && R.r.color_mgt_flag & R_COLOR_MANAGEMENT)
srgb_to_linearrgb_v3_v3(tcol, tcol);
}
if(mtex->mapto & MAP_COL) {
@@ -2404,11 +2409,6 @@ void do_volume_tex(ShadeInput *shi, float *xyz, int mapto_flag, float *col, floa
texres.tin= texres.ta;
}
/* inverse gamma correction */
if (R.r.color_mgt_flag & R_COLOR_MANAGEMENT) {
color_manage_linearize(tcol, tcol);
}
/* used for emit */
if((mapto_flag & MAP_EMISSION_COL) && (mtex->mapto & MAP_EMISSION_COL)) {
float colemitfac= mtex->colemitfac*stencilTin;
@@ -2556,8 +2556,13 @@ void do_halo_tex(HaloRen *har, float xn, float yn, float *colf)
else texres.tin= texres.ta;
/* inverse gamma correction */
if (R.r.color_mgt_flag & R_COLOR_MANAGEMENT) {
color_manage_linearize(&texres.tr, &texres.tr);
if (mtex->tex->type==TEX_IMAGE) {
Image *ima = mtex->tex->ima;
ImBuf *ibuf = BKE_image_get_ibuf(ima, &mtex->tex->iuser);
/* don't linearize float buffers, assumed to be linear */
if (ibuf && !(ibuf->rect_float) && R.r.color_mgt_flag & R_COLOR_MANAGEMENT)
srgb_to_linearrgb_v3_v3(&texres.tr, &texres.tr);
}
fact= texres.tin*mtex->colfac;
@@ -2605,6 +2610,7 @@ void do_halo_tex(HaloRen *har, float xn, float yn, float *colf)
void do_sky_tex(float *rco, float *lo, float *dxyview, float *hor, float *zen, float *blend, int skyflag, short thread)
{
MTex *mtex;
Tex *tex;
TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
float *co, fact, stencilTin=1.0;
float tempvec[3], texvec[3], dxt[3], dyt[3];
@@ -2618,7 +2624,8 @@ void do_sky_tex(float *rco, float *lo, float *dxyview, float *hor, float *zen, f
if(R.wrld.mtex[tex_nr]) {
mtex= R.wrld.mtex[tex_nr];
if(mtex->tex==0) continue;
tex= mtex->tex;
if(tex==0) continue;
/* if(mtex->mapto==0) continue; */
/* which coords */
@@ -2700,7 +2707,7 @@ void do_sky_tex(float *rco, float *lo, float *dxyview, float *hor, float *zen, f
else texvec[2]= mtex->size[2]*(mtex->ofs[2]);
/* texture */
if(mtex->tex->type==TEX_IMAGE) do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt);
if(tex->type==TEX_IMAGE) do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt);
rgb= multitex(mtex->tex, texvec, dxt, dyt, R.osa, &texres, thread, mtex->which_output);
@@ -2748,8 +2755,13 @@ void do_sky_tex(float *rco, float *lo, float *dxyview, float *hor, float *zen, f
tcol[0]= texres.tr; tcol[1]= texres.tg; tcol[2]= texres.tb;
/* inverse gamma correction */
if (R.r.color_mgt_flag & R_COLOR_MANAGEMENT) {
color_manage_linearize(tcol, tcol);
if (tex->type==TEX_IMAGE) {
Image *ima = tex->ima;
ImBuf *ibuf = BKE_image_get_ibuf(ima, &tex->iuser);
/* don't linearize float buffers, assumed to be linear */
if (ibuf && !(ibuf->rect_float) && R.r.color_mgt_flag & R_COLOR_MANAGEMENT)
srgb_to_linearrgb_v3_v3(tcol, tcol);
}
if(mtex->mapto & WOMAP_HORIZ) {
@@ -2947,8 +2959,13 @@ void do_lamp_tex(LampRen *la, float *lavec, ShadeInput *shi, float *colf, int ef
else texres.tin= texres.ta;
/* inverse gamma correction */
if (R.r.color_mgt_flag & R_COLOR_MANAGEMENT) {
color_manage_linearize(&texres.tr, &texres.tr);
if (tex->type==TEX_IMAGE) {
Image *ima = tex->ima;
ImBuf *ibuf = BKE_image_get_ibuf(ima, &tex->iuser);
/* don't linearize float buffers, assumed to be linear */
if (ibuf && !(ibuf->rect_float) && R.r.color_mgt_flag & R_COLOR_MANAGEMENT)
srgb_to_linearrgb_v3_v3(&texres.tr, &texres.tr);
}
/* lamp colors were premultiplied with this */