Working on optimization: GPU skinning and binary animations
This commit is contained in:
parent
a589765b7e
commit
f708843747
312
convert_anim_to_binary.py
Normal file
312
convert_anim_to_binary.py
Normal file
@ -0,0 +1,312 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Convert a text-based bone animation file to the BSAF binary format.
|
||||
|
||||
Usage:
|
||||
python convert_anim_to_binary.py <input.txt> <output.bin>
|
||||
|
||||
Binary format (BSAF v1) -- all values little-endian:
|
||||
|
||||
HEADER
|
||||
4 bytes magic "BSAF"
|
||||
uint32 version (1)
|
||||
|
||||
BONES
|
||||
uint32 numBones
|
||||
per bone:
|
||||
3 x float boneStartWorld (from HEAD_LOCAL)
|
||||
float boneLength
|
||||
9 x float 3x3 rotation matrix (row-major)
|
||||
int32 parentIndex (-1 if none)
|
||||
uint32 numChildren
|
||||
numChildren x int32 childIndices
|
||||
|
||||
VERTICES
|
||||
uint32 numVertices
|
||||
numVertices x 3 x float positions
|
||||
|
||||
UV COORDINATES
|
||||
uint32 numFaces
|
||||
numFaces x 6 x float 3 UV pairs per face (u0,v0,u1,v1,u2,v2)
|
||||
|
||||
NORMALS
|
||||
numVertices x 3 x float normals
|
||||
|
||||
TRIANGLES
|
||||
uint32 numTriangles
|
||||
numTriangles x 3 x int32 vertex indices
|
||||
|
||||
VERTEX WEIGHTS
|
||||
per vertex (numVertices):
|
||||
uint32 numGroups
|
||||
numGroups x (int32 boneIndex, float weight)
|
||||
|
||||
ANIMATION KEYFRAMES
|
||||
uint32 numKeyframes
|
||||
per keyframe:
|
||||
int32 frameNumber
|
||||
per bone (numBones, in index order 0..N-1):
|
||||
3 x float location
|
||||
16 x float 4x4 matrix (row-major)
|
||||
"""
|
||||
|
||||
import struct
|
||||
import re
|
||||
import sys
|
||||
|
||||
|
||||
def parse_floats(line):
|
||||
return [float(x) for x in re.findall(r'[-]?\d+\.\d+', line)]
|
||||
|
||||
|
||||
def parse_first_int(line):
|
||||
m = re.search(r'\d+', line)
|
||||
if m:
|
||||
return int(m.group())
|
||||
raise ValueError(f"No integer found in: {line}")
|
||||
|
||||
|
||||
def parse_children(line):
|
||||
return re.findall(r"'([^']+)'", line)
|
||||
|
||||
|
||||
def convert(input_path, output_path):
|
||||
with open(input_path, 'r', encoding='utf-8', errors='replace') as f:
|
||||
lines = f.readlines()
|
||||
|
||||
idx = 0
|
||||
|
||||
def next_line():
|
||||
nonlocal idx
|
||||
line = lines[idx].rstrip()
|
||||
idx += 1
|
||||
return line
|
||||
|
||||
# --- Skip armature matrix (5 lines) ---
|
||||
for _ in range(5):
|
||||
next_line()
|
||||
|
||||
# --- Bone count ---
|
||||
line = next_line() # "=== Armature Bones: 65"
|
||||
num_bones = parse_first_int(line)
|
||||
|
||||
bone_names = []
|
||||
bones = []
|
||||
bone_parent_names = []
|
||||
bone_children_names = []
|
||||
|
||||
for _ in range(num_bones):
|
||||
bone = {}
|
||||
|
||||
# "Bone: mixamorig:Hips"
|
||||
line = next_line()
|
||||
bone_name = line[6:]
|
||||
bone_names.append(bone_name)
|
||||
|
||||
# " HEAD_LOCAL: <Vector (x, y, z)>"
|
||||
line = next_line()
|
||||
bone['head'] = parse_floats(line)[:3]
|
||||
|
||||
# " TAIL_LOCAL: ..." -- skip
|
||||
next_line()
|
||||
|
||||
# " Length: 0.123"
|
||||
line = next_line()
|
||||
bone['length'] = parse_floats(line)[0]
|
||||
|
||||
# 3x3 matrix (3 rows)
|
||||
mat = []
|
||||
for _ in range(3):
|
||||
mat.extend(parse_floats(next_line()))
|
||||
bone['matrix_3x3'] = mat
|
||||
|
||||
# " Parent: None" or " Parent: boneName"
|
||||
line = next_line()
|
||||
if line == " Parent: None":
|
||||
bone_parent_names.append(None)
|
||||
else:
|
||||
bone_parent_names.append(line[10:])
|
||||
|
||||
# " Children: ['a', 'b'] or []"
|
||||
line = next_line()
|
||||
bone_children_names.append(parse_children(line))
|
||||
|
||||
bones.append(bone)
|
||||
|
||||
# Build name -> index map
|
||||
name_to_idx = {name: i for i, name in enumerate(bone_names)}
|
||||
|
||||
# Resolve parent / child indices
|
||||
for i in range(num_bones):
|
||||
if bone_parent_names[i] is None:
|
||||
bones[i]['parent'] = -1
|
||||
else:
|
||||
bones[i]['parent'] = name_to_idx[bone_parent_names[i]]
|
||||
bones[i]['children'] = [name_to_idx[c] for c in bone_children_names[i]]
|
||||
|
||||
# --- Vertices ---
|
||||
line = next_line() # "===Vertices: 5140"
|
||||
num_vertices = parse_first_int(line)
|
||||
|
||||
vertices = []
|
||||
for _ in range(num_vertices):
|
||||
vertices.append(parse_floats(next_line())[:3])
|
||||
|
||||
# --- UV Coordinates ---
|
||||
next_line() # "===UV Coordinates:"
|
||||
line = next_line() # "Face count: 8602"
|
||||
num_faces = parse_first_int(line)
|
||||
|
||||
uvs = []
|
||||
for _ in range(num_faces):
|
||||
next_line() # "Face N"
|
||||
next_line() # "UV Count: 3"
|
||||
face_uvs = []
|
||||
for _ in range(3):
|
||||
face_uvs.extend(parse_floats(next_line())[:2])
|
||||
uvs.append(face_uvs) # 6 floats
|
||||
|
||||
# --- Normals ---
|
||||
next_line() # "===Normals:"
|
||||
|
||||
normals = []
|
||||
for _ in range(num_vertices):
|
||||
normals.append(parse_floats(next_line())[:3])
|
||||
|
||||
# --- Triangles ---
|
||||
line = next_line() # "===Triangles: 8602"
|
||||
num_triangles = parse_first_int(line)
|
||||
|
||||
triangles = []
|
||||
for _ in range(num_triangles):
|
||||
line = next_line()
|
||||
ints = [int(x) for x in re.findall(r'[-]?\d+', line)]
|
||||
triangles.append(ints[:3])
|
||||
|
||||
# --- Vertex Weights ---
|
||||
next_line() # "=== Vertex Weights ..."
|
||||
|
||||
vertex_weights = []
|
||||
for _ in range(num_vertices):
|
||||
next_line() # "Vertex N:"
|
||||
line = next_line() # "Vertex groups: 2"
|
||||
num_groups = parse_first_int(line)
|
||||
|
||||
groups = []
|
||||
for _ in range(num_groups):
|
||||
line = next_line()
|
||||
m = re.search(r"'([^']+)'.*?([-]?\d+\.\d+)", line)
|
||||
bone_name = m.group(1)
|
||||
weight = float(m.group(2))
|
||||
groups.append((name_to_idx[bone_name], weight))
|
||||
|
||||
vertex_weights.append(groups)
|
||||
|
||||
# --- Animation Keyframes ---
|
||||
next_line() # "=== Animation Keyframes ==="
|
||||
next_line() # "=== Bone Transforms per Keyframe ==="
|
||||
line = next_line() # "Keyframes: 32"
|
||||
num_keyframes = parse_first_int(line)
|
||||
|
||||
keyframes = []
|
||||
for _ in range(num_keyframes):
|
||||
line = next_line() # "Frame: 0"
|
||||
frame_number = parse_first_int(line)
|
||||
|
||||
bone_data = {}
|
||||
for _ in range(num_bones):
|
||||
line = next_line() # " Bone: mixamorig:Hips"
|
||||
bone_name = line.strip()
|
||||
if bone_name.startswith("Bone: "):
|
||||
bone_name = bone_name[6:]
|
||||
bone_idx = name_to_idx[bone_name]
|
||||
|
||||
# Location
|
||||
location = parse_floats(next_line())[:3]
|
||||
|
||||
# Rotation (skip)
|
||||
next_line()
|
||||
|
||||
# " Matrix:" (skip header)
|
||||
next_line()
|
||||
|
||||
# 4 rows of 4 floats
|
||||
matrix = []
|
||||
for _ in range(4):
|
||||
matrix.extend(parse_floats(next_line()))
|
||||
|
||||
bone_data[bone_idx] = {
|
||||
'location': location,
|
||||
'matrix': matrix,
|
||||
}
|
||||
|
||||
keyframes.append((frame_number, bone_data))
|
||||
|
||||
# ================================================================
|
||||
# Write binary file
|
||||
# ================================================================
|
||||
with open(output_path, 'wb') as out:
|
||||
# Header
|
||||
out.write(b'BSAF')
|
||||
out.write(struct.pack('<I', 1))
|
||||
|
||||
# Bones
|
||||
out.write(struct.pack('<I', num_bones))
|
||||
for i in range(num_bones):
|
||||
b = bones[i]
|
||||
out.write(struct.pack('<3f', *b['head']))
|
||||
out.write(struct.pack('<f', b['length']))
|
||||
out.write(struct.pack('<9f', *b['matrix_3x3']))
|
||||
out.write(struct.pack('<i', b['parent']))
|
||||
out.write(struct.pack('<I', len(b['children'])))
|
||||
for c in b['children']:
|
||||
out.write(struct.pack('<i', c))
|
||||
|
||||
# Vertices
|
||||
out.write(struct.pack('<I', num_vertices))
|
||||
for v in vertices:
|
||||
out.write(struct.pack('<3f', *v))
|
||||
|
||||
# UV Coordinates
|
||||
out.write(struct.pack('<I', num_faces))
|
||||
for uv in uvs:
|
||||
out.write(struct.pack('<6f', *uv))
|
||||
|
||||
# Normals
|
||||
for n in normals:
|
||||
out.write(struct.pack('<3f', *n))
|
||||
|
||||
# Triangles
|
||||
out.write(struct.pack('<I', num_triangles))
|
||||
for t in triangles:
|
||||
out.write(struct.pack('<3i', *t))
|
||||
|
||||
# Vertex Weights
|
||||
for vw in vertex_weights:
|
||||
out.write(struct.pack('<I', len(vw)))
|
||||
for bone_idx, weight in vw:
|
||||
out.write(struct.pack('<if', bone_idx, weight))
|
||||
|
||||
# Animation Keyframes
|
||||
out.write(struct.pack('<I', num_keyframes))
|
||||
for frame_num, bone_data in keyframes:
|
||||
out.write(struct.pack('<i', frame_num))
|
||||
for i in range(num_bones):
|
||||
bd = bone_data[i]
|
||||
out.write(struct.pack('<3f', *bd['location']))
|
||||
out.write(struct.pack('<16f', *bd['matrix']))
|
||||
|
||||
input_size = sum(len(l) for l in lines)
|
||||
import os
|
||||
output_size = os.path.getsize(output_path)
|
||||
print(f"Converted: {input_path} ({input_size:,} bytes text) -> {output_path} ({output_size:,} bytes binary)")
|
||||
print(f" Bones: {num_bones}, Vertices: {num_vertices}, Faces: {num_faces}, "
|
||||
f"Triangles: {num_triangles}, Keyframes: {num_keyframes}")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) != 3:
|
||||
print(f"Usage: {sys.argv[0]} <input.txt> <output.bin>")
|
||||
sys.exit(1)
|
||||
|
||||
convert(sys.argv[1], sys.argv[2])
|
||||
@ -4,8 +4,8 @@
|
||||
"id": "npc_01_default",
|
||||
"name": "NPC Default Guard",
|
||||
"texturePath": "resources/w/default_skin001.png",
|
||||
"animationIdlePath": "resources/w/default_idle002.txt",
|
||||
"animationWalkPath": "resources/w/default_walk001.txt",
|
||||
"animationIdlePath": "resources/w/default_idle002.anim",
|
||||
"animationWalkPath": "resources/w/default_walk001.anim",
|
||||
"positionX": 0.0,
|
||||
"positionY": 0.0,
|
||||
"positionZ": -10.0,
|
||||
@ -26,8 +26,8 @@
|
||||
"id": "npc_03_ghost",
|
||||
"name": "NPC Floating Ghost",
|
||||
"texturePath": "resources/w/ghost_skin001.png",
|
||||
"animationIdlePath": "resources/w/default_float001.txt",
|
||||
"animationWalkPath": "resources/w/default_float001.txt",
|
||||
"animationIdlePath": "resources/w/default_float001.anim",
|
||||
"animationWalkPath": "resources/w/default_float001.anim",
|
||||
"positionX": 0.0,
|
||||
"positionY": 0.0,
|
||||
"positionZ": -5.0,
|
||||
|
||||
50
resources/shaders/skinning.vertex
Normal file
50
resources/shaders/skinning.vertex
Normal file
@ -0,0 +1,50 @@
|
||||
attribute vec3 vPosition;
|
||||
attribute vec2 vTexCoord;
|
||||
attribute vec4 aBoneIndices0;
|
||||
attribute vec2 aBoneIndices1;
|
||||
attribute vec4 aBoneWeights0;
|
||||
attribute vec2 aBoneWeights1;
|
||||
|
||||
varying vec2 texCoord;
|
||||
|
||||
uniform mat4 ProjectionModelViewMatrix;
|
||||
uniform mat4 uBoneMatrices[64];
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 skinnedPos = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
vec4 originalPos = vec4(vPosition, 1.0);
|
||||
float totalWeight = 0.0;
|
||||
|
||||
if (aBoneWeights0.x > 0.0) {
|
||||
skinnedPos += uBoneMatrices[int(aBoneIndices0.x)] * originalPos * aBoneWeights0.x;
|
||||
totalWeight += aBoneWeights0.x;
|
||||
}
|
||||
if (aBoneWeights0.y > 0.0) {
|
||||
skinnedPos += uBoneMatrices[int(aBoneIndices0.y)] * originalPos * aBoneWeights0.y;
|
||||
totalWeight += aBoneWeights0.y;
|
||||
}
|
||||
if (aBoneWeights0.z > 0.0) {
|
||||
skinnedPos += uBoneMatrices[int(aBoneIndices0.z)] * originalPos * aBoneWeights0.z;
|
||||
totalWeight += aBoneWeights0.z;
|
||||
}
|
||||
if (aBoneWeights0.w > 0.0) {
|
||||
skinnedPos += uBoneMatrices[int(aBoneIndices0.w)] * originalPos * aBoneWeights0.w;
|
||||
totalWeight += aBoneWeights0.w;
|
||||
}
|
||||
if (aBoneWeights1.x > 0.0) {
|
||||
skinnedPos += uBoneMatrices[int(aBoneIndices1.x)] * originalPos * aBoneWeights1.x;
|
||||
totalWeight += aBoneWeights1.x;
|
||||
}
|
||||
if (aBoneWeights1.y > 0.0) {
|
||||
skinnedPos += uBoneMatrices[int(aBoneIndices1.y)] * originalPos * aBoneWeights1.y;
|
||||
totalWeight += aBoneWeights1.y;
|
||||
}
|
||||
|
||||
if (totalWeight < 0.001) {
|
||||
skinnedPos = originalPos;
|
||||
}
|
||||
|
||||
gl_Position = ProjectionModelViewMatrix * skinnedPos;
|
||||
texCoord = vTexCoord;
|
||||
}
|
||||
BIN
resources/w/default_float001.anim
(Stored with Git LFS)
Normal file
BIN
resources/w/default_float001.anim
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
resources/w/default_float001_cut.anim
(Stored with Git LFS)
Normal file
BIN
resources/w/default_float001_cut.anim
(Stored with Git LFS)
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
BIN
resources/w/default_idle002.anim
(Stored with Git LFS)
Normal file
BIN
resources/w/default_idle002.anim
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
resources/w/default_walk001.anim
(Stored with Git LFS)
Normal file
BIN
resources/w/default_walk001.anim
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
resources/w/float_attack003.anim
(Stored with Git LFS)
Normal file
BIN
resources/w/float_attack003.anim
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
resources/w/float_attack003_cut.anim
(Stored with Git LFS)
Normal file
BIN
resources/w/float_attack003_cut.anim
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
resources/w/gg/gg_action_attack001.anim
(Stored with Git LFS)
Normal file
BIN
resources/w/gg/gg_action_attack001.anim
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
resources/w/gg/gg_action_idle001.anim
(Stored with Git LFS)
Normal file
BIN
resources/w/gg/gg_action_idle001.anim
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
resources/w/gg/gg_action_to_stand001.anim
(Stored with Git LFS)
Normal file
BIN
resources/w/gg/gg_action_to_stand001.anim
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
resources/w/gg/gg_stand_idle001.anim
(Stored with Git LFS)
Normal file
BIN
resources/w/gg/gg_stand_idle001.anim
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
resources/w/gg/gg_stand_to_action002.anim
(Stored with Git LFS)
Normal file
BIN
resources/w/gg/gg_stand_to_action002.anim
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
resources/w/gg/gg_walking001.anim
(Stored with Git LFS)
Normal file
BIN
resources/w/gg/gg_walking001.anim
(Stored with Git LFS)
Normal file
Binary file not shown.
@ -4,6 +4,7 @@
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <cstring>
|
||||
|
||||
namespace ZL
|
||||
{
|
||||
@ -588,6 +589,264 @@ namespace ZL
|
||||
startMesh = mesh;
|
||||
}
|
||||
|
||||
void BoneSystem::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();
|
||||
|
||||
auto readRaw = [&](void* dst, size_t n) {
|
||||
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()}; };
|
||||
|
||||
// Header
|
||||
char magic[4];
|
||||
readRaw(magic, 4);
|
||||
if (std::memcmp(magic, "BSAF", 4) != 0)
|
||||
throw std::runtime_error("Invalid binary animation file (bad magic)");
|
||||
uint32_t version = readUint32();
|
||||
if (version != 1)
|
||||
throw std::runtime_error("Unsupported binary animation file version");
|
||||
|
||||
// ---- 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();
|
||||
|
||||
// 3x3 matrix (row-major in file).
|
||||
// Stored with stride-3 into Matrix4f to match the text loader.
|
||||
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;
|
||||
|
||||
// ---- Vertices ----
|
||||
uint32_t numVertices = readUint32();
|
||||
std::vector<Vector3f> vertices(numVertices);
|
||||
for (uint32_t i = 0; i < numVertices; i++)
|
||||
vertices[i] = readVec3();
|
||||
|
||||
// ---- UV Coordinates ----
|
||||
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();
|
||||
|
||||
// ---- Normals (read but not currently used by mesh) ----
|
||||
std::vector<Vector3f> normals(numVertices);
|
||||
for (uint32_t i = 0; i < numVertices; i++)
|
||||
normals[i] = readVec3();
|
||||
|
||||
// ---- Triangles ----
|
||||
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() };
|
||||
|
||||
// ---- Vertex Weights ----
|
||||
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;
|
||||
}
|
||||
}
|
||||
// Normalize weights
|
||||
uint32_t cap = (numGroups < MAX_BONE_COUNT) ? numGroups : MAX_BONE_COUNT;
|
||||
for (uint32_t j = 0; j < cap; j++)
|
||||
localVerticesBoneWeight[i][j].weight /= sumWeights;
|
||||
}
|
||||
|
||||
// ---- 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();
|
||||
|
||||
// 4x4 matrix (row-major in file, stored with stride-4 into Matrix4f)
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Build per-triangle mesh (same expansion as text loader) ----
|
||||
for (uint32_t i = 0; i < numTriangles; i++)
|
||||
{
|
||||
mesh.PositionData.push_back(vertices[triangles[i][0]]);
|
||||
mesh.PositionData.push_back(vertices[triangles[i][1]]);
|
||||
mesh.PositionData.push_back(vertices[triangles[i][2]]);
|
||||
|
||||
verticesBoneWeight.push_back(localVerticesBoneWeight[triangles[i][0]]);
|
||||
verticesBoneWeight.push_back(localVerticesBoneWeight[triangles[i][1]]);
|
||||
verticesBoneWeight.push_back(localVerticesBoneWeight[triangles[i][2]]);
|
||||
|
||||
mesh.TexCoordData.push_back(uvCoords[i][0]);
|
||||
mesh.TexCoordData.push_back(uvCoords[i][1]);
|
||||
mesh.TexCoordData.push_back(uvCoords[i][2]);
|
||||
}
|
||||
|
||||
startMesh = mesh;
|
||||
}
|
||||
|
||||
void BoneSystem::PrepareGpuSkinningData()
|
||||
{
|
||||
size_t vertexCount = verticesBoneWeight.size();
|
||||
gpuBoneData.boneIndices0.resize(vertexCount);
|
||||
gpuBoneData.boneIndices1.resize(vertexCount);
|
||||
gpuBoneData.boneWeights0.resize(vertexCount);
|
||||
gpuBoneData.boneWeights1.resize(vertexCount);
|
||||
|
||||
for (size_t i = 0; i < vertexCount; i++)
|
||||
{
|
||||
gpuBoneData.boneIndices0[i] = Vector4f(
|
||||
static_cast<float>(max(0, verticesBoneWeight[i][0].boneIndex)),
|
||||
static_cast<float>(max(0, verticesBoneWeight[i][1].boneIndex)),
|
||||
static_cast<float>(max(0, verticesBoneWeight[i][2].boneIndex)),
|
||||
static_cast<float>(max(0, verticesBoneWeight[i][3].boneIndex))
|
||||
);
|
||||
gpuBoneData.boneIndices1[i] = Vector2f(
|
||||
static_cast<float>(max(0, verticesBoneWeight[i][4].boneIndex)),
|
||||
static_cast<float>(max(0, verticesBoneWeight[i][5].boneIndex))
|
||||
);
|
||||
gpuBoneData.boneWeights0[i] = Vector4f(
|
||||
verticesBoneWeight[i][0].weight,
|
||||
verticesBoneWeight[i][1].weight,
|
||||
verticesBoneWeight[i][2].weight,
|
||||
verticesBoneWeight[i][3].weight
|
||||
);
|
||||
gpuBoneData.boneWeights1[i] = Vector2f(
|
||||
verticesBoneWeight[i][4].weight,
|
||||
verticesBoneWeight[i][5].weight
|
||||
);
|
||||
}
|
||||
|
||||
gpuBoneData.prepared = true;
|
||||
|
||||
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 BoneSystem::ComputeSkinningMatrices(int frame, std::vector<Matrix4f>& outMatrices) const
|
||||
{
|
||||
int startingKeyFrame = -1;
|
||||
for (size_t i = 0; i < 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 = static_cast<int>(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (startingKeyFrame == -1)
|
||||
{
|
||||
outMatrices.resize(startBones.size());
|
||||
for (auto& m : outMatrices) m = Matrix4f::Identity();
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
const std::vector<Bone>& oneFrameBones = animations[0].keyFrames[startingKeyFrame].bones;
|
||||
const std::vector<Bone>& nextFrameBones = animations[0].keyFrames[startingKeyFrame + 1].bones;
|
||||
|
||||
outMatrices.resize(startBones.size());
|
||||
|
||||
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 = animations[0].keyFrames[0].bones[i].boneMatrixWorld;
|
||||
Matrix4f invertedStartBoneMatrixWorld4 = startBoneMatrixWorld4.inverse();
|
||||
|
||||
outMatrices[i] = currentBoneMatrixWorld4 * invertedStartBoneMatrixWorld4;
|
||||
}
|
||||
}
|
||||
|
||||
void BoneSystem::Interpolate(int frame)
|
||||
{
|
||||
int startingFrame = -1;
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
namespace ZL
|
||||
{
|
||||
constexpr int MAX_BONE_COUNT = 6;
|
||||
constexpr int MAX_GPU_BONES = 64;
|
||||
struct Bone
|
||||
{
|
||||
Vector3f boneStartWorld;
|
||||
@ -35,12 +36,20 @@ namespace ZL
|
||||
std::vector<AnimationKeyFrame> keyFrames;
|
||||
};
|
||||
|
||||
struct GpuBoneData {
|
||||
std::vector<Vector4f> boneIndices0; // bone indices 0-3 per vertex (as float)
|
||||
std::vector<Vector2f> boneIndices1; // bone indices 4-5 per vertex
|
||||
std::vector<Vector4f> boneWeights0; // bone weights 0-3 per vertex
|
||||
std::vector<Vector2f> boneWeights1; // bone weights 4-5 per vertex
|
||||
bool prepared = false;
|
||||
};
|
||||
|
||||
struct BoneSystem
|
||||
{
|
||||
VertexDataStruct mesh;
|
||||
VertexDataStruct startMesh;
|
||||
std::vector<std::array<BoneWeight, MAX_BONE_COUNT>> verticesBoneWeight;
|
||||
|
||||
|
||||
Matrix4f armatureMatrix;
|
||||
|
||||
std::vector<Bone> startBones;
|
||||
@ -49,9 +58,17 @@ namespace ZL
|
||||
std::vector<Animation> animations;
|
||||
int startingFrame = 0;
|
||||
|
||||
GpuBoneData gpuBoneData;
|
||||
|
||||
void LoadFromFile(const std::string& fileName, const std::string& ZIPFileName = "");
|
||||
void LoadFromBinaryFile(const std::string& fileName, const std::string& ZIPFileName = "");
|
||||
|
||||
void Interpolate(int frame);
|
||||
|
||||
// GPU skinning: prepare per-vertex bone data for VBO upload
|
||||
void PrepareGpuSkinningData();
|
||||
// GPU skinning: compute skinning matrices without modifying the mesh
|
||||
void ComputeSkinningMatrices(int frame, std::vector<Matrix4f>& outMatrices) const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
#include "Character.h"
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include "GameConstants.h"
|
||||
#include "Environment.h"
|
||||
|
||||
namespace ZL {
|
||||
|
||||
@ -15,7 +17,16 @@ void Character::loadAnimation(AnimationState state, const std::string& filename,
|
||||
data.totalFrames = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void Character::loadBinaryAnimation(AnimationState state, const std::string& filename, const std::string& zipFile) {
|
||||
auto& data = animations[state];
|
||||
data.model.LoadFromBinaryFile(filename, zipFile);
|
||||
if (!data.model.animations.empty() && !data.model.animations[0].keyFrames.empty()) {
|
||||
data.totalFrames = data.model.animations[0].keyFrames.back().frame + 1;
|
||||
}
|
||||
else {
|
||||
data.totalFrames = 1;
|
||||
}
|
||||
}
|
||||
/*void Character::setTexture(std::shared_ptr<Texture> tex) {
|
||||
texture = tex;
|
||||
}*/
|
||||
@ -123,38 +134,6 @@ void Character::update(int64_t deltaMs) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if (isPlayer) //Player should decide only by himself
|
||||
{
|
||||
if (attackTarget != nullptr)
|
||||
{
|
||||
auto pos = attackTarget->position;
|
||||
float distToTarget = (position - pos).norm();
|
||||
|
||||
if (distToTarget > 1.0)
|
||||
{
|
||||
setTarget(Eigen::Vector3f(pos.x(), 0.f, pos.z()));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (battle_state != 1)
|
||||
{
|
||||
setTarget(position);
|
||||
battle_state = 1;
|
||||
//player->attack = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (battle_state != 0)
|
||||
{
|
||||
battle_state = 0;
|
||||
attack = 0;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
if (battle_state == 1)
|
||||
{
|
||||
if (currentState == AnimationState::STAND || currentState == AnimationState::WALK) {
|
||||
@ -226,17 +205,32 @@ void Character::update(int64_t deltaMs) {
|
||||
|
||||
|
||||
if (static_cast<int>(anim.currentFrame) != anim.lastFrame) {
|
||||
anim.model.Interpolate(static_cast<int>(anim.currentFrame));
|
||||
if (useGpuSkinning) {
|
||||
anim.model.ComputeSkinningMatrices(static_cast<int>(anim.currentFrame), anim.skinningMatrices);
|
||||
} else {
|
||||
anim.model.Interpolate(static_cast<int>(anim.currentFrame));
|
||||
}
|
||||
anim.lastFrame = static_cast<int>(anim.currentFrame);
|
||||
}
|
||||
}
|
||||
|
||||
void Character::draw(Renderer& renderer) {
|
||||
//std::cout << "draw called for Character at position: " << position.transpose() << std::endl;
|
||||
if (useGpuSkinning) {
|
||||
drawGpuSkinning(renderer);
|
||||
return;
|
||||
}
|
||||
|
||||
AnimationState drawState = resolveActiveState();
|
||||
auto it = animations.find(drawState);
|
||||
if (it == animations.end() || !texture) return;
|
||||
|
||||
renderer.shaderManager.PushShader(defaultShaderName);
|
||||
renderer.RenderUniform1i(textureUniformName, 0);
|
||||
|
||||
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
||||
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
||||
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
|
||||
|
||||
renderer.PushMatrix();
|
||||
renderer.TranslateMatrix({ position.x(), position.y(), position.z() });
|
||||
renderer.RotateMatrix(Eigen::Quaternionf(Eigen::AngleAxisf(-facingAngle, Eigen::Vector3f::UnitY())).toRotationMatrix());
|
||||
@ -250,6 +244,114 @@ void Character::draw(Renderer& renderer) {
|
||||
renderer.DrawVertexRenderStruct(anim.modelMutable);
|
||||
|
||||
renderer.PopMatrix();
|
||||
renderer.PopProjectionMatrix();
|
||||
renderer.shaderManager.PopShader();
|
||||
}
|
||||
|
||||
void Character::prepareGpuSkinningVBOs(AnimationData& anim) {
|
||||
if (anim.gpuSkinningPrepared) return;
|
||||
|
||||
anim.model.PrepareGpuSkinningData();
|
||||
|
||||
// Upload bind-pose mesh (static, done once)
|
||||
anim.bindPoseMutable.AssignFrom(anim.model.startMesh);
|
||||
|
||||
auto& gpu = anim.model.gpuBoneData;
|
||||
|
||||
anim.boneIndices0VBO = std::make_shared<VBOHolder>();
|
||||
glBindBuffer(GL_ARRAY_BUFFER, anim.boneIndices0VBO->getBuffer());
|
||||
glBufferData(GL_ARRAY_BUFFER, gpu.boneIndices0.size() * sizeof(Eigen::Vector4f),
|
||||
gpu.boneIndices0.data(), GL_STATIC_DRAW);
|
||||
|
||||
anim.boneIndices1VBO = std::make_shared<VBOHolder>();
|
||||
glBindBuffer(GL_ARRAY_BUFFER, anim.boneIndices1VBO->getBuffer());
|
||||
glBufferData(GL_ARRAY_BUFFER, gpu.boneIndices1.size() * sizeof(Eigen::Vector2f),
|
||||
gpu.boneIndices1.data(), GL_STATIC_DRAW);
|
||||
|
||||
anim.boneWeights0VBO = std::make_shared<VBOHolder>();
|
||||
glBindBuffer(GL_ARRAY_BUFFER, anim.boneWeights0VBO->getBuffer());
|
||||
glBufferData(GL_ARRAY_BUFFER, gpu.boneWeights0.size() * sizeof(Eigen::Vector4f),
|
||||
gpu.boneWeights0.data(), GL_STATIC_DRAW);
|
||||
|
||||
anim.boneWeights1VBO = std::make_shared<VBOHolder>();
|
||||
glBindBuffer(GL_ARRAY_BUFFER, anim.boneWeights1VBO->getBuffer());
|
||||
glBufferData(GL_ARRAY_BUFFER, gpu.boneWeights1.size() * sizeof(Eigen::Vector2f),
|
||||
gpu.boneWeights1.data(), GL_STATIC_DRAW);
|
||||
|
||||
anim.gpuSkinningPrepared = true;
|
||||
}
|
||||
|
||||
void Character::drawGpuSkinning(Renderer& renderer) {
|
||||
AnimationState drawState = resolveActiveState();
|
||||
auto it = animations.find(drawState);
|
||||
if (it == animations.end() || !texture) return;
|
||||
|
||||
auto& anim = it->second;
|
||||
prepareGpuSkinningVBOs(anim);
|
||||
|
||||
if (anim.skinningMatrices.empty()) return;
|
||||
|
||||
static const std::string skinningShaderName = "skinning";
|
||||
static const std::string boneMatricesUniform = "uBoneMatrices[0]";
|
||||
|
||||
renderer.shaderManager.PushShader(skinningShaderName);
|
||||
renderer.RenderUniform1i(textureUniformName, 0);
|
||||
|
||||
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
||||
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
||||
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
|
||||
|
||||
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());
|
||||
|
||||
// Upload bone skinning matrices
|
||||
renderer.RenderUniformMatrix4fvArray(boneMatricesUniform,
|
||||
static_cast<int>(anim.skinningMatrices.size()), false,
|
||||
anim.skinningMatrices[0].data());
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture->getTexID());
|
||||
|
||||
// Bind VAO (desktop only)
|
||||
#ifndef EMSCRIPTEN
|
||||
#ifndef __ANDROID__
|
||||
if (anim.bindPoseMutable.vao) {
|
||||
glBindVertexArray(anim.bindPoseMutable.vao->getBuffer());
|
||||
renderer.shaderManager.EnableVertexAttribArrays();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Bind position and texcoord VBOs
|
||||
glBindBuffer(GL_ARRAY_BUFFER, anim.bindPoseMutable.positionVBO->getBuffer());
|
||||
renderer.VertexAttribPointer3fv("vPosition", 0, NULL);
|
||||
|
||||
if (anim.bindPoseMutable.texCoordVBO) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, anim.bindPoseMutable.texCoordVBO->getBuffer());
|
||||
renderer.VertexAttribPointer2fv("vTexCoord", 0, NULL);
|
||||
}
|
||||
|
||||
// Bind bone index VBOs
|
||||
glBindBuffer(GL_ARRAY_BUFFER, anim.boneIndices0VBO->getBuffer());
|
||||
renderer.VertexAttribPointer4fv("aBoneIndices0", 0, NULL);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, anim.boneIndices1VBO->getBuffer());
|
||||
renderer.VertexAttribPointer2fv("aBoneIndices1", 0, NULL);
|
||||
|
||||
// Bind bone weight VBOs
|
||||
glBindBuffer(GL_ARRAY_BUFFER, anim.boneWeights0VBO->getBuffer());
|
||||
renderer.VertexAttribPointer4fv("aBoneWeights0", 0, NULL);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, anim.boneWeights1VBO->getBuffer());
|
||||
renderer.VertexAttribPointer2fv("aBoneWeights1", 0, NULL);
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, static_cast<GLsizei>(anim.bindPoseMutable.data.PositionData.size()));
|
||||
|
||||
renderer.PopMatrix();
|
||||
renderer.PopProjectionMatrix();
|
||||
renderer.shaderManager.PopShader();
|
||||
}
|
||||
|
||||
} // namespace ZL
|
||||
|
||||
@ -23,6 +23,7 @@ enum class AnimationState {
|
||||
class Character {
|
||||
public:
|
||||
void loadAnimation(AnimationState state, const std::string& filename, const std::string& zipFile = "");
|
||||
void loadBinaryAnimation(AnimationState state, const std::string& filename, const std::string& zipFile = "");
|
||||
// void setTexture(std::shared_ptr<Texture> texture);
|
||||
void setTexture(std::shared_ptr<Texture> texture) {
|
||||
this->texture = texture;
|
||||
@ -59,6 +60,7 @@ public:
|
||||
bool canAttack = false;
|
||||
Character* attackTarget = nullptr;
|
||||
bool isPlayer = false;
|
||||
bool useGpuSkinning = true;
|
||||
|
||||
private:
|
||||
struct AnimationData {
|
||||
@ -67,6 +69,15 @@ private:
|
||||
float currentFrame = 0.f;
|
||||
int lastFrame = -1;
|
||||
int totalFrames = 1;
|
||||
|
||||
// GPU skinning data (lazily initialized)
|
||||
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;
|
||||
std::vector<Eigen::Matrix4f> skinningMatrices;
|
||||
};
|
||||
|
||||
std::map<AnimationState, AnimationData> animations;
|
||||
@ -81,6 +92,11 @@ private:
|
||||
// Returns the animation state to actually play/draw, falling back to IDLE
|
||||
// if the requested state has no loaded animation.
|
||||
AnimationState resolveActiveState() const;
|
||||
|
||||
// GPU skinning: prepare per-animation VBOs (called lazily on first draw)
|
||||
void prepareGpuSkinningVBOs(AnimationData& anim);
|
||||
// GPU skinning: draw using shader-based skinning
|
||||
void drawGpuSkinning(Renderer& renderer);
|
||||
};
|
||||
|
||||
} // namespace ZL
|
||||
|
||||
19
src/Game.cpp
19
src/Game.cpp
@ -130,6 +130,7 @@ namespace ZL
|
||||
renderer.shaderManager.AddShaderFromFiles("planetStone", "resources/shaders/planet_stone.vertex", "resources/shaders/planet_stone_web.fragment", CONST_ZIP_FILE);
|
||||
renderer.shaderManager.AddShaderFromFiles("planetLand", "resources/shaders/planet_land.vertex", "resources/shaders/planet_land_web.fragment", CONST_ZIP_FILE);
|
||||
renderer.shaderManager.AddShaderFromFiles("spark", "resources/shaders/spark.vertex", "resources/shaders/spark_web.fragment", CONST_ZIP_FILE);
|
||||
renderer.shaderManager.AddShaderFromFiles("skinning", "resources/shaders/skinning.vertex", "resources/shaders/default_web.fragment", CONST_ZIP_FILE);
|
||||
|
||||
#else
|
||||
renderer.shaderManager.AddShaderFromFiles("env_sky", "resources/shaders/env_sky.vertex", "resources/shaders/env_sky_desktop.fragment", CONST_ZIP_FILE);
|
||||
@ -138,6 +139,7 @@ namespace ZL
|
||||
renderer.shaderManager.AddShaderFromFiles("planetStone", "resources/shaders/planet_stone.vertex", "resources/shaders/planet_stone_desktop.fragment", CONST_ZIP_FILE);
|
||||
renderer.shaderManager.AddShaderFromFiles("planetLand", "resources/shaders/planet_land.vertex", "resources/shaders/planet_land_desktop.fragment", CONST_ZIP_FILE);
|
||||
renderer.shaderManager.AddShaderFromFiles("spark", "resources/shaders/spark.vertex", "resources/shaders/spark_desktop.fragment", CONST_ZIP_FILE);
|
||||
renderer.shaderManager.AddShaderFromFiles("skinning", "resources/shaders/skinning.vertex", "resources/shaders/default_desktop.fragment", CONST_ZIP_FILE);
|
||||
#endif
|
||||
|
||||
std::cout << "Load resurces step 4" << std::endl;
|
||||
@ -158,12 +160,20 @@ namespace ZL
|
||||
|
||||
// Player (Viola)
|
||||
player = std::make_unique<Character>();
|
||||
/*
|
||||
player->loadAnimation(AnimationState::STAND, "resources/w/gg/gg_stand_idle001.txt", CONST_ZIP_FILE);
|
||||
player->loadAnimation(AnimationState::WALK, "resources/w/gg/gg_walking001.txt", CONST_ZIP_FILE);
|
||||
player->loadAnimation(AnimationState::STAND_TO_ACTION, "resources/w/gg/gg_stand_to_action002.txt", CONST_ZIP_FILE);
|
||||
player->loadAnimation(AnimationState::ACTION_ATTACK, "resources/w/gg/gg_action_attack001.txt", CONST_ZIP_FILE);
|
||||
player->loadAnimation(AnimationState::ACTION_IDLE, "resources/w/gg/gg_action_idle001.txt", CONST_ZIP_FILE);
|
||||
player->loadAnimation(AnimationState::ACTION_TO_STAND, "resources/w/gg/gg_action_to_stand001.txt", 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::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_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->setTexture(violaTexture);
|
||||
player->walkSpeed = 3.0f;
|
||||
@ -209,13 +219,20 @@ namespace ZL
|
||||
|
||||
std::cout << "Load resurces step 11" << std::endl;
|
||||
auto npc02 = std::make_unique<Character>();
|
||||
/*
|
||||
npc02->loadAnimation(AnimationState::STAND, "resources/w/default_float001.txt", CONST_ZIP_FILE);
|
||||
npc02->loadAnimation(AnimationState::WALK, "resources/w/default_float001.txt", CONST_ZIP_FILE);
|
||||
npc02->loadAnimation(AnimationState::ACTION_IDLE, "resources/w/float_attack003_cut.txt", CONST_ZIP_FILE);
|
||||
npc02->loadAnimation(AnimationState::ACTION_ATTACK, "resources/w/float_attack003.txt", CONST_ZIP_FILE);
|
||||
npc02->loadAnimation(AnimationState::STAND_TO_ACTION, "resources/w/default_float001_cut.txt", CONST_ZIP_FILE);
|
||||
npc02->loadAnimation(AnimationState::ACTION_TO_STAND, "resources/w/default_float001_cut.txt", CONST_ZIP_FILE);
|
||||
|
||||
*/
|
||||
npc02->loadBinaryAnimation(AnimationState::STAND, "resources/w/default_float001.anim", CONST_ZIP_FILE);
|
||||
npc02->loadBinaryAnimation(AnimationState::WALK, "resources/w/default_float001.anim", CONST_ZIP_FILE);
|
||||
npc02->loadBinaryAnimation(AnimationState::ACTION_IDLE, "resources/w/float_attack003_cut.anim", CONST_ZIP_FILE);
|
||||
npc02->loadBinaryAnimation(AnimationState::ACTION_ATTACK, "resources/w/float_attack003.anim", CONST_ZIP_FILE);
|
||||
npc02->loadBinaryAnimation(AnimationState::STAND_TO_ACTION, "resources/w/default_float001_cut.anim", CONST_ZIP_FILE);
|
||||
npc02->loadBinaryAnimation(AnimationState::ACTION_TO_STAND, "resources/w/default_float001_cut.anim", CONST_ZIP_FILE);
|
||||
//npc02->loadAnimation(AnimationState::STAND, "resources/w/float_attack003.txt", CONST_ZIP_FILE);
|
||||
//npc02->loadAnimation(AnimationState::STAND, "resources/idleviola_uv010.txt", CONST_ZIP_FILE);
|
||||
npc02->setTexture(ghostTexture);
|
||||
|
||||
@ -331,7 +331,14 @@ namespace ZL {
|
||||
|
||||
// Load animations
|
||||
try {
|
||||
npc->loadAnimation(AnimationState::STAND, npcData.animationIdlePath, zipPath);
|
||||
if (npcData.animationIdlePath.substr(npcData.animationIdlePath.size() - 5) == ".anim")
|
||||
{
|
||||
npc->loadBinaryAnimation(AnimationState::STAND, npcData.animationIdlePath, zipPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
npc->loadAnimation(AnimationState::STAND, npcData.animationIdlePath, zipPath);
|
||||
}
|
||||
std::cout << " Loaded IDLE animation: " << npcData.animationIdlePath << std::endl;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
@ -340,7 +347,15 @@ namespace ZL {
|
||||
}
|
||||
|
||||
try {
|
||||
npc->loadAnimation(AnimationState::WALK, npcData.animationWalkPath, zipPath);
|
||||
if (npcData.animationIdlePath.substr(npcData.animationIdlePath.size() - 5) == ".anim")
|
||||
{
|
||||
npc->loadBinaryAnimation(AnimationState::WALK, npcData.animationIdlePath, zipPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
npc->loadAnimation(AnimationState::WALK, npcData.animationWalkPath, zipPath);
|
||||
}
|
||||
|
||||
std::cout << " Loaded WALK animation: " << npcData.animationWalkPath << std::endl;
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
|
||||
@ -774,7 +774,7 @@ namespace ZL {
|
||||
void Renderer::RenderUniformMatrix4fv(const std::string& uniformName, bool transpose, const float* value)
|
||||
{
|
||||
auto shader = shaderManager.GetCurrentShader();
|
||||
|
||||
|
||||
auto uniform = shader->uniformList.find(uniformName);
|
||||
|
||||
if (uniform != shader->uniformList.end())
|
||||
@ -783,6 +783,18 @@ namespace ZL {
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::RenderUniformMatrix4fvArray(const std::string& uniformName, int count, bool transpose, const float* value)
|
||||
{
|
||||
auto shader = shaderManager.GetCurrentShader();
|
||||
|
||||
auto uniform = shader->uniformList.find(uniformName);
|
||||
|
||||
if (uniform != shader->uniformList.end())
|
||||
{
|
||||
glUniformMatrix4fv(uniform->second, count, transpose, value);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::RenderUniform3fv(const std::string& uniformName, const float* value)
|
||||
{
|
||||
auto shader = shaderManager.GetCurrentShader();
|
||||
@ -847,6 +859,13 @@ namespace ZL {
|
||||
glVertexAttribPointer(shader->attribList[attribName], 3, GL_FLOAT, GL_FALSE, stride, pointer);
|
||||
}
|
||||
|
||||
void Renderer::VertexAttribPointer4fv(const std::string& attribName, int stride, const char* pointer)
|
||||
{
|
||||
auto shader = shaderManager.GetCurrentShader();
|
||||
if (shader->attribList.find(attribName) != shader->attribList.end())
|
||||
glVertexAttribPointer(shader->attribList[attribName], 4, GL_FLOAT, GL_FALSE, stride, pointer);
|
||||
}
|
||||
|
||||
void Renderer::DisableVertexAttribArray(const std::string& attribName)
|
||||
{
|
||||
auto shader = shaderManager.GetCurrentShader();
|
||||
|
||||
@ -129,6 +129,7 @@ namespace ZL {
|
||||
|
||||
void RenderUniformMatrix3fv(const std::string& uniformName, bool transpose, const float* value);
|
||||
void RenderUniformMatrix4fv(const std::string& uniformName, bool transpose, const float* value);
|
||||
void RenderUniformMatrix4fvArray(const std::string& uniformName, int count, bool transpose, const float* value);
|
||||
void RenderUniform1i(const std::string& uniformName, const int value);
|
||||
void RenderUniform3fv(const std::string& uniformName, const float* value);
|
||||
void RenderUniform4fv(const std::string& uniformName, const float* value);
|
||||
@ -138,6 +139,8 @@ namespace ZL {
|
||||
|
||||
void VertexAttribPointer3fv(const std::string& attribName, int stride, const char* pointer);
|
||||
|
||||
void VertexAttribPointer4fv(const std::string& attribName, int stride, const char* pointer);
|
||||
|
||||
void DisableVertexAttribArray(const std::string& attribName);
|
||||
|
||||
void DrawVertexRenderStruct(const VertexRenderStruct& VertexRenderStruct);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user