Fix: USD: Support color attributes on all relevant domains
Color primvars/attributes were historically treated as a special case for both import and export. This was mostly done to align with how painting and viewport display works in Blender. Export would generally ignore color attributes except when they were found on a Mesh's Point or FaceCorner domains. And import went out of its way to map incoming color primvars to the FaceCorner domain in more situations than necessary. To facilitate better roundtripping in Blender<=>USD workflows, and to reduce code duplication, this PR teaches the common attribute utilities how to handle color types. The color attributes will now work on all relevant Mesh and Curve domains. There were tests in place for this already but they were set to verify the inverse state, i.e. the technically broken state, until this could be fixed. There remains one special case: "displayColor" primvars and attributes. The "displayColor" is a special primvar in USD and is the de-facto way to set a simple viewport color in that ecosystem. It must also be a color3f type. In order to not regress import, if a "displayColor" primvar is found on the Face domain we will map it to FaceCorner instead so it can be displayed in the viewport; which has been the case for the past several releases. We can drop this special-case if/when Blender can display Face colors through the Viewport Shading "Attribute" color type. Additionally, Blender will export this, and only this, color attribute as a color3f. Note: As was the case prior to this PR, the following 2 discrepancies still prevent "perfect" round-trips: - USD does not have an equivalent to Blender's byte colors; they are treated as float during IO - Blender does not have an equivalent to USD's color3 types; they are treated as color4 during IO Pull Request: https://projects.blender.org/blender/blender/pulls/127784
This commit is contained in:
committed by
Jesse Yurkovich
parent
a6d5652043
commit
2cdbe7b5f3
@@ -21,7 +21,7 @@
|
||||
namespace blender::io::usd {
|
||||
|
||||
std::optional<pxr::SdfValueTypeName> convert_blender_type_to_usd(
|
||||
const eCustomDataType blender_type)
|
||||
const eCustomDataType blender_type, bool use_color3f_type)
|
||||
{
|
||||
switch (blender_type) {
|
||||
case CD_PROP_FLOAT:
|
||||
@@ -38,6 +38,10 @@ std::optional<pxr::SdfValueTypeName> convert_blender_type_to_usd(
|
||||
return pxr::SdfValueTypeNames->StringArray;
|
||||
case CD_PROP_BOOL:
|
||||
return pxr::SdfValueTypeNames->BoolArray;
|
||||
case CD_PROP_COLOR:
|
||||
case CD_PROP_BYTE_COLOR:
|
||||
return use_color3f_type ? pxr::SdfValueTypeNames->Color3fArray :
|
||||
pxr::SdfValueTypeNames->Color4fArray;
|
||||
case CD_PROP_QUATERNION:
|
||||
return pxr::SdfValueTypeNames->QuatfArray;
|
||||
default:
|
||||
@@ -187,6 +191,26 @@ void copy_blender_attribute_to_primvar(const GVArray &attribute,
|
||||
copy_blender_buffer_to_primvar<bool, bool>(
|
||||
attribute.typed<bool>(), timecode, primvar, value_writer);
|
||||
break;
|
||||
case CD_PROP_COLOR:
|
||||
if (primvar.GetTypeName() == pxr::SdfValueTypeNames->Color3fArray) {
|
||||
copy_blender_buffer_to_primvar<ColorGeometry4f, pxr::GfVec3f>(
|
||||
attribute.typed<ColorGeometry4f>(), timecode, primvar, value_writer);
|
||||
}
|
||||
else {
|
||||
copy_blender_buffer_to_primvar<ColorGeometry4f, pxr::GfVec4f>(
|
||||
attribute.typed<ColorGeometry4f>(), timecode, primvar, value_writer);
|
||||
}
|
||||
break;
|
||||
case CD_PROP_BYTE_COLOR:
|
||||
if (primvar.GetTypeName() == pxr::SdfValueTypeNames->Color3fArray) {
|
||||
copy_blender_buffer_to_primvar<ColorGeometry4b, pxr::GfVec3f>(
|
||||
attribute.typed<ColorGeometry4b>(), timecode, primvar, value_writer);
|
||||
}
|
||||
else {
|
||||
copy_blender_buffer_to_primvar<ColorGeometry4b, pxr::GfVec4f>(
|
||||
attribute.typed<ColorGeometry4b>(), timecode, primvar, value_writer);
|
||||
}
|
||||
break;
|
||||
case CD_PROP_QUATERNION:
|
||||
copy_blender_buffer_to_primvar<math::Quaternion, pxr::GfQuatf>(
|
||||
attribute.typed<math::Quaternion>(), timecode, primvar, value_writer);
|
||||
|
||||
@@ -29,6 +29,10 @@
|
||||
#include <optional>
|
||||
#include <type_traits>
|
||||
|
||||
namespace usdtokens {
|
||||
inline const pxr::TfToken displayColor("displayColor", pxr::TfToken::Immortal);
|
||||
}
|
||||
|
||||
namespace blender::io::usd {
|
||||
|
||||
namespace detail {
|
||||
@@ -66,6 +70,16 @@ template<> inline pxr::GfVec4f convert_value(const ColorGeometry4f value)
|
||||
{
|
||||
return pxr::GfVec4f(value.r, value.g, value.b, value.a);
|
||||
}
|
||||
template<> inline pxr::GfVec3f convert_value(const ColorGeometry4b value)
|
||||
{
|
||||
ColorGeometry4f color4f = value.decode();
|
||||
return pxr::GfVec3f(color4f.r, color4f.g, color4f.b);
|
||||
}
|
||||
template<> inline pxr::GfVec4f convert_value(const ColorGeometry4b value)
|
||||
{
|
||||
ColorGeometry4f color4f = value.decode();
|
||||
return pxr::GfVec4f(color4f.r, color4f.g, color4f.b, color4f.a);
|
||||
}
|
||||
template<> inline pxr::GfQuatf convert_value(const math::Quaternion value)
|
||||
{
|
||||
return pxr::GfQuatf(value.w, value.x, value.y, value.z);
|
||||
@@ -96,7 +110,7 @@ template<> inline math::Quaternion convert_value(const pxr::GfQuatf value)
|
||||
} // namespace detail
|
||||
|
||||
std::optional<pxr::SdfValueTypeName> convert_blender_type_to_usd(
|
||||
const eCustomDataType blender_type);
|
||||
const eCustomDataType blender_type, bool use_color3f_type = false);
|
||||
|
||||
std::optional<eCustomDataType> convert_usd_type_to_blender(const pxr::SdfValueTypeName usd_type);
|
||||
|
||||
|
||||
@@ -7,150 +7,124 @@
|
||||
#include "usd_hash_types.hh"
|
||||
|
||||
#include "BKE_attribute.hh"
|
||||
#include "BKE_report.hh"
|
||||
|
||||
#include "BLI_color.hh"
|
||||
#include "BLI_span.hh"
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
|
||||
#include "CLG_log.h"
|
||||
static CLG_LogRef LOG = {"io.usd"};
|
||||
|
||||
namespace blender::io::usd {
|
||||
|
||||
template<typename USDT>
|
||||
static void read_color_data_primvar(Mesh *mesh,
|
||||
static void read_face_display_color(Mesh *mesh,
|
||||
const pxr::UsdGeomPrimvar &primvar,
|
||||
double motion_sample_time,
|
||||
ReportList *reports,
|
||||
bool is_left_handed)
|
||||
const pxr::TfToken &pv_name,
|
||||
double motion_sample_time)
|
||||
{
|
||||
const pxr::VtArray<USDT> usd_colors = get_primvar_array<USDT>(primvar, motion_sample_time);
|
||||
if (usd_colors.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const pxr::TfToken interp = primvar.GetInterpolation();
|
||||
|
||||
if ((interp == pxr::UsdGeomTokens->faceVarying && usd_colors.size() != mesh->corners_num) ||
|
||||
(interp == pxr::UsdGeomTokens->varying && usd_colors.size() != mesh->corners_num) ||
|
||||
(interp == pxr::UsdGeomTokens->vertex && usd_colors.size() != mesh->verts_num) ||
|
||||
(interp == pxr::UsdGeomTokens->constant && usd_colors.size() != 1) ||
|
||||
(interp == pxr::UsdGeomTokens->uniform && usd_colors.size() != mesh->faces_num))
|
||||
{
|
||||
BKE_reportf(
|
||||
reports,
|
||||
RPT_WARNING,
|
||||
"USD Import: color attribute value '%s' count inconsistent with interpolation type",
|
||||
primvar.GetName().GetText());
|
||||
return;
|
||||
}
|
||||
|
||||
const StringRef primvar_name(primvar.GetBaseName().GetString());
|
||||
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
|
||||
const bke::AttrDomain color_domain = bke::AttrDomain::Corner;
|
||||
|
||||
bke::AttrDomain color_domain = bke::AttrDomain::Point;
|
||||
|
||||
if (ELEM(interp,
|
||||
pxr::UsdGeomTokens->varying,
|
||||
pxr::UsdGeomTokens->faceVarying,
|
||||
pxr::UsdGeomTokens->uniform))
|
||||
{
|
||||
color_domain = bke::AttrDomain::Corner;
|
||||
}
|
||||
|
||||
bke::SpanAttributeWriter<ColorGeometry4f> color_data;
|
||||
color_data = attributes.lookup_or_add_for_write_only_span<ColorGeometry4f>(primvar_name,
|
||||
color_domain);
|
||||
const StringRef attr_name(pv_name.GetString());
|
||||
bke::SpanAttributeWriter<ColorGeometry4f> color_data =
|
||||
attributes.lookup_or_add_for_write_only_span<ColorGeometry4f>(attr_name, color_domain);
|
||||
if (!color_data) {
|
||||
BKE_reportf(reports,
|
||||
RPT_WARNING,
|
||||
"USD Import: couldn't add color attribute '%s'",
|
||||
primvar.GetBaseName().GetText());
|
||||
CLOG_WARN(&LOG, "Primvar '%s' could not be added to Blender", primvar.GetBaseName().GetText());
|
||||
return;
|
||||
}
|
||||
|
||||
if (ELEM(interp, pxr::UsdGeomTokens->constant)) {
|
||||
/* For situations where there's only a single item, flood fill the object. */
|
||||
color_data.span.fill(detail::convert_value<USDT, ColorGeometry4f>(usd_colors[0]));
|
||||
}
|
||||
/* Check for situations that allow for a straight-forward copy by index. */
|
||||
else if (interp == pxr::UsdGeomTokens->vertex ||
|
||||
(interp == pxr::UsdGeomTokens->faceVarying && !is_left_handed))
|
||||
{
|
||||
for (int i = 0; i < usd_colors.size(); i++) {
|
||||
color_data.span[i] = detail::convert_value<USDT, ColorGeometry4f>(usd_colors[i]);
|
||||
const OffsetIndices faces = mesh->faces();
|
||||
for (const int i : faces.index_range()) {
|
||||
if (i >= usd_colors.size()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Catch all for the remaining cases. */
|
||||
|
||||
/* Special case: we will 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.
|
||||
*/
|
||||
const OffsetIndices faces = mesh->faces();
|
||||
const Span<int> corner_verts = mesh->corner_verts();
|
||||
for (const int i : faces.index_range()) {
|
||||
const IndexRange face = faces[i];
|
||||
for (int j = 0; j < face.size(); ++j) {
|
||||
int loop_index = face[j];
|
||||
|
||||
/* Default for constant interpolation. */
|
||||
int usd_index = 0;
|
||||
|
||||
if (interp == pxr::UsdGeomTokens->vertex) {
|
||||
usd_index = corner_verts[loop_index];
|
||||
}
|
||||
else if (interp == pxr::UsdGeomTokens->faceVarying) {
|
||||
usd_index = face.start();
|
||||
if (is_left_handed) {
|
||||
usd_index += face.size() - 1 - j;
|
||||
}
|
||||
else {
|
||||
usd_index += j;
|
||||
}
|
||||
}
|
||||
else if (interp == pxr::UsdGeomTokens->uniform) {
|
||||
/* Uniform varying uses the face index. */
|
||||
usd_index = i;
|
||||
}
|
||||
|
||||
if (usd_index >= usd_colors.size()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
color_data.span[loop_index] = detail::convert_value<USDT, ColorGeometry4f>(
|
||||
usd_colors[usd_index]);
|
||||
}
|
||||
/* Take the per-face USD color and place it on each face-corner. */
|
||||
const IndexRange face = faces[i];
|
||||
for (const int j : face.index_range()) {
|
||||
const int corner = face.start() + j;
|
||||
color_data.span[corner] = detail::convert_value<USDT, ColorGeometry4f>(usd_colors[i]);
|
||||
}
|
||||
}
|
||||
|
||||
color_data.finish();
|
||||
}
|
||||
|
||||
void read_color_data_primvar(Mesh *mesh,
|
||||
const pxr::UsdGeomPrimvar &primvar,
|
||||
double motion_sample_time,
|
||||
ReportList *reports,
|
||||
bool is_left_handed)
|
||||
static std::optional<bke::AttrDomain> convert_usd_varying_to_blender(const pxr::TfToken usd_domain)
|
||||
{
|
||||
if (!(mesh && primvar && primvar.HasValue())) {
|
||||
static const blender::Map<pxr::TfToken, bke::AttrDomain> domain_map = []() {
|
||||
blender::Map<pxr::TfToken, bke::AttrDomain> map;
|
||||
map.add_new(pxr::UsdGeomTokens->faceVarying, bke::AttrDomain::Corner);
|
||||
map.add_new(pxr::UsdGeomTokens->vertex, bke::AttrDomain::Point);
|
||||
map.add_new(pxr::UsdGeomTokens->varying, bke::AttrDomain::Point);
|
||||
map.add_new(pxr::UsdGeomTokens->face, bke::AttrDomain::Face);
|
||||
/* As there's no "constant" type in Blender, for now we're
|
||||
* translating into a point Attribute. */
|
||||
map.add_new(pxr::UsdGeomTokens->constant, bke::AttrDomain::Point);
|
||||
map.add_new(pxr::UsdGeomTokens->uniform, bke::AttrDomain::Face);
|
||||
/* Notice: Edge types are not supported! */
|
||||
return map;
|
||||
}();
|
||||
|
||||
const bke::AttrDomain *value = domain_map.lookup_ptr(usd_domain);
|
||||
|
||||
if (value == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return *value;
|
||||
}
|
||||
|
||||
void read_generic_mesh_primvar(Mesh *mesh,
|
||||
const pxr::UsdGeomPrimvar &primvar,
|
||||
const double motionSampleTime,
|
||||
const bool is_left_handed)
|
||||
{
|
||||
const pxr::SdfValueTypeName pv_type = primvar.GetTypeName();
|
||||
const pxr::TfToken pv_interp = primvar.GetInterpolation();
|
||||
const pxr::TfToken pv_name = pxr::UsdGeomPrimvar::StripPrimvarsName(primvar.GetPrimvarName());
|
||||
|
||||
const std::optional<bke::AttrDomain> domain = convert_usd_varying_to_blender(pv_interp);
|
||||
const std::optional<eCustomDataType> type = convert_usd_type_to_blender(pv_type);
|
||||
|
||||
if (!domain.has_value() || !type.has_value()) {
|
||||
CLOG_WARN(&LOG,
|
||||
"Primvar '%s' (interpolation %s, type %s) cannot be converted to Blender",
|
||||
pv_name.GetText(),
|
||||
pv_interp.GetText(),
|
||||
pv_type.GetAsToken().GetText());
|
||||
return;
|
||||
}
|
||||
|
||||
const pxr::SdfValueTypeName pv_type = primvar.GetTypeName();
|
||||
if (ELEM(pv_type,
|
||||
pxr::SdfValueTypeNames->Color3fArray,
|
||||
pxr::SdfValueTypeNames->Color3hArray,
|
||||
pxr::SdfValueTypeNames->Color3dArray))
|
||||
{
|
||||
read_color_data_primvar<pxr::GfVec3f>(
|
||||
mesh, primvar, motion_sample_time, reports, is_left_handed);
|
||||
/* Blender does not currently support displaying Face colors with the Viewport Shading
|
||||
* "Attribute" color type. Make a special case for "displayColor" primvars and put them on
|
||||
* the Corner domain instead. */
|
||||
if (pv_name == usdtokens::displayColor && domain == bke::AttrDomain::Face) {
|
||||
if (ELEM(pv_type,
|
||||
pxr::SdfValueTypeNames->Color3fArray,
|
||||
pxr::SdfValueTypeNames->Color3hArray,
|
||||
pxr::SdfValueTypeNames->Color3dArray))
|
||||
{
|
||||
read_face_display_color<pxr::GfVec3f>(mesh, primvar, pv_name, motionSampleTime);
|
||||
}
|
||||
else {
|
||||
read_face_display_color<pxr::GfVec4f>(mesh, primvar, pv_name, motionSampleTime);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else {
|
||||
read_color_data_primvar<pxr::GfVec4f>(
|
||||
mesh, primvar, motion_sample_time, reports, is_left_handed);
|
||||
|
||||
OffsetIndices<int> faces;
|
||||
if (is_left_handed) {
|
||||
faces = mesh->faces();
|
||||
}
|
||||
|
||||
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
|
||||
copy_primvar_to_blender_attribute(primvar, motionSampleTime, *type, *domain, faces, attributes);
|
||||
}
|
||||
|
||||
} // namespace blender::io::usd
|
||||
|
||||
@@ -5,14 +5,12 @@
|
||||
#include <pxr/usd/usdGeom/primvar.h>
|
||||
|
||||
struct Mesh;
|
||||
struct ReportList;
|
||||
|
||||
namespace blender::io::usd {
|
||||
|
||||
void read_color_data_primvar(Mesh *mesh,
|
||||
const pxr::UsdGeomPrimvar &color_primvar,
|
||||
double motion_sample_time,
|
||||
ReportList *reports,
|
||||
bool is_left_handed);
|
||||
void read_generic_mesh_primvar(Mesh *mesh,
|
||||
const pxr::UsdGeomPrimvar &primvar,
|
||||
double motionSampleTime,
|
||||
bool is_left_handed);
|
||||
|
||||
} // namespace blender::io::usd
|
||||
|
||||
@@ -51,8 +51,6 @@ namespace usdtokens {
|
||||
/* Materials */
|
||||
static const pxr::TfToken st("st", pxr::TfToken::Immortal);
|
||||
static const pxr::TfToken UVMap("UVMap", pxr::TfToken::Immortal);
|
||||
static const pxr::TfToken Cd("Cd", pxr::TfToken::Immortal);
|
||||
static const pxr::TfToken displayColor("displayColor", pxr::TfToken::Immortal);
|
||||
static const pxr::TfToken normalsPrimvar("normals", pxr::TfToken::Immortal);
|
||||
} // namespace usdtokens
|
||||
|
||||
@@ -161,31 +159,6 @@ USDMeshReader::USDMeshReader(const pxr::UsdPrim &prim,
|
||||
{
|
||||
}
|
||||
|
||||
static std::optional<bke::AttrDomain> convert_usd_varying_to_blender(const pxr::TfToken usd_domain)
|
||||
{
|
||||
static const blender::Map<pxr::TfToken, bke::AttrDomain> domain_map = []() {
|
||||
blender::Map<pxr::TfToken, bke::AttrDomain> map;
|
||||
map.add_new(pxr::UsdGeomTokens->faceVarying, bke::AttrDomain::Corner);
|
||||
map.add_new(pxr::UsdGeomTokens->vertex, bke::AttrDomain::Point);
|
||||
map.add_new(pxr::UsdGeomTokens->varying, bke::AttrDomain::Point);
|
||||
map.add_new(pxr::UsdGeomTokens->face, bke::AttrDomain::Face);
|
||||
/* As there's no "constant" type in Blender, for now we're
|
||||
* translating into a point Attribute. */
|
||||
map.add_new(pxr::UsdGeomTokens->constant, bke::AttrDomain::Point);
|
||||
map.add_new(pxr::UsdGeomTokens->uniform, bke::AttrDomain::Face);
|
||||
/* Notice: Edge types are not supported! */
|
||||
return map;
|
||||
}();
|
||||
|
||||
const bke::AttrDomain *value = domain_map.lookup_ptr(usd_domain);
|
||||
|
||||
if (value == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return *value;
|
||||
}
|
||||
|
||||
void USDMeshReader::create_object(Main *bmain, const double /*motionSampleTime*/)
|
||||
{
|
||||
Mesh *mesh = BKE_mesh_add(bmain, name_.c_str());
|
||||
@@ -380,36 +353,6 @@ void USDMeshReader::read_uv_data_primvar(Mesh *mesh,
|
||||
uv_data.finish();
|
||||
}
|
||||
|
||||
void USDMeshReader::read_generic_data_primvar(Mesh *mesh,
|
||||
const pxr::UsdGeomPrimvar &primvar,
|
||||
const double motionSampleTime)
|
||||
{
|
||||
const pxr::SdfValueTypeName pv_type = primvar.GetTypeName();
|
||||
const pxr::TfToken pv_interp = primvar.GetInterpolation();
|
||||
|
||||
const std::optional<bke::AttrDomain> domain = convert_usd_varying_to_blender(pv_interp);
|
||||
const std::optional<eCustomDataType> type = convert_usd_type_to_blender(pv_type);
|
||||
|
||||
if (!domain.has_value() || !type.has_value()) {
|
||||
const pxr::TfToken pv_name = pxr::UsdGeomPrimvar::StripPrimvarsName(primvar.GetPrimvarName());
|
||||
BKE_reportf(reports(),
|
||||
RPT_WARNING,
|
||||
"Primvar '%s' (interpolation %s, type %s) cannot be converted to Blender",
|
||||
pv_name.GetText(),
|
||||
pv_interp.GetText(),
|
||||
pv_type.GetAsToken().GetText());
|
||||
return;
|
||||
}
|
||||
|
||||
OffsetIndices<int> faces;
|
||||
if (is_left_handed_) {
|
||||
faces = mesh->faces();
|
||||
}
|
||||
|
||||
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
|
||||
copy_primvar_to_blender_attribute(primvar, motionSampleTime, *type, *domain, faces, attributes);
|
||||
}
|
||||
|
||||
void USDMeshReader::read_vertex_creases(Mesh *mesh, const double motionSampleTime)
|
||||
{
|
||||
pxr::VtIntArray corner_indices;
|
||||
@@ -645,7 +588,7 @@ void USDMeshReader::read_custom_data(const ImportSettings *settings,
|
||||
active_color_name = name;
|
||||
}
|
||||
|
||||
read_color_data_primvar(mesh, pv, motionSampleTime, reports(), is_left_handed_);
|
||||
read_generic_mesh_primvar(mesh, pv, motionSampleTime, is_left_handed_);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -663,14 +606,14 @@ void USDMeshReader::read_custom_data(const ImportSettings *settings,
|
||||
if (active_uv_set_name.IsEmpty() || name == usdtokens::st) {
|
||||
active_uv_set_name = name;
|
||||
}
|
||||
read_uv_data_primvar(mesh, pv, motionSampleTime);
|
||||
this->read_uv_data_primvar(mesh, pv, motionSampleTime);
|
||||
}
|
||||
}
|
||||
|
||||
/* Read all other primvars. */
|
||||
else {
|
||||
if ((settings->read_flag & MOD_MESHSEQ_READ_ATTRIBUTES) != 0) {
|
||||
read_generic_data_primvar(mesh, pv, motionSampleTime);
|
||||
read_generic_mesh_primvar(mesh, pv, motionSampleTime, is_left_handed_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -97,9 +97,6 @@ class USDMeshReader : public USDGeomReader {
|
||||
void read_uv_data_primvar(Mesh *mesh,
|
||||
const pxr::UsdGeomPrimvar &primvar,
|
||||
const double motionSampleTime);
|
||||
void read_generic_data_primvar(Mesh *mesh,
|
||||
const pxr::UsdGeomPrimvar &primvar,
|
||||
const double motionSampleTime);
|
||||
|
||||
/**
|
||||
* Override transform computation to account for the binding
|
||||
|
||||
@@ -28,11 +28,6 @@
|
||||
#include <pxr/usdImaging/usdImaging/cylinderAdapter.h>
|
||||
#include <pxr/usdImaging/usdImaging/sphereAdapter.h>
|
||||
|
||||
namespace usdtokens {
|
||||
/* Materials */
|
||||
static const pxr::TfToken displayColor("displayColor", pxr::TfToken::Immortal);
|
||||
} // namespace usdtokens
|
||||
|
||||
namespace blender::io::usd {
|
||||
|
||||
USDShapeReader::USDShapeReader(const pxr::UsdPrim &prim,
|
||||
@@ -223,13 +218,13 @@ void USDShapeReader::apply_primvars_to_mesh(Mesh *mesh, const double motionSampl
|
||||
if (active_color_name.IsEmpty() || name == usdtokens::displayColor) {
|
||||
active_color_name = name;
|
||||
}
|
||||
}
|
||||
|
||||
read_color_data_primvar(mesh, pv, motionSampleTime, reports(), false);
|
||||
read_generic_mesh_primvar(mesh, pv, motionSampleTime, false);
|
||||
|
||||
/* Record whether the primvar attribute might be time varying. */
|
||||
if (!primvar_time_varying_map_.contains(name)) {
|
||||
primvar_time_varying_map_.add(name, pv.ValueMightBeTimeVarying());
|
||||
}
|
||||
/* Record whether the primvar attribute might be time varying. */
|
||||
if (!primvar_time_varying_map_.contains(name)) {
|
||||
primvar_time_varying_map_.add(name, pv.ValueMightBeTimeVarying());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
#include "BLI_array_utils.hh"
|
||||
#include "BLI_assert.h"
|
||||
#include "BLI_color.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
|
||||
#include "BKE_attribute.hh"
|
||||
@@ -192,15 +191,6 @@ void USDGenericMeshWriter::write_custom_data(const Object *obj,
|
||||
}
|
||||
}
|
||||
|
||||
/* Color data. */
|
||||
else if (ELEM(meta_data.domain, bke::AttrDomain::Corner, bke::AttrDomain::Point) &&
|
||||
ELEM(meta_data.data_type, CD_PROP_BYTE_COLOR, CD_PROP_COLOR))
|
||||
{
|
||||
if (usd_export_context_.export_params.export_mesh_colors) {
|
||||
this->write_color_data(mesh, usd_mesh, attribute_id, meta_data);
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
this->write_generic_data(mesh, usd_mesh, attribute_id, meta_data);
|
||||
}
|
||||
@@ -231,10 +221,12 @@ void USDGenericMeshWriter::write_generic_data(const Mesh *mesh,
|
||||
const StringRef attribute_id,
|
||||
const bke::AttributeMetaData &meta_data)
|
||||
{
|
||||
/* Varying type depends on original domain. */
|
||||
const pxr::TfToken pv_name(
|
||||
make_safe_name(attribute_id, usd_export_context_.export_params.allow_unicode));
|
||||
const bool use_color3f_type = pv_name == usdtokens::displayColor;
|
||||
const std::optional<pxr::TfToken> pv_interp = convert_blender_domain_to_usd(meta_data.domain);
|
||||
const std::optional<pxr::SdfValueTypeName> pv_type = convert_blender_type_to_usd(
|
||||
meta_data.data_type);
|
||||
meta_data.data_type, use_color3f_type);
|
||||
|
||||
if (!pv_interp || !pv_type) {
|
||||
BKE_reportf(reports(),
|
||||
@@ -254,8 +246,6 @@ void USDGenericMeshWriter::write_generic_data(const Mesh *mesh,
|
||||
}
|
||||
|
||||
const pxr::UsdTimeCode timecode = get_export_time_code();
|
||||
const pxr::TfToken pv_name(
|
||||
make_safe_name(attribute_id, usd_export_context_.export_params.allow_unicode));
|
||||
const pxr::UsdGeomPrimvarsAPI pv_api = pxr::UsdGeomPrimvarsAPI(usd_mesh);
|
||||
|
||||
pxr::UsdGeomPrimvar pv_attr = pv_api.CreatePrimvar(pv_name, *pv_type, *pv_interp);
|
||||
@@ -293,41 +283,6 @@ void USDGenericMeshWriter::write_uv_data(const Mesh *mesh,
|
||||
copy_blender_buffer_to_primvar<float2, pxr::GfVec2f>(buffer, timecode, pv_uv, usd_value_writer_);
|
||||
}
|
||||
|
||||
void USDGenericMeshWriter::write_color_data(const Mesh *mesh,
|
||||
const pxr::UsdGeomMesh &usd_mesh,
|
||||
const StringRef attribute_id,
|
||||
const bke::AttributeMetaData &meta_data)
|
||||
{
|
||||
const VArray<ColorGeometry4f> buffer = *mesh->attributes().lookup<ColorGeometry4f>(
|
||||
attribute_id, meta_data.domain);
|
||||
if (buffer.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const pxr::UsdTimeCode timecode = get_export_time_code();
|
||||
const pxr::TfToken pv_name(
|
||||
make_safe_name(attribute_id, usd_export_context_.export_params.allow_unicode));
|
||||
const pxr::UsdGeomPrimvarsAPI pv_api = pxr::UsdGeomPrimvarsAPI(usd_mesh);
|
||||
|
||||
/* Varying type depends on original domain. */
|
||||
const pxr::TfToken pv_interp = meta_data.domain == bke::AttrDomain::Corner ?
|
||||
pxr::UsdGeomTokens->faceVarying :
|
||||
pxr::UsdGeomTokens->vertex;
|
||||
|
||||
pxr::UsdGeomPrimvar colors_pv = pv_api.CreatePrimvar(
|
||||
pv_name, pxr::SdfValueTypeNames->Color4fArray, pv_interp);
|
||||
|
||||
switch (meta_data.domain) {
|
||||
case bke::AttrDomain::Corner:
|
||||
case bke::AttrDomain::Point:
|
||||
copy_blender_buffer_to_primvar<ColorGeometry4f, pxr::GfVec4f>(
|
||||
buffer, timecode, colors_pv, usd_value_writer_);
|
||||
break;
|
||||
default:
|
||||
BLI_assert_msg(0, "Invalid type for mesh color data.");
|
||||
}
|
||||
}
|
||||
|
||||
void USDGenericMeshWriter::free_export_mesh(Mesh *mesh)
|
||||
{
|
||||
BKE_id_free(nullptr, mesh);
|
||||
|
||||
@@ -56,10 +56,6 @@ class USDGenericMeshWriter : public USDAbstractWriter {
|
||||
const pxr::UsdGeomMesh &usd_mesh,
|
||||
const StringRef attribute_id,
|
||||
const StringRef active_uvmap_name);
|
||||
void write_color_data(const Mesh *mesh,
|
||||
const pxr::UsdGeomMesh &usd_mesh,
|
||||
const StringRef attribute_id,
|
||||
const bke::AttributeMetaData &meta_data);
|
||||
};
|
||||
|
||||
class USDMeshWriter : public USDGenericMeshWriter {
|
||||
|
||||
@@ -270,8 +270,8 @@ class USDExportTest(AbstractUSDTest):
|
||||
self.check_primvar(prim, "f_int8", "VtArray<unsigned char>", "uniform", 1)
|
||||
self.check_primvar(prim, "f_int32", "VtArray<int>", "uniform", 1)
|
||||
self.check_primvar(prim, "f_float", "VtArray<float>", "uniform", 1)
|
||||
self.check_primvar_missing(prim, "f_color")
|
||||
self.check_primvar_missing(prim, "f_byte_color")
|
||||
self.check_primvar(prim, "f_color", "VtArray<GfVec4f>", "uniform", 1)
|
||||
self.check_primvar(prim, "f_byte_color", "VtArray<GfVec4f>", "uniform", 1)
|
||||
self.check_primvar(prim, "f_vec2", "VtArray<GfVec2f>", "uniform", 1)
|
||||
self.check_primvar(prim, "f_vec3", "VtArray<GfVec3f>", "uniform", 1)
|
||||
self.check_primvar(prim, "f_quat", "VtArray<GfQuatf>", "uniform", 1)
|
||||
@@ -294,8 +294,8 @@ class USDExportTest(AbstractUSDTest):
|
||||
self.check_primvar(prim, "p_int8", "VtArray<unsigned char>", "vertex", 24)
|
||||
self.check_primvar(prim, "p_int32", "VtArray<int>", "vertex", 24)
|
||||
self.check_primvar(prim, "p_float", "VtArray<float>", "vertex", 24)
|
||||
self.check_primvar_missing(prim, "p_color")
|
||||
self.check_primvar_missing(prim, "p_byte_color")
|
||||
self.check_primvar(prim, "p_color", "VtArray<GfVec4f>", "vertex", 24)
|
||||
self.check_primvar(prim, "p_byte_color", "VtArray<GfVec4f>", "vertex", 24)
|
||||
self.check_primvar(prim, "p_vec2", "VtArray<GfVec2f>", "vertex", 24)
|
||||
self.check_primvar(prim, "p_vec3", "VtArray<GfVec3f>", "vertex", 24)
|
||||
self.check_primvar(prim, "p_quat", "VtArray<GfQuatf>", "vertex", 24)
|
||||
@@ -305,8 +305,8 @@ class USDExportTest(AbstractUSDTest):
|
||||
self.check_primvar(prim, "sp_int8", "VtArray<unsigned char>", "uniform", 2)
|
||||
self.check_primvar(prim, "sp_int32", "VtArray<int>", "uniform", 2)
|
||||
self.check_primvar(prim, "sp_float", "VtArray<float>", "uniform", 2)
|
||||
self.check_primvar_missing(prim, "sp_color")
|
||||
self.check_primvar_missing(prim, "sp_byte_color")
|
||||
self.check_primvar(prim, "sp_color", "VtArray<GfVec4f>", "uniform", 2)
|
||||
self.check_primvar(prim, "sp_byte_color", "VtArray<GfVec4f>", "uniform", 2)
|
||||
self.check_primvar(prim, "sp_vec2", "VtArray<GfVec2f>", "uniform", 2)
|
||||
self.check_primvar(prim, "sp_vec3", "VtArray<GfVec3f>", "uniform", 2)
|
||||
self.check_primvar(prim, "sp_quat", "VtArray<GfQuatf>", "uniform", 2)
|
||||
@@ -318,8 +318,8 @@ class USDExportTest(AbstractUSDTest):
|
||||
self.check_primvar(prim, "p_int8", "VtArray<unsigned char>", "varying", 10)
|
||||
self.check_primvar(prim, "p_int32", "VtArray<int>", "varying", 10)
|
||||
self.check_primvar(prim, "p_float", "VtArray<float>", "varying", 10)
|
||||
self.check_primvar_missing(prim, "p_color")
|
||||
self.check_primvar_missing(prim, "p_byte_color")
|
||||
self.check_primvar(prim, "p_color", "VtArray<GfVec4f>", "varying", 10)
|
||||
self.check_primvar(prim, "p_byte_color", "VtArray<GfVec4f>", "varying", 10)
|
||||
self.check_primvar(prim, "p_vec2", "VtArray<GfVec2f>", "varying", 10)
|
||||
self.check_primvar(prim, "p_vec3", "VtArray<GfVec3f>", "varying", 10)
|
||||
self.check_primvar(prim, "p_quat", "VtArray<GfQuatf>", "varying", 10)
|
||||
@@ -329,8 +329,8 @@ class USDExportTest(AbstractUSDTest):
|
||||
self.check_primvar(prim, "sp_int8", "VtArray<unsigned char>", "uniform", 3)
|
||||
self.check_primvar(prim, "sp_int32", "VtArray<int>", "uniform", 3)
|
||||
self.check_primvar(prim, "sp_float", "VtArray<float>", "uniform", 3)
|
||||
self.check_primvar_missing(prim, "sp_color")
|
||||
self.check_primvar_missing(prim, "sp_byte_color")
|
||||
self.check_primvar(prim, "sp_color", "VtArray<GfVec4f>", "uniform", 3)
|
||||
self.check_primvar(prim, "sp_byte_color", "VtArray<GfVec4f>", "uniform", 3)
|
||||
self.check_primvar(prim, "sp_vec2", "VtArray<GfVec2f>", "uniform", 3)
|
||||
self.check_primvar(prim, "sp_vec3", "VtArray<GfVec3f>", "uniform", 3)
|
||||
self.check_primvar(prim, "sp_quat", "VtArray<GfQuatf>", "uniform", 3)
|
||||
|
||||
@@ -818,8 +818,8 @@ class USDImportTest(AbstractUSDTest):
|
||||
self.check_attribute(mesh, "f_int8", 'FACE', 'INT8', 1)
|
||||
self.check_attribute(mesh, "f_int32", 'FACE', 'INT', 1)
|
||||
self.check_attribute(mesh, "f_float", 'FACE', 'FLOAT', 1)
|
||||
self.check_attribute_missing(mesh, "f_byte_color") # Not supported?
|
||||
self.check_attribute_missing(mesh, "f_color") # Not supported?
|
||||
self.check_attribute(mesh, "f_byte_color", 'FACE', 'FLOAT_COLOR', 1)
|
||||
self.check_attribute(mesh, "f_color", 'FACE', 'FLOAT_COLOR', 1)
|
||||
self.check_attribute(mesh, "f_vec2", 'FACE', 'FLOAT2', 1)
|
||||
self.check_attribute(mesh, "f_vec3", 'FACE', 'FLOAT_VECTOR', 1)
|
||||
self.check_attribute_missing(mesh, "f_quat")
|
||||
@@ -845,8 +845,8 @@ class USDImportTest(AbstractUSDTest):
|
||||
self.check_attribute(curves, "p_int8", 'POINT', 'INT8', 24)
|
||||
self.check_attribute(curves, "p_int32", 'POINT', 'INT', 24)
|
||||
self.check_attribute(curves, "p_float", 'POINT', 'FLOAT', 24)
|
||||
self.check_attribute_missing(curves, "p_byte_color")
|
||||
self.check_attribute_missing(curves, "p_color")
|
||||
self.check_attribute(curves, "p_byte_color", 'POINT', 'FLOAT_COLOR', 24)
|
||||
self.check_attribute(curves, "p_color", 'POINT', 'FLOAT_COLOR', 24)
|
||||
self.check_attribute(curves, "p_vec2", 'POINT', 'FLOAT2', 24)
|
||||
self.check_attribute(curves, "p_vec3", 'POINT', 'FLOAT_VECTOR', 24)
|
||||
self.check_attribute(curves, "p_quat", 'POINT', 'QUATERNION', 24)
|
||||
@@ -856,8 +856,8 @@ class USDImportTest(AbstractUSDTest):
|
||||
self.check_attribute(curves, "sp_int8", 'CURVE', 'INT8', 2)
|
||||
self.check_attribute(curves, "sp_int32", 'CURVE', 'INT', 2)
|
||||
self.check_attribute(curves, "sp_float", 'CURVE', 'FLOAT', 2)
|
||||
self.check_attribute_missing(curves, "sp_byte_color")
|
||||
self.check_attribute_missing(curves, "sp_color")
|
||||
self.check_attribute(curves, "sp_byte_color", 'CURVE', 'FLOAT_COLOR', 2)
|
||||
self.check_attribute(curves, "sp_color", 'CURVE', 'FLOAT_COLOR', 2)
|
||||
self.check_attribute(curves, "sp_vec2", 'CURVE', 'FLOAT2', 2)
|
||||
self.check_attribute(curves, "sp_vec3", 'CURVE', 'FLOAT_VECTOR', 2)
|
||||
self.check_attribute(curves, "sp_quat", 'CURVE', 'QUATERNION', 2)
|
||||
@@ -871,8 +871,8 @@ class USDImportTest(AbstractUSDTest):
|
||||
self.check_attribute(curves, "p_int8", 'POINT', 'INT8', 10)
|
||||
self.check_attribute(curves, "p_int32", 'POINT', 'INT', 10)
|
||||
self.check_attribute(curves, "p_float", 'POINT', 'FLOAT', 10)
|
||||
self.check_attribute_missing(curves, "p_byte_color")
|
||||
self.check_attribute_missing(curves, "p_color")
|
||||
self.check_attribute(curves, "p_byte_color", 'POINT', 'FLOAT_COLOR', 10)
|
||||
self.check_attribute(curves, "p_color", 'POINT', 'FLOAT_COLOR', 10)
|
||||
self.check_attribute(curves, "p_vec2", 'POINT', 'FLOAT2', 10)
|
||||
self.check_attribute(curves, "p_vec3", 'POINT', 'FLOAT_VECTOR', 10)
|
||||
self.check_attribute(curves, "p_quat", 'POINT', 'QUATERNION', 10)
|
||||
@@ -882,8 +882,8 @@ class USDImportTest(AbstractUSDTest):
|
||||
self.check_attribute(curves, "sp_int8", 'CURVE', 'INT8', 3)
|
||||
self.check_attribute(curves, "sp_int32", 'CURVE', 'INT', 3)
|
||||
self.check_attribute(curves, "sp_float", 'CURVE', 'FLOAT', 3)
|
||||
self.check_attribute_missing(curves, "sp_byte_color")
|
||||
self.check_attribute_missing(curves, "sp_color")
|
||||
self.check_attribute(curves, "sp_byte_color", 'CURVE', 'FLOAT_COLOR', 3)
|
||||
self.check_attribute(curves, "sp_color", 'CURVE', 'FLOAT_COLOR', 3)
|
||||
self.check_attribute(curves, "sp_vec2", 'CURVE', 'FLOAT2', 3)
|
||||
self.check_attribute(curves, "sp_vec3", 'CURVE', 'FLOAT_VECTOR', 3)
|
||||
self.check_attribute(curves, "sp_quat", 'CURVE', 'QUATERNION', 3)
|
||||
|
||||
Reference in New Issue
Block a user