Working on new animations
This commit is contained in:
1 parent
fe01a5d1b2
commit
52c4ad8ee0
33 files changed
+417521
-113
No files matched your search
@@ -5,11 +5,11 @@ Convert a text-based bone animation file to the BSAF binary format.
|
|||||||
Usage:
|
Usage:
|
||||||
python convert_anim_to_binary.py <input.txt> <output.bin>
|
python convert_anim_to_binary.py <input.txt> <output.bin>
|
||||||
|
|
||||||
Binary format (BSAF v1) -- all values little-endian:
|
Binary format (BSAF v2) -- all values little-endian:
|
||||||
|
|
||||||
HEADER
|
HEADER
|
||||||
4 bytes magic "BSAF"
|
4 bytes magic "BSAF"
|
||||||
uint32 version (1)
|
uint32 version (2)
|
||||||
|
|
||||||
BONES
|
BONES
|
||||||
uint32 numBones
|
uint32 numBones
|
||||||
@@ -21,6 +21,11 @@ Binary format (BSAF v1) -- all values little-endian:
|
|||||||
uint32 numChildren
|
uint32 numChildren
|
||||||
numChildren x int32 childIndices
|
numChildren x int32 childIndices
|
||||||
|
|
||||||
|
BONE NAMES (v2+)
|
||||||
|
per bone:
|
||||||
|
uint32 nameLen
|
||||||
|
nameLen bytes UTF-8 name (no terminator)
|
||||||
|
|
||||||
VERTICES
|
VERTICES
|
||||||
uint32 numVertices
|
uint32 numVertices
|
||||||
numVertices x 3 x float positions
|
numVertices x 3 x float positions
|
||||||
@@ -248,7 +253,7 @@ def convert(input_path, output_path):
|
|||||||
with open(output_path, 'wb') as out:
|
with open(output_path, 'wb') as out:
|
||||||
# Header
|
# Header
|
||||||
out.write(b'BSAF')
|
out.write(b'BSAF')
|
||||||
out.write(struct.pack('<I', 1))
|
out.write(struct.pack('<I', 2))
|
||||||
|
|
||||||
# Bones
|
# Bones
|
||||||
out.write(struct.pack('<I', num_bones))
|
out.write(struct.pack('<I', num_bones))
|
||||||
@@ -262,6 +267,12 @@ def convert(input_path, output_path):
|
|||||||
for c in b['children']:
|
for c in b['children']:
|
||||||
out.write(struct.pack('<i', c))
|
out.write(struct.pack('<i', c))
|
||||||
|
|
||||||
|
# Bone names (v2+)
|
||||||
|
for name in bone_names:
|
||||||
|
name_bytes = name.encode('utf-8')
|
||||||
|
out.write(struct.pack('<I', len(name_bytes)))
|
||||||
|
out.write(name_bytes)
|
||||||
|
|
||||||
# Vertices
|
# Vertices
|
||||||
out.write(struct.pack('<I', num_vertices))
|
out.write(struct.pack('<I', num_vertices))
|
||||||
for v in vertices:
|
for v in vertices:
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,64 @@
|
|||||||
|
===Vertices (Split by UV/Normal): 41
|
||||||
|
V 0: Pos(0.02, 0.15, 0.0) Norm(0.577338, 0.577356, -0.577357) UV(0.77503, 0.750033)
|
||||||
|
V 1: Pos(-0.02, -0.15, 0.0) Norm(-0.577338, -0.577356, -0.577357) UV(0.808365, 0.500022)
|
||||||
|
V 2: Pos(-0.02, 0.15, 0.0) Norm(-0.577347, 0.577357, -0.577347) UV(0.808365, 0.750033)
|
||||||
|
V 3: Pos(0.02, -0.15, 0.6) Norm(0.577338, -0.577356, 0.577357) UV(0.866701, 0.496276)
|
||||||
|
V 4: Pos(-0.02, 0.15, 0.6) Norm(-0.577338, 0.577356, 0.577357) UV(0.833366, 0.746287)
|
||||||
|
V 5: Pos(-0.02, -0.15, 0.6) Norm(-0.577347, -0.577357, 0.577347) UV(0.833366, 0.496276)
|
||||||
|
V 6: Pos(0.02, -0.15, 0.0) Norm(0.577347, -0.577357, -0.577347) UV(0.833366, 0.496276)
|
||||||
|
V 7: Pos(-0.02, -0.15, 0.6) Norm(-0.577347, -0.577357, 0.577347) UV(0.866701, 0.0)
|
||||||
|
V 8: Pos(-0.02, -0.15, 0.0) Norm(-0.577338, -0.577356, -0.577357) UV(0.866701, 0.496276)
|
||||||
|
V 9: Pos(0.02, 0.15, 0.0) Norm(0.577338, 0.577356, -0.577357) UV(0.500022, 0.5)
|
||||||
|
V 10: Pos(0.02, -0.15, 0.6) Norm(0.577338, -0.577356, 0.577357) UV(0.750033, 0.0)
|
||||||
|
V 11: Pos(0.02, -0.15, 0.0) Norm(0.577347, -0.577357, -0.577347) UV(0.750033, 0.5)
|
||||||
|
V 12: Pos(-0.02, 0.15, 0.0) Norm(-0.577347, 0.577357, -0.577347) UV(0.77503, 0.500022)
|
||||||
|
V 13: Pos(0.02, 0.15, 0.6) Norm(0.577347, 0.577357, 0.577347) UV(0.808365, 0.0)
|
||||||
|
V 14: Pos(0.02, 0.15, 0.0) Norm(0.577338, 0.577356, -0.577357) UV(0.808365, 0.500022)
|
||||||
|
V 15: Pos(-0.02, -0.15, 0.0) Norm(-0.577338, -0.577356, -0.577357) UV(0.500022, 1.0)
|
||||||
|
V 16: Pos(-0.02, 0.15, 0.6) Norm(-0.577338, 0.577356, 0.577357) UV(0.750033, 0.5)
|
||||||
|
V 17: Pos(-0.02, 0.15, 0.0) Norm(-0.577347, 0.577357, -0.577347) UV(0.750033, 1.0)
|
||||||
|
V 18: Pos(0.015, 0.15, 0.6) Norm(0.583227, 0.576373, -0.572398) UV(0.8667, 0.250011)
|
||||||
|
V 19: Pos(-0.015, -0.15, 0.6) Norm(-0.570792, -0.648582, -0.503526) UV(0.891702, 0.0)
|
||||||
|
V 20: Pos(-0.015, 0.15, 0.6) Norm(-0.583229, 0.576375, -0.572394) UV(0.891702, 0.250011)
|
||||||
|
V 21: Pos(0.0, 0.05, 1.4) Norm(0.0, -0.417006, 0.908904) UV(0.166674, 0.0)
|
||||||
|
V 22: Pos(-0.015, 0.15, 0.6) Norm(-0.583229, 0.576375, -0.572394) UV(0.250011, 0.666784)
|
||||||
|
V 23: Pos(-0.015, -0.15, 0.6) Norm(-0.570792, -0.648582, -0.503526) UV(0.0, 0.666784)
|
||||||
|
V 24: Pos(0.015, 0.15, 0.6) Norm(0.583227, 0.576373, -0.572398) UV(0.250011, 0.666784)
|
||||||
|
V 25: Pos(0.0, 0.05, 1.4) Norm(0.0, -0.417006, 0.908904) UV(0.333348, 0.0)
|
||||||
|
V 26: Pos(0.015, -0.15, 0.6) Norm(0.570794, -0.648585, -0.50352) UV(0.500022, 0.666784)
|
||||||
|
V 27: Pos(-0.015, -0.15, 0.6) Norm(-0.570792, -0.648582, -0.503526) UV(0.77503, 0.68218)
|
||||||
|
V 28: Pos(0.015, -0.15, 0.6) Norm(0.570794, -0.648585, -0.50352) UV(0.750033, 0.681722)
|
||||||
|
V 29: Pos(0.0, 0.05, 1.4) Norm(0.0, -0.417006, 0.908904) UV(0.77503, 0.0)
|
||||||
|
V 30: Pos(-0.015, 0.15, 0.6) Norm(-0.583229, 0.576375, -0.572394) UV(0.808365, 0.666696)
|
||||||
|
V 31: Pos(0.0, 0.15, 1.4) Norm(0.0, 0.536928, 0.843628) UV(0.820865, 0.0)
|
||||||
|
V 32: Pos(0.015, 0.15, 0.6) Norm(0.583227, 0.576373, -0.572398) UV(0.833366, 0.666696)
|
||||||
|
V 33: Pos(0.02, -0.15, 0.0) Norm(0.577347, -0.577357, -0.577347) UV(0.77503, 0.500022)
|
||||||
|
V 34: Pos(0.02, 0.15, 0.6) Norm(0.577347, 0.577357, 0.577347) UV(0.866701, 0.746287)
|
||||||
|
V 35: Pos(0.02, -0.15, 0.6) Norm(0.577338, -0.577356, 0.577357) UV(0.833366, 0.0)
|
||||||
|
V 36: Pos(0.02, 0.15, 0.6) Norm(0.577347, 0.577357, 0.577347) UV(0.500022, 0.0)
|
||||||
|
V 37: Pos(-0.02, 0.15, 0.6) Norm(-0.577338, 0.577356, 0.577357) UV(0.77503, 0.0)
|
||||||
|
V 38: Pos(-0.02, -0.15, 0.6) Norm(-0.577347, -0.577357, 0.577347) UV(0.500022, 0.5)
|
||||||
|
V 39: Pos(0.015, -0.15, 0.6) Norm(0.570794, -0.648585, -0.50352) UV(0.8667, 0.0)
|
||||||
|
V 40: Pos(0.0, 0.15, 1.4) Norm(0.0, 0.536928, 0.843628) UV(0.250011, 0.0)
|
||||||
|
|
||||||
|
===Triangles (Indices): 20
|
||||||
|
Tri: 0 1 2
|
||||||
|
Tri: 3 4 5
|
||||||
|
Tri: 6 7 8
|
||||||
|
Tri: 9 10 11
|
||||||
|
Tri: 12 13 14
|
||||||
|
Tri: 15 16 17
|
||||||
|
Tri: 18 19 20
|
||||||
|
Tri: 21 22 23
|
||||||
|
Tri: 24 25 26
|
||||||
|
Tri: 27 28 29
|
||||||
|
Tri: 30 31 32
|
||||||
|
Tri: 0 33 1
|
||||||
|
Tri: 3 34 4
|
||||||
|
Tri: 6 35 7
|
||||||
|
Tri: 9 36 10
|
||||||
|
Tri: 12 37 13
|
||||||
|
Tri: 15 38 16
|
||||||
|
Tri: 18 39 19
|
||||||
|
Tri: 21 40 22
|
||||||
|
Tri: 24 40 25
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
===Vertices (Split by UV/Normal): 41
|
||||||
|
V 0: Pos(0.02, 0.15, 0.0) Norm(0.577338, 0.577356, -0.577357) UV(0.77503, 0.750033)
|
||||||
|
V 1: Pos(-0.02, -0.15, 0.0) Norm(-0.577338, -0.577356, -0.577357) UV(0.808365, 0.500022)
|
||||||
|
V 2: Pos(-0.02, 0.15, 0.0) Norm(-0.577347, 0.577357, -0.577347) UV(0.808365, 0.750033)
|
||||||
|
V 3: Pos(0.02, -0.15, 0.6) Norm(0.577338, -0.577356, 0.577357) UV(0.866701, 0.496276)
|
||||||
|
V 4: Pos(-0.02, 0.15, 0.6) Norm(-0.577338, 0.577356, 0.577357) UV(0.833366, 0.746287)
|
||||||
|
V 5: Pos(-0.02, -0.15, 0.6) Norm(-0.577347, -0.577357, 0.577347) UV(0.833366, 0.496276)
|
||||||
|
V 6: Pos(0.02, -0.15, 0.0) Norm(0.577347, -0.577357, -0.577347) UV(0.833366, 0.496276)
|
||||||
|
V 7: Pos(-0.02, -0.15, 0.6) Norm(-0.577347, -0.577357, 0.577347) UV(0.866701, 0.0)
|
||||||
|
V 8: Pos(-0.02, -0.15, 0.0) Norm(-0.577338, -0.577356, -0.577357) UV(0.866701, 0.496276)
|
||||||
|
V 9: Pos(0.02, 0.15, 0.0) Norm(0.577338, 0.577356, -0.577357) UV(0.500022, 0.5)
|
||||||
|
V 10: Pos(0.02, -0.15, 0.6) Norm(0.577338, -0.577356, 0.577357) UV(0.750033, 0.0)
|
||||||
|
V 11: Pos(0.02, -0.15, 0.0) Norm(0.577347, -0.577357, -0.577347) UV(0.750033, 0.5)
|
||||||
|
V 12: Pos(-0.02, 0.15, 0.0) Norm(-0.577347, 0.577357, -0.577347) UV(0.77503, 0.500022)
|
||||||
|
V 13: Pos(0.02, 0.15, 0.6) Norm(0.577347, 0.577357, 0.577347) UV(0.808365, 0.0)
|
||||||
|
V 14: Pos(0.02, 0.15, 0.0) Norm(0.577338, 0.577356, -0.577357) UV(0.808365, 0.500022)
|
||||||
|
V 15: Pos(-0.02, -0.15, 0.0) Norm(-0.577338, -0.577356, -0.577357) UV(0.500022, 1.0)
|
||||||
|
V 16: Pos(-0.02, 0.15, 0.6) Norm(-0.577338, 0.577356, 0.577357) UV(0.750033, 0.5)
|
||||||
|
V 17: Pos(-0.02, 0.15, 0.0) Norm(-0.577347, 0.577357, -0.577347) UV(0.750033, 1.0)
|
||||||
|
V 18: Pos(0.015, 0.15, 0.6) Norm(0.583227, 0.576373, -0.572398) UV(0.8667, 0.250011)
|
||||||
|
V 19: Pos(-0.015, -0.15, 0.6) Norm(-0.570792, -0.648582, -0.503526) UV(0.891702, 0.0)
|
||||||
|
V 20: Pos(-0.015, 0.15, 0.6) Norm(-0.583229, 0.576375, -0.572394) UV(0.891702, 0.250011)
|
||||||
|
V 21: Pos(0.0, 0.05, 1.4) Norm(0.0, -0.417006, 0.908904) UV(0.166674, 0.0)
|
||||||
|
V 22: Pos(-0.015, 0.15, 0.6) Norm(-0.583229, 0.576375, -0.572394) UV(0.250011, 0.666784)
|
||||||
|
V 23: Pos(-0.015, -0.15, 0.6) Norm(-0.570792, -0.648582, -0.503526) UV(0.0, 0.666784)
|
||||||
|
V 24: Pos(0.015, 0.15, 0.6) Norm(0.583227, 0.576373, -0.572398) UV(0.250011, 0.666784)
|
||||||
|
V 25: Pos(0.0, 0.05, 1.4) Norm(0.0, -0.417006, 0.908904) UV(0.333348, 0.0)
|
||||||
|
V 26: Pos(0.015, -0.15, 0.6) Norm(0.570794, -0.648585, -0.50352) UV(0.500022, 0.666784)
|
||||||
|
V 27: Pos(-0.015, -0.15, 0.6) Norm(-0.570792, -0.648582, -0.503526) UV(0.77503, 0.68218)
|
||||||
|
V 28: Pos(0.015, -0.15, 0.6) Norm(0.570794, -0.648585, -0.50352) UV(0.750033, 0.681722)
|
||||||
|
V 29: Pos(0.0, 0.05, 1.4) Norm(0.0, -0.417006, 0.908904) UV(0.77503, 0.0)
|
||||||
|
V 30: Pos(-0.015, 0.15, 0.6) Norm(-0.583229, 0.576375, -0.572394) UV(0.808365, 0.666696)
|
||||||
|
V 31: Pos(0.0, 0.15, 1.4) Norm(0.0, 0.536928, 0.843628) UV(0.820865, 0.0)
|
||||||
|
V 32: Pos(0.015, 0.15, 0.6) Norm(0.583227, 0.576373, -0.572398) UV(0.833366, 0.666696)
|
||||||
|
V 33: Pos(0.02, -0.15, 0.0) Norm(0.577347, -0.577357, -0.577347) UV(0.77503, 0.500022)
|
||||||
|
V 34: Pos(0.02, 0.15, 0.6) Norm(0.577347, 0.577357, 0.577347) UV(0.866701, 0.746287)
|
||||||
|
V 35: Pos(0.02, -0.15, 0.6) Norm(0.577338, -0.577356, 0.577357) UV(0.833366, 0.0)
|
||||||
|
V 36: Pos(0.02, 0.15, 0.6) Norm(0.577347, 0.577357, 0.577347) UV(0.500022, 0.0)
|
||||||
|
V 37: Pos(-0.02, 0.15, 0.6) Norm(-0.577338, 0.577356, 0.577357) UV(0.77503, 0.0)
|
||||||
|
V 38: Pos(-0.02, -0.15, 0.6) Norm(-0.577347, -0.577357, 0.577347) UV(0.500022, 0.5)
|
||||||
|
V 39: Pos(0.015, -0.15, 0.6) Norm(0.570794, -0.648585, -0.50352) UV(0.8667, 0.0)
|
||||||
|
V 40: Pos(0.0, 0.15, 1.4) Norm(0.0, 0.536928, 0.843628) UV(0.250011, 0.0)
|
||||||
|
|
||||||
|
===Triangles (Indices): 20
|
||||||
|
Tri: 0 1 2
|
||||||
|
Tri: 3 4 5
|
||||||
|
Tri: 6 7 8
|
||||||
|
Tri: 9 10 11
|
||||||
|
Tri: 12 13 14
|
||||||
|
Tri: 15 16 17
|
||||||
|
Tri: 18 19 20
|
||||||
|
Tri: 21 22 23
|
||||||
|
Tri: 24 25 26
|
||||||
|
Tri: 27 28 29
|
||||||
|
Tri: 30 31 32
|
||||||
|
Tri: 0 33 1
|
||||||
|
Tri: 3 34 4
|
||||||
|
Tri: 6 35 7
|
||||||
|
Tri: 9 36 10
|
||||||
|
Tri: 12 37 13
|
||||||
|
Tri: 15 38 16
|
||||||
|
Tri: 18 39 19
|
||||||
|
Tri: 21 40 22
|
||||||
|
Tri: 24 40 25
|
||||||
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
File diff suppressed because it is too large.
Load diff
Binary file not shown.
File diff suppressed because it is too large.
Load diff
BIN
Binary file not shown.
@@ -211,6 +211,7 @@ namespace ZL
|
|||||||
|
|
||||||
startBones = bones;
|
startBones = bones;
|
||||||
currentBones = bones;
|
currentBones = bones;
|
||||||
|
this->boneNames = boneNames;
|
||||||
|
|
||||||
std::getline(f, tempLine); //vertice count
|
std::getline(f, tempLine); //vertice count
|
||||||
int numberVertices;
|
int numberVertices;
|
||||||
@@ -597,7 +598,7 @@ namespace ZL
|
|||||||
if (std::memcmp(magic, "BSAF", 4) != 0)
|
if (std::memcmp(magic, "BSAF", 4) != 0)
|
||||||
throw std::runtime_error("Invalid binary animation file (bad magic)");
|
throw std::runtime_error("Invalid binary animation file (bad magic)");
|
||||||
uint32_t version = readUint32();
|
uint32_t version = readUint32();
|
||||||
if (version != 1)
|
if (version != 2)
|
||||||
throw std::runtime_error("Unsupported binary animation file version");
|
throw std::runtime_error("Unsupported binary animation file version");
|
||||||
|
|
||||||
// ---- Bones ----
|
// ---- Bones ----
|
||||||
@@ -630,6 +631,15 @@ namespace ZL
|
|||||||
startBones = bones;
|
startBones = bones;
|
||||||
currentBones = bones;
|
currentBones = bones;
|
||||||
|
|
||||||
|
// ---- Bone names ----
|
||||||
|
boneNames.resize(numBones);
|
||||||
|
for (uint32_t i = 0; i < numBones; i++)
|
||||||
|
{
|
||||||
|
uint32_t nameLen = readUint32();
|
||||||
|
boneNames[i].resize(nameLen);
|
||||||
|
if (nameLen > 0) readRaw(&boneNames[i][0], nameLen);
|
||||||
|
}
|
||||||
|
|
||||||
// ---- Vertices ----
|
// ---- Vertices ----
|
||||||
uint32_t numVertices = readUint32();
|
uint32_t numVertices = readUint32();
|
||||||
std::vector<Vector3f> vertices(numVertices);
|
std::vector<Vector3f> vertices(numVertices);
|
||||||
@@ -728,6 +738,15 @@ namespace ZL
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int BoneSystem::findBoneIndex(const std::string& name) const
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < boneNames.size(); i++)
|
||||||
|
{
|
||||||
|
if (boneNames[i] == name) return static_cast<int>(i);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
void GpuBoneData::PrepareGpuSkinningData(const std::vector<std::array<BoneWeight, MAX_BONE_COUNT>>& verticesBoneWeight)
|
void GpuBoneData::PrepareGpuSkinningData(const std::vector<std::array<BoneWeight, MAX_BONE_COUNT>>& verticesBoneWeight)
|
||||||
{
|
{
|
||||||
size_t vertexCount = verticesBoneWeight.size();
|
size_t vertexCount = verticesBoneWeight.size();
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ namespace ZL
|
|||||||
|
|
||||||
std::vector<Bone> startBones;
|
std::vector<Bone> startBones;
|
||||||
std::vector<Bone> currentBones;
|
std::vector<Bone> currentBones;
|
||||||
|
std::vector<std::string> boneNames;
|
||||||
|
|
||||||
std::vector<Animation> animations;
|
std::vector<Animation> animations;
|
||||||
int startingFrame = 0;
|
int startingFrame = 0;
|
||||||
@@ -62,6 +63,8 @@ namespace ZL
|
|||||||
|
|
||||||
void Interpolate(int frame);
|
void Interpolate(int frame);
|
||||||
|
|
||||||
|
int findBoneIndex(const std::string& name) const;
|
||||||
|
|
||||||
// GPU skinning: compute skinning matrices without modifying the mesh
|
// GPU skinning: compute skinning matrices without modifying the mesh
|
||||||
//void ComputeSkinningMatrices(int frame, std::vector<Matrix4f>& outMatrices) const;
|
//void ComputeSkinningMatrices(int frame, std::vector<Matrix4f>& outMatrices) const;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,870 @@
|
|||||||
|
#include "BoneAnimatedModelNew.h"
|
||||||
|
#include <regex>
|
||||||
|
#include <string>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
namespace ZL
|
||||||
|
{
|
||||||
|
#ifdef EMSCRIPTEN
|
||||||
|
using std::min;
|
||||||
|
using std::max;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern int getIndexByValue(const std::string& name, const std::vector<std::string>& words);
|
||||||
|
|
||||||
|
static std::string trimRight(const std::string& s)
|
||||||
|
{
|
||||||
|
size_t end = s.size();
|
||||||
|
while (end > 0 && (s[end - 1] == '\r' || s[end - 1] == '\n' || s[end - 1] == ' ' || s[end - 1] == '\t'))
|
||||||
|
end--;
|
||||||
|
return s.substr(0, end);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoneSystemNew::LoadFromFile(const std::string& fileName, const std::string& ZIPFileName)
|
||||||
|
{
|
||||||
|
std::ifstream filestream;
|
||||||
|
std::istringstream zipStream;
|
||||||
|
|
||||||
|
if (!ZIPFileName.empty())
|
||||||
|
{
|
||||||
|
std::vector<char> fileData = readFileFromZIP(fileName, ZIPFileName);
|
||||||
|
std::string fileContents(fileData.begin(), fileData.end());
|
||||||
|
zipStream.str(fileContents);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
filestream.open(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::istream& f = (!ZIPFileName.empty()) ? static_cast<std::istream&>(zipStream) : static_cast<std::istream&>(filestream);
|
||||||
|
|
||||||
|
static const std::regex pattern_count(R"(\d+)");
|
||||||
|
static const std::regex pattern_float(R"([-]?\d+\.\d+)");
|
||||||
|
static const std::regex pattern_int(R"([-]?\d+)");
|
||||||
|
static const std::regex pattern_boneChildren(R"(\'([^\']+)\')");
|
||||||
|
static const std::regex pattern_bone_weight(R"(\'([^\']+)\'.*?([-]?\d+\.\d+))");
|
||||||
|
|
||||||
|
std::smatch match;
|
||||||
|
std::string tempLine;
|
||||||
|
|
||||||
|
// ---- Armature matrix (4 lines after the header) ----
|
||||||
|
std::getline(f, tempLine); // === Armature Matrix ===
|
||||||
|
armatureMatrix = Matrix4f::Identity();
|
||||||
|
for (int r = 0; r < 4; r++)
|
||||||
|
{
|
||||||
|
std::getline(f, tempLine);
|
||||||
|
std::vector<float> floatValues;
|
||||||
|
auto b = tempLine.cbegin();
|
||||||
|
auto e = tempLine.cend();
|
||||||
|
while (std::regex_search(b, e, match, pattern_float)) {
|
||||||
|
floatValues.push_back(std::stof(match.str()));
|
||||||
|
b = match.suffix().first;
|
||||||
|
}
|
||||||
|
if (floatValues.size() >= 4)
|
||||||
|
{
|
||||||
|
for (int c = 0; c < 4; c++)
|
||||||
|
armatureMatrix.data()[r + c * 4] = floatValues[c];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Bones ----
|
||||||
|
std::getline(f, tempLine); // === Armature Bones: N
|
||||||
|
int numberBones;
|
||||||
|
if (std::regex_search(tempLine, match, pattern_count)) {
|
||||||
|
numberBones = std::stoi(match.str());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw std::runtime_error("Armature bones count not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Bone> bones;
|
||||||
|
std::vector<std::string> boneNames;
|
||||||
|
std::vector<std::string> boneParentNames;
|
||||||
|
std::unordered_map<std::string, std::vector<std::string>> boneChildren;
|
||||||
|
|
||||||
|
bones.resize(numberBones);
|
||||||
|
boneNames.resize(numberBones);
|
||||||
|
boneParentNames.resize(numberBones);
|
||||||
|
|
||||||
|
for (int i = 0; i < numberBones; i++)
|
||||||
|
{
|
||||||
|
std::getline(f, tempLine); // Bone: name
|
||||||
|
std::string boneName = trimRight(tempLine.substr(6));
|
||||||
|
boneNames[i] = boneName;
|
||||||
|
|
||||||
|
std::getline(f, tempLine); // HEAD_LOCAL
|
||||||
|
std::vector<float> floatValues;
|
||||||
|
auto b = tempLine.cbegin();
|
||||||
|
auto e = tempLine.cend();
|
||||||
|
while (std::regex_search(b, e, match, pattern_float)) {
|
||||||
|
floatValues.push_back(std::stof(match.str()));
|
||||||
|
b = match.suffix().first;
|
||||||
|
}
|
||||||
|
bones[i].boneStartWorld = Vector3f{ floatValues[0], floatValues[1], floatValues[2] };
|
||||||
|
|
||||||
|
std::getline(f, tempLine); // TAIL_LOCAL
|
||||||
|
|
||||||
|
std::getline(f, tempLine); // Length
|
||||||
|
if (std::regex_search(tempLine, match, pattern_float)) {
|
||||||
|
bones[i].boneLength = std::stof(match.str());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw std::runtime_error("Bone length not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3x3 matrix
|
||||||
|
for (int r = 0; r < 3; r++)
|
||||||
|
{
|
||||||
|
std::getline(f, tempLine);
|
||||||
|
b = tempLine.cbegin();
|
||||||
|
e = tempLine.cend();
|
||||||
|
floatValues.clear();
|
||||||
|
while (std::regex_search(b, e, match, pattern_float)) {
|
||||||
|
floatValues.push_back(std::stof(match.str()));
|
||||||
|
b = match.suffix().first;
|
||||||
|
}
|
||||||
|
bones[i].boneMatrixWorld.data()[r] = floatValues[0];
|
||||||
|
bones[i].boneMatrixWorld.data()[r + 1 * 3] = floatValues[1];
|
||||||
|
bones[i].boneMatrixWorld.data()[r + 2 * 3] = floatValues[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::getline(f, tempLine); // Parent
|
||||||
|
std::string parentLine = trimRight(tempLine);
|
||||||
|
if (parentLine == " Parent: None")
|
||||||
|
{
|
||||||
|
bones[i].parent = -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
boneParentNames[i] = parentLine.substr(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::getline(f, tempLine); // Children
|
||||||
|
auto bc = tempLine.cbegin();
|
||||||
|
auto ec = tempLine.cend();
|
||||||
|
while (std::regex_search(bc, ec, match, pattern_boneChildren)) {
|
||||||
|
boneChildren[boneName].push_back(match.str(1));
|
||||||
|
bc = match.suffix().first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resolve parent/child indices
|
||||||
|
for (int i = 0; i < numberBones; i++)
|
||||||
|
{
|
||||||
|
const std::string& boneName = boneNames[i];
|
||||||
|
const std::string& boneParent = boneParentNames[i];
|
||||||
|
if (boneParent == "" || boneParent == "None")
|
||||||
|
bones[i].parent = -1;
|
||||||
|
else
|
||||||
|
bones[i].parent = getIndexByValue(boneParent, boneNames);
|
||||||
|
|
||||||
|
for (size_t j = 0; j < boneChildren[boneName].size(); j++)
|
||||||
|
bones[i].children.push_back(getIndexByValue(boneChildren[boneName][j], boneNames));
|
||||||
|
}
|
||||||
|
|
||||||
|
startBones = bones;
|
||||||
|
currentBones = bones;
|
||||||
|
|
||||||
|
// ---- Multi-mesh header ----
|
||||||
|
std::getline(f, tempLine); // === TOTAL MESHES TO EXPORT: N ===
|
||||||
|
int numberMeshes;
|
||||||
|
if (std::regex_search(tempLine, match, pattern_count)) {
|
||||||
|
numberMeshes = std::stoi(match.str());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw std::runtime_error("Total meshes count not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int meshIdx = 0; meshIdx < numberMeshes; meshIdx++)
|
||||||
|
{
|
||||||
|
// === Mesh Object: Name ===
|
||||||
|
std::getline(f, tempLine);
|
||||||
|
std::string meshHeader = trimRight(tempLine);
|
||||||
|
// Extract mesh name: strip "=== Mesh Object: " prefix and " ===" suffix
|
||||||
|
const std::string prefix = "=== Mesh Object: ";
|
||||||
|
const std::string suffix = " ===";
|
||||||
|
std::string meshName;
|
||||||
|
if (meshHeader.size() >= prefix.size() + suffix.size() &&
|
||||||
|
meshHeader.compare(0, prefix.size(), prefix) == 0 &&
|
||||||
|
meshHeader.compare(meshHeader.size() - suffix.size(), suffix.size(), suffix) == 0)
|
||||||
|
{
|
||||||
|
meshName = meshHeader.substr(prefix.size(),
|
||||||
|
meshHeader.size() - prefix.size() - suffix.size());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Invalid mesh header: " + meshHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
MeshBoneData meshData;
|
||||||
|
|
||||||
|
// Vertices
|
||||||
|
std::getline(f, tempLine); // ===Vertices: N
|
||||||
|
int numberVertices;
|
||||||
|
if (std::regex_search(tempLine, match, pattern_count)) {
|
||||||
|
numberVertices = std::stoi(match.str());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw std::runtime_error("Vertex count not found for mesh " + meshName);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Vector3f> vertices(numberVertices);
|
||||||
|
for (int i = 0; i < numberVertices; i++)
|
||||||
|
{
|
||||||
|
std::getline(f, tempLine);
|
||||||
|
std::vector<float> floatValues;
|
||||||
|
auto b = tempLine.cbegin();
|
||||||
|
auto e = tempLine.cend();
|
||||||
|
while (std::regex_search(b, e, match, pattern_float)) {
|
||||||
|
floatValues.push_back(std::stof(match.str()));
|
||||||
|
b = match.suffix().first;
|
||||||
|
}
|
||||||
|
vertices[i] = Vector3f{ floatValues[0], floatValues[1], floatValues[2] };
|
||||||
|
}
|
||||||
|
|
||||||
|
// UV coordinates
|
||||||
|
std::getline(f, tempLine); // ===UV Coordinates:
|
||||||
|
std::getline(f, tempLine); // Face count: M
|
||||||
|
int numberFaces;
|
||||||
|
if (std::regex_search(tempLine, match, pattern_count)) {
|
||||||
|
numberFaces = std::stoi(match.str());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw std::runtime_error("Face count not found for mesh " + meshName);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::array<Vector2f, 3>> uvCoords(numberFaces);
|
||||||
|
for (int i = 0; i < numberFaces; i++)
|
||||||
|
{
|
||||||
|
std::getline(f, tempLine); // Face X
|
||||||
|
std::getline(f, tempLine); // UV Count: 3
|
||||||
|
int uvCount;
|
||||||
|
if (std::regex_search(tempLine, match, pattern_count)) {
|
||||||
|
uvCount = std::stoi(match.str());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw std::runtime_error("UV count not found");
|
||||||
|
}
|
||||||
|
if (uvCount != 3)
|
||||||
|
throw std::runtime_error("more than 3 uvs");
|
||||||
|
|
||||||
|
for (int j = 0; j < 3; j++)
|
||||||
|
{
|
||||||
|
std::getline(f, tempLine); // UV <Vector (u, v)>
|
||||||
|
std::vector<float> floatValues;
|
||||||
|
auto b = tempLine.cbegin();
|
||||||
|
auto e = tempLine.cend();
|
||||||
|
while (std::regex_search(b, e, match, pattern_float)) {
|
||||||
|
floatValues.push_back(std::stof(match.str()));
|
||||||
|
b = match.suffix().first;
|
||||||
|
}
|
||||||
|
if (floatValues.size() != 2)
|
||||||
|
throw std::runtime_error("more than 2 uvs---");
|
||||||
|
uvCoords[i][j] = Vector2f{ floatValues[0], floatValues[1] };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Normals
|
||||||
|
std::getline(f, tempLine); // ===Normals:
|
||||||
|
std::vector<Vector3f> normals(numberVertices);
|
||||||
|
for (int i = 0; i < numberVertices; i++)
|
||||||
|
{
|
||||||
|
std::getline(f, tempLine);
|
||||||
|
std::vector<float> floatValues;
|
||||||
|
auto b = tempLine.cbegin();
|
||||||
|
auto e = tempLine.cend();
|
||||||
|
while (std::regex_search(b, e, match, pattern_float)) {
|
||||||
|
floatValues.push_back(std::stof(match.str()));
|
||||||
|
b = match.suffix().first;
|
||||||
|
}
|
||||||
|
normals[i] = Vector3f{ floatValues[0], floatValues[1], floatValues[2] };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Triangles
|
||||||
|
std::getline(f, tempLine); // ===Triangles: M
|
||||||
|
int numberTriangles;
|
||||||
|
if (std::regex_search(tempLine, match, pattern_count)) {
|
||||||
|
numberTriangles = std::stoi(match.str());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw std::runtime_error("Triangle count not found for mesh " + meshName);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::array<int, 3>> triangles(numberTriangles);
|
||||||
|
for (int i = 0; i < numberTriangles; i++)
|
||||||
|
{
|
||||||
|
std::getline(f, tempLine);
|
||||||
|
std::vector<int> intValues;
|
||||||
|
auto b = tempLine.cbegin();
|
||||||
|
auto e = tempLine.cend();
|
||||||
|
while (std::regex_search(b, e, match, pattern_int)) {
|
||||||
|
intValues.push_back(std::stoi(match.str()));
|
||||||
|
b = match.suffix().first;
|
||||||
|
}
|
||||||
|
triangles[i] = { intValues[0], intValues[1], intValues[2] };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Vertex weights
|
||||||
|
std::getline(f, tempLine); // === Vertex Weights (Max 5 bones per vertex) ===
|
||||||
|
std::vector<std::array<BoneWeight, MAX_BONE_COUNT>> localVerticesBoneWeight(numberVertices);
|
||||||
|
for (int i = 0; i < numberVertices; i++)
|
||||||
|
{
|
||||||
|
std::getline(f, tempLine); // Vertex X:
|
||||||
|
std::getline(f, tempLine); // Vertex groups: K
|
||||||
|
int boneCount;
|
||||||
|
if (std::regex_search(tempLine, match, pattern_count)) {
|
||||||
|
boneCount = std::stoi(match.str());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw std::runtime_error("Vertex group count not found");
|
||||||
|
}
|
||||||
|
if (boneCount > MAX_BONE_COUNT)
|
||||||
|
throw std::runtime_error("more than 5 bones");
|
||||||
|
|
||||||
|
float sumWeights = 0;
|
||||||
|
for (int j = 0; j < boneCount; j++)
|
||||||
|
{
|
||||||
|
std::getline(f, tempLine);
|
||||||
|
if (std::regex_search(tempLine, match, pattern_bone_weight)) {
|
||||||
|
std::string word = match.str(1);
|
||||||
|
double weight = std::stod(match.str(2));
|
||||||
|
int boneNumber = getIndexByValue(word, boneNames);
|
||||||
|
localVerticesBoneWeight[i][j].boneIndex = boneNumber;
|
||||||
|
localVerticesBoneWeight[i][j].weight = static_cast<float>(weight);
|
||||||
|
sumWeights += static_cast<float>(weight);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw std::runtime_error("No match found in bone weight line");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int j = 0; j < boneCount; j++)
|
||||||
|
localVerticesBoneWeight[i][j].weight /= sumWeights;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build per-triangle expanded mesh
|
||||||
|
for (int i = 0; i < numberTriangles; i++)
|
||||||
|
{
|
||||||
|
meshData.mesh.PositionData.push_back(vertices[triangles[i][0]]);
|
||||||
|
meshData.mesh.PositionData.push_back(vertices[triangles[i][1]]);
|
||||||
|
meshData.mesh.PositionData.push_back(vertices[triangles[i][2]]);
|
||||||
|
|
||||||
|
meshData.verticesBoneWeight.push_back(localVerticesBoneWeight[triangles[i][0]]);
|
||||||
|
meshData.verticesBoneWeight.push_back(localVerticesBoneWeight[triangles[i][1]]);
|
||||||
|
meshData.verticesBoneWeight.push_back(localVerticesBoneWeight[triangles[i][2]]);
|
||||||
|
|
||||||
|
meshData.mesh.TexCoordData.push_back(uvCoords[i][0]);
|
||||||
|
meshData.mesh.TexCoordData.push_back(uvCoords[i][1]);
|
||||||
|
meshData.mesh.TexCoordData.push_back(uvCoords[i][2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
meshData.startMesh = meshData.mesh;
|
||||||
|
|
||||||
|
meshes[meshName] = std::move(meshData);
|
||||||
|
meshNamesOrdered.push_back(meshName);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Loaded " << numberMeshes << " meshes from " << fileName << std::endl;
|
||||||
|
|
||||||
|
// ---- Animation Keyframes ----
|
||||||
|
std::getline(f, tempLine); // === Animation Keyframes ===
|
||||||
|
std::getline(f, tempLine); // === Bone Transforms per Keyframe ===
|
||||||
|
std::getline(f, tempLine); // Keyframes: N
|
||||||
|
int numberKeyFrames;
|
||||||
|
if (std::regex_search(tempLine, match, pattern_count)) {
|
||||||
|
numberKeyFrames = std::stoi(match.str());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw std::runtime_error("Keyframe count not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
animations.resize(1);
|
||||||
|
animations[0].keyFrames.resize(numberKeyFrames);
|
||||||
|
|
||||||
|
for (int i = 0; i < numberKeyFrames; i++)
|
||||||
|
{
|
||||||
|
std::getline(f, tempLine); // Frame: N
|
||||||
|
int numberFrame;
|
||||||
|
if (std::regex_search(tempLine, match, pattern_count)) {
|
||||||
|
numberFrame = std::stoi(match.str());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw std::runtime_error("Frame number not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
animations[0].keyFrames[i].frame = numberFrame;
|
||||||
|
animations[0].keyFrames[i].bones.resize(numberBones);
|
||||||
|
|
||||||
|
for (int j = 0; j < numberBones; j++)
|
||||||
|
{
|
||||||
|
std::getline(f, tempLine); // Bone: name
|
||||||
|
std::string boneName = trimRight(tempLine.substr(8));
|
||||||
|
int boneNumber = getIndexByValue(boneName, boneNames);
|
||||||
|
animations[0].keyFrames[i].bones[boneNumber] = startBones[boneNumber];
|
||||||
|
|
||||||
|
std::getline(f, tempLine); // Location
|
||||||
|
std::vector<float> floatValues;
|
||||||
|
auto b = tempLine.cbegin();
|
||||||
|
auto e = tempLine.cend();
|
||||||
|
while (std::regex_search(b, e, match, pattern_float)) {
|
||||||
|
floatValues.push_back(std::stof(match.str()));
|
||||||
|
b = match.suffix().first;
|
||||||
|
}
|
||||||
|
animations[0].keyFrames[i].bones[boneNumber].boneStartWorld =
|
||||||
|
Vector3f{ floatValues[0], floatValues[1], floatValues[2] };
|
||||||
|
|
||||||
|
std::getline(f, tempLine); // Rotation
|
||||||
|
std::getline(f, tempLine); // Matrix:
|
||||||
|
|
||||||
|
for (int r = 0; r < 4; r++)
|
||||||
|
{
|
||||||
|
std::getline(f, tempLine);
|
||||||
|
b = tempLine.cbegin();
|
||||||
|
e = tempLine.cend();
|
||||||
|
floatValues.clear();
|
||||||
|
while (std::regex_search(b, e, match, pattern_float)) {
|
||||||
|
floatValues.push_back(std::stof(match.str()));
|
||||||
|
b = match.suffix().first;
|
||||||
|
}
|
||||||
|
animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.data()[r] = floatValues[0];
|
||||||
|
animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.data()[r + 1 * 4] = floatValues[1];
|
||||||
|
animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.data()[r + 2 * 4] = floatValues[2];
|
||||||
|
animations[0].keyFrames[i].bones[boneNumber].boneMatrixWorld.data()[r + 3 * 4] = floatValues[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startBones.size() > MAX_GPU_BONES)
|
||||||
|
{
|
||||||
|
std::cout << "Warning: model has " << startBones.size()
|
||||||
|
<< " bones, exceeding GPU skinning limit of " << MAX_GPU_BONES << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoneSystemNew::LoadFromBinaryFile(const std::string& fileName, const std::string& ZIPFileName)
|
||||||
|
{
|
||||||
|
std::vector<char> fileData;
|
||||||
|
|
||||||
|
if (!ZIPFileName.empty())
|
||||||
|
{
|
||||||
|
fileData = readFileFromZIP(fileName, ZIPFileName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::ifstream f(fileName, std::ios::binary | std::ios::ate);
|
||||||
|
if (!f.is_open()) throw std::runtime_error("Failed to open binary file: " + fileName);
|
||||||
|
std::streamsize fileSize = f.tellg();
|
||||||
|
f.seekg(0);
|
||||||
|
fileData.resize(static_cast<size_t>(fileSize));
|
||||||
|
f.read(fileData.data(), fileSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* ptr = fileData.data();
|
||||||
|
const char* end = ptr + fileData.size();
|
||||||
|
|
||||||
|
auto readRaw = [&](void* dst, size_t n) {
|
||||||
|
if (ptr + n > end) throw std::runtime_error("Unexpected EOF in binary animation file");
|
||||||
|
std::memcpy(dst, ptr, n);
|
||||||
|
ptr += n;
|
||||||
|
};
|
||||||
|
auto readUint32 = [&]() -> uint32_t { uint32_t v; readRaw(&v, 4); return v; };
|
||||||
|
auto readInt32 = [&]() -> int32_t { int32_t v; readRaw(&v, 4); return v; };
|
||||||
|
auto readFloat = [&]() -> float { float v; readRaw(&v, 4); return v; };
|
||||||
|
auto readVec3 = [&]() -> Vector3f { return Vector3f{readFloat(), readFloat(), readFloat()}; };
|
||||||
|
auto readVec2 = [&]() -> Vector2f { return Vector2f{readFloat(), readFloat()}; };
|
||||||
|
auto readString = [&]() -> std::string {
|
||||||
|
uint32_t len = readUint32();
|
||||||
|
std::string s(len, '\0');
|
||||||
|
if (len > 0) readRaw(&s[0], len);
|
||||||
|
return s;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Header
|
||||||
|
char magic[4];
|
||||||
|
readRaw(magic, 4);
|
||||||
|
if (std::memcmp(magic, "BSMF", 4) != 0)
|
||||||
|
throw std::runtime_error("Invalid multi-mesh binary animation file (bad magic)");
|
||||||
|
uint32_t version = readUint32();
|
||||||
|
if (version != 1)
|
||||||
|
throw std::runtime_error("Unsupported multi-mesh binary animation file version");
|
||||||
|
|
||||||
|
// Armature matrix (row-major in file, stored with stride-4 into Matrix4f)
|
||||||
|
{
|
||||||
|
float m[16];
|
||||||
|
for (int k = 0; k < 16; k++) m[k] = readFloat();
|
||||||
|
armatureMatrix = Matrix4f::Identity();
|
||||||
|
for (int r = 0; r < 4; r++)
|
||||||
|
for (int c = 0; c < 4; c++)
|
||||||
|
armatureMatrix.data()[r + c * 4] = m[r * 4 + c];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bones
|
||||||
|
uint32_t numBones = readUint32();
|
||||||
|
std::vector<Bone> bones(numBones);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < numBones; i++)
|
||||||
|
{
|
||||||
|
bones[i].boneStartWorld = readVec3();
|
||||||
|
bones[i].boneLength = readFloat();
|
||||||
|
|
||||||
|
float m[9];
|
||||||
|
for (int j = 0; j < 9; j++) m[j] = readFloat();
|
||||||
|
|
||||||
|
bones[i].boneMatrixWorld = Matrix4f::Zero();
|
||||||
|
for (int r = 0; r < 3; r++)
|
||||||
|
for (int c = 0; c < 3; c++)
|
||||||
|
bones[i].boneMatrixWorld.data()[r + c * 3] = m[r * 3 + c];
|
||||||
|
|
||||||
|
bones[i].parent = readInt32();
|
||||||
|
|
||||||
|
uint32_t numChildren = readUint32();
|
||||||
|
bones[i].children.resize(numChildren);
|
||||||
|
for (uint32_t j = 0; j < numChildren; j++)
|
||||||
|
bones[i].children[j] = readInt32();
|
||||||
|
}
|
||||||
|
|
||||||
|
startBones = bones;
|
||||||
|
currentBones = bones;
|
||||||
|
|
||||||
|
// Meshes
|
||||||
|
uint32_t numMeshes = readUint32();
|
||||||
|
|
||||||
|
for (uint32_t meshIdx = 0; meshIdx < numMeshes; meshIdx++)
|
||||||
|
{
|
||||||
|
std::string meshName = readString();
|
||||||
|
MeshBoneData meshData;
|
||||||
|
|
||||||
|
uint32_t numVertices = readUint32();
|
||||||
|
std::vector<Vector3f> vertices(numVertices);
|
||||||
|
for (uint32_t i = 0; i < numVertices; i++)
|
||||||
|
vertices[i] = readVec3();
|
||||||
|
|
||||||
|
uint32_t numFaces = readUint32();
|
||||||
|
std::vector<std::array<Vector2f, 3>> uvCoords(numFaces);
|
||||||
|
for (uint32_t i = 0; i < numFaces; i++)
|
||||||
|
for (int j = 0; j < 3; j++)
|
||||||
|
uvCoords[i][j] = readVec2();
|
||||||
|
|
||||||
|
std::vector<Vector3f> normals(numVertices);
|
||||||
|
for (uint32_t i = 0; i < numVertices; i++)
|
||||||
|
normals[i] = readVec3();
|
||||||
|
|
||||||
|
uint32_t numTriangles = readUint32();
|
||||||
|
std::vector<std::array<int, 3>> triangles(numTriangles);
|
||||||
|
for (uint32_t i = 0; i < numTriangles; i++)
|
||||||
|
triangles[i] = { readInt32(), readInt32(), readInt32() };
|
||||||
|
|
||||||
|
std::vector<std::array<BoneWeight, MAX_BONE_COUNT>> localVerticesBoneWeight(numVertices);
|
||||||
|
for (uint32_t i = 0; i < numVertices; i++)
|
||||||
|
{
|
||||||
|
uint32_t numGroups = readUint32();
|
||||||
|
float sumWeights = 0;
|
||||||
|
for (uint32_t j = 0; j < numGroups; j++)
|
||||||
|
{
|
||||||
|
int boneIdx = readInt32();
|
||||||
|
float weight = readFloat();
|
||||||
|
if (j < MAX_BONE_COUNT)
|
||||||
|
{
|
||||||
|
localVerticesBoneWeight[i][j].boneIndex = boneIdx;
|
||||||
|
localVerticesBoneWeight[i][j].weight = weight;
|
||||||
|
sumWeights += weight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint32_t cap = (numGroups < MAX_BONE_COUNT) ? numGroups : MAX_BONE_COUNT;
|
||||||
|
for (uint32_t j = 0; j < cap; j++)
|
||||||
|
localVerticesBoneWeight[i][j].weight /= sumWeights;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < numTriangles; i++)
|
||||||
|
{
|
||||||
|
meshData.mesh.PositionData.push_back(vertices[triangles[i][0]]);
|
||||||
|
meshData.mesh.PositionData.push_back(vertices[triangles[i][1]]);
|
||||||
|
meshData.mesh.PositionData.push_back(vertices[triangles[i][2]]);
|
||||||
|
|
||||||
|
meshData.verticesBoneWeight.push_back(localVerticesBoneWeight[triangles[i][0]]);
|
||||||
|
meshData.verticesBoneWeight.push_back(localVerticesBoneWeight[triangles[i][1]]);
|
||||||
|
meshData.verticesBoneWeight.push_back(localVerticesBoneWeight[triangles[i][2]]);
|
||||||
|
|
||||||
|
meshData.mesh.TexCoordData.push_back(uvCoords[i][0]);
|
||||||
|
meshData.mesh.TexCoordData.push_back(uvCoords[i][1]);
|
||||||
|
meshData.mesh.TexCoordData.push_back(uvCoords[i][2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
meshData.startMesh = meshData.mesh;
|
||||||
|
|
||||||
|
meshes[meshName] = std::move(meshData);
|
||||||
|
meshNamesOrdered.push_back(meshName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Animation Keyframes
|
||||||
|
uint32_t numKeyframes = readUint32();
|
||||||
|
animations.resize(1);
|
||||||
|
animations[0].keyFrames.resize(numKeyframes);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < numKeyframes; i++)
|
||||||
|
{
|
||||||
|
animations[0].keyFrames[i].frame = readInt32();
|
||||||
|
animations[0].keyFrames[i].bones.resize(numBones);
|
||||||
|
|
||||||
|
for (uint32_t j = 0; j < numBones; j++)
|
||||||
|
{
|
||||||
|
animations[0].keyFrames[i].bones[j] = startBones[j];
|
||||||
|
animations[0].keyFrames[i].bones[j].boneStartWorld = readVec3();
|
||||||
|
|
||||||
|
float m[16];
|
||||||
|
for (int k = 0; k < 16; k++) m[k] = readFloat();
|
||||||
|
|
||||||
|
for (int r = 0; r < 4; r++)
|
||||||
|
for (int c = 0; c < 4; c++)
|
||||||
|
animations[0].keyFrames[i].bones[j].boneMatrixWorld.data()[r + c * 4] = m[r * 4 + c];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startBones.size() > MAX_GPU_BONES)
|
||||||
|
{
|
||||||
|
std::cout << "Warning: model has " << startBones.size()
|
||||||
|
<< " bones, exceeding GPU skinning limit of " << MAX_GPU_BONES << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoneSystemNew::Interpolate(int frame)
|
||||||
|
{
|
||||||
|
int startingKeyFrame = -1;
|
||||||
|
for (int i = 0; i < static_cast<int>(animations[0].keyFrames.size()) - 1; i++)
|
||||||
|
{
|
||||||
|
int oldFrame = animations[0].keyFrames[i].frame;
|
||||||
|
int nextFrame = animations[0].keyFrames[i + 1].frame;
|
||||||
|
if (frame >= oldFrame && frame < nextFrame)
|
||||||
|
{
|
||||||
|
startingKeyFrame = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startingKeyFrame == -1)
|
||||||
|
{
|
||||||
|
std::cout << "Exception here: frame number is out of range of keyframes. Frame: " << frame << std::endl;
|
||||||
|
throw std::runtime_error("Exception here");
|
||||||
|
}
|
||||||
|
|
||||||
|
int modifiedFrameNumber = frame - animations[0].keyFrames[startingKeyFrame].frame;
|
||||||
|
int diffFrames = animations[0].keyFrames[startingKeyFrame + 1].frame - animations[0].keyFrames[startingKeyFrame].frame;
|
||||||
|
float t = (modifiedFrameNumber + 0.f) / diffFrames;
|
||||||
|
|
||||||
|
std::vector<Bone>& oneFrameBones = animations[0].keyFrames[startingKeyFrame].bones;
|
||||||
|
std::vector<Bone>& nextFrameBones = animations[0].keyFrames[startingKeyFrame + 1].bones;
|
||||||
|
|
||||||
|
std::vector<Matrix4f> skinningMatrixForEachBone(currentBones.size());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < currentBones.size(); i++)
|
||||||
|
{
|
||||||
|
currentBones[i].boneStartWorld(0) = oneFrameBones[i].boneStartWorld(0) + t * (nextFrameBones[i].boneStartWorld(0) - oneFrameBones[i].boneStartWorld(0));
|
||||||
|
currentBones[i].boneStartWorld(1) = oneFrameBones[i].boneStartWorld(1) + t * (nextFrameBones[i].boneStartWorld(1) - oneFrameBones[i].boneStartWorld(1));
|
||||||
|
currentBones[i].boneStartWorld(2) = oneFrameBones[i].boneStartWorld(2) + t * (nextFrameBones[i].boneStartWorld(2) - oneFrameBones[i].boneStartWorld(2));
|
||||||
|
|
||||||
|
Matrix3f oneFrameBonesMatrix = oneFrameBones[i].boneMatrixWorld.block<3, 3>(0, 0);
|
||||||
|
Matrix3f nextFrameBonesMatrix = nextFrameBones[i].boneMatrixWorld.block<3, 3>(0, 0);
|
||||||
|
|
||||||
|
Eigen::Quaternionf q1 = Eigen::Quaternionf(oneFrameBonesMatrix).normalized();
|
||||||
|
Eigen::Quaternionf q2 = Eigen::Quaternionf(nextFrameBonesMatrix).normalized();
|
||||||
|
Eigen::Quaternionf result = q1.slerp(t, q2);
|
||||||
|
|
||||||
|
Matrix3f boneMatrixWorld3 = result.toRotationMatrix();
|
||||||
|
|
||||||
|
currentBones[i].boneMatrixWorld = Eigen::Matrix4f::Identity();
|
||||||
|
currentBones[i].boneMatrixWorld.block<3, 3>(0, 0) = boneMatrixWorld3;
|
||||||
|
currentBones[i].boneMatrixWorld.block<3, 1>(0, 3) = currentBones[i].boneStartWorld;
|
||||||
|
|
||||||
|
Matrix4f startBoneMatrixWorld4 = animations[0].keyFrames[0].bones[i].boneMatrixWorld;
|
||||||
|
skinningMatrixForEachBone[i] = currentBones[i].boneMatrixWorld * startBoneMatrixWorld4.inverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& name : meshNamesOrdered)
|
||||||
|
{
|
||||||
|
auto it = meshes.find(name);
|
||||||
|
if (it == meshes.end()) continue;
|
||||||
|
MeshBoneData& md = it->second;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < md.mesh.PositionData.size(); i++)
|
||||||
|
{
|
||||||
|
Vector4f originalPos = {
|
||||||
|
md.startMesh.PositionData[i](0),
|
||||||
|
md.startMesh.PositionData[i](1),
|
||||||
|
md.startMesh.PositionData[i](2), 1.0f };
|
||||||
|
|
||||||
|
Vector4f finalPos = Vector4f{ 0.f, 0.f, 0.f, 0.f };
|
||||||
|
bool vMoved = false;
|
||||||
|
|
||||||
|
for (int j = 0; j < MAX_BONE_COUNT; j++)
|
||||||
|
{
|
||||||
|
if (md.verticesBoneWeight[i][j].weight != 0)
|
||||||
|
{
|
||||||
|
if (md.verticesBoneWeight[i][j].boneIndex == -1)
|
||||||
|
{
|
||||||
|
std::cout << "Exception here: bone index is -1 but weight is > 0" << std::endl;
|
||||||
|
throw std::runtime_error("Bones loaded incorrectly - bone index is -1 but weight is > 0");
|
||||||
|
}
|
||||||
|
vMoved = true;
|
||||||
|
finalPos = finalPos + (skinningMatrixForEachBone[md.verticesBoneWeight[i][j].boneIndex] * originalPos) * md.verticesBoneWeight[i][j].weight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vMoved) finalPos = originalPos;
|
||||||
|
|
||||||
|
md.mesh.PositionData[i](0) = finalPos(0);
|
||||||
|
md.mesh.PositionData[i](1) = finalPos(1);
|
||||||
|
md.mesh.PositionData[i](2) = finalPos(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MeshGpuSkinningData::prepareGpuSkinningVBOs(MeshBoneData& meshData)
|
||||||
|
{
|
||||||
|
if (gpuSkinningPrepared) return;
|
||||||
|
|
||||||
|
gpuBoneData.PrepareGpuSkinningData(meshData.verticesBoneWeight);
|
||||||
|
bindPoseMutable.AssignFrom(meshData.startMesh);
|
||||||
|
|
||||||
|
auto& gpu = gpuBoneData;
|
||||||
|
|
||||||
|
boneIndices0VBO = std::make_shared<VBOHolder>();
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, boneIndices0VBO->getBuffer());
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, gpu.boneIndices0.size() * sizeof(Eigen::Vector4f),
|
||||||
|
gpu.boneIndices0.data(), GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
boneIndices1VBO = std::make_shared<VBOHolder>();
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, boneIndices1VBO->getBuffer());
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, gpu.boneIndices1.size() * sizeof(Eigen::Vector2f),
|
||||||
|
gpu.boneIndices1.data(), GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
boneWeights0VBO = std::make_shared<VBOHolder>();
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, boneWeights0VBO->getBuffer());
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, gpu.boneWeights0.size() * sizeof(Eigen::Vector4f),
|
||||||
|
gpu.boneWeights0.data(), GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
boneWeights1VBO = std::make_shared<VBOHolder>();
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, boneWeights1VBO->getBuffer());
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, gpu.boneWeights1.size() * sizeof(Eigen::Vector2f),
|
||||||
|
gpu.boneWeights1.data(), GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
gpuSkinningPrepared = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MeshGpuSkinningData::RenderVBO(Renderer& renderer)
|
||||||
|
{
|
||||||
|
CheckGlError(__FILE__, __LINE__);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, bindPoseMutable.positionVBO->getBuffer());
|
||||||
|
renderer.VertexAttribPointer3fv("vPosition", 0, NULL);
|
||||||
|
CheckGlError(__FILE__, __LINE__);
|
||||||
|
|
||||||
|
if (bindPoseMutable.texCoordVBO) {
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, bindPoseMutable.texCoordVBO->getBuffer());
|
||||||
|
renderer.VertexAttribPointer2fv("vTexCoord", 0, NULL);
|
||||||
|
CheckGlError(__FILE__, __LINE__);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bindPoseMutable.normalVBO) {
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, bindPoseMutable.normalVBO->getBuffer());
|
||||||
|
renderer.VertexAttribPointer3fv("vNormal", 0, NULL);
|
||||||
|
CheckGlError(__FILE__, __LINE__);
|
||||||
|
} else {
|
||||||
|
renderer.DisableVertexAttribArray("vNormal");
|
||||||
|
CheckGlError(__FILE__, __LINE__);
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, boneIndices0VBO->getBuffer());
|
||||||
|
renderer.VertexAttribPointer4fv("aBoneIndices0", 0, NULL);
|
||||||
|
CheckGlError(__FILE__, __LINE__);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, boneIndices1VBO->getBuffer());
|
||||||
|
renderer.VertexAttribPointer2fv("aBoneIndices1", 0, NULL);
|
||||||
|
CheckGlError(__FILE__, __LINE__);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, boneWeights0VBO->getBuffer());
|
||||||
|
renderer.VertexAttribPointer4fv("aBoneWeights0", 0, NULL);
|
||||||
|
CheckGlError(__FILE__, __LINE__);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, boneWeights1VBO->getBuffer());
|
||||||
|
renderer.VertexAttribPointer2fv("aBoneWeights1", 0, NULL);
|
||||||
|
CheckGlError(__FILE__, __LINE__);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, static_cast<GLsizei>(bindPoseMutable.data.PositionData.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GpuSkinningShaderDataNew::prepareGpuSkinningVBOs(BoneSystemNew& model)
|
||||||
|
{
|
||||||
|
for (const auto& name : model.meshNamesOrdered)
|
||||||
|
{
|
||||||
|
auto it = model.meshes.find(name);
|
||||||
|
if (it == model.meshes.end()) continue;
|
||||||
|
perMesh[name].prepareGpuSkinningVBOs(it->second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GpuSkinningShaderDataNew::RenderVBO(Renderer& renderer, const std::vector<std::string>& meshNamesOrdered)
|
||||||
|
{
|
||||||
|
for (const auto& name : meshNamesOrdered)
|
||||||
|
{
|
||||||
|
auto it = perMesh.find(name);
|
||||||
|
if (it == perMesh.end()) continue;
|
||||||
|
it->second.RenderVBO(renderer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GpuSkinningShaderDataNew::ComputeSkinningMatrices(const std::vector<Bone>& startBones, const std::vector<AnimationKeyFrame>& keyFrames, int frame)
|
||||||
|
{
|
||||||
|
int startingKeyFrame = -1;
|
||||||
|
for (size_t i = 0; i < keyFrames.size() - 1; i++)
|
||||||
|
{
|
||||||
|
int oldFrame = keyFrames[i].frame;
|
||||||
|
int nextFrame = keyFrames[i + 1].frame;
|
||||||
|
if (frame >= oldFrame && frame < nextFrame)
|
||||||
|
{
|
||||||
|
startingKeyFrame = static_cast<int>(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
skinningMatrices.resize(startBones.size());
|
||||||
|
|
||||||
|
if (startingKeyFrame == -1)
|
||||||
|
{
|
||||||
|
for (auto& m : skinningMatrices) m = Matrix4f::Identity();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int modifiedFrameNumber = frame - keyFrames[startingKeyFrame].frame;
|
||||||
|
int diffFrames = keyFrames[startingKeyFrame + 1].frame - keyFrames[startingKeyFrame].frame;
|
||||||
|
float t = (modifiedFrameNumber + 0.f) / diffFrames;
|
||||||
|
|
||||||
|
const std::vector<Bone>& oneFrameBones = keyFrames[startingKeyFrame].bones;
|
||||||
|
const std::vector<Bone>& nextFrameBones = keyFrames[startingKeyFrame + 1].bones;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < startBones.size(); i++)
|
||||||
|
{
|
||||||
|
Vector3f interpPos;
|
||||||
|
interpPos(0) = oneFrameBones[i].boneStartWorld(0) + t * (nextFrameBones[i].boneStartWorld(0) - oneFrameBones[i].boneStartWorld(0));
|
||||||
|
interpPos(1) = oneFrameBones[i].boneStartWorld(1) + t * (nextFrameBones[i].boneStartWorld(1) - oneFrameBones[i].boneStartWorld(1));
|
||||||
|
interpPos(2) = oneFrameBones[i].boneStartWorld(2) + t * (nextFrameBones[i].boneStartWorld(2) - oneFrameBones[i].boneStartWorld(2));
|
||||||
|
|
||||||
|
Matrix3f oneFrameBonesMatrix = oneFrameBones[i].boneMatrixWorld.block<3, 3>(0, 0);
|
||||||
|
Matrix3f nextFrameBonesMatrix = nextFrameBones[i].boneMatrixWorld.block<3, 3>(0, 0);
|
||||||
|
|
||||||
|
Eigen::Quaternionf q1 = Eigen::Quaternionf(oneFrameBonesMatrix).normalized();
|
||||||
|
Eigen::Quaternionf q2 = Eigen::Quaternionf(nextFrameBonesMatrix).normalized();
|
||||||
|
Eigen::Quaternionf result = q1.slerp(t, q2);
|
||||||
|
|
||||||
|
Matrix3f boneMatrixWorld3 = result.toRotationMatrix();
|
||||||
|
|
||||||
|
Matrix4f currentBoneMatrixWorld4 = Eigen::Matrix4f::Identity();
|
||||||
|
currentBoneMatrixWorld4.block<3, 3>(0, 0) = boneMatrixWorld3;
|
||||||
|
currentBoneMatrixWorld4.block<3, 1>(0, 3) = interpPos;
|
||||||
|
|
||||||
|
Matrix4f startBoneMatrixWorld4 = keyFrames[0].bones[i].boneMatrixWorld;
|
||||||
|
skinningMatrices[i] = currentBoneMatrixWorld4 * startBoneMatrixWorld4.inverse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "BoneAnimatedModel.h"
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
namespace ZL
|
||||||
|
{
|
||||||
|
struct MeshBoneData
|
||||||
|
{
|
||||||
|
VertexDataStruct mesh;
|
||||||
|
VertexDataStruct startMesh;
|
||||||
|
std::vector<std::array<BoneWeight, MAX_BONE_COUNT>> verticesBoneWeight;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BoneSystemNew
|
||||||
|
{
|
||||||
|
std::unordered_map<std::string, MeshBoneData> meshes;
|
||||||
|
std::vector<std::string> meshNamesOrdered;
|
||||||
|
|
||||||
|
Matrix4f armatureMatrix;
|
||||||
|
|
||||||
|
std::vector<Bone> startBones;
|
||||||
|
std::vector<Bone> currentBones;
|
||||||
|
|
||||||
|
std::vector<Animation> animations;
|
||||||
|
int startingFrame = 0;
|
||||||
|
|
||||||
|
void LoadFromFile(const std::string& fileName, const std::string& ZIPFileName = "");
|
||||||
|
void LoadFromBinaryFile(const std::string& fileName, const std::string& ZIPFileName = "");
|
||||||
|
|
||||||
|
void Interpolate(int frame);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MeshGpuSkinningData
|
||||||
|
{
|
||||||
|
GpuBoneData gpuBoneData;
|
||||||
|
|
||||||
|
VertexRenderStruct bindPoseMutable;
|
||||||
|
std::shared_ptr<VBOHolder> boneIndices0VBO;
|
||||||
|
std::shared_ptr<VBOHolder> boneIndices1VBO;
|
||||||
|
std::shared_ptr<VBOHolder> boneWeights0VBO;
|
||||||
|
std::shared_ptr<VBOHolder> boneWeights1VBO;
|
||||||
|
bool gpuSkinningPrepared = false;
|
||||||
|
|
||||||
|
void prepareGpuSkinningVBOs(MeshBoneData& meshData);
|
||||||
|
void RenderVBO(Renderer& renderer);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GpuSkinningShaderDataNew
|
||||||
|
{
|
||||||
|
std::unordered_map<std::string, MeshGpuSkinningData> perMesh;
|
||||||
|
std::vector<Eigen::Matrix4f> skinningMatrices;
|
||||||
|
|
||||||
|
void prepareGpuSkinningVBOs(BoneSystemNew& model);
|
||||||
|
void RenderVBO(Renderer& renderer, const std::vector<std::string>& meshNamesOrdered);
|
||||||
|
void ComputeSkinningMatrices(const std::vector<Bone>& startBones, const std::vector<AnimationKeyFrame>& keyFrames, int frame);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct BoneAnimationDataNew
|
||||||
|
{
|
||||||
|
BoneSystemNew model;
|
||||||
|
float currentFrame = 0.f;
|
||||||
|
int lastFrame = -1;
|
||||||
|
int totalFrames = 1;
|
||||||
|
|
||||||
|
GpuSkinningShaderDataNew gpuSkinningShaderData;
|
||||||
|
};
|
||||||
|
};
|
||||||
+154
-70
@@ -7,6 +7,8 @@
|
|||||||
namespace ZL {
|
namespace ZL {
|
||||||
|
|
||||||
const float ATTACK_COOLDOWN_TIME = 3.0f;
|
const float ATTACK_COOLDOWN_TIME = 3.0f;
|
||||||
|
extern float x;
|
||||||
|
extern float y;
|
||||||
|
|
||||||
void Character::loadAnimation(AnimationState state, const std::string& filename, const std::string& zipFile) {
|
void Character::loadAnimation(AnimationState state, const std::string& filename, const std::string& zipFile) {
|
||||||
auto& data = animations[state];
|
auto& data = animations[state];
|
||||||
@@ -79,13 +81,68 @@ AnimationState Character::resolveActiveState() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Character::update(int64_t deltaMs) {
|
void Character::update(int64_t deltaMs) {
|
||||||
//std::cout << "update called with deltaMs: " << deltaMs << std::endl;
|
|
||||||
// Move toward walk target on the XZ plane
|
//weaponInitialRotation = Eigen::AngleAxisf(x/180.0, Eigen::Vector3f::UnitZ()).toRotationMatrix();
|
||||||
Eigen::Vector3f activeTarget = walkTarget;
|
//weaponInitialRotation = Eigen::AngleAxisf(-M_PI*0.5, Eigen::Vector3f::UnitZ()).toRotationMatrix();
|
||||||
|
//weaponInitialPosition = Eigen::Vector3f(0, 0.09, 0.016);
|
||||||
|
/*if (deltaMs > 200)
|
||||||
|
{
|
||||||
|
deltaMs = 200;
|
||||||
|
}*/
|
||||||
|
Eigen::Vector3f activeTarget;
|
||||||
|
Eigen::Vector3f lookTarget;
|
||||||
|
|
||||||
|
if (attackTarget == nullptr)
|
||||||
|
{
|
||||||
|
battle_state = 0;
|
||||||
|
attack = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (attackTarget != nullptr)
|
||||||
|
{
|
||||||
|
float distToGhost = (attackTarget->position - position).norm();
|
||||||
|
if (distToGhost >= 10.f)
|
||||||
|
{
|
||||||
|
if (isPlayer)
|
||||||
|
{
|
||||||
|
setTarget(attackTarget->position);
|
||||||
|
}
|
||||||
|
battle_state = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (distToGhost < 10.0f && distToGhost >= 1.f) {
|
||||||
|
setTarget(attackTarget->position);
|
||||||
|
battle_state = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
battle_state = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!pathWaypoints.empty() && currentWaypointIndex < pathWaypoints.size()) {
|
if (!pathWaypoints.empty() && currentWaypointIndex < pathWaypoints.size()) {
|
||||||
activeTarget = pathWaypoints[currentWaypointIndex];
|
activeTarget = pathWaypoints[currentWaypointIndex];
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
activeTarget = walkTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (battle_state == 0)
|
||||||
|
{
|
||||||
|
lookTarget = activeTarget;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lookTarget = attackTarget->position;
|
||||||
|
}
|
||||||
|
|
||||||
|
targetFacingAngle = facingAngle;
|
||||||
|
|
||||||
|
if (currentState == AnimationState::WALK || currentState == AnimationState::STAND)
|
||||||
|
{
|
||||||
Eigen::Vector3f toTarget = activeTarget - position;
|
Eigen::Vector3f toTarget = activeTarget - position;
|
||||||
toTarget.y() = 0.f;
|
toTarget.y() = 0.f;
|
||||||
float dist = toTarget.norm();
|
float dist = toTarget.norm();
|
||||||
@@ -96,21 +153,15 @@ void Character::update(int64_t deltaMs) {
|
|||||||
if (moveAmount >= dist) {
|
if (moveAmount >= dist) {
|
||||||
position = activeTarget;
|
position = activeTarget;
|
||||||
position.y() = 0.f;
|
position.y() = 0.f;
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
position += dir * moveAmount;
|
position += dir * moveAmount;
|
||||||
}
|
}
|
||||||
targetFacingAngle = atan2(dir.x(), -dir.z());
|
targetFacingAngle = atan2(dir.x(), -dir.z());
|
||||||
if (battle_state == 0 && currentState == AnimationState::STAND)
|
|
||||||
{
|
|
||||||
currentState = AnimationState::WALK;
|
currentState = AnimationState::WALK;
|
||||||
}
|
}
|
||||||
} else {
|
else {
|
||||||
if (battle_state == 0 &&
|
|
||||||
currentState == AnimationState::WALK
|
|
||||||
)
|
|
||||||
{
|
|
||||||
currentState = AnimationState::STAND;
|
currentState = AnimationState::STAND;
|
||||||
}
|
|
||||||
|
|
||||||
const bool hasNextWaypoint = !pathWaypoints.empty() && currentWaypointIndex + 1 < pathWaypoints.size();
|
const bool hasNextWaypoint = !pathWaypoints.empty() && currentWaypointIndex + 1 < pathWaypoints.size();
|
||||||
if (hasNextWaypoint) {
|
if (hasNextWaypoint) {
|
||||||
@@ -126,66 +177,15 @@ void Character::update(int64_t deltaMs) {
|
|||||||
onArrivedCallback = nullptr;
|
onArrivedCallback = nullptr;
|
||||||
cb();
|
cb();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (battle_state == 1 && attack == 1 && attackTarget != nullptr)
|
targetFacingAngle = facingAngle;
|
||||||
{
|
|
||||||
targetFacingAngle = atan2(attackTarget->position.x() - position.x(), -(attackTarget->position.z() - position.z()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rotate toward target facing angle at constant angular speed
|
|
||||||
float angleDiff = targetFacingAngle - facingAngle;
|
|
||||||
while (angleDiff > static_cast<float>(M_PI)) angleDiff -= 2.f * static_cast<float>(M_PI);
|
|
||||||
while (angleDiff < -static_cast<float>(M_PI)) angleDiff += 2.f * static_cast<float>(M_PI);
|
|
||||||
float rotStep = rotationSpeed * static_cast<float>(deltaMs) / 1000.f;
|
|
||||||
if (std::fabs(angleDiff) <= rotStep) {
|
|
||||||
facingAngle = targetFacingAngle;
|
|
||||||
} else {
|
|
||||||
facingAngle += (angleDiff > 0.f ? rotStep : -rotStep);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (canAttack && attackTarget != nullptr)
|
|
||||||
{
|
|
||||||
float distToGhost = (attackTarget->position - position).norm();
|
|
||||||
if (distToGhost >= 10.f)
|
|
||||||
{
|
|
||||||
if (isPlayer)
|
|
||||||
{
|
|
||||||
setTarget(attackTarget->position);
|
|
||||||
}
|
|
||||||
if (battle_state != 0)
|
|
||||||
{
|
|
||||||
battle_state = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (distToGhost < 10.0f && distToGhost >= 1.f) {
|
|
||||||
setTarget(attackTarget->position);
|
|
||||||
if (battle_state != 0)
|
|
||||||
{
|
|
||||||
battle_state = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
setTarget(position);
|
|
||||||
if (battle_state != 1)
|
|
||||||
{
|
|
||||||
battle_state = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (attackTarget == nullptr)
|
|
||||||
{
|
|
||||||
if (battle_state != 0)
|
|
||||||
{
|
|
||||||
battle_state = 0;
|
|
||||||
attack = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (battle_state == 1)
|
if (battle_state == 1)
|
||||||
{
|
{
|
||||||
|
targetFacingAngle = atan2(lookTarget.x() - position.x(), -(lookTarget.z() - position.z()));
|
||||||
|
|
||||||
if (currentState == AnimationState::STAND || currentState == AnimationState::WALK) {
|
if (currentState == AnimationState::STAND || currentState == AnimationState::WALK) {
|
||||||
currentState = AnimationState::STAND_TO_ACTION;
|
currentState = AnimationState::STAND_TO_ACTION;
|
||||||
resetAnim = true;
|
resetAnim = true;
|
||||||
@@ -218,6 +218,19 @@ void Character::update(int64_t deltaMs) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rotate toward target facing angle at constant angular speed
|
||||||
|
float angleDiff = targetFacingAngle - facingAngle;
|
||||||
|
while (angleDiff > static_cast<float>(M_PI)) angleDiff -= 2.f * static_cast<float>(M_PI);
|
||||||
|
while (angleDiff < -static_cast<float>(M_PI)) angleDiff += 2.f * static_cast<float>(M_PI);
|
||||||
|
float rotStep = rotationSpeed * static_cast<float>(deltaMs) / 1000.f;
|
||||||
|
if (std::fabs(angleDiff) <= rotStep) {
|
||||||
|
facingAngle = targetFacingAngle;
|
||||||
|
} else {
|
||||||
|
facingAngle += (angleDiff > 0.f ? rotStep : -rotStep);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
auto it = animations.find(currentState);
|
auto it = animations.find(currentState);
|
||||||
if (it == animations.end()) return;
|
if (it == animations.end()) return;
|
||||||
|
|
||||||
@@ -229,7 +242,22 @@ void Character::update(int64_t deltaMs) {
|
|||||||
anim.currentFrame = 0;
|
anim.currentFrame = 0;
|
||||||
}
|
}
|
||||||
anim.currentFrame += static_cast<float>(deltaMs) / 24.f;
|
anim.currentFrame += static_cast<float>(deltaMs) / 24.f;
|
||||||
|
|
||||||
//std::cout << "Current animation frame: " << anim.currentFrame << " / " << anim.totalFrames << " -- " << anim.lastFrame << std::endl;
|
//std::cout << "Current animation frame: " << anim.currentFrame << " / " << anim.totalFrames << " -- " << anim.lastFrame << std::endl;
|
||||||
|
|
||||||
|
if (static_cast<int>(anim.currentFrame) >= 20 && currentState == AnimationState::STAND_TO_ACTION)
|
||||||
|
{
|
||||||
|
showWeapon = true;
|
||||||
|
}
|
||||||
|
else if (static_cast<int>(anim.currentFrame) <= 32 && currentState == AnimationState::ACTION_TO_STAND)
|
||||||
|
{
|
||||||
|
showWeapon = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
showWeapon = false;
|
||||||
|
}
|
||||||
|
|
||||||
int frms = anim.model.animations[0].keyFrames[anim.model.animations[0].keyFrames.size() - 1].frame;
|
int frms = anim.model.animations[0].keyFrames[anim.model.animations[0].keyFrames.size() - 1].frame;
|
||||||
if (static_cast<int>(anim.currentFrame) >= frms) {
|
if (static_cast<int>(anim.currentFrame) >= frms) {
|
||||||
anim.currentFrame = anim.model.startingFrame;
|
anim.currentFrame = anim.model.startingFrame;
|
||||||
@@ -255,9 +283,8 @@ void Character::update(int64_t deltaMs) {
|
|||||||
|
|
||||||
|
|
||||||
if (static_cast<int>(anim.currentFrame) != anim.lastFrame) {
|
if (static_cast<int>(anim.currentFrame) != anim.lastFrame) {
|
||||||
if (useGpuSkinning) {
|
|
||||||
anim.gpuSkinningShaderData.ComputeSkinningMatrices(anim.model.startBones, anim.model.animations[0].keyFrames, static_cast<int>(anim.currentFrame));
|
anim.gpuSkinningShaderData.ComputeSkinningMatrices(anim.model.startBones, anim.model.animations[0].keyFrames, static_cast<int>(anim.currentFrame));
|
||||||
} else {
|
if (!useGpuSkinning) {
|
||||||
anim.model.Interpolate(static_cast<int>(anim.currentFrame));
|
anim.model.Interpolate(static_cast<int>(anim.currentFrame));
|
||||||
}
|
}
|
||||||
anim.lastFrame = static_cast<int>(anim.currentFrame);
|
anim.lastFrame = static_cast<int>(anim.currentFrame);
|
||||||
@@ -294,6 +321,9 @@ void Character::draw(Renderer& renderer) {
|
|||||||
renderer.DrawVertexRenderStruct(modelMutable);
|
renderer.DrawVertexRenderStruct(modelMutable);
|
||||||
|
|
||||||
renderer.PopMatrix();
|
renderer.PopMatrix();
|
||||||
|
|
||||||
|
drawAttachedWeapon(renderer);
|
||||||
|
|
||||||
renderer.PopProjectionMatrix();
|
renderer.PopProjectionMatrix();
|
||||||
renderer.shaderManager.PopShader();
|
renderer.shaderManager.PopShader();
|
||||||
}
|
}
|
||||||
@@ -353,6 +383,12 @@ void Character::drawGpuSkinning(Renderer& renderer) {
|
|||||||
anim.gpuSkinningShaderData.RenderVBO(renderer);
|
anim.gpuSkinningShaderData.RenderVBO(renderer);
|
||||||
|
|
||||||
renderer.PopMatrix();
|
renderer.PopMatrix();
|
||||||
|
|
||||||
|
renderer.shaderManager.PushShader(defaultShaderName);
|
||||||
|
renderer.RenderUniform1i(textureUniformName, 0);
|
||||||
|
drawAttachedWeapon(renderer);
|
||||||
|
renderer.shaderManager.PopShader();
|
||||||
|
|
||||||
renderer.PopProjectionMatrix();
|
renderer.PopProjectionMatrix();
|
||||||
renderer.shaderManager.PopShader();
|
renderer.shaderManager.PopShader();
|
||||||
}
|
}
|
||||||
@@ -385,6 +421,38 @@ bool Character::prepareGpuSkinning()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Character::drawAttachedWeapon(Renderer& renderer)
|
||||||
|
{
|
||||||
|
if (!showWeapon) return;
|
||||||
|
if (weaponMesh.data.PositionData.size() == 0 || !weaponTexture) return;
|
||||||
|
|
||||||
|
auto it = animations.find(resolveActiveState());
|
||||||
|
if (it == animations.end()) return;
|
||||||
|
|
||||||
|
auto& anim = it->second;
|
||||||
|
if (anim.gpuSkinningShaderData.skinningMatrices.empty()) return;
|
||||||
|
|
||||||
|
int boneIdx = anim.model.findBoneIndex(weaponAttachBoneName);
|
||||||
|
if (boneIdx < 0) return;
|
||||||
|
|
||||||
|
const Eigen::Matrix4f& bindBone = anim.model.animations[0].keyFrames[0].bones[boneIdx].boneMatrixWorld;
|
||||||
|
Eigen::Matrix4f currentBone = anim.gpuSkinningShaderData.skinningMatrices[boneIdx] * bindBone;
|
||||||
|
|
||||||
|
renderer.PushMatrix();
|
||||||
|
renderer.TranslateMatrix({ position.x(), position.y(), position.z() });
|
||||||
|
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(-facingAngle, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
||||||
|
renderer.ScaleMatrix(modelScale);
|
||||||
|
renderer.RotateMatrix(modelCorrectionRotation.toRotationMatrix());
|
||||||
|
renderer.TranslateMatrix(Eigen::Vector3f(currentBone.block<3, 1>(0, 3)));
|
||||||
|
renderer.RotateMatrix(Eigen::Matrix3f(currentBone.block<3, 3>(0, 0)));
|
||||||
|
renderer.TranslateMatrix(weaponInitialPosition);
|
||||||
|
renderer.RotateMatrix(weaponInitialRotation);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, weaponTexture->getTexID());
|
||||||
|
renderer.DrawVertexRenderStruct(weaponMesh);
|
||||||
|
renderer.PopMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
// ==================== Shadow depth pass ====================
|
// ==================== Shadow depth pass ====================
|
||||||
|
|
||||||
void Character::drawShadowDepth(Renderer& renderer) {
|
void Character::drawShadowDepth(Renderer& renderer) {
|
||||||
@@ -412,8 +480,9 @@ void Character::drawShadowDepthCpu(Renderer& renderer) {
|
|||||||
modelMutable.AssignFrom(anim.model.mesh);
|
modelMutable.AssignFrom(anim.model.mesh);
|
||||||
modelMutable.RefreshVBO();
|
modelMutable.RefreshVBO();
|
||||||
renderer.DrawVertexRenderStruct(modelMutable);
|
renderer.DrawVertexRenderStruct(modelMutable);
|
||||||
|
|
||||||
renderer.PopMatrix();
|
renderer.PopMatrix();
|
||||||
|
|
||||||
|
drawAttachedWeapon(renderer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Character::drawShadowDepthGpuSkinning(Renderer& renderer) {
|
void Character::drawShadowDepthGpuSkinning(Renderer& renderer) {
|
||||||
@@ -453,6 +522,8 @@ void Character::drawShadowDepthGpuSkinning(Renderer& renderer) {
|
|||||||
renderer.PopMatrix();
|
renderer.PopMatrix();
|
||||||
renderer.shaderManager.PopShader();
|
renderer.shaderManager.PopShader();
|
||||||
|
|
||||||
|
drawAttachedWeapon(renderer);
|
||||||
|
|
||||||
CheckGlError(__FILE__, __LINE__);
|
CheckGlError(__FILE__, __LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -500,6 +571,12 @@ void Character::drawCpuWithShadow(Renderer& renderer, const Eigen::Matrix4f& lig
|
|||||||
renderer.DrawVertexRenderStruct(modelMutable);
|
renderer.DrawVertexRenderStruct(modelMutable);
|
||||||
|
|
||||||
renderer.PopMatrix();
|
renderer.PopMatrix();
|
||||||
|
|
||||||
|
renderer.shaderManager.PushShader(defaultShaderName);
|
||||||
|
renderer.RenderUniform1i(textureUniformName, 0);
|
||||||
|
drawAttachedWeapon(renderer);
|
||||||
|
renderer.shaderManager.PopShader();
|
||||||
|
|
||||||
renderer.PopProjectionMatrix();
|
renderer.PopProjectionMatrix();
|
||||||
renderer.shaderManager.PopShader();
|
renderer.shaderManager.PopShader();
|
||||||
}
|
}
|
||||||
@@ -553,9 +630,16 @@ void Character::drawGpuSkinningWithShadow(Renderer& renderer, const Eigen::Matri
|
|||||||
CheckGlError(__FILE__, __LINE__);
|
CheckGlError(__FILE__, __LINE__);
|
||||||
it->second.gpuSkinningShaderData.RenderVBO(renderer);
|
it->second.gpuSkinningShaderData.RenderVBO(renderer);
|
||||||
|
|
||||||
|
renderer.PopMatrix();
|
||||||
|
|
||||||
|
renderer.shaderManager.PushShader(defaultShaderName);
|
||||||
|
renderer.RenderUniform1i(textureUniformName, 0);
|
||||||
|
drawAttachedWeapon(renderer);
|
||||||
|
renderer.shaderManager.PopShader();
|
||||||
|
|
||||||
CheckGlError(__FILE__, __LINE__);
|
CheckGlError(__FILE__, __LINE__);
|
||||||
|
|
||||||
renderer.PopMatrix();
|
|
||||||
renderer.PopProjectionMatrix();
|
renderer.PopProjectionMatrix();
|
||||||
renderer.shaderManager.PopShader();
|
renderer.shaderManager.PopShader();
|
||||||
|
|
||||||
|
|||||||
@@ -75,6 +75,13 @@ public:
|
|||||||
|
|
||||||
float interactionRadius = 0.0f;
|
float interactionRadius = 0.0f;
|
||||||
|
|
||||||
|
VertexRenderStruct weaponMesh;
|
||||||
|
std::shared_ptr<Texture> weaponTexture;
|
||||||
|
Eigen::Matrix3f weaponInitialRotation = Eigen::Matrix3f::Identity();
|
||||||
|
Eigen::Vector3f weaponInitialPosition = Eigen::Vector3f::Zero();
|
||||||
|
std::string weaponAttachBoneName = "RightHand";
|
||||||
|
bool showWeapon = true;
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@@ -99,6 +106,10 @@ private:
|
|||||||
|
|
||||||
bool prepareGpuSkinning();
|
bool prepareGpuSkinning();
|
||||||
|
|
||||||
|
// Draws the weapon mesh attached to weaponAttachBoneName.
|
||||||
|
// Caller must ensure the right shader is active with matching uniforms.
|
||||||
|
void drawAttachedWeapon(Renderer& renderer);
|
||||||
|
|
||||||
// GPU skinning: draw using shader-based skinning
|
// GPU skinning: draw using shader-based skinning
|
||||||
void drawGpuSkinning(Renderer& renderer);
|
void drawGpuSkinning(Renderer& renderer);
|
||||||
// Shadow: draw into depth map (no texture, no projection push)
|
// Shadow: draw into depth map (no texture, no projection push)
|
||||||
|
|||||||
@@ -503,10 +503,20 @@ namespace ZL
|
|||||||
currentLocation->dialogueSystem.startDialogue("test_cutscene_pan_dialogue");
|
currentLocation->dialogueSystem.startDialogue("test_cutscene_pan_dialogue");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SDLK_o:
|
||||||
|
y = y + 0.002;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SDLK_k:
|
||||||
|
y = y - 0.002;
|
||||||
|
break;
|
||||||
|
|
||||||
case SDLK_p:
|
case SDLK_p:
|
||||||
|
x = x + 0.002;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDLK_l:
|
case SDLK_l:
|
||||||
|
x = x - 0.002;
|
||||||
break;
|
break;
|
||||||
case SDLK_RETURN:
|
case SDLK_RETURN:
|
||||||
|
|
||||||
|
|||||||
+44
-15
@@ -41,23 +41,50 @@ namespace ZL
|
|||||||
interactiveObjects = GameObjectLoader::loadAndCreateInteractiveObjects("resources/config2/gameobjects.json", renderer, CONST_ZIP_FILE);
|
interactiveObjects = GameObjectLoader::loadAndCreateInteractiveObjects("resources/config2/gameobjects.json", renderer, CONST_ZIP_FILE);
|
||||||
|
|
||||||
|
|
||||||
auto playerTexture = std::make_shared<Texture>(CreateTextureDataFromPng("resources/w/gg/IMG_20260413_182354_992.png", CONST_ZIP_FILE));
|
//auto playerTexture = std::make_shared<Texture>(CreateTextureDataFromPng("resources/w/gg/IMG_20260413_182354_992.png", CONST_ZIP_FILE));
|
||||||
|
auto playerTexture = std::make_shared<Texture>(CreateTextureDataFromPng("resources/w/gg/UniV_Grid_2K_Base_color.png", CONST_ZIP_FILE));
|
||||||
|
|
||||||
player = std::make_unique<Character>();
|
player = std::make_unique<Character>();
|
||||||
|
/*
|
||||||
player->loadBinaryAnimation(AnimationState::STAND, "resources/w/gg/gg_stand_idle001.anim", CONST_ZIP_FILE);
|
player->loadBinaryAnimation(AnimationState::STAND, "resources/w/gg/gg_stand_idle001.anim", CONST_ZIP_FILE);
|
||||||
player->loadBinaryAnimation(AnimationState::WALK, "resources/w/gg/gg_walking001.anim", CONST_ZIP_FILE);
|
player->loadBinaryAnimation(AnimationState::WALK, "resources/w/gg/gg_walking001.anim", CONST_ZIP_FILE);
|
||||||
player->loadBinaryAnimation(AnimationState::STAND_TO_ACTION, "resources/w/gg/gg_stand_to_action002.anim", CONST_ZIP_FILE);
|
player->loadBinaryAnimation(AnimationState::STAND_TO_ACTION, "resources/w/gg/gg_stand_to_action002.anim", CONST_ZIP_FILE);
|
||||||
player->loadBinaryAnimation(AnimationState::ACTION_ATTACK, "resources/w/gg/gg_action_attack001.anim", CONST_ZIP_FILE);
|
player->loadBinaryAnimation(AnimationState::ACTION_ATTACK, "resources/w/gg/gg_action_attack001.anim", CONST_ZIP_FILE);
|
||||||
player->loadBinaryAnimation(AnimationState::ACTION_IDLE, "resources/w/gg/gg_action_idle001.anim", CONST_ZIP_FILE);
|
player->loadBinaryAnimation(AnimationState::ACTION_IDLE, "resources/w/gg/gg_action_idle001.anim", CONST_ZIP_FILE);
|
||||||
player->loadBinaryAnimation(AnimationState::ACTION_TO_STAND, "resources/w/gg/gg_action_to_stand001.anim", CONST_ZIP_FILE);
|
player->loadBinaryAnimation(AnimationState::ACTION_TO_STAND, "resources/w/gg/gg_action_to_stand001.anim", CONST_ZIP_FILE);
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
player->loadBinaryAnimation(AnimationState::STAND, "resources/w/gg/new/gg_stand_idle001.anim", CONST_ZIP_FILE);
|
||||||
|
player->loadBinaryAnimation(AnimationState::WALK, "resources/w/gg/new/gg_walk001.anim", CONST_ZIP_FILE);
|
||||||
|
player->loadBinaryAnimation(AnimationState::STAND_TO_ACTION, "resources/w/gg/new/gg_stand_to_action001.anim", CONST_ZIP_FILE);
|
||||||
|
|
||||||
|
player->loadBinaryAnimation(AnimationState::ACTION_ATTACK, "resources/w/gg/gg_action_attack001.anim", CONST_ZIP_FILE);
|
||||||
|
player->loadBinaryAnimation(AnimationState::ACTION_IDLE, "resources/w/gg/gg_action_idle001.anim", CONST_ZIP_FILE);
|
||||||
|
player->loadBinaryAnimation(AnimationState::ACTION_TO_STAND, "resources/w/gg/new/gg_action_to_stand001.anim", CONST_ZIP_FILE);
|
||||||
|
|
||||||
|
player->weaponTexture = std::make_shared<Texture>(CreateTextureDataFromPng("resources/w/white.png", CONST_ZIP_FILE));
|
||||||
|
//player->weaponMesh.AssignFrom(LoadFromTextFile02("resources/w/gg/knife001.txt", CONST_ZIP_FILE));
|
||||||
|
|
||||||
|
player->weaponMesh.data = LoadFromTextFile02("resources/w/gg/knife002.txt", CONST_ZIP_FILE);
|
||||||
|
player->weaponMesh.data.Scale(0.1f);
|
||||||
|
//player->weaponMesh.data.RotateByMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(-M_PI * 0.5, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
||||||
|
player->weaponMesh.RefreshVBO();
|
||||||
|
player->weaponAttachBoneName = "RightHand";
|
||||||
|
player->weaponInitialRotation = Eigen::AngleAxisf(-M_PI * 0.5, Eigen::Vector3f::UnitZ()).toRotationMatrix();
|
||||||
|
player->weaponInitialPosition = Eigen::Vector3f(0, 0.09, 0.016);
|
||||||
|
|
||||||
player->setTexture(playerTexture);
|
player->setTexture(playerTexture);
|
||||||
player->walkSpeed = 3.0f;
|
player->walkSpeed = 3.0f;
|
||||||
player->rotationSpeed = 8.0f;
|
player->rotationSpeed = 8.0f;
|
||||||
|
|
||||||
player->modelScale = 1.f;
|
player->modelScale = 1.f;
|
||||||
player->modelCorrectionRotation = Eigen::Quaternionf(Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitY()));
|
player->modelCorrectionRotation = Eigen::Quaternionf(
|
||||||
|
Eigen::AngleAxisf(M_PI, Eigen::Vector3f::UnitY())
|
||||||
|
*
|
||||||
|
Eigen::AngleAxisf(-M_PI*0.5, Eigen::Vector3f::UnitX())
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
player->canAttack = true;
|
player->canAttack = true;
|
||||||
player->isPlayer = true;
|
player->isPlayer = true;
|
||||||
@@ -295,14 +322,6 @@ namespace ZL
|
|||||||
renderer.DrawVertexRenderStruct(gameObj.mesh);
|
renderer.DrawVertexRenderStruct(gameObj.mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
glBindTexture(GL_TEXTURE_2D, fireboxTexture->getTexID());
|
|
||||||
renderer.DrawVertexRenderStruct(fireboxMesh);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, inaiTexture->getTexID());
|
|
||||||
renderer.DrawVertexRenderStruct(inaiMesh);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, benchTexture->getTexID());
|
|
||||||
renderer.DrawVertexRenderStruct(benchMesh);
|
|
||||||
*/
|
|
||||||
for (auto& intObj : interactiveObjects) {
|
for (auto& intObj : interactiveObjects) {
|
||||||
if (intObj.isActive) {
|
if (intObj.isActive) {
|
||||||
intObj.draw(renderer);
|
intObj.draw(renderer);
|
||||||
@@ -499,7 +518,14 @@ namespace ZL
|
|||||||
player->update(delta);
|
player->update(delta);
|
||||||
dialogueSystem.update(static_cast<int>(delta), player->position);
|
dialogueSystem.update(static_cast<int>(delta), player->position);
|
||||||
}
|
}
|
||||||
for (auto& npc : npcs) npc->update(delta);
|
for (auto& npc : npcs)
|
||||||
|
{
|
||||||
|
if (npc->canAttack)
|
||||||
|
{
|
||||||
|
npc->update(delta);
|
||||||
|
}
|
||||||
|
//npc->update(delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -573,6 +599,7 @@ namespace ZL
|
|||||||
|
|
||||||
targetInteractiveObject = clickedObject;
|
targetInteractiveObject = clickedObject;
|
||||||
player->setTarget(clickedObject->position);
|
player->setTarget(clickedObject->position);
|
||||||
|
player->attackTarget = nullptr;
|
||||||
std::cout << "[CLICK] Player moving to object..." << std::endl;
|
std::cout << "[CLICK] Player moving to object..." << std::endl;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -602,6 +629,10 @@ namespace ZL
|
|||||||
{
|
{
|
||||||
player->attackTarget = clickedNpc;
|
player->attackTarget = clickedNpc;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
player->attackTarget = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -611,10 +642,8 @@ namespace ZL
|
|||||||
Eigen::Vector3f hit = camPos + rayDir * t;
|
Eigen::Vector3f hit = camPos + rayDir * t;
|
||||||
std::cout << "[CLICK] Clicked on ground at: (" << hit.x() << ", " << hit.z() << ")" << std::endl;
|
std::cout << "[CLICK] Clicked on ground at: (" << hit.x() << ", " << hit.z() << ")" << std::endl;
|
||||||
|
|
||||||
if (player->currentState == AnimationState::STAND || player->currentState == AnimationState::WALK)
|
|
||||||
{
|
|
||||||
player->setTarget(Eigen::Vector3f(hit.x(), 0.f, hit.z()));
|
player->setTarget(Eigen::Vector3f(hit.x(), 0.f, hit.z()));
|
||||||
}
|
player->attackTarget = nullptr;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
std::cout << "[CLICK] No valid target found" << std::endl;
|
std::cout << "[CLICK] No valid target found" << std::endl;
|
||||||
|
|||||||
Reference in new issue
Block a user