Fix Cycles not rendering byte precision vertex domain colors

Code was not yet updated to use generic attributes for vertex colors. This also
makes generic attributes work for adaptive subdivision.
This commit is contained in:
Brecht Van Lommel 2022-05-27 15:45:29 +02:00
parent bf6aa5d63d
commit 3a4f2131c2
1 changed files with 100 additions and 134 deletions

View File

@ -267,75 +267,62 @@ static void mikk_compute_tangents(
genTangSpaceDefault(&context);
}
/* Create sculpt vertex color attributes. */
static void attr_create_sculpt_vertex_color(Scene *scene,
Mesh *mesh,
BL::Mesh &b_mesh,
bool subdivision)
{
for (BL::MeshVertColorLayer &l : b_mesh.sculpt_vertex_colors) {
const bool active_render = l.active_render();
AttributeStandard vcol_std = (active_render) ? ATTR_STD_VERTEX_COLOR : ATTR_STD_NONE;
ustring vcol_name = ustring(l.name().c_str());
const bool need_vcol = mesh->need_attribute(scene, vcol_name) ||
mesh->need_attribute(scene, vcol_std);
if (!need_vcol) {
continue;
}
AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes;
Attribute *vcol_attr = attributes.add(vcol_name, TypeRGBA, ATTR_ELEMENT_VERTEX);
vcol_attr->std = vcol_std;
float4 *cdata = vcol_attr->data_float4();
int numverts = b_mesh.vertices.length();
for (int i = 0; i < numverts; i++) {
*(cdata++) = get_float4(l.data[i].color());
}
}
}
template<typename TypeInCycles, typename GetValueAtIndex>
static void fill_generic_attribute(BL::Mesh &b_mesh,
TypeInCycles *data,
const BL::Attribute::domain_enum b_domain,
const bool subdivision,
const GetValueAtIndex &get_value_at_index)
{
switch (b_domain) {
case BL::Attribute::domain_CORNER: {
for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
const int index = t.index() * 3;
BL::Array<int, 3> loops = t.loops();
data[index] = get_value_at_index(loops[0]);
data[index + 1] = get_value_at_index(loops[1]);
data[index + 2] = get_value_at_index(loops[2]);
if (subdivision) {
for (BL::MeshPolygon &p : b_mesh.polygons) {
int n = p.loop_total();
for (int i = 0; i < n; i++) {
*data = get_value_at_index(p.loop_start() + i);
data++;
}
}
}
else {
for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
const int index = t.index() * 3;
BL::Array<int, 3> loops = t.loops();
data[index] = get_value_at_index(loops[0]);
data[index + 1] = get_value_at_index(loops[1]);
data[index + 2] = get_value_at_index(loops[2]);
}
}
break;
}
case BL::Attribute::domain_EDGE: {
/* Averge edge attributes at vertices. */
const size_t num_verts = b_mesh.vertices.length();
vector<int> count(num_verts, 0);
for (BL::MeshEdge &e : b_mesh.edges) {
BL::Array<int, 2> vertices = e.vertices();
TypeInCycles value = get_value_at_index(e.index());
data[vertices[0]] += value;
data[vertices[1]] += value;
count[vertices[0]]++;
count[vertices[1]]++;
if constexpr (std::is_same_v<TypeInCycles, uchar4>) {
/* uchar4 edge attributes do not exist, and averaging in place
* would not work. */
assert(0);
}
else {
/* Averge edge attributes at vertices. */
const size_t num_verts = b_mesh.vertices.length();
vector<int> count(num_verts, 0);
for (size_t i = 0; i < num_verts; i++) {
if (count[i] > 1) {
data[i] /= (float)count[i];
for (BL::MeshEdge &e : b_mesh.edges) {
BL::Array<int, 2> vertices = e.vertices();
TypeInCycles value = get_value_at_index(e.index());
data[vertices[0]] += value;
data[vertices[1]] += value;
count[vertices[0]]++;
count[vertices[1]]++;
}
for (size_t i = 0; i < num_verts; i++) {
if (count[i] > 1) {
data[i] /= (float)count[i];
}
}
}
break;
}
case BL::Attribute::domain_POINT: {
@ -346,8 +333,16 @@ static void fill_generic_attribute(BL::Mesh &b_mesh,
break;
}
case BL::Attribute::domain_FACE: {
for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
data[t.index()] = get_value_at_index(t.polygon_index());
if (subdivision) {
const int num_polygons = b_mesh.polygons.length();
for (int i = 0; i < num_polygons; i++) {
data[i] = get_value_at_index(i);
}
}
else {
for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
data[t.index()] = get_value_at_index(t.polygon_index());
}
}
break;
}
@ -395,21 +390,22 @@ static void attr_create_generic(Scene *scene,
const bool need_motion,
const float motion_scale)
{
if (subdivision) {
/* TODO: Handle subdivision correctly. */
return;
}
AttributeSet &attributes = mesh->attributes;
AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes;
static const ustring u_velocity("velocity");
int attribute_index = 0;
int render_color_index = b_mesh.attributes.render_color_index();
for (BL::Attribute &b_attribute : b_mesh.attributes) {
const ustring name{b_attribute.name().c_str()};
const bool is_render_color = (attribute_index++ == render_color_index);
if (need_motion && name == u_velocity) {
attr_create_motion(mesh, b_attribute, motion_scale);
}
if (!mesh->need_attribute(scene, name)) {
if (!(mesh->need_attribute(scene, name) ||
(is_render_color && mesh->need_attribute(scene, ATTR_STD_VERTEX_COLOR)))) {
continue;
}
if (attributes.find(name)) {
@ -445,15 +441,16 @@ static void attr_create_generic(Scene *scene,
BL::FloatAttribute b_float_attribute{b_attribute};
Attribute *attr = attributes.add(name, TypeFloat, element);
float *data = attr->data_float();
fill_generic_attribute(
b_mesh, data, b_domain, [&](int i) { return b_float_attribute.data[i].value(); });
fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) {
return b_float_attribute.data[i].value();
});
break;
}
case BL::Attribute::data_type_BOOLEAN: {
BL::BoolAttribute b_bool_attribute{b_attribute};
Attribute *attr = attributes.add(name, TypeFloat, element);
float *data = attr->data_float();
fill_generic_attribute(b_mesh, data, b_domain, [&](int i) {
fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) {
return (float)b_bool_attribute.data[i].value();
});
break;
@ -462,25 +459,59 @@ static void attr_create_generic(Scene *scene,
BL::IntAttribute b_int_attribute{b_attribute};
Attribute *attr = attributes.add(name, TypeFloat, element);
float *data = attr->data_float();
fill_generic_attribute(
b_mesh, data, b_domain, [&](int i) { return (float)b_int_attribute.data[i].value(); });
fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) {
return (float)b_int_attribute.data[i].value();
});
break;
}
case BL::Attribute::data_type_FLOAT_VECTOR: {
BL::FloatVectorAttribute b_vector_attribute{b_attribute};
Attribute *attr = attributes.add(name, TypeVector, element);
float3 *data = attr->data_float3();
fill_generic_attribute(b_mesh, data, b_domain, [&](int i) {
fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) {
BL::Array<float, 3> v = b_vector_attribute.data[i].vector();
return make_float3(v[0], v[1], v[2]);
});
break;
}
case BL::Attribute::data_type_BYTE_COLOR: {
BL::ByteColorAttribute b_color_attribute{b_attribute};
if (element == ATTR_ELEMENT_CORNER) {
element = ATTR_ELEMENT_CORNER_BYTE;
}
Attribute *attr = attributes.add(name, TypeRGBA, element);
if (is_render_color) {
attr->std = ATTR_STD_VERTEX_COLOR;
}
if (element == ATTR_ELEMENT_CORNER_BYTE) {
uchar4 *data = attr->data_uchar4();
fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) {
/* Compress/encode vertex color using the sRGB curve. */
const float4 c = get_float4(b_color_attribute.data[i].color());
return color_float4_to_uchar4(color_linear_to_srgb_v4(c));
});
}
else {
float4 *data = attr->data_float4();
fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) {
BL::Array<float, 4> v = b_color_attribute.data[i].color();
return make_float4(v[0], v[1], v[2], v[3]);
});
}
break;
}
case BL::Attribute::data_type_FLOAT_COLOR: {
BL::FloatColorAttribute b_color_attribute{b_attribute};
Attribute *attr = attributes.add(name, TypeRGBA, element);
if (is_render_color) {
attr->std = ATTR_STD_VERTEX_COLOR;
}
float4 *data = attr->data_float4();
fill_generic_attribute(b_mesh, data, b_domain, [&](int i) {
fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) {
BL::Array<float, 4> v = b_color_attribute.data[i].color();
return make_float4(v[0], v[1], v[2], v[3]);
});
@ -490,7 +521,7 @@ static void attr_create_generic(Scene *scene,
BL::Float2Attribute b_float2_attribute{b_attribute};
Attribute *attr = attributes.add(name, TypeFloat2, element);
float2 *data = attr->data_float2();
fill_generic_attribute(b_mesh, data, b_domain, [&](int i) {
fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) {
BL::Array<float, 2> v = b_float2_attribute.data[i].vector();
return make_float2(v[0], v[1]);
});
@ -503,69 +534,6 @@ static void attr_create_generic(Scene *scene,
}
}
/* Create vertex color attributes. */
static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool subdivision)
{
for (BL::MeshLoopColorLayer &l : b_mesh.vertex_colors) {
const bool active_render = l.active_render();
AttributeStandard vcol_std = (active_render) ? ATTR_STD_VERTEX_COLOR : ATTR_STD_NONE;
ustring vcol_name = ustring(l.name().c_str());
const bool need_vcol = mesh->need_attribute(scene, vcol_name) ||
mesh->need_attribute(scene, vcol_std);
if (!need_vcol) {
continue;
}
Attribute *vcol_attr = NULL;
if (subdivision) {
if (active_render) {
vcol_attr = mesh->subd_attributes.add(vcol_std, vcol_name);
}
else {
vcol_attr = mesh->subd_attributes.add(vcol_name, TypeRGBA, ATTR_ELEMENT_CORNER_BYTE);
}
uchar4 *cdata = vcol_attr->data_uchar4();
for (BL::MeshPolygon &p : b_mesh.polygons) {
int n = p.loop_total();
for (int i = 0; i < n; i++) {
float4 color = get_float4(l.data[p.loop_start() + i].color());
/* Compress/encode vertex color using the sRGB curve. */
*(cdata++) = color_float4_to_uchar4(color);
}
}
}
else {
if (active_render) {
vcol_attr = mesh->attributes.add(vcol_std, vcol_name);
}
else {
vcol_attr = mesh->attributes.add(vcol_name, TypeRGBA, ATTR_ELEMENT_CORNER_BYTE);
}
uchar4 *cdata = vcol_attr->data_uchar4();
for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) {
int3 li = get_int3(t.loops());
float4 c1 = get_float4(l.data[li[0]].color());
float4 c2 = get_float4(l.data[li[1]].color());
float4 c3 = get_float4(l.data[li[2]].color());
/* Compress/encode vertex color using the sRGB curve. */
cdata[0] = color_float4_to_uchar4(c1);
cdata[1] = color_float4_to_uchar4(c2);
cdata[2] = color_float4_to_uchar4(c3);
cdata += 3;
}
}
}
}
/* Create uv map attributes. */
static void attr_create_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh)
{
@ -1029,8 +997,6 @@ static void create_mesh(Scene *scene,
* The calculate functions will check whether they're needed or not.
*/
attr_create_pointiness(scene, mesh, b_mesh, subdivision);
attr_create_vertex_color(scene, mesh, b_mesh, subdivision);
attr_create_sculpt_vertex_color(scene, mesh, b_mesh, subdivision);
attr_create_random_per_island(scene, mesh, b_mesh, subdivision);
attr_create_generic(scene, mesh, b_mesh, subdivision, need_motion, motion_scale);