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
109 lines
3.8 KiB
C++
109 lines
3.8 KiB
C++
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
* Adapted from the Blender Alembic importer implementation.
|
|
* Modifications Copyright 2021 Tangent Animation and. NVIDIA Corporation. All rights reserved. */
|
|
#pragma once
|
|
|
|
#include "BLI_map.hh"
|
|
#include "BLI_span.hh"
|
|
|
|
#include "usd.hh"
|
|
#include "usd_reader_geom.hh"
|
|
|
|
#include <pxr/usd/usdGeom/mesh.h>
|
|
|
|
namespace blender::io::usd {
|
|
|
|
class USDMeshReader : public USDGeomReader {
|
|
private:
|
|
pxr::UsdGeomMesh mesh_prim_;
|
|
|
|
blender::Map<std::string, pxr::TfToken> uv_token_map_;
|
|
blender::Map<const pxr::TfToken, bool> primvar_varying_map_;
|
|
|
|
/* TODO(makowalski): Is it the best strategy to cache the
|
|
* mesh geometry in the following members? It appears these
|
|
* arrays are never cleared, so this might bloat memory. */
|
|
pxr::VtIntArray face_indices_;
|
|
pxr::VtIntArray face_counts_;
|
|
pxr::VtVec3fArray positions_;
|
|
pxr::VtVec3fArray normals_;
|
|
|
|
pxr::TfToken normal_interpolation_;
|
|
pxr::TfToken orientation_;
|
|
bool is_left_handed_;
|
|
bool is_time_varying_;
|
|
|
|
/* This is to ensure we load all data once, because we reuse the read_mesh function
|
|
* in the mesh seq modifier, and in initial load. Ideally, a better fix would be
|
|
* implemented. Note this will break if faces or positions vary. */
|
|
bool is_initial_load_;
|
|
|
|
public:
|
|
USDMeshReader(const pxr::UsdPrim &prim,
|
|
const USDImportParams &import_params,
|
|
const ImportSettings &settings);
|
|
|
|
bool valid() const override;
|
|
|
|
void create_object(Main *bmain, double motionSampleTime) override;
|
|
void read_object_data(Main *bmain, double motionSampleTime) override;
|
|
|
|
void read_geometry(bke::GeometrySet &geometry_set,
|
|
USDMeshReadParams params,
|
|
const char **r_err_str) override;
|
|
|
|
bool topology_changed(const Mesh *existing_mesh, double motionSampleTime) override;
|
|
|
|
/**
|
|
* If the USD mesh prim has a valid `UsdSkel` schema defined, return the USD path
|
|
* string to the bound skeleton, if any. Returns the empty string if no skeleton
|
|
* binding is defined.
|
|
*
|
|
* The returned path is currently used to match armature modifiers with armature
|
|
* objects during import.
|
|
*/
|
|
std::string get_skeleton_path() const;
|
|
|
|
private:
|
|
void process_normals_vertex_varying(Mesh *mesh);
|
|
void process_normals_face_varying(Mesh *mesh) const;
|
|
/** Set USD uniform (per-face) normals as Blender loop normals. */
|
|
void process_normals_uniform(Mesh *mesh) const;
|
|
void readFaceSetsSample(Main *bmain, Mesh *mesh, double motionSampleTime);
|
|
void assign_facesets_to_material_indices(double motionSampleTime,
|
|
MutableSpan<int> material_indices,
|
|
blender::Map<pxr::SdfPath, int> *r_mat_map);
|
|
|
|
void read_mpolys(Mesh *mesh) const;
|
|
void read_vertex_creases(Mesh *mesh, double motionSampleTime);
|
|
void read_velocities(Mesh *mesh, double motionSampleTime);
|
|
|
|
void read_mesh_sample(ImportSettings *settings,
|
|
Mesh *mesh,
|
|
double motionSampleTime,
|
|
bool new_mesh);
|
|
|
|
Mesh *read_mesh(struct Mesh *existing_mesh,
|
|
const USDMeshReadParams params,
|
|
const char **r_err_str);
|
|
|
|
void read_custom_data(const ImportSettings *settings,
|
|
Mesh *mesh,
|
|
double motionSampleTime,
|
|
bool new_mesh);
|
|
|
|
void read_uv_data_primvar(Mesh *mesh,
|
|
const pxr::UsdGeomPrimvar &primvar,
|
|
const double motionSampleTime);
|
|
|
|
/**
|
|
* Override transform computation to account for the binding
|
|
* transformation for skinned meshes.
|
|
*/
|
|
std::optional<XformResult> get_local_usd_xform(float time) const override;
|
|
};
|
|
|
|
} // namespace blender::io::usd
|