Blender V5.0
usd_writer_hair.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2019 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4#include "usd_writer_hair.hh"
6
7#include <pxr/usd/usdGeom/basisCurves.h>
8#include <pxr/usd/usdGeom/tokens.h>
9
10#include "BKE_particle.h"
11
12#include "BLI_math_matrix.hh"
14
15#include "DNA_particle_types.h"
16
17namespace blender::io::usd {
18
20
22{
23 ParticleSystem *psys = context.particle_system;
24 ParticleCacheKey **cache = psys->pathcache;
25 if (cache == nullptr) {
26 return;
27 }
28
29 pxr::UsdTimeCode time = get_export_time_code();
30 pxr::UsdGeomBasisCurves curves = pxr::UsdGeomBasisCurves::Define(usd_export_context_.stage,
31 usd_export_context_.usd_path);
32
33 if (psys->part->flag & PART_HAIR_BSPLINE) {
34 curves.CreateBasisAttr(pxr::VtValue(pxr::UsdGeomTokens->bspline));
35 curves.CreateTypeAttr(pxr::VtValue(pxr::UsdGeomTokens->cubic));
36 }
37 else {
38 curves.CreateBasisAttr(pxr::VtValue(pxr::UsdGeomTokens->catmullRom));
39 curves.CreateTypeAttr(pxr::VtValue(pxr::UsdGeomTokens->linear));
40 curves.CreateWrapAttr(pxr::VtValue(pxr::UsdGeomTokens->pinned));
41 }
42
43 pxr::VtArray<pxr::GfVec3f> points;
44 pxr::VtIntArray curve_point_counts;
45 curve_point_counts.reserve(psys->totpart);
46
47 /* Reverse current transform since the Hair curves will be placed under the object's Xform and we
48 * don't want a double-transform to happen. */
49 const blender::float4x4 inv = blender::math::invert(context.object->object_to_world());
50
51 ParticleCacheKey *strand;
52 for (int strand_index = 0; strand_index < psys->totpart; ++strand_index) {
53 strand = cache[strand_index];
54
55 int point_count = strand->segments + 1;
56 curve_point_counts.push_back(point_count);
57
58 for (int point_index = 0; point_index < point_count; ++point_index, ++strand) {
59 const float3 vert = blender::math::transform_point(inv, float3(strand->co));
60 points.push_back(pxr::GfVec3f(vert.x, vert.y, vert.z));
61 }
62 }
63
64 pxr::UsdAttribute attr_points = curves.CreatePointsAttr(pxr::VtValue(), true);
65 pxr::UsdAttribute attr_vertex_counts = curves.CreateCurveVertexCountsAttr(pxr::VtValue(), true);
66 if (!attr_points.HasValue()) {
67 attr_points.Set(points, pxr::UsdTimeCode::Default());
68 attr_vertex_counts.Set(curve_point_counts, pxr::UsdTimeCode::Default());
69 }
70 usd_value_writer_.SetAttribute(attr_points, pxr::VtValue(points), time);
71 usd_value_writer_.SetAttribute(attr_vertex_counts, pxr::VtValue(curve_point_counts), time);
72
73 if (psys->totpart > 0) {
74 pxr::VtArray<pxr::GfVec3f> colors;
75 colors.push_back(pxr::GfVec3f(cache[0]->col));
76 curves.CreateDisplayColorAttr(pxr::VtValue(colors));
77 }
78
79 if (psys->part) {
80 auto prim = curves.GetPrim();
81 write_id_properties(prim, psys->part->id, time);
82 }
83
84 this->author_extent(curves, time);
85}
86
88{
89 return true;
90}
91
92} // namespace blender::io::usd
@ PART_HAIR_BSPLINE
void author_extent(const pxr::UsdGeomBoundable &boundable, const pxr::UsdTimeCode time)
pxr::UsdTimeCode get_export_time_code() const
pxr::UsdUtilsSparseValueWriter usd_value_writer_
USDAbstractWriter(const USDExporterContext &usd_export_context)
void write_id_properties(const pxr::UsdPrim &prim, const ID &id, pxr::UsdTimeCode=pxr::UsdTimeCode::Default()) const
const USDExporterContext usd_export_context_
bool check_is_animated(const HierarchyContext &context) const override
void do_write(HierarchyContext &context) override
USDHairWriter(const USDExporterContext &ctx)
uint col
static int point_count(int usdCount, CurveType curve_type, bool is_cyclic)
CartesianBasis invert(const CartesianBasis &basis)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
MatBase< float, 4, 4 > float4x4
VecBase< float, 3 > float3
ParticleSettings * part
struct ParticleCacheKey ** pathcache