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