Files
vr-poser/include/MorphManager.h
2026-03-15 22:03:30 -04:00

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();
};