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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user