2
0
mirror of https://github.com/AxioDL/metaforce.git synced 2025-12-16 22:57:02 +00:00

Implement CVertexMorphEffect & CSkinnedModelWithAvgNormals (prev. CMorphableSkinnedModel)

This commit is contained in:
2022-03-10 18:56:50 -05:00
parent ddc34e3a0c
commit d7dbec5be0
13 changed files with 101 additions and 72 deletions

View File

@@ -36,8 +36,8 @@ void CSkinnedModel::AllocateStorage() {
}
}
void CSkinnedModel::Calculate(const CPoseAsTransforms& pose, const std::optional<CVertexMorphEffect>& morphEffect,
TConstVectorRef morphMagnitudes, SSkinningWorkspace* workspace) {
void CSkinnedModel::Calculate(const CPoseAsTransforms& pose, CVertexMorphEffect* morphEffect,
TConstVectorRef averagedNormals, SSkinningWorkspace* workspace) {
if (workspace == nullptr) {
if (x35_disableWorkspaces) {
x10_skinRules->BuildAccumulatedTransforms(pose, *x1c_layoutInfo);
@@ -52,7 +52,7 @@ void CSkinnedModel::Calculate(const CPoseAsTransforms& pose, const std::optional
x10_skinRules->BuildNormals(x4_model->GetNormals(), &workspace->m_normalWorkspace);
if (morphEffect) {
morphEffect->MorphVertices(*workspace, morphMagnitudes, x10_skinRules, pose);
morphEffect->MorphVertices(*workspace, averagedNormals, x10_skinRules, pose, x10_skinRules->GetVertexCount());
}
if (g_PointGenFunc != nullptr) {
g_PointGenFunc(*workspace);
@@ -93,13 +93,13 @@ void CSkinnedModel::DoDrawCallback(const FCustomDraw& func) const {
}
}
CMorphableSkinnedModel::CMorphableSkinnedModel(IObjectStore& store, CAssetId model, CAssetId skinRules,
CAssetId layoutInfo)
CSkinnedModelWithAvgNormals::CSkinnedModelWithAvgNormals(IObjectStore& store, CAssetId model, CAssetId skinRules,
CAssetId layoutInfo)
: CSkinnedModel(store, model, skinRules, layoutInfo) {
const auto vertexCount = GetSkinRules()->GetVertexCount();
const auto& modelPositions = *GetModel()->GetPositions();
x40_morphMagnitudes.resize(vertexCount);
x40_averagedNormals.resize(vertexCount);
std::vector<std::pair<zeus::CVector3f, std::list<u32>>> vertMap;
for (int vertIdx = 0; vertIdx < vertexCount; ++vertIdx) {
const auto curPos = modelPositions[vertIdx];
@@ -123,7 +123,7 @@ CMorphableSkinnedModel::CMorphableSkinnedModel(IObjectStore& store, CAssetId mod
}
averagedNormal.normalize();
for (const auto idx : idxs) {
x40_morphMagnitudes[idx] = averagedNormal;
x40_averagedNormals[idx] = averagedNormal;
}
}
}

View File

@@ -60,8 +60,11 @@ public:
const TLockedToken<CCharLayoutInfo>& GetLayoutInfo() const { return x1c_layoutInfo; }
void AllocateStorage();
void Calculate(const CPoseAsTransforms& pose, const std::optional<CVertexMorphEffect>& morphEffect,
TConstVectorRef averagedNormals, SSkinningWorkspace* workspace);
// Metaforce addition: Originally morphEffect is rstl::optional_object<CVertexMorphEffect>*
// This prevents constructing it as a reference to the held pointer in CPatterned, thus in
// retail it's copied in every invocation of RenderIceModelWithFlags.
void Calculate(const CPoseAsTransforms& pose, CVertexMorphEffect* morphEffect, TConstVectorRef averagedNormals,
SSkinningWorkspace* workspace);
void Draw(TConstVectorRef verts, TConstVectorRef normals, const CModelFlags& drawFlags);
void Draw(const CModelFlags& drawFlags);
void DoDrawCallback(const FCustomDraw& func) const;
@@ -71,13 +74,12 @@ public:
static FPointGenerator g_PointGenFunc;
};
class CMorphableSkinnedModel : public CSkinnedModel {
std::vector<zeus::CVector3f> x40_morphMagnitudes; // was rstl::auto_ptr<float[]>
class CSkinnedModelWithAvgNormals : public CSkinnedModel {
std::vector<zeus::CVector3f> x40_averagedNormals; // was rstl::auto_ptr<float[]>
public:
CMorphableSkinnedModel(IObjectStore& store, CAssetId model, CAssetId skinRules, CAssetId layoutInfo);
TConstVectorRef GetMorphMagnitudes() const { return &x40_morphMagnitudes; }
TVectorRef GetMorphMagnitudes() { return &x40_morphMagnitudes; }
CSkinnedModelWithAvgNormals(IObjectStore& store, CAssetId model, CAssetId skinRules, CAssetId layoutInfo);
TConstVectorRef GetAveragedNormals() const { return &x40_averagedNormals; }
};
} // namespace metaforce

View File

@@ -1,15 +1,46 @@
#include "Runtime/Graphics/CVertexMorphEffect.hpp"
#include "Runtime/Character/CSkinRules.hpp"
#include "Runtime/Graphics/CSkinnedModel.hpp"
namespace metaforce {
CVertexMorphEffect::CVertexMorphEffect(const zeus::CUnitVector3f& v1, const zeus::CVector3f& v2, float diagExtent,
float f2, CRandom16& random)
: x0_(v1), x20_diagExtent(diagExtent), x24_random(random) {}
CVertexMorphEffect::CVertexMorphEffect(const zeus::CUnitVector3f& dir, const zeus::CVector3f& pos, float duration,
float diagExtent, CRandom16& random)
: x0_dir(dir), xc_pos(pos), x18_duration(duration), x20_diagExtent(diagExtent), x24_random(random) {}
void CVertexMorphEffect::MorphVertices(SSkinningWorkspace& workspace, TConstVectorRef magnitudes,
const TLockedToken<CSkinRules>& skinRules, const CPoseAsTransforms& pose) const {
void CVertexMorphEffect::MorphVertices(SSkinningWorkspace& workspace, TConstVectorRef averagedNormals,
TLockedToken<CSkinRules>& skinRules, const CPoseAsTransforms& pose,
u32 vertexCount) {
if (x28_indices.empty()) {
std::vector<zeus::CVector3f> normalsOut;
normalsOut.reserve(vertexCount);
skinRules->BuildNormals(averagedNormals, &normalsOut);
for (int i = 0; i < vertexCount; ++i) {
float dist = normalsOut[i].dot(x0_dir);
if (dist > 0.5f) {
x28_indices.emplace_back(i);
const auto vert = workspace.m_vertexWorkspace[i];
const auto length = vert.x() + vert.y() + vert.z();
x38_floats.emplace_back((length - std::trunc(length)) * (dist - 0.5f));
}
}
}
for (int i = 0; i < x28_indices.size(); ++i) {
const auto scale = x1c_elapsed / x18_duration;
workspace.m_vertexWorkspace[x28_indices[i]] += scale * x20_diagExtent * x38_floats[i] * x0_dir;
}
}
void CVertexMorphEffect::Reset(const zeus::CVector3f& dir, const zeus::CVector3f& pos, float duration) {
x0_dir = dir;
xc_pos = pos;
x18_duration = duration;
x1c_elapsed = 0.f;
x28_indices.clear();
x38_floats.clear();
}
void CVertexMorphEffect::Update(float dt) { x1c_elapsed = std::min(x1c_elapsed + dt, x18_duration); }
} // namespace metaforce

View File

@@ -16,24 +16,22 @@ class CSkinRules;
struct SSkinningWorkspace;
class CVertexMorphEffect {
zeus::CUnitVector3f x0_;
float xc_ = 0.f;
float x10_ = 0.f;
float x14_ = 0.f;
float x18_ = 0.f;
float x1c_ = 0.f;
zeus::CUnitVector3f x0_dir;
zeus::CVector3f xc_pos;
float x18_duration;
float x1c_elapsed = 0.f;
float x20_diagExtent;
CRandom16& x24_random;
std::vector<u32> x28_;
std::vector<u32> x38_;
std::vector<u32> x28_indices;
std::vector<float> x38_floats;
public:
CVertexMorphEffect(const zeus::CUnitVector3f& v1, const zeus::CVector3f& v2, float diagExtent, float f2,
CVertexMorphEffect(const zeus::CUnitVector3f& dir, const zeus::CVector3f& pos, float duration, float diagExtent,
CRandom16& random);
void MorphVertices(SSkinningWorkspace& workspace, TConstVectorRef magnitudes,
const TLockedToken<CSkinRules>& skinRules, const CPoseAsTransforms& pose) const;
void Reset(const zeus::CVector3f& dir, const zeus::CVector3f& pos, float duration) {}
void Update(float) {}
void MorphVertices(SSkinningWorkspace& workspace, TConstVectorRef averagedNormals,
TLockedToken<CSkinRules>& skinRules, const CPoseAsTransforms& pose, u32 vertexCount);
void Reset(const zeus::CVector3f& dir, const zeus::CVector3f& pos, float duration);
void Update(float dt);
};
} // namespace metaforce