mirror of
https://github.com/blender/blender
synced 2026-09-29 04:37:17 +03:00
Fix #148436: Incorrect legacy hair offset with USD export
The report in question uncovered two sources of issues. The primary one being that there was an accidental double-transform from placing the basis curves prim under the main Xform of the mesh too. This is solved by considering the inverse of mesh's world transform when writing out the curve points. The second was exposed with the new, more correct, viewport drawing of curves that showed that we were exporting the wrong curve type. This would manifest as a disappearing curve segment at the beginning and end of the curve. Fixed by explicitly writing out catmull-rom, pinned, curves for the hair rather than using bsplines. As a result the Storm-USD tests now match much closer to the native Storm-Hydra variants. Pull Request: https://projects.blender.org/blender/blender/pulls/148543
This commit is contained in:
parent
6cbbb54d8c
commit
67752cc66e
15 changed files with 52 additions and 38 deletions
|
|
@ -9,6 +9,9 @@
|
|||
|
||||
#include "BKE_particle.h"
|
||||
|
||||
#include "BLI_math_matrix.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
|
||||
#include "DNA_particle_types.h"
|
||||
|
||||
namespace blender::io::usd {
|
||||
|
|
@ -27,14 +30,24 @@ void USDHairWriter::do_write(HierarchyContext &context)
|
|||
pxr::UsdGeomBasisCurves curves = pxr::UsdGeomBasisCurves::Define(usd_export_context_.stage,
|
||||
usd_export_context_.usd_path);
|
||||
|
||||
/* TODO(Sybren): deal with (psys->part->flag & PART_HAIR_BSPLINE) */
|
||||
curves.CreateBasisAttr(pxr::VtValue(pxr::UsdGeomTokens->bspline));
|
||||
curves.CreateTypeAttr(pxr::VtValue(pxr::UsdGeomTokens->cubic));
|
||||
if (psys->part->flag & PART_HAIR_BSPLINE) {
|
||||
curves.CreateBasisAttr(pxr::VtValue(pxr::UsdGeomTokens->bspline));
|
||||
curves.CreateTypeAttr(pxr::VtValue(pxr::UsdGeomTokens->cubic));
|
||||
}
|
||||
else {
|
||||
curves.CreateBasisAttr(pxr::VtValue(pxr::UsdGeomTokens->catmullRom));
|
||||
curves.CreateTypeAttr(pxr::VtValue(pxr::UsdGeomTokens->linear));
|
||||
curves.CreateWrapAttr(pxr::VtValue(pxr::UsdGeomTokens->pinned));
|
||||
}
|
||||
|
||||
pxr::VtArray<pxr::GfVec3f> points;
|
||||
pxr::VtIntArray curve_point_counts;
|
||||
curve_point_counts.reserve(psys->totpart);
|
||||
|
||||
/* Reverse current transform since the Hair curves will be placed under the object's Xform and we
|
||||
* don't want a double-transform to happen. */
|
||||
const blender::float4x4 inv = blender::math::invert(context.object->object_to_world());
|
||||
|
||||
ParticleCacheKey *strand;
|
||||
for (int strand_index = 0; strand_index < psys->totpart; ++strand_index) {
|
||||
strand = cache[strand_index];
|
||||
|
|
@ -43,7 +56,8 @@ void USDHairWriter::do_write(HierarchyContext &context)
|
|||
curve_point_counts.push_back(point_count);
|
||||
|
||||
for (int point_index = 0; point_index < point_count; ++point_index, ++strand) {
|
||||
points.push_back(pxr::GfVec3f(strand->co));
|
||||
const float3 vert = blender::math::transform_point(inv, float3(strand->co));
|
||||
points.push_back(pxr::GfVec3f(vert.x, vert.y, vert.z));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:056f05c238c5a35e467c8e1b5df635f58a8e47276911b14879bb13458f74621c
|
||||
size 1448
|
||||
oid sha256:18bb866d0483ad3a2af070da1e75ed0a931088845998088c5a45ccfe967613f0
|
||||
size 1487
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:78a994390987ae71d122f711a059da923a8ebc2754b350c06341566a75036c7e
|
||||
size 933
|
||||
oid sha256:80eb07336eec80945fa6071272fb5ed89ee2c48b74543be3848312808141f544
|
||||
size 1683
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:056b08ea90ba933b7e08c5f646950f33ab0abfc8e4fdddd1377322c788400030
|
||||
size 955
|
||||
oid sha256:7e1c54c34f9545cc549827cd67941c50d6de73743bb964940a70ca8e74c02dbf
|
||||
size 3111
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:2e006d081384e4d3e518c3090505508d95f136328e8454d056c847899346306f
|
||||
size 6578
|
||||
oid sha256:fa4a518c50d13a82057cc8a2387bbb54c128c5e5207faea26ae95c7a8438099c
|
||||
size 11570
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a893f9b4f70c24a568a288d8151bacd545c4bb72b9fd1afecf21e0197b372001
|
||||
size 885
|
||||
oid sha256:7fc7e76a1b167871f4ea7380377b5c52ae09af511b76fe0bf7e9a6ed8f096830
|
||||
size 1690
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:dfc90d81a399f3dcc357c94ec14a4715b650cc384dac4649e269578d5fe1bfb3
|
||||
size 6282
|
||||
oid sha256:a88409c33674d8ea30bb3cb8a0680c374bd490ff031acaa949f93cffd365e98e
|
||||
size 10825
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:e25037087446e2ff1f3bff7b606e20d38342ccc7caef974a37331bc39f6383dc
|
||||
size 940
|
||||
oid sha256:b53689af07cc1c6ac1ebc33994ac4e4c743d9ad2fae0085017e00dc9ce9d0735
|
||||
size 1690
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4c3b4a7f6761c5a8c3f052c75f30e54db3e8e53b6ee9fc0b5e903c651ff0c21f
|
||||
size 1846
|
||||
oid sha256:529536ecce9652642af712b98c254a443afb4f22d1d9a28e4089fbff2f4dbe2b
|
||||
size 1710
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:c6b28fa6587d713cd551672da0e5b6c3b77759af507cc3a0543cd5ab9214ff79
|
||||
size 1839
|
||||
oid sha256:50c2776c7dac9cab387756dd236e0e69c53e2b62e879d832d765b32925533930
|
||||
size 1703
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:a861c9af24dbdbc834f1eca830c9b470e44eb33412e22d32b083674cf30fcdee
|
||||
size 1845
|
||||
oid sha256:b936db41b5e749f62c2d9bffc5a1800b270c789b548f25e16c1e967b1aa244c5
|
||||
size 1709
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:28939bf8869635716ce2014697640915ef4d46e73bc19e8fe08026461f0a4da2
|
||||
size 2195
|
||||
oid sha256:188ebf7e81de30973fdfb6249ff0a666b2455f279bf8a840b2feb497544c19e2
|
||||
size 2939
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:0ac731b35867f91e32a811e985f20b40227238e8ef2c075ff136530469da8cde
|
||||
size 9959
|
||||
oid sha256:5f689c8ad59f3e4670db79502f7e7b6b26f9da15ac00adce64dc79f09bff75eb
|
||||
size 9950
|
||||
|
|
|
|||
|
|
@ -535,8 +535,8 @@ class USDExportTest(AbstractUSDTest):
|
|||
|
||||
hair_curves = UsdGeom.BasisCurves(hair_prim)
|
||||
hair_samples = hair_curves.GetPointsAttr().GetTimeSamples()
|
||||
self.assertEqual(hair_curves.GetTypeAttr().Get(), "cubic")
|
||||
self.assertEqual(hair_curves.GetBasisAttr().Get(), "bspline")
|
||||
self.assertEqual(hair_curves.GetTypeAttr().Get(), "linear")
|
||||
self.assertEqual(hair_curves.GetBasisAttr().Get(), "catmullRom")
|
||||
self.assertEqual(len(hair_samples), 10)
|
||||
|
||||
def check_primvar(self, prim, pv_name, pv_typeName, pv_interp, elements_len):
|
||||
|
|
|
|||
|
|
@ -904,8 +904,8 @@ class USDImportTest(AbstractUSDTest):
|
|||
self.assertAlmostEqual(f.evaluate(10), 0.0, 2, "Unexpected value for rotation quaternion Z curve at frame 10")
|
||||
|
||||
def check_curve(self, blender_curve, usd_curve):
|
||||
curve_type_map = {"linear": 1, "cubic-bezier": 2, "cubic-bspline": 3}
|
||||
cyclic_map = {"nonperiodic": False, "periodic": True}
|
||||
curve_type_map = {"linear-bezier": 1, "linear-catmullRom": 1, "cubic-bezier": 2, "cubic-bspline": 3}
|
||||
cyclic_map = {"pinned": False, "nonperiodic": False, "periodic": True}
|
||||
|
||||
# Check correct spline count.
|
||||
blender_spline_count = len(blender_curve.attributes["curve_type"].data)
|
||||
|
|
@ -913,10 +913,7 @@ class USDImportTest(AbstractUSDTest):
|
|||
self.assertEqual(blender_spline_count, usd_spline_count)
|
||||
|
||||
# Check correct type of curve. All splines should have the same type and periodicity.
|
||||
usd_curve_type = usd_curve.GetTypeAttr().Get()
|
||||
usd_curve_type_basis = usd_curve_type
|
||||
if usd_curve_type != "linear":
|
||||
usd_curve_type_basis = usd_curve_type + "-" + usd_curve.GetBasisAttr().Get()
|
||||
usd_curve_type_basis = usd_curve.GetTypeAttr().Get() + "-" + usd_curve.GetBasisAttr().Get()
|
||||
usd_cyclic = usd_curve.GetWrapAttr().Get()
|
||||
expected_curve_type = curve_type_map[usd_curve_type_basis]
|
||||
expected_cyclic = cyclic_map[usd_cyclic]
|
||||
|
|
@ -935,7 +932,7 @@ class USDImportTest(AbstractUSDTest):
|
|||
blender_positions = blender_curve.attributes["position"].data
|
||||
|
||||
point_count = 0
|
||||
if usd_curve_type_basis == "linear":
|
||||
if usd_curve_type_basis in ("linear-bezier", "linear-catmullRom"):
|
||||
point_count = len(usd_positions)
|
||||
self.assertEqual(len(blender_positions), point_count)
|
||||
elif usd_curve_type_basis == "cubic-bezier":
|
||||
|
|
@ -957,10 +954,13 @@ class USDImportTest(AbstractUSDTest):
|
|||
if usd_curve_type_basis == "cubic-bspline":
|
||||
return
|
||||
|
||||
if not usd_curve.GetWidthsAttr().IsAuthored():
|
||||
return
|
||||
|
||||
usd_width_interpolation = usd_curve.GetWidthsInterpolation()
|
||||
usd_radius = [w / 2 for w in usd_curve.GetWidthsAttr().Get()]
|
||||
blender_radius = [r.value for r in blender_curve.attributes["radius"].data]
|
||||
if usd_curve_type_basis == "linear":
|
||||
if usd_curve_type_basis == "linear-bezier":
|
||||
if usd_width_interpolation == "constant":
|
||||
usd_radius = usd_radius * point_count
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue