Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e8ef7924d2 | ||
|
|
0a45497de9 | ||
|
|
7c8b44247b |
@@ -133,6 +133,7 @@ enum class SocketType {
|
||||
SocketTypeUndefined = 0,
|
||||
SocketTypeBool,
|
||||
SocketTypeAnimation,
|
||||
SocketTypeInt,
|
||||
SocketTypeFloat,
|
||||
SocketTypeVec3,
|
||||
SocketTypeQuat,
|
||||
@@ -143,7 +144,7 @@ enum class SocketType {
|
||||
constexpr size_t cSocketStringValueMaxLength = 256;
|
||||
|
||||
static const char* SocketTypeNames[] =
|
||||
{"", "Bool", "Animation", "Float", "Vec3", "Quat", "String"};
|
||||
{"", "Bool", "Animation", "Int", "Float", "Vec3", "Quat", "String"};
|
||||
|
||||
enum SocketFlags { SocketFlagNone = 0, SocketFlagAffectsTime = 1 };
|
||||
|
||||
@@ -152,6 +153,7 @@ struct Socket {
|
||||
SocketType m_type = SocketType::SocketTypeUndefined;
|
||||
union SocketValue {
|
||||
bool flag;
|
||||
int int_value;
|
||||
float float_value;
|
||||
Vec3 vec3;
|
||||
Quat quat;
|
||||
@@ -172,6 +174,10 @@ struct Socket {
|
||||
m_value.flag = value;
|
||||
}
|
||||
|
||||
if constexpr (std::is_same<T, int>::value) {
|
||||
m_value.int_value = value;
|
||||
}
|
||||
|
||||
if constexpr (std::is_same<T, float>::value) {
|
||||
m_value.float_value = value;
|
||||
}
|
||||
@@ -188,6 +194,35 @@ struct Socket {
|
||||
m_value_string = value;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T GetValue() const {
|
||||
if constexpr (std::is_same<T, bool>::value) {
|
||||
return m_value.flag;
|
||||
}
|
||||
|
||||
if constexpr (std::is_same<T, int>::value) {
|
||||
return m_value.int_value;
|
||||
}
|
||||
|
||||
if constexpr (std::is_same<T, float>::value) {
|
||||
return m_value.float_value;
|
||||
}
|
||||
|
||||
if constexpr (std::is_same<T, Vec3>::value) {
|
||||
return m_value.vec3;
|
||||
}
|
||||
|
||||
if constexpr (std::is_same<T, Quat>::value) {
|
||||
return m_value.quat;
|
||||
}
|
||||
|
||||
if constexpr (std::is_same<T, std::string>::value) {
|
||||
return m_value_string;
|
||||
}
|
||||
|
||||
return T();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@@ -200,6 +235,10 @@ SocketType GetSocketType() {
|
||||
return SocketType::SocketTypeAnimation;
|
||||
}
|
||||
|
||||
if constexpr (std::is_same<T, int>::value) {
|
||||
return SocketType::SocketTypeInt;
|
||||
}
|
||||
|
||||
if constexpr (std::is_same<T, float>::value) {
|
||||
return SocketType::SocketTypeFloat;
|
||||
}
|
||||
@@ -356,6 +395,13 @@ struct NodeDescriptorBase {
|
||||
return *static_cast<T*>(socket->m_reference.ptr);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T GetPropertyValue(const char* name) {
|
||||
Socket* socket = FindSocket(name, m_properties);
|
||||
assert(GetSocketType<T>() == socket->m_type);
|
||||
return socket->GetValue<T>();
|
||||
}
|
||||
|
||||
virtual void UpdateFlags(){};
|
||||
|
||||
protected:
|
||||
|
||||
@@ -18,6 +18,8 @@ ImNodesPinShape sGetSocketShapeFromSocketType(const SocketType& socket_type) {
|
||||
switch (socket_type) {
|
||||
case SocketType::SocketTypeAnimation:
|
||||
return ImNodesPinShape_QuadFilled;
|
||||
case SocketType::SocketTypeInt:
|
||||
return ImNodesPinShape_CircleFilled;
|
||||
case SocketType::SocketTypeFloat:
|
||||
return ImNodesPinShape_CircleFilled;
|
||||
case SocketType::SocketTypeVec3:
|
||||
@@ -165,16 +167,24 @@ void AnimGraphEditorRenderSidebar(
|
||||
int num_properties = node_resource.m_socket_accessor->m_properties.size();
|
||||
for (int i = 0; i < num_properties; i++) {
|
||||
Socket& property = node_resource.m_socket_accessor->m_properties[i];
|
||||
if (property.m_type == SocketType::SocketTypeFloat) {
|
||||
if (property.m_type == SocketType::SocketTypeInt) {
|
||||
ImGui::InputInt(
|
||||
property.m_name.c_str(),
|
||||
reinterpret_cast<int*>(&property.m_value.int_value),
|
||||
1);
|
||||
} else if (property.m_type == SocketType::SocketTypeFloat) {
|
||||
ImGui::SliderFloat(
|
||||
property.m_name.c_str(),
|
||||
reinterpret_cast<float*>(&property.m_value.float_value),
|
||||
-100.f,
|
||||
100.f);
|
||||
} else if (property.m_type == SocketType::SocketTypeBool) {
|
||||
ImGui::Checkbox(
|
||||
bool flag_value = property.GetValue<bool>();
|
||||
if (ImGui::Checkbox(
|
||||
property.m_name.c_str(),
|
||||
reinterpret_cast<bool*>(property.m_reference.ptr));
|
||||
&flag_value)) {
|
||||
property.SetValue(flag_value);
|
||||
}
|
||||
} else if (property.m_type == SocketType::SocketTypeString) {
|
||||
char string_buf[1024];
|
||||
memset(string_buf, '\0', sizeof(string_buf));
|
||||
@@ -300,6 +310,10 @@ void AnimGraphEditorUpdate() {
|
||||
node_type_name = "SpeedScale";
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("LockTranslationNode")) {
|
||||
node_type_name = "LockTranslationNode";
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("MathAddNode")) {
|
||||
node_type_name = "MathAddNode";
|
||||
}
|
||||
@@ -373,6 +387,17 @@ void AnimGraphEditorUpdate() {
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
|
||||
if (!socket_connected && (socket.m_type == SocketType::SocketTypeInt)) {
|
||||
ImGui::SameLine();
|
||||
int socket_value = socket.m_value.int_value;
|
||||
ImGui::PushItemWidth(
|
||||
130.0f - ImGui::CalcTextSize(socket.m_name.c_str()).x);
|
||||
if (ImGui::InputInt("##hidelabel", &socket_value, 1)) {
|
||||
socket.SetValue(socket_value);
|
||||
}
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
|
||||
ImNodes::PushAttributeFlag(
|
||||
ImNodesAttributeFlags_EnableLinkDetachWithDragClick);
|
||||
ImNodes::EndInputAttribute();
|
||||
|
||||
@@ -82,10 +82,40 @@ void AnimSamplerNode::Evaluate(AnimGraphContext& context) {
|
||||
ozz::animation::SamplingJob sampling_job;
|
||||
sampling_job.animation = m_animation;
|
||||
sampling_job.context = &m_sampling_context;
|
||||
sampling_job.ratio = m_time_now;
|
||||
sampling_job.ratio = fmodf(m_time_now, m_animation->duration());
|
||||
sampling_job.output = make_span(o_output->m_local_matrices);
|
||||
|
||||
if (!sampling_job.Run()) {
|
||||
ozz::log::Err() << "Error sampling animation." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void LockTranslationNode::Evaluate(AnimGraphContext& context) {
|
||||
o_output->m_local_matrices = i_input->m_local_matrices;
|
||||
ozz::math::SoaFloat3 translation =
|
||||
o_output->m_local_matrices[m_locked_bone_index].translation;
|
||||
float x[4];
|
||||
float y[4];
|
||||
float z[4];
|
||||
_mm_store_ps(x, translation.x);
|
||||
_mm_store_ps(y, translation.y);
|
||||
_mm_store_ps(z, translation.z);
|
||||
|
||||
if (m_lock_x) {
|
||||
x[0] = 0.f;
|
||||
}
|
||||
|
||||
if (m_lock_y) {
|
||||
y[0] = 0.f;
|
||||
}
|
||||
|
||||
if (m_lock_z) {
|
||||
z[0] = 0.f;
|
||||
}
|
||||
|
||||
translation.x = _mm_load_ps(x);
|
||||
translation.y = _mm_load_ps(y);
|
||||
translation.z = _mm_load_ps(z);
|
||||
|
||||
o_output->m_local_matrices[m_locked_bone_index].translation = translation;
|
||||
}
|
||||
@@ -156,8 +156,8 @@ struct SpeedScaleNode : public AnimNode {
|
||||
float* i_speed_scale = nullptr;
|
||||
|
||||
void UpdateTime(float time_last, float time_now) override {
|
||||
m_time_last = time_last;
|
||||
m_time_now = time_last + (time_now - time_last) * (*i_speed_scale);
|
||||
m_time_last = m_time_now;
|
||||
m_time_now = m_time_last + (time_now - time_last) * (*i_speed_scale);
|
||||
m_state = AnimNodeEvalState::TimeUpdated;
|
||||
}
|
||||
|
||||
@@ -196,7 +196,7 @@ struct AnimSamplerNode : public AnimNode {
|
||||
virtual bool Init(AnimGraphContext& context) override;
|
||||
void UpdateTime(float time_last, float time_now) override {
|
||||
m_time_last = time_last;
|
||||
m_time_now = fmodf(time_last + (time_now - time_last), m_animation->duration());
|
||||
m_time_now = time_now;
|
||||
m_state = AnimNodeEvalState::TimeUpdated;
|
||||
}
|
||||
virtual void Evaluate(AnimGraphContext& context) override;
|
||||
@@ -211,6 +211,34 @@ struct NodeDescriptor<AnimSamplerNode> : public NodeDescriptorBase {
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// LockTranslationNode
|
||||
//
|
||||
struct LockTranslationNode : public AnimNode {
|
||||
AnimData* i_input = nullptr;
|
||||
AnimData* o_output = nullptr;
|
||||
int m_locked_bone_index;
|
||||
bool m_lock_x;
|
||||
bool m_lock_y;
|
||||
bool m_lock_z;
|
||||
|
||||
virtual void Evaluate(AnimGraphContext& context) override;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct NodeDescriptor<LockTranslationNode> : public NodeDescriptorBase {
|
||||
NodeDescriptor(LockTranslationNode* node) {
|
||||
RegisterInput("Input", &node->i_input);
|
||||
RegisterOutput("Output", &node->o_output);
|
||||
|
||||
RegisterProperty("BoneIndex", &node->m_locked_bone_index);
|
||||
RegisterProperty("LockAxisX", &node->m_lock_x);
|
||||
RegisterProperty("LockAxisY", &node->m_lock_y);
|
||||
RegisterProperty("LockAxisZ", &node->m_lock_z);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// ConstScalarNode
|
||||
//
|
||||
@@ -296,6 +324,8 @@ static inline AnimNode* AnimNodeFactory(const std::string& name) {
|
||||
result = new SpeedScaleNode;
|
||||
} else if (name == "AnimSampler") {
|
||||
result = new AnimSamplerNode;
|
||||
} else if (name == "LockTranslationNode") {
|
||||
result = new LockTranslationNode;
|
||||
} else if (name == "BlendTree") {
|
||||
result = new BlendTreeNode;
|
||||
} else if (name == "MathAddNode") {
|
||||
@@ -324,6 +354,8 @@ static inline NodeDescriptorBase* AnimNodeDescriptorFactory(
|
||||
return CreateNodeDescriptor<SpeedScaleNode>(node);
|
||||
} else if (node_type_name == "AnimSampler") {
|
||||
return CreateNodeDescriptor<AnimSamplerNode>(node);
|
||||
} else if (node_type_name == "LockTranslationNode") {
|
||||
return CreateNodeDescriptor<LockTranslationNode>(node);
|
||||
} else if (node_type_name == "BlendTree") {
|
||||
return CreateNodeDescriptor<BlendTreeNode>(node);
|
||||
} else if (node_type_name == "MathAddNode") {
|
||||
|
||||
@@ -35,6 +35,8 @@ json sSocketToJson(const Socket& socket) {
|
||||
if (socket.m_type == SocketType::SocketTypeBool) {
|
||||
result["value"] = socket.m_value.flag;
|
||||
} else if (socket.m_type == SocketType::SocketTypeAnimation) {
|
||||
} else if (socket.m_type == SocketType::SocketTypeInt) {
|
||||
result["value"] = socket.m_value.int_value;
|
||||
} else if (socket.m_type == SocketType::SocketTypeFloat) {
|
||||
result["value"] = socket.m_value.float_value;
|
||||
} else if (socket.m_type == SocketType::SocketTypeVec3) {
|
||||
@@ -72,6 +74,12 @@ Socket sJsonToSocket(const json& json_data) {
|
||||
} else if (type_string == "Animation") {
|
||||
result.m_type = SocketType::SocketTypeAnimation;
|
||||
result.m_type_size = sizeof(AnimData);
|
||||
} else if (type_string == "Int") {
|
||||
result.m_type = SocketType::SocketTypeInt;
|
||||
result.m_type_size = sizeof(int);
|
||||
if (have_value) {
|
||||
result.m_value.int_value = json_data["value"];
|
||||
}
|
||||
} else if (type_string == "Float") {
|
||||
result.m_type = SocketType::SocketTypeFloat;
|
||||
result.m_type_size = sizeof(float);
|
||||
@@ -572,6 +580,11 @@ void AnimGraphResource::setRuntimeNodeProperties(AnimGraph& instance) const {
|
||||
name.c_str(),
|
||||
property.m_value.flag);
|
||||
break;
|
||||
case SocketType::SocketTypeInt:
|
||||
node_instance_accessor->SetProperty(
|
||||
name.c_str(),
|
||||
property.m_value.int_value);
|
||||
break;
|
||||
case SocketType::SocketTypeFloat:
|
||||
node_instance_accessor->SetProperty(
|
||||
name.c_str(),
|
||||
|
||||
+8
-3
@@ -76,6 +76,7 @@ static struct {
|
||||
} loaded;
|
||||
struct {
|
||||
double frame;
|
||||
double anim_update_time;
|
||||
float absolute;
|
||||
uint64_t laptime;
|
||||
float factor;
|
||||
@@ -511,7 +512,10 @@ int main() {
|
||||
stm_round_to_common_refresh_rate(stm_laptime(&state.time.laptime)));
|
||||
|
||||
if (!state.time.paused) {
|
||||
state.time.anim_update_time = state.time.frame;
|
||||
state.time.absolute += state.time.frame * state.time.factor;
|
||||
} else {
|
||||
state.time.anim_update_time = 0.;
|
||||
}
|
||||
|
||||
if (state.ozz.animation != nullptr) {
|
||||
@@ -725,7 +729,8 @@ int main() {
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Step")) {
|
||||
state.time.absolute += state.time.frame;
|
||||
state.time.anim_update_time = 1. / 30.f;
|
||||
state.time.absolute += state.time.anim_update_time;
|
||||
}
|
||||
|
||||
if (state.ozz.animation != nullptr) {
|
||||
@@ -758,9 +763,9 @@ int main() {
|
||||
skinned_mesh.CalcModelMatrices();
|
||||
}
|
||||
|
||||
if (state.time.use_graph && anim_graph.m_nodes.size() > 0) {
|
||||
if (state.time.use_graph && anim_graph.m_nodes.size() > 0 && state.time.anim_update_time > 0.) {
|
||||
anim_graph.markActiveNodes();
|
||||
anim_graph.updateTime(state.time.frame);
|
||||
anim_graph.updateTime(state.time.anim_update_time);
|
||||
anim_graph.evaluate(anim_graph_context);
|
||||
skinned_mesh.m_local_matrices = anim_graph_output.m_local_matrices;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user