diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2018-05-02 16:36:09 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2018-05-02 17:45:08 +0300 |
commit | a2b05accea6e2879832ae4ac4465ca11d49622c5 (patch) | |
tree | 55f92258fd9e16d4081c480b7f6ece31d3cd9083 /source | |
parent | 648de1be52d0d205c657a130f462882c4d54b296 (diff) |
Eevee: Fix vertex color being in srgb space.
Now they are properly converted to Linear space before interpolation.
Since the only way to get vertex color in eevee and cycles is via the
attribute node with the CD_AUTO_FROM_NAME flag, we have to know at binding
time which type of buffer will be connected to this auto input.
We store this information inside the batch cache (together with the according
uniform name) and pass it as uniform to the shader which does conversion if
needed. The same shader can then be reused to draw another mesh with
different auto layers configuration.
Diffstat (limited to 'source')
-rw-r--r-- | source/blender/draw/engines/eevee/eevee_materials.c | 25 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache.c | 18 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache.h | 6 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl.h | 3 | ||||
-rw-r--r-- | source/blender/draw/intern/draw_cache_impl_mesh.c | 52 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_codegen.c | 28 |
6 files changed, 119 insertions, 13 deletions
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index de65084f553..036fd041620 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -1380,7 +1380,13 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sld bool use_volume_material = (gpumat_array[0] && GPU_material_use_domain_volume(gpumat_array[0])); /* Get per-material split surface */ - struct Gwn_Batch **mat_geom = DRW_cache_object_surface_material_get(ob, gpumat_array, materials_len); + char *auto_layer_names; + int *auto_layer_is_srgb; + int auto_layer_count; + struct Gwn_Batch **mat_geom = DRW_cache_object_surface_material_get(ob, gpumat_array, materials_len, + &auto_layer_names, + &auto_layer_is_srgb, + &auto_layer_count); if (mat_geom) { for (int i = 0; i < materials_len; ++i) { EEVEE_ObjectEngineData *oedata = NULL; @@ -1412,6 +1418,23 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sld ADD_SHGROUP_CALL_SAFE(shgrp_depth_array[i], ob, mat_geom[i], oedata); ADD_SHGROUP_CALL_SAFE(shgrp_depth_clip_array[i], ob, mat_geom[i], oedata); + char *name = auto_layer_names; + for (int j = 0; j < auto_layer_count; ++j) { + /* TODO don't add these uniform when not needed (default pass shaders). */ + if (shgrp_array[i]) { + DRW_shgroup_uniform_bool(shgrp_array[i], name, &auto_layer_is_srgb[j], 1); + } + if (shgrp_depth_array[i]) { + DRW_shgroup_uniform_bool(shgrp_depth_array[i], name, &auto_layer_is_srgb[j], 1); + } + if (shgrp_depth_clip_array[i]) { + DRW_shgroup_uniform_bool(shgrp_depth_clip_array[i], name, &auto_layer_is_srgb[j], 1); + } + /* Go to next layer name. */ + while (*name != '\0') { name++; } + name += 1; + } + /* Shadow Pass */ if (ma->use_nodes && ma->nodetree && (ma->blend_method != MA_BM_SOLID)) { struct GPUMaterial *gpumat; diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index e84a2378a48..110e986f652 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -523,11 +523,19 @@ Gwn_Batch *DRW_cache_object_surface_get(Object *ob) } Gwn_Batch **DRW_cache_object_surface_material_get( - struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len) + struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len, + char **auto_layer_names, int **auto_layer_is_srgb, int *auto_layer_count) { + if (auto_layer_names != NULL) { + *auto_layer_names = NULL; + *auto_layer_is_srgb = NULL; + *auto_layer_count = 0; + } + switch (ob->type) { case OB_MESH: - return DRW_cache_mesh_surface_shaded_get(ob, gpumat_array, gpumat_array_len); + return DRW_cache_mesh_surface_shaded_get(ob, gpumat_array, gpumat_array_len, + auto_layer_names, auto_layer_is_srgb, auto_layer_count); case OB_CURVE: return DRW_cache_curve_surface_shaded_get(ob, gpumat_array, gpumat_array_len); case OB_SURF: @@ -2298,12 +2306,14 @@ Gwn_Batch *DRW_cache_mesh_surface_vert_colors_get(Object *ob) /* Return list of batches */ Gwn_Batch **DRW_cache_mesh_surface_shaded_get( - Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len) + Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len, + char **auto_layer_names, int **auto_layer_is_srgb, int *auto_layer_count) { BLI_assert(ob->type == OB_MESH); Mesh *me = ob->data; - return DRW_mesh_batch_cache_get_surface_shaded(me, gpumat_array, gpumat_array_len); + return DRW_mesh_batch_cache_get_surface_shaded(me, gpumat_array, gpumat_array_len, + auto_layer_names, auto_layer_is_srgb, auto_layer_count); } /* Return list of batches */ diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h index 2ef57884a44..b56f2c0218b 100644 --- a/source/blender/draw/intern/draw_cache.h +++ b/source/blender/draw/intern/draw_cache.h @@ -49,7 +49,8 @@ struct Gwn_Batch *DRW_cache_screenspace_circle_get(void); struct Gwn_Batch *DRW_cache_object_wire_outline_get(struct Object *ob); struct Gwn_Batch *DRW_cache_object_surface_get(struct Object *ob); struct Gwn_Batch **DRW_cache_object_surface_material_get( - struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len); + struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len, + char **auto_layer_names, int **auto_layer_is_srgb, int *auto_layer_count); /* Empties */ struct Gwn_Batch *DRW_cache_plain_axes_get(void); @@ -127,7 +128,8 @@ struct Gwn_Batch *DRW_cache_mesh_edges_paint_overlay_get(struct Object *ob, bool struct Gwn_Batch *DRW_cache_mesh_faces_weight_overlay_get(struct Object *ob); struct Gwn_Batch *DRW_cache_mesh_verts_weight_overlay_get(struct Object *ob); struct Gwn_Batch **DRW_cache_mesh_surface_shaded_get( - struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len); + struct Object *ob, struct GPUMaterial **gpumat_array, uint gpumat_array_len, + char **auto_layer_names, int **auto_layer_is_srgb, int *auto_layer_count); struct Gwn_Batch **DRW_cache_mesh_surface_texpaint_get(struct Object *ob); struct Gwn_Batch *DRW_cache_mesh_surface_texpaint_single_get(struct Object *ob); diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h index 83cc87307b5..cfc57dd6e40 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -91,7 +91,8 @@ struct Gwn_Batch *DRW_lattice_batch_cache_get_overlay_verts(struct Lattice *lt); /* Mesh */ struct Gwn_Batch **DRW_mesh_batch_cache_get_surface_shaded( - struct Mesh *me, struct GPUMaterial **gpumat_array, uint gpumat_array_len); + struct Mesh *me, struct GPUMaterial **gpumat_array, uint gpumat_array_len, + char **auto_layer_names, int **auto_layer_is_srgb, int *auto_layer_count); struct Gwn_Batch **DRW_mesh_batch_cache_get_surface_texpaint(struct Mesh *me); struct Gwn_Batch *DRW_mesh_batch_cache_get_surface_texpaint_single(struct Mesh *me); struct Gwn_Batch *DRW_mesh_batch_cache_get_weight_overlay_edges(struct Mesh *me, bool use_wire, bool use_sel); diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index fb6fe306792..3c75b78976d 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -1564,6 +1564,12 @@ typedef struct MeshBatchCache { Gwn_Batch *overlay_weight_verts; Gwn_Batch *overlay_paint_edges; + /* arrays of bool uniform names (and value) that will be use to + * set srgb conversion for auto attribs.*/ + char *auto_layer_names; + int *auto_layer_is_srgb; + int auto_layer_ct; + /* settings to determine if cache is invalid */ bool is_maybe_dirty; bool is_dirty; /* Instantly invalidates cache, skipping mesh check */ @@ -1806,6 +1812,9 @@ static void mesh_batch_cache_clear(Mesh *me) MEM_SAFE_FREE(cache->shaded_triangles_in_order); MEM_SAFE_FREE(cache->shaded_triangles); + MEM_SAFE_FREE(cache->auto_layer_names); + MEM_SAFE_FREE(cache->auto_layer_is_srgb); + if (cache->texpaint_triangles) { for (int i = 0; i < cache->mat_len; ++i) { GWN_BATCH_DISCARD_SAFE(cache->texpaint_triangles[i]); @@ -1855,6 +1864,27 @@ static Gwn_VertBuf *mesh_batch_cache_get_tri_shading_data(MeshRenderData *rdata, if (tangent_len == 0) { tangent_id = NULL; } if (vcol_len == 0) { vcol_id = NULL; } + /* Count number of auto layer and allocate big enough name buffer. */ + uint auto_names_len = 0; + uint auto_ofs = 0; + uint auto_id = 0; + cache->auto_layer_ct = 0; + for (uint i = 0; i < uv_len; i++) { + const char *attrib_name = mesh_render_data_uv_auto_layer_uuid_get(rdata, i); + auto_names_len += strlen(attrib_name) + 2; /* include null terminator and b prefix. */ + cache->auto_layer_ct++; + } + for (uint i = 0; i < vcol_len; i++) { + if (rdata->cd.layers.auto_vcol[i]) { + const char *attrib_name = mesh_render_data_vcol_auto_layer_uuid_get(rdata, i); + auto_names_len += strlen(attrib_name) + 2; /* include null terminator and b prefix. */ + cache->auto_layer_ct++; + } + } + auto_names_len += 1; /* add an ultimate '\0' terminator */ + cache->auto_layer_names = MEM_callocN(auto_names_len * sizeof(char), "Auto layer name buf"); + cache->auto_layer_is_srgb = MEM_mallocN(cache->auto_layer_ct * sizeof(int), "Auto layer value buf"); + for (uint i = 0; i < uv_len; i++) { /* UV */ const char *attrib_name = mesh_render_data_uv_layer_uuid_get(rdata, i); @@ -1868,6 +1898,10 @@ static Gwn_VertBuf *mesh_batch_cache_get_tri_shading_data(MeshRenderData *rdata, attrib_name = mesh_render_data_uv_auto_layer_uuid_get(rdata, i); GWN_vertformat_alias_add(format, attrib_name); + /* +1 include null terminator. */ + auto_ofs += 1 + BLI_snprintf_rlen(cache->auto_layer_names + auto_ofs, auto_names_len - auto_ofs, "b%s", attrib_name); + cache->auto_layer_is_srgb[auto_id++] = 0; /* tag as not srgb */ + if (i == rdata->cd.layers.uv_active) { GWN_vertformat_alias_add(format, "u"); } @@ -1896,7 +1930,12 @@ static Gwn_VertBuf *mesh_batch_cache_get_tri_shading_data(MeshRenderData *rdata, /* Auto layer */ if (rdata->cd.layers.auto_vcol[i]) { attrib_name = mesh_render_data_vcol_auto_layer_uuid_get(rdata, i); + GWN_vertformat_alias_add(format, attrib_name); + + /* +1 include null terminator. */ + auto_ofs += 1 + BLI_snprintf_rlen(cache->auto_layer_names + auto_ofs, auto_names_len - auto_ofs, "b%s", attrib_name); + cache->auto_layer_is_srgb[auto_id++] = 1; /* tag as srgb */ } if (i == rdata->cd.layers.vcol_active) { @@ -3809,7 +3848,8 @@ Gwn_Batch *DRW_mesh_batch_cache_get_verts_with_select_id(Mesh *me, uint select_i } Gwn_Batch **DRW_mesh_batch_cache_get_surface_shaded( - Mesh *me, struct GPUMaterial **gpumat_array, uint gpumat_array_len) + Mesh *me, struct GPUMaterial **gpumat_array, uint gpumat_array_len, + char **auto_layer_names, int **auto_layer_is_srgb, int *auto_layer_count) { MeshBatchCache *cache = mesh_batch_cache_get(me); @@ -3827,19 +3867,25 @@ Gwn_Batch **DRW_mesh_batch_cache_get_surface_shaded( Gwn_IndexBuf **el = mesh_batch_cache_get_triangles_in_order_split_by_material(rdata, cache); Gwn_VertBuf *vbo = mesh_batch_cache_get_tri_pos_and_normals(rdata, cache); + Gwn_VertBuf *vbo_shading = mesh_batch_cache_get_tri_shading_data(rdata, cache); + for (int i = 0; i < mat_len; ++i) { cache->shaded_triangles[i] = GWN_batch_create( GWN_PRIM_TRIS, vbo, el[i]); - Gwn_VertBuf *vbo_shading = mesh_batch_cache_get_tri_shading_data(rdata, cache); if (vbo_shading) { GWN_batch_vertbuf_add(cache->shaded_triangles[i], vbo_shading); } } - mesh_render_data_free(rdata); } + if (auto_layer_names) { + *auto_layer_names = cache->auto_layer_names; + *auto_layer_is_srgb = cache->auto_layer_is_srgb; + *auto_layer_count = cache->auto_layer_ct; + } + return cache->shaded_triangles; } diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index d66aaf0a33d..7a4af0521bb 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -914,6 +914,12 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u GPU_DATATYPE_STR[input->type], attrib_prefix_get(input->attribtype), hash); BLI_dynstr_appendf(ds, "#define att%d %s%u\n", input->attribid, attrib_prefix_get(input->attribtype), hash); + /* Auto attrib can be vertex color byte buffer. + * We need to know and convert them to linear space in VS. */ + if (!use_geom && input->attribtype == CD_AUTO_FROM_NAME) { + BLI_dynstr_appendf(ds, "uniform bool ba%u;\n", hash); + BLI_dynstr_appendf(ds, "#define att%d_is_srgb ba%u\n", input->attribid, hash); + } } BLI_dynstr_appendf(ds, "out %s var%d%s;\n", GPU_DATATYPE_STR[input->type], input->attribid, use_geom ? "g" : ""); @@ -923,8 +929,17 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u BLI_dynstr_append(ds, "\n"); - BLI_dynstr_append(ds, "#define ATTRIB\n"); - BLI_dynstr_append(ds, "uniform mat3 NormalMatrix;\n"); + BLI_dynstr_append(ds, + "#define ATTRIB\n" + "uniform mat3 NormalMatrix;\n" + "vec3 srgb_to_linear_attrib(vec3 c) {\n" + "\tc = max(c, vec3(0.0));\n" + "\tvec3 c1 = c * (1.0 / 12.92);\n" + "\tvec3 c2 = pow((c + 0.055) * (1.0 / 1.055), vec3(2.4));\n" + "\treturn mix(c1, c2, step(vec3(0.04045), c));\n" + "}\n\n" + ); + BLI_dynstr_append(ds, "void pass_attrib(in vec3 position) {\n"); for (node = nodes->first; node; node = node->next) { @@ -942,6 +957,15 @@ static char *code_generate_vertex(ListBase *nodes, const char *vert_code, bool u BLI_dynstr_appendf(ds, "\tvar%d%s = OrcoTexCoFactors[0] + position * OrcoTexCoFactors[1];\n", input->attribid, use_geom ? "g" : ""); } + else if (input->attribtype == CD_MCOL) { + BLI_dynstr_appendf(ds, "\tvar%d%s = srgb_to_linear_attrib(att%d);\n", + input->attribid, use_geom ? "g" : "", input->attribid); + } + else if (input->attribtype == CD_AUTO_FROM_NAME) { + BLI_dynstr_appendf(ds, "\tvar%d%s = (att%d_is_srgb) ? srgb_to_linear_attrib(att%d) : att%d;\n", + input->attribid, use_geom ? "g" : "", + input->attribid, input->attribid, input->attribid); + } else { BLI_dynstr_appendf(ds, "\tvar%d%s = att%d;\n", input->attribid, use_geom ? "g" : "", input->attribid); |