myou-engine/tests/armature.nim

109 lines
3.7 KiB
Nim

import myou_engine
import std/sequtils
# Create engine, scene, camera
let engine = newMyouEngine(1024, 768)
let scene = engine.newScene()
let cam = scene.newCamera()
# Move the camera upwards (the default rotation looks down)
cam.position.z = 10
let armature = engine.newArmature(scene=scene)
let b0 = armature.add_bone("Bone", vec3(), quat(), 0, "", 0.5)
let b1 = armature.add_bone("Bone1", vec3(0,0.5,0), quat(), 1, "Bone", 0.5)
let b2 = armature.add_bone("Bone2", vec3(0,0.5,0), quat(), 2, "Bone1", 0.5)
let b3 = armature.add_bone("Bone3", vec3(0,0.5,0), quat(), 3, "Bone2", 0.5)
armature.update_rest_matrices
armature.position.y = -1
var layout: AttributeList
layout.add Attribute(name: "vertex", dtype: Float, count: 3)
layout.add Attribute(name: "weights", dtype: UByte, count: 4)
layout.add Attribute(name: "b_indices", dtype: UByte, count: 4)
var vertices: seq[(Vec3, array[4, uint8], array[4, uint8])]
var indices: seq[uint16]
const faces_x = 2
const faces_y = 16
for y in 0 .. faces_y:
for x in 0 .. faces_x:
let pos = vec3(0.5 * (x/faces_x - 0.5), 2f * (y/faces_y), -0.1)
let p = vec3(0, pos.y, 0)
var weights = [
clamp(0.5-(b0.dist_to_sphere(p) * 3), 0, 1),
clamp(0.5-(b1.dist_to_sphere(p) * 3), 0, 1),
clamp(0.5-(b2.dist_to_sphere(p) * 3), 0, 1),
clamp(0.5-(b3.dist_to_sphere(p) * 3), 0, 1),
]
let sum = weights.foldl a+b
let w_u8 = weights.mapIt uint8(255 * it/sum)
let w_u8a = [w_u8[0], w_u8[1], w_u8[2], w_u8[3]]
vertices.add (pos, w_u8a, [0'u8,1,2,3])
for y in 0'u16 ..< faces_y.uint16:
let p = y * (faces_x.uint16 + 1)
for x in p ..< p + faces_x.uint16:
let x2 = x + faces_x.uint16 + 1
indices.add @[
x, x+1, x2,
x2, x+1, x2+1,
]
let grid = scene.newMesh("grid",
layout = layout,
vertex_array = vertices,
index_array = indices,
)
grid.parent_to armature, keep_transform=false
grid.armature = armature
grid.add_modifier engine.newArmatureModifier(4)
grid.materials.add engine.newSolidMaterial("blue", vec4(0.1,0.3,1,1))
# TODO: Move visualization of armature wireframe to the engine
let wireframe = scene.newMesh("wireframe", draw_method=Lines, vertex_count=8)
wireframe.parent_to armature, keep_transform=false
wireframe.materials.add engine.newSolidMaterial("white", vec4(1))
const OCTAEDRON = @[
vec3(0), vec3(-0.1, 0.1, -0.1),
vec3(0), vec3(-0.1, 0.1, 0.1),
vec3(0), vec3(0.1, 0.1, -0.1),
vec3(0), vec3(0.1, 0.1, 0.1),
vec3(0.1, 0.1, 0.1), vec3(-0.1, 0.1, -0.1),
vec3(-0.1, 0.1, -0.1), vec3(-0.1, 0.1, 0.1),
vec3(-0.1, 0.1, 0.1), vec3(0.1, 0.1, -0.1),
vec3(0.1, 0.1, -0.1), vec3(0.1, 0.1, 0.1),
vec3(-0.1, 0.1, -0.1), vec3(0,1,0),
vec3(-0.1, 0.1, 0.1), vec3(0,1,0),
vec3(0.1, 0.1, -0.1), vec3(0,1,0),
vec3(0.1, 0.1, 0.1), vec3(0,1,0),
]
proc update_wireframe() =
armature.recalculate_bone_matrices() # only needed here for visualization
wireframe.clear_vertices()
wireframe.ensure_capacity(OCTAEDRON.len * armature.bone_list.len)
for bone in armature.bone_list:
let m = bone.matrix
for point in OCTAEDRON:
wireframe.add_vertex(m * (bone.blength * point))
wireframe.data.update_varray()
update_wireframe()
var time = -1.0
scene.pre_draw_callbacks.add proc(scene: Scene, dt: float) =
time += dt
if time < 0:
return
let f = time * 2f
const w = 1.0
armature.bones["Bone"].rotation = quat().rotateZ(-sin(f) * w)
armature.bones["Bone1"].rotation = quat().rotateZ(-sin(f*1.1) * w)
armature.bones["Bone2"].rotation = quat().rotateZ(-sin(f*1.2) * w)
armature.bones["Bone3"].rotation = quat().rotateZ(-sin(f*1.4) * w)
update_wireframe()
scene.enable_render()
engine.run()