Problem description:
I’m saving a point cloud from Houdini with an orient attribute (quaternion) into a .pbc file for later use in Unreal via a Rule Processor.
If I load the same point cloud saved as a .bgeo file and bring it in through the same HDA, the orientation works perfectly — all local axes (N, up, side) are reproduced correctly, with no tilting or flipping, even with large rotations (>180°).
But when I load the .pbc version with the exact same orient attribute, the Rule Processor applies the transform incorrectly: I get unwanted tilts or wrong rotations.
- The orient attribute is built correctly in Houdini (setattribtypeinfo is set to quaternion).
- In Houdini and when using .bgeo in Unreal, the local frame is stable.
- The issue only happens when reading the .pbc through the Rule Processor.
My question:
Is there any difference in how .pbc or the Rule Processor reads or interprets the orient attribute compared to .bgeo?
Do I need extra steps when saving or loading .pbc to make sure orient works exactly the same way?
I am sharing google drive link with UE project and Houdini project.
Steps to Reproduce
I am sharing google drive link with UE project and Houdini project.
Hi Aram,
So while we don’t really support Rule Processor (it’s been developed for the City Sample demo) and have since replaced its usage by PCG, what happens is that the coordinate system isn’t the same in Houdini vs in Unreal.
In the case of HDAs, the Houdini plugin does the transformation as you’d expect it - and some exporters have different support for specific coordinate systems.
Now as far as I remember it, the Rule Processor does something special for the position/orientation/scale on points as you already expect, but if you have additional attributes that are quaternions, then they will not have that transformation applied.
I can explain a bit the setup that was used in this case (for the CitySample demo):
position -> vector( position.x, position.z, position.y)
scale -> vector( scale.x, scale.z, scale.y )
orient -> quat( orient.x, orient.z, orient.y, -orient.w ) (notice the w gets flipped here)
You can probably transform the quaternion yourself on the Houdini side of things and that should work as-is I think.
Let me know if that works for you.
Cheers,
Julien
hello [mention removed]
Thanks for the response!
We’ve tested every possible quaternion conversion from Houdini — including flipping W, swapping axes, handing over untouched raw data, etc.
The issue isn’t that orient is completely ignored — it’s that Rule Processor seems to misinterpret the quaternion more and more as the rotation angle increases. Small deviations work okay, but once you get rotations that lean further away from vertical, the output becomes totally unpredictable.
The purple vectors in the image are the correct orientations from Houdini. The colored RGB axes are the result of Rule Processor interpreting the same orient. As you can see, some match, others are completely off, and there’s no consistent pattern we can rely on.
We’ve ruled out coordinate system mismatch on our end. Something about Rule Processor’s internal quaternion handling seems broken or incompatible with Houdini’s output format.
Would appreciate if someone from Epic could confirm if Rule Processor was ever intended to handle orient properly — or if it’s just not safe to use for quaternions at all.
Please take a closer look at the attached screenshots and documentation. We’ve included both the Houdini file and the Unreal Engine project to make it easy to reproduce.
Any support will be appreciated!
Regards.
Hi Aram,
I looked a bit more into it - you’re right, there’s something fishy there for sure.
I could actually reproduce with Rule Processor vs PCG (I’m not setup at all to run Houdini) so it was a bit easier for me to compare (since I worked on both).
So as far as I can tell, the issue is because of this line in PointCloudAlembicHelpers.cpp (ln 333).
Ori = FQuat(Orientation.r, Orientation.axis().y, Orientation.axis().x, - Orientation.axis().z);
Because the axis() call normalizes the value, but it’s not kept in sync with the ‘r’ value here, this leads to an invalid quaternion, which is also renormalized after.
Using this instead:
Ori = FQuat(Orientation[0], Orientation[2], Orientation[1], -Orientation[3]);
Seems to work as expected (I get the same result) - let me know if that fixes your issue.
Cheers,
Julien