2
0
mirror of https://github.com/AxioDL/metaforce.git synced 2025-12-15 02:46:10 +00:00

Reimplement CSkinRules/CSkinnedModel; skinning kinda works!

This commit is contained in:
2022-03-10 01:33:17 -05:00
parent 8714fbf844
commit cd963c4a5c
35 changed files with 346 additions and 284 deletions

View File

@@ -31,31 +31,47 @@ CSkinRules::CSkinRules(CInputStream& in) {
x14_normalCount = ReadCount(in);
}
// void CSkinRules::TransformVerticesCPU(std::vector<std::pair<zeus::CVector3f, zeus::CVector3f>>& vnOut,
// const CPoseAsTransforms& pose, const CModel& model) const {
// OPTICK_EVENT();
// vnOut.resize(m_poolToSkinIdx.size());
// for (size_t i = 0; i < m_poolToSkinIdx.size(); ++i) {
// const CVirtualBone& vb = m_virtualBones[m_poolToSkinIdx[i]];
// zeus::CVector3f origVertex = model.GetPoolVertex(i);
// zeus::CVector3f vertex;
// zeus::CVector3f origNormal = model.GetPoolNormal(i);
// zeus::CVector3f normal;
// for (const SSkinWeighting& w : vb.GetWeights()) {
// const zeus::CTransform& xf = pose.GetRestToAccumTransform(w.m_id);
// vertex += (xf * origVertex) * w.m_weight;
// normal += (xf.basis.inverted().transposed() * origNormal) * w.m_weight;
// }
// vnOut[i] = std::make_pair(vertex, normal.normalized());
// }
// }
void CSkinRules::BuildAccumulatedTransforms(const CPoseAsTransforms& pose, const CCharLayoutInfo& info) {
std::array<zeus::CVector3f, 100> points;
CSegId segId = pose.GetLastInserted();
while (segId != 0) {
zeus::CVector3f origin;
if (segId != 3) { // root ID
origin = info.GetFromRootUnrotated(segId);
}
const auto rotatedOrigin = pose.GetRotation(segId) * origin;
points[segId] = pose.GetOffset(segId) - rotatedOrigin;
segId = pose.GetParent(segId);
}
for (auto& bone : x0_bones) {
bone.BuildAccumulatedTransform(pose, points.data());
}
}
void CSkinRules::BuildPoints(TConstVectorRef positions, TVectorRef out) {
size_t offset = 0;
for (auto& bone : x0_bones) {
u32 vertexCount = bone.GetVertexCount();
bone.BuildPoints(positions->data() + offset, out, vertexCount);
offset += vertexCount;
}
}
void CSkinRules::BuildNormals(TConstVectorRef normals, TVectorRef out) {
size_t offset = 0;
for (auto& bone : x0_bones) {
u32 vertexCount = bone.GetVertexCount();
bone.BuildNormals(normals->data() + offset, out, vertexCount);
offset += vertexCount;
}
}
CFactoryFnReturn FSkinRulesFactory(const SObjectTag& tag, CInputStream& in, const CVParamTransfer& params,
CObjectReference* selfRef) {
return TToken<CSkinRules>::GetIObjObjectFor(std::make_unique<CSkinRules>(in));
}
auto StreamInSkinWeighting(CInputStream& in) {
static inline auto StreamInSkinWeighting(CInputStream& in) {
rstl::reserved_vector<SSkinWeighting, 3> weights;
u32 weightCount = in.ReadLong();
for (int i = 0; i < std::min(3u, weightCount); ++i) {
@@ -67,6 +83,58 @@ auto StreamInSkinWeighting(CInputStream& in) {
return weights;
}
CVirtualBone::CVirtualBone(CInputStream& in)
: x0_weights(StreamInSkinWeighting(in)), x1c_vertexCount(in.ReadLong()) {}
CVirtualBone::CVirtualBone(CInputStream& in) : x0_weights(StreamInSkinWeighting(in)), x1c_vertexCount(in.ReadLong()) {}
void CVirtualBone::BuildPoints(const zeus::CVector3f* in, TVectorRef out, u32 count) const {
for (u32 i = 0; i < count; ++i) {
out->emplace_back(x20_xf * in[i]);
}
}
void CVirtualBone::BuildNormals(const zeus::CVector3f* in, TVectorRef out, u32 count) const {
for (u32 i = 0; i < count; ++i) {
out->emplace_back(x50_rotation * in[i]);
}
}
void CVirtualBone::BuildAccumulatedTransform(const CPoseAsTransforms& pose, const zeus::CVector3f* points) {
BuildFinalPosMatrix(pose, points);
x50_rotation = pose.GetRotation(x0_weights[0].x0_id);
}
static constexpr zeus::CMatrix3f WeightedMatrix(const zeus::CMatrix3f& m1, float w1, const zeus::CMatrix3f& m2, float w2) {
return {
m1[0] * w1 + m2[0] * w2,
m1[1] * w1 + m2[1] * w2,
m1[2] * w1 + m2[2] * w2,
};
}
static constexpr zeus::CVector3f WeightedVector(const zeus::CVector3f& v1, float w1, const zeus::CVector3f& v2, float w2) {
return v1 * w1 + v2 * w2;
}
void CVirtualBone::BuildFinalPosMatrix(const CPoseAsTransforms& pose, const zeus::CVector3f* points) {
if (x0_weights.size() == 1) {
const auto id = x0_weights[0].x0_id;
x20_xf = {pose.GetRotation(id), points[id]};
} else if (x0_weights.size() == 2) {
const auto w0 = x0_weights[0];
const auto w1 = x0_weights[1];
x20_xf = {
WeightedMatrix(pose.GetRotation(w0.x0_id), w0.x4_weight, pose.GetRotation(w1.x0_id), w1.x4_weight),
WeightedVector(points[w0.x0_id], w0.x4_weight, points[w1.x0_id], w1.x4_weight),
};
} else if (x0_weights.size() == 3) {
const auto w0 = x0_weights[0];
const auto w1 = x0_weights[1];
const auto w2 = x0_weights[2];
auto rot = WeightedMatrix(pose.GetRotation(w0.x0_id), w0.x4_weight, pose.GetRotation(w1.x0_id), w1.x4_weight);
auto pos = WeightedVector(points[w0.x0_id], w0.x4_weight, points[w1.x0_id], w1.x4_weight);
pose.AccumulateScaledTransform(w2.x0_id, rot, w2.x4_weight);
x20_xf = {rot, pos + points[w2.x0_id] * w2.x4_weight};
} else {
x20_xf = {};
}
}
} // namespace metaforce