USD IO: Move to the new Mesh attributes API for colors #104542
|
@ -1 +1 @@
|
|||
Subproject commit 4331c8e76c2f42b9fd903716c333d6cdeaa5cebd
|
||||
Subproject commit 547a54b294f32ee11bce73273c6f183d8b235f92
|
|
@ -1 +1 @@
|
|||
Subproject commit b3f0ffc587d197b37eac9a1566d1d24b7bee7d9a
|
||||
Subproject commit 78b0fc30b6b6e610ef897fc7d26e812da348f2ff
|
|
@ -1 +1 @@
|
|||
Subproject commit 14ab9273409ea0231d08ba6e86fdc73d4e459e99
|
||||
Subproject commit 65ff08e325d54a58b47fb3219ec7dbf417f20f18
|
|
@ -326,7 +326,7 @@ void WM_OT_usd_export(struct wmOperatorType *ot)
|
|||
"overwrite_textures",
|
||||
false,
|
||||
"Overwrite Textures",
|
||||
"Allow overwriting existing texture files when exporting textures");
|
||||
"Overwrite existing files when exporting textures");
|
||||
|
||||
RNA_def_boolean(ot->srna,
|
||||
"relative_paths",
|
||||
|
@ -608,7 +608,7 @@ void WM_OT_usd_import(struct wmOperatorType *ot)
|
|||
RNA_def_boolean(ot->srna, "read_mesh_uvs", true, "UV Coordinates", "Read mesh UV coordinates");
|
||||
|
||||
RNA_def_boolean(
|
||||
ot->srna, "read_mesh_colors", false, "Color Attributes", "Read mesh color attributes");
|
||||
ot->srna, "read_mesh_colors", true, "Color Attributes", "Read mesh color attributes");
|
||||
|
||||
RNA_def_string(ot->srna,
|
||||
"prim_path_mask",
|
||||
|
|
|
@ -25,6 +25,9 @@
|
|||
#include "DNA_meshdata_types.h"
|
||||
#include "DNA_modifier_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_windowmanager_types.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
|
@ -35,6 +38,7 @@
|
|||
#include <pxr/usd/usdGeom/mesh.h>
|
||||
#include <pxr/usd/usdGeom/primvarsAPI.h>
|
||||
#include <pxr/usd/usdGeom/subset.h>
|
||||
#include <pxr/usd/usdGeom/primvarsAPI.h>
|
||||
#include <pxr/usd/usdShade/materialBindingAPI.h>
|
||||
|
||||
#include <iostream>
|
||||
|
@ -410,100 +414,154 @@ void USDMeshReader::read_uvs(Mesh *mesh, const double motionSampleTime, const bo
|
|||
}
|
||||
}
|
||||
|
||||
void USDMeshReader::read_colors(Mesh *mesh, const double motionSampleTime)
|
||||
void USDMeshReader::read_color_data_all(Mesh *mesh, const double motionSampleTime)
|
||||
{
|
||||
if (!(mesh && mesh_prim_ && mesh->totloop > 0)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Early out if we read the display color before and if this attribute isn't animated. */
|
||||
if (primvar_varying_map_.find(usdtokens::displayColor) != primvar_varying_map_.end() &&
|
||||
!primvar_varying_map_.at(usdtokens::displayColor)) {
|
||||
pxr::UsdGeomPrimvarsAPI pv_api = pxr::UsdGeomPrimvarsAPI(mesh_prim_);
|
||||
std::vector<pxr::UsdGeomPrimvar> primvars = pv_api.GetPrimvarsWithValues();
|
||||
|
||||
/* Convert color primvars to custom layer data. */
|
||||
for (pxr::UsdGeomPrimvar &pv : primvars) {
|
||||
|
||||
pxr::SdfValueTypeName type = pv.GetTypeName();
|
||||
|
||||
if (!ELEM(type,
|
||||
pxr::SdfValueTypeNames->Color3hArray,
|
||||
pxr::SdfValueTypeNames->Color3fArray,
|
||||
pxr::SdfValueTypeNames->Color3dArray)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
pxr::TfToken name = pv.GetPrimvarName();
|
||||
|
||||
/* Skip if we read this primvar before and it isn't animated. */
|
||||
const std::map<const pxr::TfToken, bool>::const_iterator is_animated_iter =
|
||||
primvar_varying_map_.find(name);
|
||||
if (is_animated_iter != primvar_varying_map_.end() && !is_animated_iter->second) {
|
||||
continue;
|
||||
}
|
||||
|
||||
read_color_data(mesh, pv, motionSampleTime);
|
||||
}
|
||||
}
|
||||
|
||||
void USDMeshReader::read_color_data(Mesh *mesh,
|
||||
const pxr::UsdGeomPrimvar &color_primvar,
|
||||
const double motionSampleTime)
|
||||
{
|
||||
if (!(mesh && color_primvar && color_primvar.HasValue())) {
|
||||
return;
|
||||
}
|
||||
|
||||
pxr::UsdGeomPrimvar color_primvar = mesh_prim_.GetDisplayColorPrimvar();
|
||||
|
||||
if (!color_primvar.HasValue()) {
|
||||
return;
|
||||
}
|
||||
|
||||
pxr::TfToken interp = color_primvar.GetInterpolation();
|
||||
|
||||
if (interp == pxr::UsdGeomTokens->varying) {
|
||||
std::cerr << "WARNING: Unsupported varying interpolation for display colors\n" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (primvar_varying_map_.find(usdtokens::displayColor) == primvar_varying_map_.end()) {
|
||||
if (primvar_varying_map_.find(color_primvar.GetPrimvarName()) == primvar_varying_map_.end()) {
|
||||
bool might_be_time_varying = color_primvar.ValueMightBeTimeVarying();
|
||||
primvar_varying_map_.insert(std::make_pair(usdtokens::displayColor, might_be_time_varying));
|
||||
primvar_varying_map_.insert(
|
||||
std::make_pair(color_primvar.GetPrimvarName(), might_be_time_varying));
|
||||
if (might_be_time_varying) {
|
||||
is_time_varying_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
pxr::VtArray<pxr::GfVec3f> display_colors;
|
||||
pxr::VtArray<pxr::GfVec3f> usd_colors;
|
||||
|
||||
if (!color_primvar.ComputeFlattened(&display_colors, motionSampleTime)) {
|
||||
std::cerr << "WARNING: Couldn't compute display colors\n" << std::endl;
|
||||
if (!color_primvar.ComputeFlattened(&usd_colors, motionSampleTime)) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"USD Import: couldn't compute values for color attribute '%s'",
|
||||
color_primvar.GetName().GetText());
|
||||
return;
|
||||
}
|
||||
|
||||
if ((interp == pxr::UsdGeomTokens->faceVarying && display_colors.size() != mesh->totloop) ||
|
||||
(interp == pxr::UsdGeomTokens->vertex && display_colors.size() != mesh->totvert) ||
|
||||
(interp == pxr::UsdGeomTokens->constant && display_colors.size() != 1) ||
|
||||
(interp == pxr::UsdGeomTokens->uniform && display_colors.size() != mesh->totpoly)) {
|
||||
std::cerr << "WARNING: display colors count mismatch\n" << std::endl;
|
||||
pxr::TfToken interp = color_primvar.GetInterpolation();
|
||||
|
||||
if ((interp == pxr::UsdGeomTokens->faceVarying && usd_colors.size() != mesh->totloop) ||
|
||||
(interp == pxr::UsdGeomTokens->varying && usd_colors.size() != mesh->totloop) ||
|
||||
(interp == pxr::UsdGeomTokens->vertex && usd_colors.size() != mesh->totvert) ||
|
||||
(interp == pxr::UsdGeomTokens->constant && usd_colors.size() != 1) ||
|
||||
(interp == pxr::UsdGeomTokens->uniform && usd_colors.size() != mesh->totpoly)) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"USD Import: color attribute value '%s' count inconsistent with interpolation type",
|
||||
color_primvar.GetName().GetText());
|
||||
return;
|
||||
}
|
||||
|
||||
void *cd_ptr = add_customdata_cb(mesh, "displayColors", CD_PROP_BYTE_COLOR);
|
||||
const StringRef color_primvar_name(color_primvar.GetBaseName().GetString());
|
||||
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
|
||||
|
||||
if (!cd_ptr) {
|
||||
std::cerr << "WARNING: Couldn't add displayColors custom data.\n";
|
||||
eAttrDomain color_domain = ATTR_DOMAIN_POINT;
|
||||
|
||||
if (ELEM(interp,
|
||||
pxr::UsdGeomTokens->varying,
|
||||
pxr::UsdGeomTokens->faceVarying,
|
||||
pxr::UsdGeomTokens->uniform)) {
|
||||
color_domain = ATTR_DOMAIN_CORNER;
|
||||
}
|
||||
|
||||
bke::SpanAttributeWriter<ColorGeometry4f> color_data;
|
||||
color_data = attributes.lookup_or_add_for_write_only_span<ColorGeometry4f>(color_primvar_name,
|
||||
color_domain);
|
||||
if (!color_data) {
|
||||
WM_reportf(RPT_WARNING,
|
||||
"USD Import: couldn't add color attribute '%s'",
|
||||
color_primvar.GetBaseName().GetText());
|
||||
return;
|
||||
}
|
||||
|
||||
MLoopCol *colors = static_cast<MLoopCol *>(cd_ptr);
|
||||
/* Check for situations that allow for a straight-forward copy by index. */
|
||||
if ((ELEM(interp, pxr::UsdGeomTokens->vertex)) ||
|
||||
(color_domain == ATTR_DOMAIN_CORNER && !is_left_handed_)) {
|
||||
for (int i = 0; i < usd_colors.size(); i++) {
|
||||
ColorGeometry4f color = ColorGeometry4f(
|
||||
usd_colors[i][0], usd_colors[i][1], usd_colors[i][2], 1.0f);
|
||||
color_data.span[i] = color;
|
||||
}
|
||||
}
|
||||
|
||||
const Span<MPoly> polys = mesh->polys();
|
||||
const Span<MLoop> loops = mesh->loops();
|
||||
for (const int i : polys.index_range()) {
|
||||
const MPoly &poly = polys[i];
|
||||
for (int j = 0; j < poly.totloop; ++j) {
|
||||
int loop_index = poly.loopstart + j;
|
||||
/* Special case: expand uniform color into corner color.
|
||||
* Uniforms in USD come through as single colors, face-varying. Since Blender does not
|
||||
* support this particular combination for paintable color attributes, we convert the type
|
||||
* here to make sure that the user gets the same visual result.
|
||||
* */
|
||||
else if (ELEM(interp, pxr::UsdGeomTokens->uniform)) {
|
||||
for (int i = 0; i < usd_colors.size(); i++) {
|
||||
const ColorGeometry4f color = ColorGeometry4f(
|
||||
usd_colors[i][0], usd_colors[i][1], usd_colors[i][2], 1.0f);
|
||||
color_data.span[i * 4] = color;
|
||||
color_data.span[i * 4 + 1] = color;
|
||||
color_data.span[i * 4 + 2] = color;
|
||||
color_data.span[i * 4 + 3] = color;
|
||||
}
|
||||
}
|
||||
|
||||
/* Default for constant varying interpolation. */
|
||||
int usd_index = 0;
|
||||
else {
|
||||
/* Loop-level data, but left-handed, requires a bit of a swizzle. */
|
||||
const Span<MPoly> polys = mesh->polys();
|
||||
|
||||
if (interp == pxr::UsdGeomTokens->vertex) {
|
||||
usd_index = loops[loop_index].v;
|
||||
}
|
||||
else if (interp == pxr::UsdGeomTokens->faceVarying) {
|
||||
usd_index = poly.loopstart;
|
||||
for (const MPoly &poly : polys) {
|
||||
for (int j = 0; j < poly.totloop; ++j) {
|
||||
/* Default for constant varying interpolation. */
|
||||
int usd_index = poly.loopstart;
|
||||
if (is_left_handed_) {
|
||||
usd_index += poly.totloop - 1 - j;
|
||||
}
|
||||
else {
|
||||
usd_index += j;
|
||||
}
|
||||
}
|
||||
else if (interp == pxr::UsdGeomTokens->uniform) {
|
||||
/* Uniform varying uses the poly index. */
|
||||
usd_index = i;
|
||||
}
|
||||
|
||||
if (usd_index >= display_colors.size()) {
|
||||
continue;
|
||||
}
|
||||
if (usd_index >= usd_colors.size()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
colors[loop_index].r = unit_float_to_uchar_clamp(display_colors[usd_index][0]);
|
||||
colors[loop_index].g = unit_float_to_uchar_clamp(display_colors[usd_index][1]);
|
||||
colors[loop_index].b = unit_float_to_uchar_clamp(display_colors[usd_index][2]);
|
||||
colors[loop_index].a = unit_float_to_uchar_clamp(1.0);
|
||||
ColorGeometry4f color = ColorGeometry4f(
|
||||
usd_colors[usd_index][0], usd_colors[usd_index][1], usd_colors[usd_index][2], 1.0f);
|
||||
color_data.span[usd_index] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
color_data.finish();
|
||||
}
|
||||
|
||||
void USDMeshReader::read_vertex_creases(Mesh *mesh, const double motionSampleTime)
|
||||
|
@ -674,9 +732,19 @@ void USDMeshReader::read_mesh_sample(ImportSettings *settings,
|
|||
read_uvs(mesh, motionSampleTime, new_mesh);
|
||||
}
|
||||
|
||||
/* Custom Data layers. */
|
||||
read_custom_data(settings, mesh, motionSampleTime);
|
||||
}
|
||||
|
||||
void USDMeshReader::read_custom_data(const ImportSettings *settings,
|
||||
Mesh *mesh,
|
||||
const double motionSampleTime)
|
||||
{
|
||||
if ((settings->read_flag & MOD_MESHSEQ_READ_COLOR) != 0) {
|
||||
read_colors(mesh, motionSampleTime);
|
||||
read_color_data_all(mesh, motionSampleTime);
|
||||
}
|
||||
|
||||
/* TODO: Generic readers for custom data layers not listed above. */
|
||||
}
|
||||
|
||||
void USDMeshReader::assign_facesets_to_material_indices(double motionSampleTime,
|
||||
|
|
|
@ -67,13 +67,19 @@ class USDMeshReader : public USDGeomReader {
|
|||
|
||||
void read_mpolys(Mesh *mesh);
|
||||
void read_uvs(Mesh *mesh, double motionSampleTime, bool load_uvs = false);
|
||||
void read_colors(Mesh *mesh, double motionSampleTime);
|
||||
void read_vertex_creases(Mesh *mesh, double motionSampleTime);
|
||||
|
||||
void read_mesh_sample(ImportSettings *settings,
|
||||
Mesh *mesh,
|
||||
double motionSampleTime,
|
||||
bool new_mesh);
|
||||
|
||||
void read_custom_data(const ImportSettings *settings,
|
||||
Mesh *mesh,
|
||||
double motionSampleTime);
|
||||
|
||||
void read_color_data_all(Mesh *mesh, double motionSampleTime);
|
||||
void read_color_data(Mesh *mesh, const pxr::UsdGeomPrimvar &color_primvar, double motionSampleTime);
|
||||
};
|
||||
|
||||
} // namespace blender::io::usd
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include "BLI_math_vector_types.hh"
|
||||
|
||||
#include "BKE_attribute.h"
|
||||
#include "BKE_attribute.hh"
|
||||
#include "BKE_customdata.h"
|
||||
#include "BKE_lib_id.h"
|
||||
#include "BKE_material.h"
|
||||
|
@ -31,6 +30,8 @@
|
|||
#include "DNA_object_fluidsim_types.h"
|
||||
#include "DNA_particle_types.h"
|
||||
|
||||
#include "WM_api.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace blender::io::usd {
|
||||
|
@ -72,6 +73,72 @@ void USDGenericMeshWriter::do_write(HierarchyContext &context)
|
|||
}
|
||||
}
|
||||
|
||||
void USDGenericMeshWriter::write_custom_data(const Mesh *mesh, pxr::UsdGeomMesh usd_mesh)
|
||||
{
|
||||
const bke::AttributeAccessor attributes = mesh->attributes();
|
||||
|
||||
attributes.for_all(
|
||||
[&](const bke::AttributeIDRef &attribute_id, const bke::AttributeMetaData &meta_data) {
|
||||
/* Color data. */
|
||||
if (ELEM(meta_data.domain, ATTR_DOMAIN_CORNER, ATTR_DOMAIN_POINT) &&
|
||||
ELEM(meta_data.data_type, CD_PROP_BYTE_COLOR, CD_PROP_COLOR)) {
|
||||
write_color_data(mesh, usd_mesh, attribute_id, meta_data);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void USDGenericMeshWriter::write_color_data(const Mesh *mesh,
|
||||
pxr::UsdGeomMesh usd_mesh,
|
||||
const bke::AttributeIDRef &attribute_id,
|
||||
const bke::AttributeMetaData &meta_data)
|
||||
{
|
||||
pxr::UsdTimeCode timecode = get_export_time_code();
|
||||
const std::string name = attribute_id.name();
|
||||
pxr::TfToken primvar_name(pxr::TfMakeValidIdentifier(name));
|
||||
const pxr::UsdGeomPrimvarsAPI pvApi = pxr::UsdGeomPrimvarsAPI(usd_mesh);
|
||||
|
||||
/* Varying type depends on original domain. */
|
||||
const pxr::TfToken prim_varying = meta_data.domain == ATTR_DOMAIN_CORNER ?
|
||||
pxr::UsdGeomTokens->faceVarying :
|
||||
pxr::UsdGeomTokens->vertex;
|
||||
|
||||
pxr::UsdGeomPrimvar colors_pv = pvApi.CreatePrimvar(
|
||||
primvar_name, pxr::SdfValueTypeNames->Color3fArray, prim_varying);
|
||||
|
||||
const VArray<ColorGeometry4f> attribute = mesh->attributes().lookup_or_default<ColorGeometry4f>(
|
||||
attribute_id, meta_data.domain, {0.0f, 0.0f, 0.0f, 1.0f});
|
||||
|
||||
pxr::VtArray<pxr::GfVec3f> colors_data;
|
||||
|
||||
/* TODO: Thread the copy, like the obj exporter. */
|
||||
switch (meta_data.domain) {
|
||||
case ATTR_DOMAIN_CORNER:
|
||||
for (size_t loop_idx = 0; loop_idx < mesh->totloop; loop_idx++) {
|
||||
const ColorGeometry4f color = attribute.get(loop_idx);
|
||||
colors_data.push_back(pxr::GfVec3f(color.r, color.g, color.b));
|
||||
}
|
||||
break;
|
||||
|
||||
case ATTR_DOMAIN_POINT:
|
||||
for (const int point_index : attribute.index_range()) {
|
||||
const ColorGeometry4f color = attribute.get(point_index);
|
||||
colors_data.push_back(pxr::GfVec3f(color.r, color.g, color.b));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
BLI_assert_msg(0, "Invalid domain for mesh color data.");
|
||||
return;
|
||||
}
|
||||
|
||||
colors_pv.Set(colors_data, timecode);
|
||||
|
||||
const pxr::UsdAttribute &prim_colors_attr = colors_pv.GetAttr();
|
||||
usd_value_writer_.SetAttribute(prim_colors_attr, pxr::VtValue(colors_data), timecode);
|
||||
}
|
||||
|
||||
void USDGenericMeshWriter::free_export_mesh(Mesh *mesh)
|
||||
{
|
||||
BKE_id_free(nullptr, mesh);
|
||||
|
@ -232,6 +299,9 @@ void USDGenericMeshWriter::write_mesh(HierarchyContext &context, Mesh *mesh)
|
|||
if (usd_export_context_.export_params.export_uvmaps) {
|
||||
write_uv_maps(mesh, usd_mesh);
|
||||
}
|
||||
|
||||
write_custom_data(mesh, usd_mesh);
|
||||
|
||||
if (usd_export_context_.export_params.export_normals) {
|
||||
write_normals(mesh, usd_mesh);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#include "usd_writer_abstract.h"
|
||||
|
||||
#include "BKE_attribute.hh"
|
||||
|
||||
#include <pxr/usd/usdGeom/mesh.h>
|
||||
|
||||
namespace blender::io::usd {
|
||||
|
@ -34,6 +36,13 @@ class USDGenericMeshWriter : public USDAbstractWriter {
|
|||
void write_uv_maps(const Mesh *mesh, pxr::UsdGeomMesh usd_mesh);
|
||||
void write_normals(const Mesh *mesh, pxr::UsdGeomMesh usd_mesh);
|
||||
void write_surface_velocity(const Mesh *mesh, pxr::UsdGeomMesh usd_mesh);
|
||||
|
||||
void write_custom_data(const Mesh *mesh, pxr::UsdGeomMesh usd_mesh);
|
||||
|
||||
void write_color_data(const Mesh *mesh,
|
||||
pxr::UsdGeomMesh usd_mesh,
|
||||
const bke::AttributeIDRef &attribute_id,
|
||||
const bke::AttributeMetaData &meta_data);
|
||||
};
|
||||
|
||||
class USDMeshWriter : public USDGenericMeshWriter {
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit e133fc08cd3254bb3d3bd1345028c8486700bca4
|
||||
Subproject commit 979bfe2504eb2f446639ab5768aac9b80b1f4864
|
Loading…
Reference in New Issue