M1+M2: gr2 -> Skeleton3D/ArrayMesh/Skin + libgr2-driven animation
- gr2_bridge: gr2 Mat4 (row-major) -> Godot Transform3D (4x4 transpose); build_skeleton (rest from local_transform, initial_placement folded into roots), build_skin (bind i -> bone i, pose = inverse_world), build_mesh (surface per gr2 mesh, ARRAY_BONES = skeleton idx via bone_bindings, rigid meshes bound to bone_bindings[0]). - dxt: DDS DXT1/3/5 decoder ported from xrender-poc. - Metin2Model: load_gr2 -> Skeleton3D + MeshInstance3D + StandardMaterial3D (runtime DDS albedo, face/body split by surface name). Z-up cm -> Y-up m conversion on the node transform (unit_scale, flip_z, flip_winding props). - Metin2AnimPlayer: _process samples a (separate) anim .gr2 with gr2::sample_pose(model.skeleton, anim, t) -> set_bone_global_pose per bone; Godot GPU-skins via skin_matrix = global_pose(i) * bind_pose(i) == gr2 deformer matrix. selfcheck() NaN-scans all anims. Verified: warrior_cheongrin renders (75 bones, 5 surfaces, 3324 verts, textured, upright). dance01 (dur 28.3s, 74 tracks) plays, 0 NaN over 25 samples, distinct poses at t=2/9/16/23. Screenshots in test/golden/. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WaHYEY9rwLWt21PULiYjeJ
This commit is contained in:
@@ -3,14 +3,24 @@
|
||||
#include <godot_cpp/classes/node3d.hpp>
|
||||
#include <godot_cpp/variant/string.hpp>
|
||||
|
||||
#include <gr2/gr2.h>
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
namespace godot {
|
||||
class Skeleton3D;
|
||||
class MeshInstance3D;
|
||||
} // namespace godot
|
||||
|
||||
namespace mtgodot {
|
||||
|
||||
// M0' placeholder node.
|
||||
// Loads a Metin2 .gr2 and builds a Godot subtree:
|
||||
// Metin2Model (transform = Z-up/cm -> Y-up/m conversion)
|
||||
// └─ Skeleton3D (rest pose from gr2 bones)
|
||||
// └─ MeshInstance3D (ArrayMesh, one surface per gr2 mesh; skinned)
|
||||
//
|
||||
// Purpose at this milestone: prove the GDExtension registers a class the Godot
|
||||
// editor can instantiate, and that libgr2 is linked in and callable from here.
|
||||
// M1 replaces the body with real Skeleton3D / ArrayMesh construction
|
||||
// (see docs/GODOT-POC-PLAN.md §M1).
|
||||
// M1: static bind-pose render. M2's Metin2AnimPlayer drives the Skeleton3D.
|
||||
class Metin2Model : public godot::Node3D {
|
||||
GDCLASS(Metin2Model, godot::Node3D)
|
||||
|
||||
@@ -18,14 +28,55 @@ public:
|
||||
Metin2Model();
|
||||
~Metin2Model() override;
|
||||
|
||||
// One-line tag proving libgr2 symbols resolved at link time.
|
||||
godot::String libgr2_info() const;
|
||||
void _ready() override;
|
||||
|
||||
// Parse a .gr2 with libgr2 and report a couple of counts (no scene build yet).
|
||||
// --- inspector properties ---
|
||||
void set_gr2_path(const godot::String &p);
|
||||
godot::String get_gr2_path() const { return gr2_path; }
|
||||
|
||||
void set_texture_dir(const godot::String &p);
|
||||
godot::String get_texture_dir() const { return texture_dir; }
|
||||
|
||||
void set_unit_scale(double s);
|
||||
double get_unit_scale() const { return unit_scale; }
|
||||
|
||||
void set_flip_z(bool v);
|
||||
bool get_flip_z() const { return flip_z; }
|
||||
|
||||
void set_flip_winding(bool v);
|
||||
bool get_flip_winding() const { return flip_winding; }
|
||||
|
||||
// Rebuild the subtree from the current properties.
|
||||
void reload();
|
||||
|
||||
// One-line summary (bones / meshes / verts / bounds).
|
||||
godot::String get_info() const;
|
||||
|
||||
// --- C++ accessors for Metin2AnimPlayer (same extension) ---
|
||||
const gr2::Skeleton *gr2_skeleton() const;
|
||||
godot::Skeleton3D *skeleton_node() const { return skel; }
|
||||
|
||||
// libgr2 sanity probe (kept from M0').
|
||||
godot::String probe_gr2(const godot::String &path) const;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
private:
|
||||
godot::String gr2_path;
|
||||
godot::String texture_dir;
|
||||
double unit_scale = 0.01;
|
||||
bool flip_z = false;
|
||||
bool flip_winding = false;
|
||||
|
||||
std::shared_ptr<std::optional<gr2::File>> file; // shared_ptr so accessor stays valid
|
||||
godot::Skeleton3D *skel = nullptr;
|
||||
godot::MeshInstance3D *mi = nullptr;
|
||||
godot::String last_info;
|
||||
|
||||
void _clear_children();
|
||||
void _apply_materials();
|
||||
godot::String _guess_texture_dir() const;
|
||||
};
|
||||
|
||||
} // namespace mtgodot
|
||||
|
||||
Reference in New Issue
Block a user