1 Commits

Author SHA1 Message Date
302f96af3f Going crazy with translations 2026-03-29 22:21:59 +02:00
3 changed files with 481 additions and 203 deletions

View File

@@ -7,39 +7,144 @@ const Mesh = @import("mesh.zig");
const Shader = @import("shader.zig");
const Tree = @import("../tree.zig").Tree;
pub const Animation = struct {
rotation: zm.Quat,
translation: zm.Mat,
};
pub const JointData = struct {
mesh: Mesh,
translation: zm.Mat,
rotation: zm.Quat,
animated_transform: zm.Mat = zm.identity(),
local_bind_transform: zm.Mat,
inverse_bind_transform: zm.Mat = zm.identity(),
keyframes: [2]Animation,
count: usize,
var counter: usize = 0;
pub fn init(mesh: Mesh, translation: zm.Mat, rotation: zm.Quat, keyframes: [2]zm.Quat) JointData {
const res = JointData{
.mesh = mesh,
.local_bind_transform = zm.mul(
zm.quatToMat(rotation),
translation,
),
.count = counter,
.keyframes = .{
.{ .rotation = keyframes[0], .translation = translation },
.{ .rotation = keyframes[1], .translation = translation },
},
};
counter += 1;
return res;
}
};
data: Tree(JointData),
animaton_duration: f32 = 1,
animaton_time: f32 = 0,
pub fn init(
data: Tree(JointData),
) @This() {
pub fn init(data: Tree(JointData)) !@This() {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const arena_allocator = arena.allocator();
var c_data = data;
var iter = try c_data.levelOrderIterator(arena_allocator);
while (iter.next()) |node| {
for (node.children.items) |*child| {
child.val.local_bind_transform = zm.mul(
child.val.local_bind_transform,
node.val.local_bind_transform,
);
}
}
return .{ .data = data };
}
pub fn draw(self: *@This(), allocator: std.mem.Allocator, shader: Shader) !void {
var iter = self.data.depthFirstIterator();
defer iter.deinit(allocator);
while (try iter.next(allocator)) |node| {
const rotation = node.val.rotation;
// var current = node;
// while (current.parent) |parent| {
// rotation = zm.qmul(rotation, parent.val.rotation);
// current = parent;
// }
pub fn draw(self: *@This(), shader: Shader) !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const allocator = arena.allocator();
const model_matrix = zm.mul(zm.quatToMat(rotation), node.val.translation);
const normal_matrix = zm.transpose(zm.inverse(model_matrix));
var iter = try self.data.preOrderIterator(allocator);
defer iter.deinit(allocator);
while (iter.next()) |node| {
const model_matrix = zm.mul(
node.val.animated_transform,
node.val.local_bind_transform,
);
shader.updateUniformMatrix("u_model_matrix", &.{model_matrix});
shader.updateUniformMatrix("u_normal_matrix", &.{normal_matrix});
shader.updateUniformMatrix("u_normal_matrix", &.{zm.transpose(zm.inverse(model_matrix))});
node.val.mesh.draw(shader);
}
}
pub fn animate(self: *@This(), delta_time: f32) !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const arena_allocator = arena.allocator();
var iter = try self.data.levelOrderIterator(arena_allocator);
self.animaton_time += delta_time;
if (self.animaton_time / self.animaton_duration < 1) {
while (iter.next()) |node| {
node.val.animated_transform = zm.mul(
zm.quatToMat(zm.slerp(
node.val.keyframes[0].rotation,
node.val.keyframes[1].rotation,
self.animaton_time / self.animaton_duration,
)),
node.val.keyframes[0].translation,
);
for (node.children.items) |*child| {
child.val.animated_transform = zm.mul(
node.val.animated_transform,
child.val.animated_transform,
);
}
}
} else if (self.animaton_time / self.animaton_duration < 2) {
while (iter.next()) |node| {
node.val.animated_transform = zm.mul(
zm.quatToMat(zm.slerp(
node.val.keyframes[1].rotation,
node.val.keyframes[0].rotation,
self.animaton_time / self.animaton_duration - 1,
)),
node.val.keyframes[1].translation,
);
for (node.children.items) |*child| {
child.val.animated_transform = zm.mul(
child.val.animated_transform,
node.val.animated_transform,
);
}
}
} else {
self.animaton_time = 0;
return;
}
iter = try self.data.levelOrderIterator(arena_allocator);
// while (iter.next()) |node| {
// for (node.children.items) |*child| {
// child.val.animated_transform = zm.mul(
// node.val.animated_transform,
// child.val.animated_transform,
// );
// }
// }
}
pub fn deinit(self: *@This(), allocator: std.mem.Allocator) !void {
try self.data.deinit(allocator);
}

View File

@@ -133,7 +133,6 @@ pub fn main() !void {
var previous_time = glfw_helper.getTime();
var current_time: f64 = 0;
var delta_time: f64 = undefined;
// var frame_counter: u16 = 0;
// OpenGL setup
const clear_color = FloatColor.sky_blue;
@@ -162,8 +161,8 @@ pub fn main() !void {
model_shader.updateUniformMatrix("u_normal_matrix", &.{zm.identity()});
floor.draw(model_shader);
// animateRobot(&frame_counter, robot);
try robot.draw(allocator, model_shader);
try robot.animate(@floatCast(delta_time));
try robot.draw(model_shader);
},
.fish => {},
}
@@ -204,125 +203,207 @@ fn initFloor(textures: ?[]const Texture) Mesh {
}
fn initRobot(allocator: std.mem.Allocator, textures: ?[]const Texture) !Model {
// var meshes = try std.ArrayList(Mesh).initCapacity(allocator, 14);
// var translations = try std.ArrayList(Mat).initCapacity(allocator, 14);
var shape = Shape.initCube();
defer shape.deinit();
shape.unweld();
shape.computeNormals();
shape.translate(-0.5, -1, -0.5);
// shape.rotate(std.math.degreesToRadians(180), 1, 0, 0);
// var foot = shape.clone();
// defer foot.deinit();
// foot.scale(0.1, 0.025, 0.15);
// meshes.appendNTimesAssumeCapacity(Mesh.initShape(foot, textures, .triangles), 2);
// translations.appendAssumeCapacity(zm.translation(-0.07, 0.025, 0));
// translations.appendAssumeCapacity(zm.translation(0.07, 0.025, 0));
// var leg = shape.clone();
// defer leg.deinit();
// leg.scale(0.08, 0.2, 0.08);
// meshes.appendNTimesAssumeCapacity(Mesh.initShape(leg, textures, .triangles), 4);
// translations.appendAssumeCapacity(zm.translation(-0.07, 0.225, 0));
// translations.appendAssumeCapacity(zm.translation(0.07, 0.225, 0));
// translations.appendAssumeCapacity(zm.translation(-0.07, 0.425, 0));
// translations.appendAssumeCapacity(zm.translation(0.07, 0.425, 0));
// var arm = shape.clone();
// defer arm.deinit();
// arm.scale(0.08, 0.2, 0.08);
// meshes.appendNTimesAssumeCapacity(Mesh.initShape(arm, textures, .triangles), 4);
// translations.appendAssumeCapacity(zm.translation(-0.3 / 2.0 - 0.04, 0.225 + 0.4, 0));
// translations.appendAssumeCapacity(zm.translation(0.3 / 2.0 + 0.04, 0.225 + 0.4, 0));
// translations.appendAssumeCapacity(zm.translation(-0.3 / 2.0 - 0.04, 0.425 + 0.4, 0));
// translations.appendAssumeCapacity(zm.translation(0.3 / 2.0 + 0.04, 0.425 + 0.4, 0));
// var hand = shape.clone();
// defer hand.deinit();
// hand.scale(0.025, 0.08, 0.07);
// meshes.appendNTimesAssumeCapacity(Mesh.initShape(hand, textures, .triangles), 2);
// translations.appendAssumeCapacity(zm.translation(-0.3 / 2.0 - 0.04, 0.425, 0));
// translations.appendAssumeCapacity(zm.translation(0.3 / 2.0 + 0.04, 0.425, 0));
var chest = shape.clone();
defer chest.deinit();
chest.scale(0.3, 0.4, 0.15);
// meshes.appendAssumeCapacity(Mesh.initShape(chest, textures, .triangles));
// translations.appendAssumeCapacity(zm.translation(0, 0.425 + 0.4, 0));
var model_data = Tree(Model.JointData).init(
.{
.mesh = Mesh.initShape(chest, textures, .triangles),
.translation = zm.translation(0, 0.425 + 0.4, 0),
.rotation = zm.qidentity(),
},
.init(
.initShape(chest, textures, .triangles),
zm.translation(0, 0.825, 0),
zm.qidentity(),
.{ zm.qidentity(), zm.qidentity() },
),
);
var head = shape.clone();
defer head.deinit();
head.scale(0.1, 0.1, 0.1);
head.rotate(std.math.degreesToRadians(180), 1, 0, 0);
try model_data.root.append(
allocator,
.init(
.initShape(head, textures, .triangles),
zm.translation(0, 0, 0),
zm.qidentity(),
.{
zm.quatFromRollPitchYaw(0, -0.5, 0),
zm.quatFromRollPitchYaw(0, 0.5, 0),
},
),
);
try model_data.root.append(allocator, .{
.mesh = Mesh.initShape(head, textures, .triangles),
.translation = zm.translation(0, 0.425 + 0.4 + 0.1, 0),
.rotation = zm.qidentity(),
});
// meshes.appendAssumeCapacity(Mesh.initShape(head, textures, .triangles));
// translations.appendAssumeCapacity(zm.translation(0, 0.425 + 0.4 + 0.1, 0));
var arm = shape.clone();
defer arm.deinit();
arm.scale(0.08, 0.2, 0.08);
var right_arm = try model_data.root.create(
allocator,
.init(
.initShape(arm, textures, .triangles),
zm.translation(-0.3 / 2.0 - 0.04, 0, 0),
zm.qidentity(),
.{
zm.quatFromRollPitchYaw(0.6, 0, 0),
zm.quatFromRollPitchYaw(-0.6, 0, 0),
},
),
);
right_arm = try right_arm.create(
allocator,
.init(
.initShape(arm, textures, .triangles),
zm.translation(0, -0.2, 0),
zm.quatFromRollPitchYaw(-0.6, 0, 0),
.{
zm.quatFromRollPitchYaw(0.6, 0, 0),
zm.quatFromRollPitchYaw(-0.6, 0, 0),
},
),
);
return Model.init(model_data);
var left_arm = try model_data.root.create(
allocator,
.init(
.initShape(arm, textures, .triangles),
zm.translation(0.3 / 2.0 + 0.04, 0, 0),
zm.qidentity(),
.{
zm.qidentity(),
zm.qidentity(),
},
),
);
left_arm = try left_arm.create(
allocator,
.init(
.initShape(arm, textures, .triangles),
zm.translation(0, -0.2, 0),
zm.qidentity(),
.{
zm.qidentity(),
zm.qidentity(),
},
),
);
var hand = shape.clone();
defer hand.deinit();
hand.scale(0.025, 0.08, 0.07);
try right_arm.append(
allocator,
.init(
.initShape(hand, textures, .triangles),
zm.translation(0, -0.2, 0),
zm.qidentity(),
.{
zm.qidentity(),
zm.qidentity(),
},
),
);
try left_arm.append(
allocator,
.init(
.initShape(hand, textures, .triangles),
zm.translation(0, -0.2, 0),
zm.qidentity(),
.{
zm.qidentity(),
zm.qidentity(),
},
),
);
var leg = shape.clone();
defer leg.deinit();
leg.scale(0.08, 0.2, 0.08);
var right_leg = try model_data.root.create(
allocator,
.init(
.initShape(leg, textures, .triangles),
zm.translation(-0.07, -0.4, 0),
zm.qidentity(),
.{
zm.qidentity(),
zm.qidentity(),
},
),
);
right_leg = try right_leg.create(
allocator,
.init(
.initShape(leg, textures, .triangles),
zm.translation(0, -0.2, 0),
zm.qidentity(),
.{
zm.qidentity(),
zm.qidentity(),
},
),
);
var left_leg = try model_data.root.create(
allocator,
.init(
.initShape(leg, textures, .triangles),
zm.translation(0.07, -0.4, 0),
zm.qidentity(),
.{
zm.qidentity(),
zm.qidentity(),
},
),
);
left_leg = try left_leg.create(
allocator,
.init(
.initShape(leg, textures, .triangles),
zm.translation(0, -0.2, 0),
zm.qidentity(),
.{
zm.qidentity(),
zm.qidentity(),
},
),
);
var foot = shape.clone();
defer foot.deinit();
foot.scale(0.1, 0.025, 0.15);
try right_leg.append(
allocator,
.init(
.initShape(foot, textures, .triangles),
zm.translation(0, -0.2, 0),
zm.qidentity(),
.{
zm.qidentity(),
zm.qidentity(),
},
),
);
try left_leg.append(
allocator,
.init(
.initShape(foot, textures, .triangles),
zm.translation(0, -0.2, 0),
zm.qidentity(),
.{
zm.qidentity(),
zm.qidentity(),
},
),
);
return try Model.init(model_data);
}
// fn initRobot(allocator: std.mem.Allocator, textures: ?[]const Texture) Model {
// var shape = Shape.initCube();
// defer shape.deinit();
// shape.unweld();
// shape.computeNormals();
// shape.translate(-0.5, -1, -0.5);
// var chest = shape.clone();
// defer chest.deinit();
// chest.scale(0.3, 0.4, 0.15);
// var model_data = Tree(Model.JointData).init(.{
// .mesh = Mesh.initShape(chest, textures, .triangles),
// .translation = zm.translation(0, 0.425 + 0.4, 0),
// .rotation = zm.qidentity(),
// });
// var head = shape.clone();
// defer head.deinit();
// head.scale(0.1, 0.1, 0.1);
// try model_data.root.append(allocator, .{
// .mesh = Mesh.initShape(head, textures, .triangles),
// .translation = zm.translation(0, 0.425 + 0.4 + 0.1, 0),
// .rotation = zm.qidentity(),
// });
// return Model.init(model_data);
// }
// fn animateRobot(frame_counter: *u16, robot: Model) void {
// if (frame_counter.* > robot.animation_frames) {
// robot.translations.items[2] = zm.mul(zm.rotationX(-std.math.degreesToRadians(1)), robot.translations.items[2]);
// robot.translations.items[3] = zm.mul(zm.rotationX(-std.math.degreesToRadians(1)), robot.translations.items[3]);
// } else {
// robot.translations.items[2] = zm.mul(zm.rotationX(std.math.degreesToRadians(1)), robot.translations.items[2]);
// robot.translations.items[3] = zm.mul(zm.rotationX(std.math.degreesToRadians(1)), robot.translations.items[3]);
// }
// frame_counter.* += 1;
// if (frame_counter.* > robot.animation_frames * 2) {
// frame_counter.* = 0;
// }
// }
fn drawGui(light_ubo: zgl.Buffer, light_shader: gl_helper.Shader, light_color: *zm.Vec) void {
if (app_state.render_gui) {
zgui.backend.newFrame(@intCast(app_state.width), @intCast(app_state.height));

View File

@@ -11,7 +11,6 @@ pub fn Tree(comptime T: type) type {
const Children = ArrayList(Node);
const Node = struct {
val: T,
// index: usize,
children: ArrayList(Node),
pub fn init(val: T) Node {
@@ -25,99 +24,195 @@ pub fn Tree(comptime T: type) type {
const child = Node.init(val);
try self.children.append(allocator, child);
}
pub fn create(self: *Node, allocator: Allocator, val: T) !*Node {
const child = Node.init(val);
try self.children.append(allocator, child);
return &self.children.items[self.children.items.len - 1];
}
};
pub fn init(val: T) @This() {
return .{ .root = .init(val) };
}
pub const DepthFirstIterator = struct {
const Frame = struct {
parent: ?*Node,
index: usize,
};
const State = enum {
GoDeeper,
GoBroader,
};
tree: *Tree(T),
current: ?*Node,
path: ArrayList(Frame),
state: State,
pub const PreOrderIterator = struct {
pre_order: ArrayList(*Node),
index: usize,
pub fn init(tree: *Tree(T)) DepthFirstIterator {
return DepthFirstIterator{
.tree = tree,
.current = &tree.root,
.path = .empty,
.state = State.GoDeeper,
pub fn init(tree: *Tree(T), allocator: Allocator) !PreOrderIterator {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const arena_allocator = arena.allocator();
var stack = try ArrayList(*Node).initCapacity(arena_allocator, 1);
stack.appendAssumeCapacity(&tree.root);
var pre_order = ArrayList(*Node).empty;
while (stack.items.len > 0) {
if (stack.pop()) |tmp| {
try pre_order.insert(allocator, 0, tmp);
for (0..tmp.children.items.len) |i| {
try stack.append(arena_allocator, &tmp.children.items[i]);
}
}
}
return .{
.index = 0,
.pre_order = pre_order,
};
}
pub fn next(it: *DepthFirstIterator, allocator: Allocator) !?*Node {
// State machine
while (it.current) |current| {
switch (it.state) {
State.GoDeeper => {
// Follow child node until deepest possible level
if (current.children.items.len > 0) {
try it.path.append(allocator, .{
.index = 0,
.parent = current,
});
it.current = &current.children.items[0];
} else {
it.state = State.GoBroader;
_ = it.path.pop();
return current;
}
},
State.GoBroader => {
const last_frame = it.path.pop();
if (last_frame) |frame| {
if (frame.parent) |parent| {
if (parent.children.items.len > frame.index + 1) {
it.current = &parent.children.items[frame.index + 1];
} else {
it.current = parent;
// return it.path.pop().?.parent;
}
} else {
return null;
}
// if (parent.children.items.len > current.index + 1) {
// it.current = &parent.children.items[current.index + 1];
// it.state = .GoDeeper;
// } else {
// it.current = current.parent;
// return current.parent;
// }
} else {
return null;
}
},
}
pub fn next(it: *PreOrderIterator) ?*Node {
while (it.index < it.pre_order.items.len) {
const val = it.pre_order.items[it.index];
it.index += 1;
return val;
}
return null;
}
pub fn reset(it: *DepthFirstIterator) void {
it.current = it.tree.root;
}
pub fn deinit(self: *DepthFirstIterator, allocator: Allocator) void {
self.path.deinit(allocator);
pub fn deinit(self: *PreOrderIterator, allocator: Allocator) void {
self.pre_order.deinit(allocator);
}
};
pub fn depthFirstIterator(tree: *@This()) DepthFirstIterator {
return DepthFirstIterator.init(tree);
pub fn preOrderIterator(tree: *@This(), allocator: Allocator) !PreOrderIterator {
return PreOrderIterator.init(tree, allocator);
}
pub const PostOrderIterator = struct {
post_order: ArrayList(*Node),
index: usize,
const Frame = struct {
node: *Node,
children_index: usize,
};
pub fn init(tree: *Tree(T), allocator: Allocator) !PostOrderIterator {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const arena_allocator = arena.allocator();
var stack = ArrayList(Frame).empty;
var current_root_index: usize = 0;
var post_order = ArrayList(*Node).empty;
var curr_node: ?*Node = &tree.root;
while (curr_node != null or stack.items.len > 0) {
if (curr_node) |cur| {
try stack.append(arena_allocator, .{
.children_index = current_root_index,
.node = cur,
});
if (cur.children.items.len >= 1) {
curr_node = &cur.children.items[0];
} else {
curr_node = null;
}
continue;
}
if (stack.pop()) |tmp| {
try post_order.append(allocator, tmp.node);
while (stack.items.len > 0 and tmp.children_index == stack.items[stack.items.len - 1].node.children.items.len - 1) {
if (stack.pop()) |tmp2| {
try post_order.append(allocator, tmp2.node);
}
}
if (stack.items.len > 0 and stack.items[stack.items.len - 1].node.children.items.len > tmp.children_index + 1) {
curr_node = &stack.items[stack.items.len - 1].node.children.items[tmp.children_index + 1];
current_root_index = tmp.children_index + 1;
}
}
}
return .{
.index = 0,
.post_order = post_order,
};
}
pub fn next(it: *PostOrderIterator) ?*Node {
while (it.index < it.post_order.items.len) {
const val = it.post_order.items[it.index];
it.index += 1;
return val;
}
return null;
}
pub fn deinit(self: *PostOrderIterator, allocator: Allocator) void {
self.post_order.deinit(allocator);
}
};
pub fn postOrderIterator(tree: *@This(), allocator: Allocator) !PostOrderIterator {
return PostOrderIterator.init(tree, allocator);
}
pub const LevelOrderIterator = struct {
level_order: ArrayList(*Node),
index: usize,
pub fn init(tree: *Tree(T), allocator: Allocator) !LevelOrderIterator {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const arena_allocator = arena.allocator();
var stack = try ArrayList(*Node).initCapacity(arena_allocator, 1);
stack.appendAssumeCapacity(&tree.root);
var level_order = ArrayList(*Node).empty;
while (stack.items.len > 0) {
if (stack.pop()) |tmp| {
try level_order.append(allocator, tmp);
for (0..tmp.children.items.len) |i| {
try stack.append(arena_allocator, &tmp.children.items[i]);
}
}
}
return .{
.index = 0,
.level_order = level_order,
};
}
pub fn next(it: *LevelOrderIterator) ?*Node {
while (it.index < it.level_order.items.len) {
const val = it.level_order.items[it.index];
it.index += 1;
return val;
}
return null;
}
pub fn deinit(self: *LevelOrderIterator, allocator: Allocator) void {
self.level_order.deinit(allocator);
}
};
pub fn levelOrderIterator(tree: *@This(), allocator: Allocator) !LevelOrderIterator {
return LevelOrderIterator.init(tree, allocator);
}
pub fn deinit(self: *@This(), allocator: Allocator) !void {
var iterator = self.depthFirstIterator();
defer iterator.deinit(allocator);
while (try iterator.next(allocator)) |node| {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit();
const arena_allocator = arena.allocator();
var iterator = try self.postOrderIterator(arena_allocator);
while (iterator.next()) |node| {
node.children.deinit(allocator);
}
}
@@ -156,20 +251,17 @@ test "Tree" {
const UTree = Tree(u16);
var tree = UTree.init(10);
defer tree.deinit(allocator);
defer tree.deinit(allocator) catch {};
try tree.root.append(allocator, 20);
try tree.root.append(allocator, 500);
var iterator = tree.depthFirstIterator();
try tree.root.children.items[1].append(allocator, 999);
var iterator = try tree.levelOrderIterator(allocator);
defer iterator.deinit(allocator);
std.debug.print("\n", .{});
while (iterator.next()) |node| {
var accumulator: u32 = node.val;
var current = node;
while (current.parent) |parent| {
accumulator *= parent.val;
current = parent;
}
std.debug.print("Val: {} Acc: {}\n", .{ node.val, accumulator });
std.debug.print("Val: {}\n", .{node.val});
}
}