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.
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user