Commit 1555a334 authored by TheNumbat's avatar TheNumbat
Browse files

upstream changes

parent 0ec99641
......@@ -26,17 +26,6 @@ void Animate::update_dim(Vec2 dim) { ui_camera.dim(dim); }
bool Animate::keydown(Widgets &widgets, Undo &undo, Scene_ID sel, SDL_Keysym key) {
#ifdef __APPLE__
if (key.sym == SDLK_BACKSPACE && key.mod & KMOD_GUI) {
#else
if (key.sym == SDLK_DELETE) {
#endif
if (joint_select)
undo.del_bone(sel, joint_select);
else if (sel)
undo.del_obj(sel);
}
if (key.sym == SDLK_SPACE) {
playing = !playing;
last_frame = SDL_GetPerformanceCounter();
......@@ -76,16 +65,17 @@ void Animate::render(Scene &scene, Scene_Maybe obj_opt, Widgets &widgets, Camera
Scene_Object &obj = item.get<Scene_Object>();
joint_id_offset = scene.used_ids();
obj.armature.render(view * obj.pose.transform(), joint_select, false, true,
obj.armature.render(view * obj.pose.transform(), joint_select, handle_select, false, true,
joint_id_offset);
if (!joint_select) {
if (!joint_select && !handle_select) {
R.begin_outline();
BBox box = obj.bbox();
obj.render(view, false, true);
obj.armature.outline(view * obj.pose.transform(), joint_select, false, true, box,
joint_id_offset);
obj.armature.outline(view * obj.pose.transform(), false, true, box, joint_id_offset);
R.end_outline(view, box);
} else if (handle_select) {
widgets.active = Widget_Type::move;
} else {
widgets.active = Widget_Type::rotate;
}
......@@ -94,7 +84,12 @@ void Animate::render(Scene &scene, Scene_Maybe obj_opt, Widgets &widgets, Camera
R.outline(view, item);
}
if (joint_select) {
if (handle_select) {
Scene_Object &obj = item.get<Scene_Object>();
widgets.render(view, pose.transform() * (handle_select->target + obj.armature.base()), scale);
} else if (joint_select) {
Scene_Object &obj = item.get<Scene_Object>();
widgets.render(view, pose.transform() * obj.armature.posed_base_of(joint_select), scale);
......@@ -150,19 +145,49 @@ void Animate::camera_spline() {
void Animate::UIsidebar(Manager &manager, Undo &undo, Scene_Maybe obj_opt, Camera &user_cam) {
if (joint_select) {
if (handle_select) {
Scene_ID id = obj_opt.value().get().id();
ImGui::Text("Edit IK Handle");
ImGui::DragFloat3("Pos", handle_select->target.data, 0.1f, 0.0f, 0.0f, "%.2f");
if (ImGui::IsItemActivated())
old_euler = handle_select->target;
if (ImGui::IsItemDeactivatedAfterEdit() && old_euler != handle_select->target) {
undo.move_handle(id, handle_select, old_euler);
}
ImGui::Checkbox("Enable", &handle_select->enabled);
ImGui::Separator();
} else if (joint_select) {
Scene_Item& item = obj_opt.value().get();
Scene_ID id = item.id();
ImGui::Text("Edit Joint");
if (ImGui::DragFloat3("Pose", joint_select->pose.data, 1.0f, 0.0f, 0.0f, "%.2f"))
obj_opt.value().get().get<Scene_Object>().set_pose_dirty();
if (ImGui::IsItemActivated())
old_euler = joint_select->pose;
if (ImGui::IsItemDeactivatedAfterEdit() && old_euler != joint_select->pose) {
joint_select->pose = joint_select->pose.range(0.0f, 360.0f);
undo.pose_bone(obj_opt.value().get().id(), joint_select, old_euler);
undo.pose_bone(id, joint_select, old_euler);
}
ImGui::Separator();
}
if (obj_opt.has_value()) {
Scene_Item& item = obj_opt.value().get();
if (item.is<Scene_Object>()) {
Scene_Object& obj = item.get<Scene_Object>();
if (obj.armature.has_bones()) {
if (obj.armature.do_ik())
obj.set_pose_dirty();
}
}
}
if (ui_camera.UI(undo, user_cam)) {
camera_selected = true;
if (obj_opt.has_value())
......@@ -171,17 +196,22 @@ void Animate::UIsidebar(Manager &manager, Undo &undo, Scene_Maybe obj_opt, Camer
}
void Animate::end_transform(Undo &undo, Scene_Item &obj) {
if (joint_select) {
if (handle_select) {
undo.move_handle(obj.id(), handle_select, old_pose.pos - obj.get<Scene_Object>().armature.base());
} else if (joint_select) {
undo.pose_bone(obj.id(), joint_select, old_euler);
} else {
undo.update_pose(obj.id(), old_pose);
}
old_pose = {};
old_euler = {};
old_p_to_j = Mat4::I;
}
Vec3 Animate::selected_pos(Scene_Item &item) {
if (joint_select) {
if (handle_select) {
return item.pose().transform() * (handle_select->target + item.get<Scene_Object>().armature.base());
} else if (joint_select) {
return item.pose().transform() *
item.get<Scene_Object>().armature.posed_base_of(joint_select);
}
......@@ -189,7 +219,9 @@ Vec3 Animate::selected_pos(Scene_Item &item) {
}
void Animate::apply_transform(Widgets &widgets, Scene_Item &item) {
if (joint_select) {
if (handle_select) {
handle_select->target = widgets.apply_action(old_pose).pos - item.get<Scene_Object>().armature.base();
} else if (joint_select) {
Scene_Object &obj = item.get<Scene_Object>();
Vec3 euler = widgets.apply_action(old_pose).euler;
joint_select->pose = (old_p_to_j * Mat4::euler(euler)).to_euler();
......@@ -204,7 +236,14 @@ bool Animate::select(Scene &scene, Widgets &widgets, Scene_ID selected, Scene_ID
if (widgets.want_drag()) {
if (joint_select) {
if (handle_select) {
Scene_Object &obj = scene.get_obj(selected);
widgets.start_drag(handle_select->target + obj.armature.base(), cam, spos, dir);
old_pose = {};
old_pose.pos = handle_select->target + obj.armature.base();
} else if (joint_select) {
Scene_Object &obj = scene.get_obj(selected);
Vec3 base = obj.pose.transform() * obj.armature.posed_base_of(joint_select);
......@@ -238,8 +277,11 @@ bool Animate::select(Scene &scene, Widgets &widgets, Scene_ID selected, Scene_ID
Scene_ID j_id = id - joint_id_offset;
joint_select = obj.armature.get_joint(j_id);
handle_select = obj.armature.get_handle(j_id);
if (joint_select) {
widgets.active = Widget_Type::rotate;
} else if(handle_select) {
widgets.active = Widget_Type::move;
}
return false;
}
......@@ -249,11 +291,13 @@ bool Animate::select(Scene &scene, Widgets &widgets, Scene_ID selected, Scene_ID
if (id >= n_Widget_IDs) {
if (id == selected) {
joint_select = nullptr;
handle_select = nullptr;
}
return true;
}
joint_select = nullptr;
handle_select = nullptr;
return false;
}
......@@ -564,6 +608,15 @@ void Animate::refresh(Scene &scene) { set_time(scene, (float)current_frame); }
void Animate::clear() {
anim_camera.splines.clear();
joint_select = nullptr;
handle_select = nullptr;
}
void Animate::invalidate(Skeleton::IK_Handle* handle) {
if (handle_select == handle) handle_select = nullptr;
}
void Animate::invalidate(Joint* j) {
if (joint_select == j) joint_select = nullptr;
}
void Animate::update(Scene &scene) {
......
......@@ -52,6 +52,8 @@ public:
const Anim_Camera &camera() const;
Anim_Camera &camera();
void set(int n_frames, int fps);
void invalidate(Skeleton::IK_Handle* handle);
void invalidate(Joint* handle);
private:
Uint64 last_frame = 0;
......@@ -66,6 +68,7 @@ private:
Anim_Camera anim_camera;
Joint *joint_select = nullptr;
Skeleton::IK_Handle *handle_select = nullptr;
unsigned int joint_id_offset = 0;
Pose old_pose;
......
......@@ -38,6 +38,8 @@ void Manager::invalidate_obj(Scene_ID id) {
if (id == layout.selected()) {
layout.clear_select();
model.unset_mesh();
rig.clear();
animate.clear();
}
}
......@@ -129,12 +131,22 @@ void Manager::save_scene(Scene &scene) {
set_error(error);
}
static bool postfix(const std::string &path, const std::string &type) {
if (path.length() >= type.length())
return path.compare(path.length() - type.length(), type.length(), type) == 0;
return false;
}
void Manager::write_scene(Scene &scene) {
char *path = nullptr;
NFD_SaveDialog("dae", nullptr, &path);
if (path) {
std::string error = scene.write(std::string(path), render.get_cam(), animate);
std::string spath(path);
if (!postfix(path, ".dae")) {
spath += ".dae";
}
std::string error = scene.write(spath, render.get_cam(), animate);
set_error(error);
free(path);
}
......
......@@ -39,6 +39,7 @@ struct Color {
RGBv(red, 163, 66, 81);
RGBv(green, 124, 172, 40);
RGBv(blue, 64, 127, 193);
RGBv(hoverg, 102, 204, 102);
static Vec3 axis(Axis a);
};
#undef RGBv
......
......@@ -13,11 +13,17 @@ bool Rig::keydown(Widgets &widgets, Undo &undo, SDL_Keysym key) {
#ifdef __APPLE__
if (key.sym == SDLK_BACKSPACE && key.mod & KMOD_GUI) {
#else
if (key.sym == SDLK_DELETE && selected) {
if (key.sym == SDLK_DELETE && (selected || handle)) {
#endif
undo.del_bone(my_obj->id(), selected);
selected = nullptr;
return true;
if (selected) {
undo.del_bone(my_obj->id(), selected);
selected = nullptr;
return true;
} else if(handle) {
undo.del_handle(my_obj->id(), handle);
handle = nullptr;
return true;
}
}
return false;
}
......@@ -38,6 +44,7 @@ void Rig::render(Scene_Maybe obj_opt, Widgets &widgets, Camera &cam) {
if (my_obj != &obj) {
my_obj = &obj;
selected = nullptr;
handle = nullptr;
}
if (my_obj->rig_dirty) {
mesh_bvh.build(obj.mesh());
......@@ -46,15 +53,17 @@ void Rig::render(Scene_Maybe obj_opt, Widgets &widgets, Camera &cam) {
Mat4 view = cam.get_view();
obj.render(view, false, false, false, false);
obj.armature.render(view, selected, root_selected, false);
obj.armature.render(view, selected, handle, root_selected, false);
if (selected || root_selected) {
if (selected || handle || root_selected) {
widgets.active = Widget_Type::move;
Vec3 pos;
if (selected)
pos = obj.armature.end_of(selected);
else if (handle)
pos = handle->target + obj.armature.base();
else
pos = obj.armature.base();
......@@ -70,11 +79,18 @@ void Rig::invalidate(Joint *j) {
new_joint = nullptr;
}
void Rig::invalidate(Skeleton::IK_Handle *j) {
if (handle == j)
handle = nullptr;
}
void Rig::end_transform(Widgets &widgets, Undo &undo, Scene_Object &obj) {
if (root_selected)
undo.move_root(obj.id(), old_ext);
else
undo.move_root(obj.id(), old_pos);
else if (selected)
undo.move_bone(obj.id(), selected, old_ext);
else if (handle)
undo.move_handle(obj.id(), handle, old_pos - my_obj->armature.base());
obj.set_skel_dirty();
}
......@@ -86,16 +102,23 @@ void Rig::apply_transform(Widgets &widgets) {
Vec3 new_pos = widgets.apply_action(Pose::moved(old_pos)).pos;
selected->extent = new_pos - old_base;
my_obj->set_skel_dirty();
} else if (handle) {
Vec3 new_pos = widgets.apply_action(Pose::moved(old_pos)).pos;
handle->target = new_pos - my_obj->armature.base();
my_obj->set_skel_dirty();
}
}
Vec3 Rig::selected_pos() {
if (root_selected) {
return my_obj->armature.base();
} else {
assert(selected);
} else if (selected) {
return my_obj->armature.end_of(selected);
} else if (handle) {
return handle->target + my_obj->armature.base();
}
assert(false);
return Vec3();
}
void Rig::select(Scene &scene, Widgets &widgets, Undo &undo, Scene_ID id, Vec3 cam, Vec2 spos,
......@@ -110,6 +133,7 @@ void Rig::select(Scene &scene, Widgets &widgets, Undo &undo, Scene_ID id, Vec3 c
selected = new_joint;
new_joint = nullptr;
handle = nullptr;
creating_bone = false;
root_selected = false;
......@@ -118,17 +142,19 @@ void Rig::select(Scene &scene, Widgets &widgets, Undo &undo, Scene_ID id, Vec3 c
if (root_selected) {
old_pos = my_obj->armature.base();
} else {
assert(selected);
} else if (selected) {
old_pos = my_obj->armature.end_of(selected);
old_base = my_obj->armature.base_of(selected);
old_ext = selected->extent;
} else if (handle) {
old_pos = handle->target + my_obj->armature.base();
}
widgets.start_drag(old_pos, cam, spos, dir);
} else if (!id || id >= n_Widget_IDs) {
selected = my_obj->armature.get_joint(id);
handle = my_obj->armature.get_handle(id);
root_selected = my_obj->armature.is_root_id(id);
}
}
......@@ -136,9 +162,13 @@ void Rig::select(Scene &scene, Widgets &widgets, Undo &undo, Scene_ID id, Vec3 c
void Rig::clear() {
my_obj = nullptr;
selected = nullptr;
handle = nullptr;
}
void Rig::clear_select() { selected = nullptr; }
void Rig::clear_select() {
selected = nullptr;
handle = nullptr;
}
void Rig::hover(Vec3 cam, Vec2 spos, Vec3 dir) {
......@@ -183,6 +213,7 @@ Mode Rig::UIsidebar(Manager &manager, Undo &undo, Widgets &widgets, Scene_Maybe
if (my_obj != &obj) {
my_obj = &obj;
selected = nullptr;
handle = nullptr;
}
if (my_obj->rig_dirty) {
mesh_bvh.build(obj.mesh());
......@@ -196,11 +227,13 @@ Mode Rig::UIsidebar(Manager &manager, Undo &undo, Widgets &widgets, Scene_Maybe
creating_bone = false;
my_obj->armature.erase(new_joint);
new_joint = nullptr;
handle = nullptr;
my_obj->set_skel_dirty();
}
} else if (ImGui::Button("New Bone")) {
creating_bone = true;
handle = nullptr;
if (!selected || root_selected) {
new_joint = my_obj->armature.add_root(Vec3{0.0f});
......@@ -223,10 +256,28 @@ Mode Rig::UIsidebar(Manager &manager, Undo &undo, Widgets &widgets, Scene_Maybe
ImGui::DragFloat3("Pose", selected->pose.data, 0.1f);
if (ImGui::Button("Add IK")) {
handle = my_obj->armature.add_handle(my_obj->armature.end_of(selected), selected);
undo.add_handle(my_obj->id(), handle);
selected = nullptr;
}
ImGui::SameLine();
if (ImGui::Button("Delete [del]")) {
undo.del_bone(my_obj->id(), selected);
selected = nullptr;
}
} else if (handle) {
ImGui::Separator();
ImGui::Text("Edit Handle");
ImGui::DragFloat3("Target", handle->target.data, 0.1f);
ImGui::Checkbox("Enable", &handle->enabled);
if (ImGui::Button("Delete [del]")) {
undo.del_handle(my_obj->id(), handle);
handle = nullptr;
}
}
return Mode::rig;
......
......@@ -25,6 +25,7 @@ public:
void clear_select();
void clear();
void invalidate(Joint *j);
void invalidate(Skeleton::IK_Handle *j);
void render(Scene_Maybe obj_opt, Widgets &widgets, Camera &cam);
Mode UIsidebar(Manager &manager, Undo &undo, Widgets &widgets, Scene_Maybe obj);
......@@ -36,6 +37,7 @@ private:
Scene_Object *my_obj = nullptr;
Joint *selected = nullptr;
Skeleton::IK_Handle *handle = nullptr;
Joint *new_joint = nullptr;
PT::Tri_Mesh mesh_bvh;
};
......
......@@ -709,6 +709,12 @@ void Widget_Render::animate(Scene &scene, Widget_Camera &cam, Camera &user_cam,
ImGui::End();
}
static bool postfix(const std::string &path, const std::string &type) {
if (path.length() >= type.length())
return path.compare(path.length() - type.length(), type.length(), type) == 0;
return false;
}
bool Widget_Render::UI(Scene &scene, Widget_Camera &cam, Camera &user_cam, std::string &err) {
bool ret = false;
......@@ -752,6 +758,11 @@ bool Widget_Render::UI(Scene &scene, Widget_Camera &cam, Camera &user_cam, std::
NFD_SaveDialog("png", nullptr, &path);
if (path) {
std::string spath(path);
if (!postfix(spath, ".png")) {
spath += ".png";
}
std::vector<unsigned char> data;
if (method == 1) {
......@@ -762,7 +773,7 @@ bool Widget_Render::UI(Scene &scene, Widget_Camera &cam, Camera &user_cam, std::
stbi_flip_vertically_on_write(true);
}
if (!stbi_write_png(path, (int)out_w, (int)out_h, 4, data.data(), (int)out_w * 4)) {
if (!stbi_write_png(spath.c_str(), (int)out_w, (int)out_h, 4, data.data(), (int)out_w * 4)) {
err = "Failed to write png!";
}
free(path);
......
......@@ -459,12 +459,19 @@ static void load_node(Scene &scobj, std::vector<std::string> &errors,
aiBone *bone = node_to_aibone[node];
aiVector3D t, r, s;
bone->mOffsetMatrix.Decompose(s, r, t);
Joint *c = skeleton.add_child(p, aiVec(t));
node_to_bone[node] = c;
c->pose = aiVec(r);
c->radius = bone->mWeights[0].mWeight;
for (unsigned int j = 0; j < node->mNumChildren; j++)
build_tree(c, node->mChildren[j]);
std::string name(bone->mName.C_Str());
if (name.find("S3D-joint-IK") != std::string::npos) {
Skeleton::IK_Handle *h = skeleton.add_handle(aiVec(t), p);
h->enabled = bone->mWeights[0].mWeight > 1.0f;
} else {
Joint *c = skeleton.add_child(p, aiVec(t));
node_to_bone[node] = c;
c->pose = aiVec(r);
c->radius = bone->mWeights[0].mWeight;
for (unsigned int j = 0; j < node->mNumChildren; j++)
build_tree(c, node->mChildren[j]);
}
};
for (unsigned int j = 0; j < arm_node->mNumChildren; j++) {
aiNode *root_node = arm_node->mChildren[j];
......@@ -1011,35 +1018,53 @@ std::string Scene::write(std::string file, const Camera &render_cam,
ai_mat->AddProperty(new float(opt.intensity), 1, AI_MATKEY_SHININESS);
if (obj.armature.has_bones()) {
ai_mesh->mNumBones = obj.armature.n_bones();
ai_mesh->mNumBones = obj.armature.n_bones() + obj.armature.n_handles();
ai_mesh->mBones = new aiBone *[ai_mesh->mNumBones];
size_t bone_idx = 0;
std::string prefix = "S3D-joint-" + std::to_string(obj.id()) + "-";
std::string jprefix = "S3D-joint-" + std::to_string(obj.id()) + "-";
std::string ikprefix = "S3D-joint-IK-" + std::to_string(obj.id()) + "-";
aiNode *arm_node = new aiNode();
scene.mRootNode->mChildren[node_idx++] = arm_node;
arm_node->mName = aiString(prefix + "armature");
arm_node->mName = aiString(jprefix + "armature");
arm_node->mTransformation = matMat(Mat4::translate(obj.armature.base_pos));
arm_node->mNumChildren = (unsigned int)obj.armature.roots.size();
arm_node->mChildren = new aiNode *[obj.armature.roots.size()];
std::unordered_map<Joint *, aiNode *> j_to_node;
std::unordered_map<Skeleton::IK_Handle *, aiNode *> ik_to_node;
std::function<void(std::string, aiNode *, Joint *)> joint_tree;
joint_tree = [&joint_tree, &j_to_node](std::string n, aiNode *node, Joint *j) {
std::string name = n + std::to_string(j->_id);
node->mName = aiString(name);
std::function<void(aiNode *, Joint *)> joint_tree;
joint_tree = [&](aiNode *node, Joint *j) {
std::string jname = jprefix + std::to_string(j->_id);
node->mName = aiString(jname);
j_to_node[j] = node;
if (j->children.size()) {
node->mNumChildren = (unsigned int)j->children.size();
node->mChildren = new aiNode *[j->children.size()];
size_t children = j->children.size();
for (Skeleton::IK_Handle* h : obj.armature.handles) {
if (h->joint == j) {
children++;
}
}
if (children > 0) {
node->mNumChildren = (unsigned int)children;
node->mChildren = new aiNode *[children];
size_t i = 0;
for (Joint *c : j->children) {
node->mChildren[i] = new aiNode();
joint_tree(n, node->mChildren[i], c);
joint_tree(node->mChildren[i], c);
i++;
}
for (Skeleton::IK_Handle* h : obj.armature.handles) {
if (h->joint == j) {
aiNode* iknode = new aiNode();
std::string ikname = ikprefix + std::to_string(h->_id);
iknode->mName = aiString(ikname);
node->mChildren[i] = iknode;
ik_to_node[h] = iknode;
i++;
}
}
}
};
......@@ -1048,7 +1073,7 @@ std::string Scene::write(std::string file, const Camera &render_cam,
aiNode *root_node = new aiNode();
arm_node->mChildren[i] = root_node;
j_to_node[j] = root_node;
joint_tree(prefix, root_node, j);
joint_tree(root_node, j);
i++;
}
......@@ -1061,12 +1086,23 @@ std::string Scene::write(std::string file, const Camera &render_cam,
ai_mesh->mBones[bone_idx++] = bone;
bone->mOffsetMatrix = matMat(Mat4::translate(j->extent) * Mat4::euler(j->pose));
bone->mNode = j_to_node[j];
std::string name = prefix + std::to_string(j->_id);
std::string name = jprefix + std::to_string(j->_id);
bone->mName = aiString(name);
bone->mNumWeights = 1;
bone->mWeights = new aiVertexWeight[1];
bone->mWeights[0].mWeight = j->radius;
});
for (Skeleton::IK_Handle* h : obj.armature.handles) {
aiBone *bone = new aiBone();
ai_mesh->mBones[bone_idx++] = bone;
bone->mOffsetMatrix = matMat(Mat4::translate(h->target));
bone->mNode = ik_to_node[h];
std::string ikname = ikprefix + std::to_string(h->_id);
bone->mName = aiString(ikname);
bone->mNumWeights = 1;
bone->mWeights = new aiVertexWeight[1];
bone->mWeights[0].mWeight = h->enabled ? 2.0f : 1.0f;
}
}
} else if (entry.second.is<Scene_Light>()) {
......
......@@ -24,8 +24,12 @@ Skeleton::Skeleton(unsigned int obj_id) {
Skeleton::~Skeleton() {
for (Joint *j : roots)
delete j;
for (Joint *j : erased)
delete j;
for (auto& e : erased)
delete e.first;
for (IK_Handle *h : handles)
delete h;
for (IK_Handle *h : erased_handles)
delete h;
}
bool Skeleton::set_time(float time) {
......@@ -57,6 +61,15 @@ void Skeleton::crop(float t) {
for_joints([t](Joint *j) { j->anim.crop(t); });
}
Skeleton::IK_Handle *Skeleton::get_handle(unsigned int id) {
IK_Handle *j = nullptr;
for(IK_Handle *h : handles) {
if (h->_id == id)
j = h;
}
return j;
}
Joint *Skeleton::get_joint(unsigned int id) {
Joint *j = nullptr;
for_joints([&](Joint *jt) {
......@@ -66,7 +79,7 @@ Joint *Skeleton::get_joint(unsigned int id) {
return j;
}
void Skeleton::render(const Mat4 &view, Joint *select, bool root, bool posed, unsigned int offset) {
void Skeleton::render(const Mat4 &view, Joint *jselect, IK_Handle *hselect, bool root, bool posed, unsigned int offset) {
Renderer &R = Renderer::get();
......@@ -81,41 +94,55 @@ void Skeleton::render(const Mat4 &view, Joint *select, bool root, bool posed, un
R.capsule(opt, j->extent.norm(), j->radius);
});
if (select) {
if (jselect) {
R.begin_outline();
Mat4 model = Mat4::translate(base_pos) *
(posed ? select->joint_to_posed() : select->joint_to_bind()) *
Mat4::rotate_to(select->extent);
(posed ? jselect->joint_to_posed() : jselect->joint_to_bind()) *
Mat4::rotate_to(jselect->extent);
Renderer::MeshOpt opt;
opt.modelview = view;
opt.id = select->_id + offset;
opt.id = jselect->_id + offset;
opt.depth_only = true;
BBox box;
R.capsule(opt, model, select->extent.norm(), select->radius, box);
R.capsule(opt, model, jselect->extent.norm(), jselect->radius, box);
R.end_outline(view, box);
}
R.reset_depth();
Renderer::MeshOpt opt;
opt.id = root_id + offset;
opt.modelview = V * Mat4::scale(Vec3{0.1f});
opt.color = root ? Gui::Color::outline : Gui::Color::hover;
R.sphere(opt);
{
Renderer::MeshOpt opt;
opt.id = root_id + offset;
opt.modelview = V * Mat4::scale(Vec3{0.1f});
opt.color = root ? Gui::Color::outline : Gui::Color::hover;
R.sphere(opt);
}
for_joints([&](Joint *j) {
Renderer::MeshOpt opt;
opt.modelview = V * (posed ? j->joint_to_posed() : j->joint_to_bind()) *
Mat4::translate(j->extent) * Mat4::scale(Vec3{j->radius * 0.25f});
opt.id = j->_id + offset;
opt.color = select == j ? Gui::Color::outline : Gui::Color::hover;
opt.color = jselect == j ? Gui::Color::outline : Gui::Color::hover;
R.sphere(opt);
});
GL::Lines ik_lines;
for(IK_Handle* h : handles) {
Renderer::MeshOpt opt;
opt.modelview = V * Mat4::translate(h->target) * Mat4::scale(Vec3{h->joint->radius * 0.3f});
opt.id = h->_id + offset;
opt.color = hselect == h ? Gui::Color::outline : Gui::Color::hoverg;
Vec3 j_world = posed ? posed_end_of(h->joint) : end_of(h->joint);
ik_lines.add(h->target, j_world - base_pos, h->enabled ? Vec3(1.0f, 0.0f, 0.0f) : Vec3(0.0f));
R.sphere(opt);
}
R.lines(ik_lines, V);
}
void Skeleton::outline(const Mat4 &view, Joint *select, bool root, bool posed, BBox &box,
void Skeleton::outline(const Mat4 &view, bool root, bool posed, BBox &box,
unsigned int offset) {
Renderer &R = Renderer::get();
......@@ -145,6 +172,10 @@ unsigned int Skeleton::n_bones() {
return n;
}
unsigned int Skeleton::n_handles() {
return (unsigned int)handles.size();
}
Vec3 &Skeleton::base() { return base_pos; }
Joint *Skeleton::add_child(Joint *j, Vec3 e) {
......@@ -162,6 +193,13 @@ void Skeleton::restore(Joint *j) {
} else {
roots.insert(j);
}
auto entry = erased.find(j);
assert(entry != erased.end());
for (IK_Handle* handle : entry->second) {
restore(handle);
}
erased.erase(j);
}
......@@ -171,7 +209,16 @@ void Skeleton::erase(Joint *j) {
} else {
roots.erase(j);
}
erased.insert(j);
std::vector<IK_Handle*> herase;
for (IK_Handle* h : handles) {
if (h->joint == j) {
herase.push_back(h);
}
}
for (IK_Handle* h : herase) {
erase(h);
}
erased.insert({j, std::move(herase)});
}
Vec3 Skeleton::posed_base_of(Joint *j) { return j->is_root() ? base() : posed_end_of(parent(j)); }
......@@ -216,3 +263,32 @@ std::unordered_map<unsigned int, Vec3> Skeleton::at(float t) {
void Skeleton::set(float t, const std::unordered_map<unsigned int, Vec3> &data) {
for_joints([&data, t](Joint *j) { j->anim.set(t, Quat::euler(data.at(j->_id))); });
}
void Skeleton::restore(IK_Handle *h) {
handles.insert(h);
erased_handles.erase(h);
}
void Skeleton::erase(IK_Handle *h) {
handles.erase(h);
erased_handles.insert(h);
}
Skeleton::IK_Handle *Skeleton::add_handle(Vec3 pos, Joint* j) {
IK_Handle* handle = new IK_Handle{pos - base_pos, j, false, next_id++};
handles.insert(handle);
return handle;
}
bool Skeleton::do_ik() {
std::vector<IK_Handle*> enabled;
for (IK_Handle* h : handles) {
if (h->enabled) {
enabled.push_back(h);
}
}
if (enabled.empty()) return false;
step_ik(std::move(enabled));
return true;
}
......@@ -59,6 +59,13 @@ private:
// Set of child joints - owned by this joint (could be shared_ptr and everything else weak_ptr)
std::unordered_set<Joint *> children;
// Current angle gradient for IK
Vec3 angle_gradient;
// Computes the gradient of IK energy for this joint and, recursively,
// upward in the heirarchy, storing the result in angle_gradient.
void compute_gradient(Vec3 target, Vec3 current);
void for_joints(std::function<void(Joint *)> func);
unsigned int _id = 0;
......@@ -70,6 +77,13 @@ private:
class Skeleton {
public:
struct IK_Handle {
Vec3 target;
Joint* joint = nullptr;
bool enabled = false;
unsigned int _id = 0;
};
Skeleton();
Skeleton(unsigned int obj_id);
~Skeleton();
......@@ -80,36 +94,51 @@ public:
void operator=(const Skeleton &src) = delete;
Skeleton &operator=(Skeleton &&src) = default;
////////////////////////////////////////////
// You will implement these functions
Vec3 end_of(Joint *j);
Vec3 posed_end_of(Joint *j);
void step_ik(std::vector<IK_Handle*> active_handles);
Mat4 joint_to_bind(const Joint *j) const;
Mat4 joint_to_posed(const Joint *j) const;
void find_joints(const GL::Mesh &src,
std::unordered_map<unsigned int, std::vector<Joint *>> &map);
void skin(const GL::Mesh &input, GL::Mesh &output,
const std::unordered_map<unsigned int, std::vector<Joint *>> &map);
////////////////////////////////////////////
Vec3 &base();
bool has_bones() const;
unsigned int n_bones();
unsigned int n_handles();
Joint *parent(Joint *j);
Joint *get_joint(unsigned int id);
void erase(Joint *j);
void restore(Joint *j);
Vec3 end_of(Joint *j);
Vec3 base_of(Joint *j);
Vec3 posed_end_of(Joint *j);
Vec3 posed_base_of(Joint *j);
void for_joints(std::function<void(Joint *)> func);
Mat4 joint_to_bind(const Joint *j) const;
Mat4 joint_to_posed(const Joint *j) const;
void erase(IK_Handle* handle);
void restore(IK_Handle* handle);
IK_Handle *get_handle(unsigned int id);
IK_Handle *add_handle(Vec3 pos, Joint* j);
bool do_ik();
Joint *add_root(Vec3 extent);
Joint *add_child(Joint *j, Vec3 extent);
bool is_root_id(unsigned int id);
bool set_time(float time);
void render(const Mat4 &view, Joint *select, bool root, bool posed, unsigned int offset = 0);
void outline(const Mat4 &view, Joint *select, bool root, bool posed, BBox &box,
unsigned int offset = 0);
void find_joints(const GL::Mesh &src,
std::unordered_map<unsigned int, std::vector<Joint *>> &map);
void skin(const GL::Mesh &input, GL::Mesh &output,
const std::unordered_map<unsigned int, std::vector<Joint *>> &map);
void render(const Mat4 &view, Joint *jselect, IK_Handle *hselect, bool root, bool posed, unsigned int offset = 0);
void outline(const Mat4 &view, bool root, bool posed, BBox &box, unsigned int offset = 0);
void set(float t);
void crop(float t);
......@@ -123,6 +152,8 @@ public:
private:
Vec3 base_pos;
unsigned int root_id, next_id;
std::unordered_set<Joint *> roots, erased;
std::unordered_set<Joint *> roots;
std::unordered_map<Joint*,std::vector<IK_Handle*>> erased;
std::unordered_set<IK_Handle*> handles, erased_handles;
friend class Scene;
};
......@@ -74,6 +74,28 @@ void Undo::del_bone(Scene_ID id, Joint *j) {
Scene_Object &obj = scene.get_obj(id);
obj.armature.erase(j);
gui.get_rig().invalidate(j);
gui.get_animate().invalidate(j);
obj.set_skel_dirty();
},
[this, id, j]() {
Scene_Object &obj = scene.get_obj(id);
obj.armature.restore(j);
obj.set_skel_dirty();
});
}
void Undo::del_handle(Scene_ID id, Skeleton::IK_Handle *j) {
Scene_Object &obj = scene.get_obj(id);
obj.armature.erase(j);
obj.set_skel_dirty();
action(
[this, id, j]() {
Scene_Object &obj = scene.get_obj(id);
obj.armature.erase(j);
gui.get_animate().invalidate(j);
gui.get_rig().invalidate(j);
obj.set_skel_dirty();
},
[this, id, j]() {
......@@ -97,6 +119,20 @@ void Undo::move_bone(Scene_ID id, Joint *j, Vec3 old) {
});
}
void Undo::move_handle(Scene_ID id, Skeleton::IK_Handle *j, Vec3 old) {
action(
[this, id, j, ne = j->target]() {
Scene_Object &obj = scene.get_obj(id);
j->target = ne;
obj.set_skel_dirty();
},
[this, id, j, oe = old]() {
Scene_Object &obj = scene.get_obj(id);
j->target = oe;
obj.set_skel_dirty();
});
}
void Undo::pose_bone(Scene_ID id, Joint *j, Vec3 old) {
action(
[this, id, j, ne = j->pose]() {
......@@ -111,6 +147,22 @@ void Undo::pose_bone(Scene_ID id, Joint *j, Vec3 old) {
});
}
void Undo::add_handle(Scene_ID id, Skeleton::IK_Handle *j) {
action(
[this, id, j]() {
Scene_Object &obj = scene.get_obj(id);
obj.armature.restore(j);
obj.set_skel_dirty();
},
[this, id, j]() {
Scene_Object &obj = scene.get_obj(id);
obj.armature.erase(j);
gui.get_rig().invalidate(j);
gui.get_animate().invalidate(j);
obj.set_skel_dirty();
});
}
void Undo::add_bone(Scene_ID id, Joint *j) {
action(
......@@ -123,6 +175,7 @@ void Undo::add_bone(Scene_ID id, Joint *j) {
Scene_Object &obj = scene.get_obj(id);
obj.armature.erase(j);
gui.get_rig().invalidate(j);
gui.get_animate().invalidate(j);
obj.set_skel_dirty();
});
}
......
......@@ -59,9 +59,12 @@ public:
void update_pose(Scene_ID id, Pose old);
void del_bone(Scene_ID id, Joint *j);
void del_handle(Scene_ID id, Skeleton::IK_Handle *j);
void add_handle(Scene_ID id, Skeleton::IK_Handle *j);
void add_bone(Scene_ID id, Joint *j);
void move_bone(Scene_ID id, Joint *j, Vec3 old);
void pose_bone(Scene_ID id, Joint *j, Vec3 old);
void move_handle(Scene_ID id, Skeleton::IK_Handle *j, Vec3 old);
void move_root(Scene_ID id, Vec3 old);
void update_light(Scene_ID id, Scene_Light::Options old);
......
......@@ -111,3 +111,19 @@ void Skeleton::skin(const GL::Mesh &input, GL::Mesh &output,
std::vector<GL::Mesh::Index> idxs = input.indices();
output.recreate(std::move(verts), std::move(idxs));
}
void Joint::compute_gradient(Vec3 target, Vec3 current) {
// TODO(Animation): Task 2
// Computes the gradient of IK energy for this joint and, should be called
// recursively upward in the heirarchy. Each call should storing the result
// in the angle_gradient for this joint.
}
void Skeleton::step_ik(std::vector<IK_Handle*> active_handles) {
// TODO(Animation): Task 2
// Do several iterations of Jacobian Transpose gradient descent for IK
}
......@@ -90,6 +90,8 @@ std::string HDR_Image::load_from(std::string file) {
size_t didx = 4 * (j * w + i);
size_t pidx = (h - j - 1) * w + i;
pixels[pidx] = Spectrum(data[didx], data[didx + 1], data[didx + 2]);
if (!pixels[pidx].valid())
pixels[pidx] = {};
}
}
......@@ -118,12 +120,12 @@ std::string HDR_Image::load_from(std::string file) {
}
stbi_image_free(data);
}
for (size_t i = 0; i < pixels.size(); i++) {
pixels[i].make_linear();
if (!pixels[i].valid())
pixels[i] = {};
for (size_t i = 0; i < pixels.size(); i++) {
pixels[i].make_linear();
if (!pixels[i].valid())
pixels[i] = {};
}
}
last_path = file;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment