84 lines
3.0 KiB
C++
84 lines
3.0 KiB
C++
#pragma once
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
#include <unordered_map>
|
|
|
|
#include <osg/ref_ptr>
|
|
#include <osg/Geometry>
|
|
#include <osg/Array>
|
|
|
|
/**
|
|
* MorphManager
|
|
* ------------
|
|
* Stores morph target data for all meshes in a loaded model and applies
|
|
* weighted blends every frame on the CPU.
|
|
*
|
|
* Usage:
|
|
* // At load time (ModelLoader calls these):
|
|
* mgr.registerMesh(geom, baseVerts, baseNormals);
|
|
* mgr.addTarget(geom, "blink", deltaVerts, deltaNormals);
|
|
*
|
|
* // Every frame (update callback calls this):
|
|
* mgr.applyWeights();
|
|
*
|
|
* // From ImGui (slider changed):
|
|
* mgr.setWeight("blink", 0.75f);
|
|
*/
|
|
class MorphManager {
|
|
public:
|
|
MorphManager() = default;
|
|
|
|
// ── Registration (called at load time) ───────────────────────────────────
|
|
|
|
/// Register a geometry's base vertex/normal arrays.
|
|
/// Must be called before addTarget() for this geometry.
|
|
void registerMesh(osg::Geometry* geom,
|
|
osg::ref_ptr<osg::Vec3Array> baseVerts,
|
|
osg::ref_ptr<osg::Vec3Array> baseNormals);
|
|
|
|
/// Add one morph target for a geometry.
|
|
/// deltaVerts/deltaNormals are OFFSETS from the base (not absolute positions).
|
|
void addTarget(osg::Geometry* geom,
|
|
const std::string& name,
|
|
osg::ref_ptr<osg::Vec3Array> deltaVerts,
|
|
osg::ref_ptr<osg::Vec3Array> deltaNormals);
|
|
|
|
// ── Weight control ───────────────────────────────────────────────────────
|
|
|
|
void setWeight(const std::string& name, float weight);
|
|
float getWeight(const std::string& name) const;
|
|
void resetAll();
|
|
|
|
/// Returns all unique morph names across all meshes, sorted.
|
|
const std::vector<std::string>& morphNames() const { return m_morphNames; }
|
|
|
|
// ── Per-frame update ─────────────────────────────────────────────────────
|
|
|
|
/// Blend all active morphs into each geometry's live vertex/normal arrays
|
|
/// and dirty them so OSG re-uploads to the GPU.
|
|
void applyWeights();
|
|
|
|
private:
|
|
// One morph target contribution for a single geometry
|
|
struct Target {
|
|
std::string name;
|
|
osg::ref_ptr<osg::Vec3Array> deltaVerts;
|
|
osg::ref_ptr<osg::Vec3Array> deltaNormals;
|
|
};
|
|
|
|
// Per-geometry morph data
|
|
struct MeshEntry {
|
|
osg::Geometry* geom = nullptr;
|
|
osg::ref_ptr<osg::Vec3Array> baseVerts;
|
|
osg::ref_ptr<osg::Vec3Array> baseNormals;
|
|
std::vector<Target> targets;
|
|
};
|
|
|
|
std::vector<MeshEntry> m_meshes;
|
|
std::unordered_map<std::string, float> m_weights; // name → 0..1
|
|
std::vector<std::string> m_morphNames; // sorted unique list
|
|
|
|
void rebuildNameList();
|
|
};
|