Properly handle vertex color color space for Cycles GLSL
authorSergey Sharybin <sergey.vfx@gmail.com>
Tue, 31 May 2016 12:39:49 +0000 (14:39 +0200)
committerSergey Sharybin <sergey.vfx@gmail.com>
Tue, 31 May 2016 12:41:51 +0000 (14:41 +0200)
A bit tricky, need to pass additional information about what the attribute
is and how to deal with it.

BI path stays unchanged, just to make things simplier for now.

Fixes T48555: Cycles GLSL- Incorrect Vertex Color results from Attribute node

12 files changed:
source/blender/blenkernel/BKE_DerivedMesh.h
source/blender/blenkernel/intern/DerivedMesh.c
source/blender/blenkernel/intern/cdderivedmesh.c
source/blender/blenkernel/intern/editderivedmesh.c
source/blender/blenkernel/intern/subsurf_ccg.c
source/blender/gpu/GPU_buffers.h
source/blender/gpu/GPU_shader.h
source/blender/gpu/intern/gpu_buffers.c
source/blender/gpu/intern/gpu_codegen.c
source/blender/gpu/intern/gpu_material.c
source/blender/gpu/shaders/gpu_shader_material.glsl
source/blender/gpu/shaders/gpu_shader_vertex.glsl

index 2b13a847e14dc32de5523b3a3c6850030c6e8b02..8ccc4a6eb0e2b702fa988d0f8dec2afba7e70482 100644 (file)
@@ -757,22 +757,22 @@ void DM_update_weight_mcol(
 typedef struct DMVertexAttribs {
        struct {
                struct MLoopUV *array;
-               int em_offset, gl_index, gl_texco;
+               int em_offset, gl_index, gl_texco, gl_info_index;
        } tface[MAX_MTFACE];
 
        struct {
                struct MLoopCol *array;
-               int em_offset, gl_index;
+               int em_offset, gl_index, gl_info_index;
        } mcol[MAX_MCOL];
 
        struct {
                float (*array)[4];
-               int em_offset, gl_index;
+               int em_offset, gl_index, gl_info_index;
        } tang[MAX_MTFACE];
 
        struct {
                float (*array)[3];
-               int em_offset, gl_index, gl_texco;
+               int em_offset, gl_index, gl_texco, gl_info_index;
        } orco;
 
        int tottface, totmcol, tottang, totorco;
index bb5cc9cb0678fe973d96e8a65f2b35d6e5744e4c..0de0e4d7797f02b11b23ac5eb4450e9a5deab00c 100644 (file)
@@ -3673,6 +3673,7 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
                        }
 
                        attribs->tface[a].gl_index = gattribs->layer[b].glindex;
+                       attribs->tface[a].gl_info_index = gattribs->layer[b].glinfoindoex;
                        attribs->tface[a].gl_texco = gattribs->layer[b].gltexco;
                }
                else if (type == CD_MCOL) {
@@ -3696,6 +3697,7 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
                        }
 
                        attribs->mcol[a].gl_index = gattribs->layer[b].glindex;
+                       attribs->mcol[a].gl_info_index = gattribs->layer[b].glinfoindoex;
                }
                else if (type == CD_TANGENT) {
                        /* note, even with 'is_editmesh' this uses the derived-meshes loop data */
@@ -3718,6 +3720,7 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
                        }
 
                        attribs->tang[a].gl_index = gattribs->layer[b].glindex;
+                       attribs->tang[a].gl_info_index = gattribs->layer[b].glinfoindoex;
                }
                else if (type == CD_ORCO) {
                        /* original coordinates */
@@ -3737,6 +3740,7 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
 
                        attribs->orco.gl_index = gattribs->layer[b].glindex;
                        attribs->orco.gl_texco = gattribs->layer[b].gltexco;
+                       attribs->orco.gl_info_index = gattribs->layer[b].glinfoindoex;
                }
        }
 }
@@ -3765,6 +3769,7 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert,
                        glTexCoord3fv(orco);
                else
                        glVertexAttrib3fv(attribs->orco.gl_index, orco);
+               glUniform1i(attribs->orco.gl_info_index, 0);
        }
 
        /* uv texture coordinates */
@@ -3783,6 +3788,7 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert,
                        glTexCoord2fv(uv);
                else
                        glVertexAttrib2fv(attribs->tface[b].gl_index, uv);
+               glUniform1i(attribs->tface[b].gl_info_index, 0);
        }
 
        /* vertex colors */
@@ -3798,6 +3804,7 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert,
                }
 
                glVertexAttrib4fv(attribs->mcol[b].gl_index, col);
+               glUniform1i(attribs->mcol[b].gl_info_index, GPU_ATTR_INFO_SRGB);
        }
 
        /* tangent for normal mapping */
@@ -3807,6 +3814,7 @@ void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert,
                        const float *tang = (array) ? array[a * 4 + vert] : zero;
                        glVertexAttrib4fv(attribs->tang[b].gl_index, tang);
                }
+               glUniform1i(attribs->tang[b].gl_info_index, 0);
        }
 }
 
index af1ad4900b3dda85f3931736bb759b839207b36e..e7e6118813ebb1d248f6ef03df4530e76127a751 100644 (file)
@@ -1032,6 +1032,7 @@ static void cdDM_drawMappedFacesGLSL(
 
                                if (matconv[a].attribs.totorco && matconv[a].attribs.orco.array) {
                                        matconv[a].datatypes[numdata].index = matconv[a].attribs.orco.gl_index;
+                                       matconv[a].datatypes[numdata].info_index = matconv[a].attribs.orco.gl_info_index;
                                        matconv[a].datatypes[numdata].size = 3;
                                        matconv[a].datatypes[numdata].type = GL_FLOAT;
                                        numdata++;
@@ -1039,6 +1040,7 @@ static void cdDM_drawMappedFacesGLSL(
                                for (b = 0; b < matconv[a].attribs.tottface; b++) {
                                        if (matconv[a].attribs.tface[b].array) {
                                                matconv[a].datatypes[numdata].index = matconv[a].attribs.tface[b].gl_index;
+                                               matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tface[b].gl_info_index;
                                                matconv[a].datatypes[numdata].size = 2;
                                                matconv[a].datatypes[numdata].type = GL_FLOAT;
                                                numdata++;
@@ -1047,6 +1049,7 @@ static void cdDM_drawMappedFacesGLSL(
                                for (b = 0; b < matconv[a].attribs.totmcol; b++) {
                                        if (matconv[a].attribs.mcol[b].array) {
                                                matconv[a].datatypes[numdata].index = matconv[a].attribs.mcol[b].gl_index;
+                                               matconv[a].datatypes[numdata].info_index = matconv[a].attribs.mcol[b].gl_info_index;
                                                matconv[a].datatypes[numdata].size = 4;
                                                matconv[a].datatypes[numdata].type = GL_UNSIGNED_BYTE;
                                                numdata++;
@@ -1055,6 +1058,7 @@ static void cdDM_drawMappedFacesGLSL(
                                for (b = 0; b < matconv[a].attribs.tottang; b++) {
                                        if (matconv[a].attribs.tang[b].array) {
                                                matconv[a].datatypes[numdata].index = matconv[a].attribs.tang[b].gl_index;
+                                               matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tang[b].gl_info_index;
                                                matconv[a].datatypes[numdata].size = 4;
                                                matconv[a].datatypes[numdata].type = GL_FLOAT;
                                                numdata++;
index 6c1174476640d9c13dbf653b5f14a299c498b88b..0de4d1b4dd52c2bb2f0793ec01c3709ed50be991 100644 (file)
@@ -57,6 +57,7 @@
 #include "MEM_guardedalloc.h"
 
 #include "GPU_glew.h"
+#include "GPU_buffers.h"
 #include "GPU_shader.h"
 #include "GPU_basic_shader.h"
 
@@ -1431,6 +1432,7 @@ static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const B
                        glTexCoord3fv(orco);
                else
                        glVertexAttrib3fv(attribs->orco.gl_index, orco);
+               glUniform1i(attribs->orco.gl_info_index, 0);
        }
        for (i = 0; i < attribs->tottface; i++) {
                const float *uv;
@@ -1447,6 +1449,7 @@ static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const B
                        glTexCoord2fv(uv);
                else
                        glVertexAttrib2fv(attribs->tface[i].gl_index, uv);
+               glUniform1i(attribs->tface[i].gl_info_index, 0);
        }
        for (i = 0; i < attribs->totmcol; i++) {
                GLubyte col[4];
@@ -1458,6 +1461,7 @@ static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const B
                        col[0] = 0; col[1] = 0; col[2] = 0; col[3] = 0;
                }
                glVertexAttrib4ubv(attribs->mcol[i].gl_index, col);
+               glUniform1i(attribs->mcol[i].gl_info_index, GPU_ATTR_INFO_SRGB);
        }
 
        for (i = 0; i < attribs->tottang; i++) {
@@ -1469,6 +1473,7 @@ static void emdm_pass_attrib_vertex_glsl(const DMVertexAttribs *attribs, const B
                        tang = zero;
                }
                glVertexAttrib4fv(attribs->tang[i].gl_index, tang);
+               glUniform1i(attribs->tang[i].gl_info_index, 0);
        }
 }
 
index 5fd418fadfca677d4e44a27fd8aaa73f3b3e8a5f..88bc3fb9854ea65388db1e671693b772f5ea0982 100644 (file)
@@ -2996,6 +2996,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
 
                                if (matconv[a].attribs.totorco && matconv[a].attribs.orco.array) {
                                        matconv[a].datatypes[numdata].index = matconv[a].attribs.orco.gl_index;
+                                       matconv[a].datatypes[numdata].info_index = matconv[a].attribs.orco.gl_info_index;
                                        matconv[a].datatypes[numdata].size = 3;
                                        matconv[a].datatypes[numdata].type = GL_FLOAT;
                                        numdata++;
@@ -3003,6 +3004,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
                                for (b = 0; b < matconv[a].attribs.tottface; b++) {
                                        if (matconv[a].attribs.tface[b].array) {
                                                matconv[a].datatypes[numdata].index = matconv[a].attribs.tface[b].gl_index;
+                                               matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tface[b].gl_info_index;
                                                matconv[a].datatypes[numdata].size = 2;
                                                matconv[a].datatypes[numdata].type = GL_FLOAT;
                                                numdata++;
@@ -3011,6 +3013,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
                                for (b = 0; b < matconv[a].attribs.totmcol; b++) {
                                        if (matconv[a].attribs.mcol[b].array) {
                                                matconv[a].datatypes[numdata].index = matconv[a].attribs.mcol[b].gl_index;
+                                               matconv[a].datatypes[numdata].info_index = matconv[a].attribs.mcol[b].gl_info_index;
                                                matconv[a].datatypes[numdata].size = 4;
                                                matconv[a].datatypes[numdata].type = GL_UNSIGNED_BYTE;
                                                numdata++;
@@ -3019,6 +3022,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
                                for (b = 0; b < matconv[a].attribs.tottang; b++) {
                                        if (matconv[a].attribs.tottang && matconv[a].attribs.tang[b].array) {
                                                matconv[a].datatypes[numdata].index = matconv[a].attribs.tang[b].gl_index;
+                                               matconv[a].datatypes[numdata].info_index = matconv[a].attribs.tang[b].gl_info_index;
                                                matconv[a].datatypes[numdata].size = 4;
                                                matconv[a].datatypes[numdata].type = GL_FLOAT;
                                                numdata++;
index a8656c052248177872d29cb0d06a2a22a8d999f1..ee7abe08aba2f1aae586f4137b39c9ff3dfceff9 100644 (file)
@@ -147,6 +147,7 @@ typedef struct GPUVertPointLink {
 /* used for GLSL materials */
 typedef struct GPUAttrib {
        int index;
+       int info_index;
        int size;
        int type;
 } GPUAttrib;
@@ -179,6 +180,10 @@ typedef enum {
        GPU_BINDING_INDEX = 1,
 } GPUBindingType;
 
+typedef enum {
+       GPU_ATTR_INFO_SRGB = (1 << 0),
+} GPUAttrInfo;
+
 /* called before drawing */
 void GPU_vertex_setup(struct DerivedMesh *dm);
 void GPU_normal_setup(struct DerivedMesh *dm);
index 4c674b460aad9e8669afc568572c0ba271df24ac..762329ee077e21cafc587800a172ac1cc0f547fe 100644 (file)
@@ -104,6 +104,7 @@ typedef struct GPUVertexAttribs {
        struct {
                int type;
                int glindex;
+               int glinfoindoex;
                int gltexco;
                int attribid;
                char name[64];  /* MAX_CUSTOMDATA_LAYER_NAME */
index 09d0a383426f86d5ae4b0d5523f98e308024adbf..f80ce3c1fab8cd4f5b6b007536ab13944a162b47 100644 (file)
@@ -822,6 +822,12 @@ void GPU_interleaved_attrib_setup(GPUBuffer *buffer, GPUAttrib data[], int numda
        
        for (i = 0; i < numdata; i++) {
                glEnableVertexAttribArray(data[i].index);
+               int info = 0;
+               if (data[i].type == GL_UNSIGNED_BYTE) {
+                       info |= GPU_ATTR_INFO_SRGB;
+               }
+               glUniform1i(data[i].info_index, info);
+
                glVertexAttribPointer(data[i].index, data[i].size, data[i].type,
                                         GL_TRUE, elementsize, BUFFER_OFFSET(offset));
                offset += data[i].size * GPU_typesize(data[i].type);
index 94d52c3617ca54a710625ed9a893d2aaa9da9718..58ef4063430827a01c1b9f8e04474847da4453d8 100644 (file)
@@ -749,6 +749,7 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type)
                                BLI_dynstr_appendf(ds, "%s %s att%d;\n",
                                        GLEW_VERSION_3_0 ? "in" : "attribute",
                                        GPU_DATATYPE_STR[input->type], input->attribid);
+                               BLI_dynstr_appendf(ds, "uniform int att%d_info;\n",  input->attribid);
                                BLI_dynstr_appendf(ds, "%s %s var%d;\n",
                                        GLEW_VERSION_3_0 ? "out" : "varying",
                                        GPU_DATATYPE_STR[input->type], input->attribid);
@@ -801,7 +802,8 @@ static char *code_generate_vertex(ListBase *nodes, const GPUMatType type)
                                                BLI_dynstr_appendf(ds, "#ifndef USE_OPENSUBDIV\n");
                                        }
 #endif
-                                       BLI_dynstr_appendf(ds, "\tvar%d = att%d;\n", input->attribid, input->attribid);
+                                       BLI_dynstr_appendf(ds, "\tset_var_from_attr(att%d, att%d_info, var%d);\n",
+                                                          input->attribid, input->attribid, input->attribid);
 #ifdef WITH_OPENSUBDIV
                                        if (is_mtface) {
                                                BLI_dynstr_appendf(ds, "#endif\n");
index aaa52b2c3f60b4d0105cb62e6e3527bfe84acafe..99ecf687f701c5d1cc93f435b544b42def48332e 100644 (file)
@@ -212,6 +212,9 @@ static void gpu_material_set_attrib_id(GPUMaterial *material)
                BLI_snprintf(name, sizeof(name), "att%d", attribs->layer[a].attribid);
                attribs->layer[a].glindex = GPU_shader_get_attribute(shader, name);
 
+               BLI_snprintf(name, sizeof(name), "att%d_info", attribs->layer[a].attribid);
+               attribs->layer[a].glinfoindoex = GPU_shader_get_uniform(shader, name);
+
                if (attribs->layer[a].glindex >= 0) {
                        attribs->layer[b] = attribs->layer[a];
                        b++;
index dae66ce7eb5fa32712164b916aaa06fecc4e47d7..9914c4bb3629057524d717ab81cc9f0f45ca6302 100644 (file)
@@ -2668,9 +2668,6 @@ void node_gamma(vec4 col, float gamma, out vec4 outcol)
 
 void node_attribute(vec3 attr, out vec4 outcol, out vec3 outvec, out float outf)
 {
-       /* TODO(sergey): This needs linearization for vertex color.
-        * But how to detect cases when input is linear and when it's srgb?
-        */
        outcol = vec4(attr, 1.0);
        outvec = attr;
        outf = (attr.x + attr.y + attr.z) / 3.0;
index 5824d5a80db582f0bd7955416fa77936e413495b..a91d9e3e6f2e6900e01387bdb4158df1c715a6b8 100644 (file)
@@ -14,6 +14,58 @@ varying vec3 varnormal;
 varying float gl_ClipDistance[6];
 #endif
 
+float srgb_to_linearrgb(float c)
+{
+       if (c < 0.04045)
+               return (c < 0.0) ? 0.0 : c * (1.0 / 12.92);
+       else
+               return pow((c + 0.055) * (1.0 / 1.055), 2.4);
+}
+
+void srgb_to_linearrgb(vec3 col_from, out vec3 col_to)
+{
+       col_to.r = srgb_to_linearrgb(col_from.r);
+       col_to.g = srgb_to_linearrgb(col_from.g);
+       col_to.b = srgb_to_linearrgb(col_from.b);
+}
+
+void srgb_to_linearrgb(vec4 col_from, out vec4 col_to)
+{
+       col_to.r = srgb_to_linearrgb(col_from.r);
+       col_to.g = srgb_to_linearrgb(col_from.g);
+       col_to.b = srgb_to_linearrgb(col_from.b);
+       col_to.a = col_from.a;
+}
+
+bool is_srgb(int info)
+{
+#ifdef USE_NEW_SHADING
+       return (info == 1)? true: false;
+#else
+       return false;
+#endif
+}
+
+void set_var_from_attr(vec3 attr, int info, out vec3 var)
+{
+       if (is_srgb(info)) {
+               srgb_to_linearrgb(attr, var);
+       }
+       else {
+               var = attr;
+       }
+}
+
+void set_var_from_attr(vec4 attr, int info, out vec4 var)
+{
+       if (is_srgb(info)) {
+               srgb_to_linearrgb(attr, var);
+       }
+       else {
+               var = attr;
+       }
+}
+
 void main()
 {
 #ifndef USE_OPENSUBDIV