载入中...
搜索中...
未找到
PcgSkinnedMesh.cpp
浏览该文件的文档.
2
3#include <algorithm>
4#include <array>
5#include <cmath>
6
8namespace {
9bool sameBind(const std::array<float, 16>& left, const std::array<float, 16>& right) {
10 return std::equal(left.begin(), left.end(), right.begin());
11}
12} // namespace
13
15 const animation::AnimSkin& skin,
16 const procgen::PcgMeshTransform& transform,
17 const std::string& defaultMaterialId) {
18 if (mesh.empty() || mesh.getVertexCount() != skin.getVertexCount() || skin.getBoneCount() <= 0 ||
19 defaultMaterialId.empty() || sources_.size() >= 4096)
21 "Pcg skinned source mesh, skin, material or budget is invalid",
22 "procgen.animation.pcgSkinnedMesh"));
24 data.vertexCount = skin.getVertexCount();
25 data.bindPositions.reserve(static_cast<std::size_t>(data.vertexCount) * 3U);
26 for (int vertex = 0; vertex < data.vertexCount; ++vertex) {
27 data.bindPositions.insert(data.bindPositions.end(), {skin.getBindPositionX(vertex),
28 skin.getBindPositionY(vertex),
29 skin.getBindPositionZ(vertex)});
30 for (int influence = 0; influence < animation::AnimSkin::kMaxInfluences; ++influence) {
31 data.vertexSkinJoints.push_back(skin.getVertexSkinJoint(vertex, influence));
32 data.vertexWeights.push_back(skin.getVertexWeight(vertex, influence));
33 }
34 }
35 data.skeletonBones.reserve(static_cast<std::size_t>(skin.getBoneCount()));
36 data.boneNames.reserve(static_cast<std::size_t>(skin.getBoneCount()));
37 data.inverseBindMatrices.reserve(static_cast<std::size_t>(skin.getBoneCount()));
38 for (int joint = 0; joint < skin.getBoneCount(); ++joint) {
39 data.skeletonBones.push_back(skin.getSkeletonBone(joint));
40 data.boneNames.push_back(skin.getSkinBoneName(joint));
41 std::array<float, 16> bind{};
42 for (int element = 0; element < 16; ++element)
43 bind[static_cast<std::size_t>(element)] = skin.getInverseBindElement(joint, element);
44 data.inverseBindMatrices.push_back(bind);
45 }
46 sources_.push_back(Source{mesh, transform, defaultMaterialId, std::move(data)});
47 return Result<void>::success();
48}
49
51 const PcgSkinnedMeshPlan& plan) {
52 if (plan.sources_.empty())
54 DiagnosticCode::InvalidArgument, "Pcg skinned combine plan is empty", "procgen.animation.pcgSkinnedMesh"));
56 for (const auto& source : plan.sources_) {
57 auto appended = meshPlan.appendSource(source.mesh, source.transform, source.defaultMaterialId);
58 if (!appended.ok()) return Result<void>::failure(appended.status());
59 }
60 procgen::MeshBuild combinedMesh;
61 auto combined = procgen::combinePcgStaticMeshesInto(combinedMesh, meshPlan);
62 if (!combined.ok()) return Result<void>::failure(combined.status());
63
65 streams.vertexCount = combinedMesh.getVertexCount();
66 streams.bindPositions = combinedMesh.positions();
67 streams.bindNormals = combinedMesh.normals();
68 streams.vertexSkinJoints.reserve(static_cast<std::size_t>(streams.vertexCount) * 4U);
69 streams.vertexWeights.reserve(static_cast<std::size_t>(streams.vertexCount) * 4U);
70
71 bool seeded = false;
72 for (const auto& source : plan.sources_) {
73 const auto& skin = source.skin;
74 std::vector<int> remap(skin.skeletonBones.size(), -1);
75 if (!seeded) {
76 streams.skeletonBones = skin.skeletonBones;
77 streams.boneNames = skin.boneNames;
78 streams.inverseBindMatrices = skin.inverseBindMatrices;
79 seeded = true;
80 }
81 for (std::size_t joint = 0; joint < skin.skeletonBones.size(); ++joint) {
82 int firstIdentity = -1;
83 for (std::size_t used = 0; used < streams.skeletonBones.size(); ++used)
84 if (streams.skeletonBones[used] == skin.skeletonBones[joint]) {
85 firstIdentity = static_cast<int>(used);
86 break;
87 }
88 if (firstIdentity < 0 || !sameBind(skin.inverseBindMatrices[joint],
89 streams.inverseBindMatrices[static_cast<std::size_t>(firstIdentity)])) {
90 firstIdentity = static_cast<int>(streams.skeletonBones.size());
91 streams.skeletonBones.push_back(skin.skeletonBones[joint]);
92 streams.boneNames.push_back(skin.boneNames[joint]);
93 streams.inverseBindMatrices.push_back(skin.inverseBindMatrices[joint]);
94 }
95 remap[joint] = firstIdentity;
96 }
97 for (std::size_t influence = 0; influence < skin.vertexWeights.size(); ++influence) {
98 const float weight = skin.vertexWeights[influence];
99 const int sourceJoint = skin.vertexSkinJoints[influence];
100 if (weight > 0.F && (sourceJoint < 0 || static_cast<std::size_t>(sourceJoint) >= remap.size()))
102 DiagnosticCode::InvalidArgument, "Pcg skinned source influence references an invalid joint",
103 "procgen.animation.pcgSkinnedMesh"));
104 streams.vertexSkinJoints.push_back(weight > 0.F ? remap[static_cast<std::size_t>(sourceJoint)] : -1);
105 streams.vertexWeights.push_back(weight);
106 }
107 }
108 auto skin = animation::AnimSkin::fromStreams(std::move(streams));
109 if (!skin.ok()) return Result<void>::failure(skin.status());
110 PcgSkinnedMeshResult candidate;
111 candidate.mesh_ = std::move(combinedMesh);
112 candidate.skin_ = std::move(skin).takeValue();
113 output = std::move(candidate);
114 return Result<void>::success();
115}
116
117} // namespace eve::procgen_animation
std::string output
HexVec3 left
HexVec3 right
Mesh * mesh
std::unordered_map< std::uint32_t, std::uint32_t > remap
std::string element
const UnitySourceAsset & source
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
CPU linear-blend skinning binding for one mesh against an AnimSkeleton.
Definition AnimSkin.h:47
int getSkeletonBone(int skinBoneIndex) const
Skeleton bone index used by skin joint i (-1 if unused).
Definition AnimSkin.cpp:104
float getInverseBindElement(int skinBoneIndex, int elementIndex) const
Inverse-bind matrix element (column-major, 0..15) for skin joint i.
Definition AnimSkin.cpp:114
int getBoneCount() const
Returns the bone count.
Definition AnimSkin.h:76
float getVertexWeight(int vertexIndex, int influenceIndex) const
Returns the vertex weight.
Definition AnimSkin.cpp:198
std::string getSkinBoneName(int skinBoneIndex) const
Returns the skin bone name.
Definition AnimSkin.cpp:109
static Result< std::unique_ptr< AnimSkin > > fromStreams(AnimSkinStreamData streams)
Construct a caller-owned skin from validated native streams.
Definition AnimSkin.cpp:55
int getVertexSkinJoint(int vertexIndex, int influenceIndex) const
Influence slot i (0..3) for vertex: skin-local joint index or -1.
Definition AnimSkin.cpp:191
static constexpr int kMaxInfluences
Definition AnimSkin.h:49
int getVertexCount() const
Definition AnimSkin.h:74
CPU triangle mesh from procedural mesh recipes (e.g. marching cubes). Positions/normals are xyz-packe...
Definition MeshBuild.h:19
const std::vector< float > & positions() const
Positions.
Definition MeshBuild.h:125
const std::vector< float > & normals() const
Normals.
Definition MeshBuild.h:127
Owned ordered input plan for Pcg static MeshCombiner.
Definition PcgMeshLod.h:64
Result< void > appendSource(const MeshBuild &mesh, const PcgMeshTransform &transform, const std::string &defaultMaterialId)
Copy one readable mesh and root-relative affine transform into the plan.
Row-major affine matrix used by Pcg's root-relative static mesh combination.
Definition PcgMeshLod.h:43
Owned ordered inputs for Pcg's skinned MeshCombiner path.
Result< void > appendSource(const procgen::MeshBuild &mesh, const animation::AnimSkin &skin, const procgen::PcgMeshTransform &transform, const std::string &defaultMaterialId)
Copy one mesh, transform and complete skin streams into the plan.
Atomically published combined mesh and matching owned AnimSkin.
Result< void > combinePcgSkinnedMeshesInto(PcgSkinnedMeshResult &output, const PcgSkinnedMeshPlan &plan)
Combine Pcg skinned meshes, preserving its bone and bindpose remap semantics.
Result< int > combinePcgStaticMeshesInto(MeshBuild &output, const PcgMeshCombinePlan &plan)
Combine static meshes with Pcg material deduplication and root-relative transforms.
Owned native streams for constructing a skin outside the model importer.
Definition AnimSkin.h:28
std::vector< std::array< float, 16 > > inverseBindMatrices
Definition AnimSkin.h:34
std::vector< int > vertexSkinJoints
Definition AnimSkin.h:35
std::vector< std::string > boneNames
Definition AnimSkin.h:33
std::vector< int > skeletonBones
Definition AnimSkin.h:32
std::vector< float > bindPositions
Definition AnimSkin.h:30
std::vector< float > bindNormals
Definition AnimSkin.h:31
std::vector< float > vertexWeights
Definition AnimSkin.h:36