Working on optimization: GPU skinning and binary animations
This commit is contained in:
1 parent
a589765b7e
commit
f708843747
24 files changed
+890
-489525
No files matched your search
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large.
Load diff
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.
@@ -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;
|
||||
|
||||
+18
-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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
+137
-35
@@ -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
|
||||
+18
-1
@@ -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) {
|
||||
|
||||
+20
-1
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user