look_at_modifier_3d.cpp 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780
  1. /**************************************************************************/
  2. /* look_at_modifier_3d.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. #include "look_at_modifier_3d.h"
  31. void LookAtModifier3D::_validate_property(PropertyInfo &p_property) const {
  32. if (p_property.name == "bone_name" || p_property.name == "origin_bone_name") {
  33. Skeleton3D *skeleton = get_skeleton();
  34. if (skeleton) {
  35. p_property.hint = PROPERTY_HINT_ENUM;
  36. p_property.hint_string = skeleton->get_concatenated_bone_names();
  37. } else {
  38. p_property.hint = PROPERTY_HINT_NONE;
  39. p_property.hint_string = "";
  40. }
  41. }
  42. if (origin_from == ORIGIN_FROM_SPECIFIC_BONE) {
  43. if (p_property.name == "origin_external_node") {
  44. p_property.usage = PROPERTY_USAGE_NONE;
  45. }
  46. } else if (origin_from == ORIGIN_FROM_EXTERNAL_NODE) {
  47. if (p_property.name == "origin_bone" || p_property.name == "origin_bone_name") {
  48. p_property.usage = PROPERTY_USAGE_NONE;
  49. }
  50. } else {
  51. if (p_property.name == "origin_external_node" || p_property.name == "origin_bone" || p_property.name == "origin_bone_name") {
  52. p_property.usage = PROPERTY_USAGE_NONE;
  53. }
  54. }
  55. if ((!use_angle_limitation &&
  56. (p_property.name == "symmetry_limitation" || p_property.name.ends_with("limit_angle") || p_property.name.ends_with("damp_threshold"))) ||
  57. (!use_secondary_rotation && p_property.name.begins_with("secondary_")) ||
  58. (!symmetry_limitation && (p_property.name == "primary_limit_angle" || p_property.name == "primary_damp_threshold" || p_property.name == "secondary_limit_angle" || p_property.name == "secondary_damp_threshold")) ||
  59. (symmetry_limitation && (p_property.name.begins_with("primary_positive") || p_property.name.begins_with("primary_negative") || p_property.name.begins_with("secondary_positive") || (p_property.name.begins_with("secondary_negative"))))) {
  60. p_property.usage = PROPERTY_USAGE_NONE;
  61. }
  62. }
  63. PackedStringArray LookAtModifier3D::get_configuration_warnings() const {
  64. PackedStringArray warnings = SkeletonModifier3D::get_configuration_warnings();
  65. if (get_axis_from_bone_axis(forward_axis) == primary_rotation_axis) {
  66. warnings.push_back(RTR("Forward axis and primary rotation axis must not be parallel."));
  67. }
  68. return warnings;
  69. }
  70. void LookAtModifier3D::_validate_bone_names() {
  71. // Prior bone name.
  72. if (!bone_name.is_empty()) {
  73. set_bone_name(bone_name);
  74. } else if (bone != -1) {
  75. set_bone(bone);
  76. }
  77. if (!origin_bone_name.is_empty()) {
  78. set_origin_bone_name(origin_bone_name);
  79. } else if (origin_bone != -1) {
  80. set_origin_bone(origin_bone);
  81. }
  82. }
  83. void LookAtModifier3D::set_bone_name(const String &p_bone_name) {
  84. bone_name = p_bone_name;
  85. Skeleton3D *sk = get_skeleton();
  86. if (sk) {
  87. set_bone(sk->find_bone(bone_name));
  88. }
  89. }
  90. String LookAtModifier3D::get_bone_name() const {
  91. return bone_name;
  92. }
  93. void LookAtModifier3D::set_bone(int p_bone) {
  94. bone = p_bone;
  95. Skeleton3D *sk = get_skeleton();
  96. if (sk) {
  97. if (bone <= -1 || bone >= sk->get_bone_count()) {
  98. WARN_PRINT("Bone index out of range!");
  99. bone = -1;
  100. } else {
  101. bone_name = sk->get_bone_name(bone);
  102. }
  103. }
  104. }
  105. int LookAtModifier3D::get_bone() const {
  106. return bone;
  107. }
  108. void LookAtModifier3D::set_forward_axis(BoneAxis p_axis) {
  109. forward_axis = p_axis;
  110. update_configuration_warnings();
  111. }
  112. SkeletonModifier3D::BoneAxis LookAtModifier3D::get_forward_axis() const {
  113. return forward_axis;
  114. }
  115. void LookAtModifier3D::set_primary_rotation_axis(Vector3::Axis p_axis) {
  116. primary_rotation_axis = p_axis;
  117. update_configuration_warnings();
  118. }
  119. Vector3::Axis LookAtModifier3D::get_primary_rotation_axis() const {
  120. return primary_rotation_axis;
  121. }
  122. void LookAtModifier3D::set_use_secondary_rotation(bool p_enabled) {
  123. use_secondary_rotation = p_enabled;
  124. notify_property_list_changed();
  125. }
  126. bool LookAtModifier3D::is_using_secondary_rotation() const {
  127. return use_secondary_rotation;
  128. }
  129. void LookAtModifier3D::set_target_node(const NodePath &p_target_node) {
  130. if (target_node != p_target_node) {
  131. init_transition();
  132. }
  133. target_node = p_target_node;
  134. }
  135. NodePath LookAtModifier3D::get_target_node() const {
  136. return target_node;
  137. }
  138. // For origin settings.
  139. void LookAtModifier3D::set_origin_from(OriginFrom p_origin_from) {
  140. origin_from = p_origin_from;
  141. notify_property_list_changed();
  142. }
  143. LookAtModifier3D::OriginFrom LookAtModifier3D::get_origin_from() const {
  144. return origin_from;
  145. }
  146. void LookAtModifier3D::set_origin_bone_name(const String &p_bone_name) {
  147. origin_bone_name = p_bone_name;
  148. Skeleton3D *sk = get_skeleton();
  149. if (sk) {
  150. set_origin_bone(sk->find_bone(origin_bone_name));
  151. }
  152. }
  153. String LookAtModifier3D::get_origin_bone_name() const {
  154. return origin_bone_name;
  155. }
  156. void LookAtModifier3D::set_origin_bone(int p_bone) {
  157. origin_bone = p_bone;
  158. Skeleton3D *sk = get_skeleton();
  159. if (sk) {
  160. if (origin_bone <= -1 || origin_bone >= sk->get_bone_count()) {
  161. WARN_PRINT("Bone index out of range!");
  162. origin_bone = -1;
  163. } else {
  164. origin_bone_name = sk->get_bone_name(origin_bone);
  165. }
  166. }
  167. }
  168. int LookAtModifier3D::get_origin_bone() const {
  169. return origin_bone;
  170. }
  171. void LookAtModifier3D::set_origin_external_node(const NodePath &p_external_node) {
  172. origin_external_node = p_external_node;
  173. }
  174. NodePath LookAtModifier3D::get_origin_external_node() const {
  175. return origin_external_node;
  176. }
  177. void LookAtModifier3D::set_origin_offset(const Vector3 &p_offset) {
  178. origin_offset = p_offset;
  179. }
  180. Vector3 LookAtModifier3D::get_origin_offset() const {
  181. return origin_offset;
  182. }
  183. void LookAtModifier3D::set_origin_safe_margin(float p_margin) {
  184. origin_safe_margin = p_margin;
  185. }
  186. float LookAtModifier3D::get_origin_safe_margin() const {
  187. return origin_safe_margin;
  188. }
  189. // For time-based interpolation.
  190. void LookAtModifier3D::set_duration(float p_duration) {
  191. duration = p_duration;
  192. if (Math::is_zero_approx(p_duration)) {
  193. time_step = 0;
  194. remaining = 0;
  195. } else {
  196. time_step = 1.0 / p_duration; // Cache to avoid division.
  197. }
  198. }
  199. float LookAtModifier3D::get_duration() const {
  200. return duration;
  201. }
  202. void LookAtModifier3D::set_transition_type(Tween::TransitionType p_transition_type) {
  203. transition_type = p_transition_type;
  204. }
  205. Tween::TransitionType LookAtModifier3D::get_transition_type() const {
  206. return transition_type;
  207. }
  208. void LookAtModifier3D::set_ease_type(Tween::EaseType p_ease_type) {
  209. ease_type = p_ease_type;
  210. }
  211. Tween::EaseType LookAtModifier3D::get_ease_type() const {
  212. return ease_type;
  213. }
  214. // For angle limitation.
  215. void LookAtModifier3D::set_use_angle_limitation(bool p_enabled) {
  216. use_angle_limitation = p_enabled;
  217. notify_property_list_changed();
  218. }
  219. bool LookAtModifier3D::is_using_angle_limitation() const {
  220. return use_angle_limitation;
  221. }
  222. void LookAtModifier3D::set_symmetry_limitation(bool p_enabled) {
  223. symmetry_limitation = p_enabled;
  224. notify_property_list_changed();
  225. }
  226. bool LookAtModifier3D::is_limitation_symmetry() const {
  227. return symmetry_limitation;
  228. }
  229. void LookAtModifier3D::set_primary_limit_angle(float p_angle) {
  230. primary_limit_angle = p_angle;
  231. }
  232. float LookAtModifier3D::get_primary_limit_angle() const {
  233. return primary_limit_angle;
  234. }
  235. void LookAtModifier3D::set_primary_damp_threshold(float p_power) {
  236. primary_damp_threshold = p_power;
  237. }
  238. float LookAtModifier3D::get_primary_damp_threshold() const {
  239. return primary_damp_threshold;
  240. }
  241. void LookAtModifier3D::set_primary_positive_limit_angle(float p_angle) {
  242. primary_positive_limit_angle = p_angle;
  243. }
  244. float LookAtModifier3D::get_primary_positive_limit_angle() const {
  245. return primary_positive_limit_angle;
  246. }
  247. void LookAtModifier3D::set_primary_positive_damp_threshold(float p_power) {
  248. primary_positive_damp_threshold = p_power;
  249. }
  250. float LookAtModifier3D::get_primary_positive_damp_threshold() const {
  251. return primary_positive_damp_threshold;
  252. }
  253. void LookAtModifier3D::set_primary_negative_limit_angle(float p_angle) {
  254. primary_negative_limit_angle = p_angle;
  255. }
  256. float LookAtModifier3D::get_primary_negative_limit_angle() const {
  257. return primary_negative_limit_angle;
  258. }
  259. void LookAtModifier3D::set_primary_negative_damp_threshold(float p_power) {
  260. primary_negative_damp_threshold = p_power;
  261. }
  262. float LookAtModifier3D::get_primary_negative_damp_threshold() const {
  263. return primary_negative_damp_threshold;
  264. }
  265. void LookAtModifier3D::set_secondary_limit_angle(float p_angle) {
  266. secondary_limit_angle = p_angle;
  267. }
  268. float LookAtModifier3D::get_secondary_limit_angle() const {
  269. return secondary_limit_angle;
  270. }
  271. void LookAtModifier3D::set_secondary_damp_threshold(float p_power) {
  272. secondary_damp_threshold = p_power;
  273. }
  274. float LookAtModifier3D::get_secondary_damp_threshold() const {
  275. return secondary_damp_threshold;
  276. }
  277. void LookAtModifier3D::set_secondary_positive_limit_angle(float p_angle) {
  278. secondary_positive_limit_angle = p_angle;
  279. }
  280. float LookAtModifier3D::get_secondary_positive_limit_angle() const {
  281. return secondary_positive_limit_angle;
  282. }
  283. void LookAtModifier3D::set_secondary_positive_damp_threshold(float p_power) {
  284. secondary_positive_damp_threshold = p_power;
  285. }
  286. float LookAtModifier3D::get_secondary_positive_damp_threshold() const {
  287. return secondary_positive_damp_threshold;
  288. }
  289. void LookAtModifier3D::set_secondary_negative_limit_angle(float p_angle) {
  290. secondary_negative_limit_angle = p_angle;
  291. }
  292. float LookAtModifier3D::get_secondary_negative_limit_angle() const {
  293. return secondary_negative_limit_angle;
  294. }
  295. void LookAtModifier3D::set_secondary_negative_damp_threshold(float p_power) {
  296. secondary_negative_damp_threshold = p_power;
  297. }
  298. float LookAtModifier3D::get_secondary_negative_damp_threshold() const {
  299. return secondary_negative_damp_threshold;
  300. }
  301. bool LookAtModifier3D::is_target_within_limitation() const {
  302. return is_within_limitations;
  303. }
  304. float LookAtModifier3D::get_interpolation_remaining() const {
  305. return remaining * duration;
  306. }
  307. bool LookAtModifier3D::is_interpolating() const {
  308. return Math::is_zero_approx(remaining);
  309. }
  310. // General API.
  311. void LookAtModifier3D::_bind_methods() {
  312. ClassDB::bind_method(D_METHOD("set_target_node", "target_node"), &LookAtModifier3D::set_target_node);
  313. ClassDB::bind_method(D_METHOD("get_target_node"), &LookAtModifier3D::get_target_node);
  314. ClassDB::bind_method(D_METHOD("set_bone_name", "bone_name"), &LookAtModifier3D::set_bone_name);
  315. ClassDB::bind_method(D_METHOD("get_bone_name"), &LookAtModifier3D::get_bone_name);
  316. ClassDB::bind_method(D_METHOD("set_bone", "bone"), &LookAtModifier3D::set_bone);
  317. ClassDB::bind_method(D_METHOD("get_bone"), &LookAtModifier3D::get_bone);
  318. ClassDB::bind_method(D_METHOD("set_forward_axis", "forward_axis"), &LookAtModifier3D::set_forward_axis);
  319. ClassDB::bind_method(D_METHOD("get_forward_axis"), &LookAtModifier3D::get_forward_axis);
  320. ClassDB::bind_method(D_METHOD("set_primary_rotation_axis", "axis"), &LookAtModifier3D::set_primary_rotation_axis);
  321. ClassDB::bind_method(D_METHOD("get_primary_rotation_axis"), &LookAtModifier3D::get_primary_rotation_axis);
  322. ClassDB::bind_method(D_METHOD("set_use_secondary_rotation", "enabled"), &LookAtModifier3D::set_use_secondary_rotation);
  323. ClassDB::bind_method(D_METHOD("is_using_secondary_rotation"), &LookAtModifier3D::is_using_secondary_rotation);
  324. ClassDB::bind_method(D_METHOD("set_origin_safe_margin", "margin"), &LookAtModifier3D::set_origin_safe_margin);
  325. ClassDB::bind_method(D_METHOD("get_origin_safe_margin"), &LookAtModifier3D::get_origin_safe_margin);
  326. ClassDB::bind_method(D_METHOD("set_origin_from", "origin_from"), &LookAtModifier3D::set_origin_from);
  327. ClassDB::bind_method(D_METHOD("get_origin_from"), &LookAtModifier3D::get_origin_from);
  328. ClassDB::bind_method(D_METHOD("set_origin_bone_name", "bone_name"), &LookAtModifier3D::set_origin_bone_name);
  329. ClassDB::bind_method(D_METHOD("get_origin_bone_name"), &LookAtModifier3D::get_origin_bone_name);
  330. ClassDB::bind_method(D_METHOD("set_origin_bone", "bone"), &LookAtModifier3D::set_origin_bone);
  331. ClassDB::bind_method(D_METHOD("get_origin_bone"), &LookAtModifier3D::get_origin_bone);
  332. ClassDB::bind_method(D_METHOD("set_origin_external_node", "external_node"), &LookAtModifier3D::set_origin_external_node);
  333. ClassDB::bind_method(D_METHOD("get_origin_external_node"), &LookAtModifier3D::get_origin_external_node);
  334. ClassDB::bind_method(D_METHOD("set_origin_offset", "offset"), &LookAtModifier3D::set_origin_offset);
  335. ClassDB::bind_method(D_METHOD("get_origin_offset"), &LookAtModifier3D::get_origin_offset);
  336. ClassDB::bind_method(D_METHOD("set_duration", "duration"), &LookAtModifier3D::set_duration);
  337. ClassDB::bind_method(D_METHOD("get_duration"), &LookAtModifier3D::get_duration);
  338. ClassDB::bind_method(D_METHOD("set_transition_type", "transition_type"), &LookAtModifier3D::set_transition_type);
  339. ClassDB::bind_method(D_METHOD("get_transition_type"), &LookAtModifier3D::get_transition_type);
  340. ClassDB::bind_method(D_METHOD("set_ease_type", "ease_type"), &LookAtModifier3D::set_ease_type);
  341. ClassDB::bind_method(D_METHOD("get_ease_type"), &LookAtModifier3D::get_ease_type);
  342. ClassDB::bind_method(D_METHOD("set_use_angle_limitation", "enabled"), &LookAtModifier3D::set_use_angle_limitation);
  343. ClassDB::bind_method(D_METHOD("is_using_angle_limitation"), &LookAtModifier3D::is_using_angle_limitation);
  344. ClassDB::bind_method(D_METHOD("set_symmetry_limitation", "enabled"), &LookAtModifier3D::set_symmetry_limitation);
  345. ClassDB::bind_method(D_METHOD("is_limitation_symmetry"), &LookAtModifier3D::is_limitation_symmetry);
  346. ClassDB::bind_method(D_METHOD("set_primary_limit_angle", "angle"), &LookAtModifier3D::set_primary_limit_angle);
  347. ClassDB::bind_method(D_METHOD("get_primary_limit_angle"), &LookAtModifier3D::get_primary_limit_angle);
  348. ClassDB::bind_method(D_METHOD("set_primary_damp_threshold", "power"), &LookAtModifier3D::set_primary_damp_threshold);
  349. ClassDB::bind_method(D_METHOD("get_primary_damp_threshold"), &LookAtModifier3D::get_primary_damp_threshold);
  350. ClassDB::bind_method(D_METHOD("set_primary_positive_limit_angle", "angle"), &LookAtModifier3D::set_primary_positive_limit_angle);
  351. ClassDB::bind_method(D_METHOD("get_primary_positive_limit_angle"), &LookAtModifier3D::get_primary_positive_limit_angle);
  352. ClassDB::bind_method(D_METHOD("set_primary_positive_damp_threshold", "power"), &LookAtModifier3D::set_primary_positive_damp_threshold);
  353. ClassDB::bind_method(D_METHOD("get_primary_positive_damp_threshold"), &LookAtModifier3D::get_primary_positive_damp_threshold);
  354. ClassDB::bind_method(D_METHOD("set_primary_negative_limit_angle", "angle"), &LookAtModifier3D::set_primary_negative_limit_angle);
  355. ClassDB::bind_method(D_METHOD("get_primary_negative_limit_angle"), &LookAtModifier3D::get_primary_negative_limit_angle);
  356. ClassDB::bind_method(D_METHOD("set_primary_negative_damp_threshold", "power"), &LookAtModifier3D::set_primary_negative_damp_threshold);
  357. ClassDB::bind_method(D_METHOD("get_primary_negative_damp_threshold"), &LookAtModifier3D::get_primary_negative_damp_threshold);
  358. ClassDB::bind_method(D_METHOD("set_secondary_limit_angle", "angle"), &LookAtModifier3D::set_secondary_limit_angle);
  359. ClassDB::bind_method(D_METHOD("get_secondary_limit_angle"), &LookAtModifier3D::get_secondary_limit_angle);
  360. ClassDB::bind_method(D_METHOD("set_secondary_damp_threshold", "power"), &LookAtModifier3D::set_secondary_damp_threshold);
  361. ClassDB::bind_method(D_METHOD("get_secondary_damp_threshold"), &LookAtModifier3D::get_secondary_damp_threshold);
  362. ClassDB::bind_method(D_METHOD("set_secondary_positive_limit_angle", "angle"), &LookAtModifier3D::set_secondary_positive_limit_angle);
  363. ClassDB::bind_method(D_METHOD("get_secondary_positive_limit_angle"), &LookAtModifier3D::get_secondary_positive_limit_angle);
  364. ClassDB::bind_method(D_METHOD("set_secondary_positive_damp_threshold", "power"), &LookAtModifier3D::set_secondary_positive_damp_threshold);
  365. ClassDB::bind_method(D_METHOD("get_secondary_positive_damp_threshold"), &LookAtModifier3D::get_secondary_positive_damp_threshold);
  366. ClassDB::bind_method(D_METHOD("set_secondary_negative_limit_angle", "angle"), &LookAtModifier3D::set_secondary_negative_limit_angle);
  367. ClassDB::bind_method(D_METHOD("get_secondary_negative_limit_angle"), &LookAtModifier3D::get_secondary_negative_limit_angle);
  368. ClassDB::bind_method(D_METHOD("set_secondary_negative_damp_threshold", "power"), &LookAtModifier3D::set_secondary_negative_damp_threshold);
  369. ClassDB::bind_method(D_METHOD("get_secondary_negative_damp_threshold"), &LookAtModifier3D::get_secondary_negative_damp_threshold);
  370. ClassDB::bind_method(D_METHOD("get_interpolation_remaining"), &LookAtModifier3D::get_interpolation_remaining);
  371. ClassDB::bind_method(D_METHOD("is_interpolating"), &LookAtModifier3D::is_interpolating);
  372. ClassDB::bind_method(D_METHOD("is_target_within_limitation"), &LookAtModifier3D::is_target_within_limitation);
  373. ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_node", PROPERTY_HINT_NODE_TYPE, "Node3D"), "set_target_node", "get_target_node");
  374. ADD_PROPERTY(PropertyInfo(Variant::STRING, "bone_name", PROPERTY_HINT_ENUM_SUGGESTION, ""), "set_bone_name", "get_bone_name");
  375. ADD_PROPERTY(PropertyInfo(Variant::INT, "bone", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_bone", "get_bone");
  376. ADD_PROPERTY(PropertyInfo(Variant::INT, "forward_axis", PROPERTY_HINT_ENUM, "+X,-X,+Y,-Y,+Z,-Z"), "set_forward_axis", "get_forward_axis");
  377. ADD_PROPERTY(PropertyInfo(Variant::INT, "primary_rotation_axis", PROPERTY_HINT_ENUM, "X,Y,Z"), "set_primary_rotation_axis", "get_primary_rotation_axis");
  378. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_secondary_rotation"), "set_use_secondary_rotation", "is_using_secondary_rotation");
  379. ADD_GROUP("Origin Settings", "origin_");
  380. ADD_PROPERTY(PropertyInfo(Variant::INT, "origin_from", PROPERTY_HINT_ENUM, "Self,SpecificBone,ExternalNode"), "set_origin_from", "get_origin_from");
  381. ADD_PROPERTY(PropertyInfo(Variant::STRING, "origin_bone_name", PROPERTY_HINT_ENUM_SUGGESTION, ""), "set_origin_bone_name", "get_origin_bone_name");
  382. ADD_PROPERTY(PropertyInfo(Variant::INT, "origin_bone", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), "set_origin_bone", "get_origin_bone");
  383. ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "origin_external_node", PROPERTY_HINT_NODE_TYPE, "Node3D"), "set_origin_external_node", "get_origin_external_node");
  384. ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "origin_offset"), "set_origin_offset", "get_origin_offset");
  385. ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "origin_safe_margin", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater,suffix:m"), "set_origin_safe_margin", "get_origin_safe_margin");
  386. ADD_GROUP("Time Based Interpolation", "");
  387. ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "duration", PROPERTY_HINT_RANGE, "0,10,0.001,or_greater,suffix:s"), "set_duration", "get_duration");
  388. ADD_PROPERTY(PropertyInfo(Variant::INT, "transition_type", PROPERTY_HINT_ENUM, "Linear,Sine,Quint,Quart,Quad,Expo,Elastic,Cubic,Circ,Bounce,Back,Spring"), "set_transition_type", "get_transition_type");
  389. ADD_PROPERTY(PropertyInfo(Variant::INT, "ease_type", PROPERTY_HINT_ENUM, "In,Out,InOut,OutIn"), "set_ease_type", "get_ease_type");
  390. ADD_GROUP("Angle Limitation", "");
  391. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_angle_limitation"), "set_use_angle_limitation", "is_using_angle_limitation");
  392. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "symmetry_limitation"), "set_symmetry_limitation", "is_limitation_symmetry");
  393. ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "primary_limit_angle", PROPERTY_HINT_RANGE, "0,360,0.01,radians_as_degrees"), "set_primary_limit_angle", "get_primary_limit_angle");
  394. ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "primary_damp_threshold", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_primary_damp_threshold", "get_primary_damp_threshold");
  395. ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "primary_positive_limit_angle", PROPERTY_HINT_RANGE, "0,180,0.01,radians_as_degrees"), "set_primary_positive_limit_angle", "get_primary_positive_limit_angle");
  396. ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "primary_positive_damp_threshold", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_primary_positive_damp_threshold", "get_primary_positive_damp_threshold");
  397. ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "primary_negative_limit_angle", PROPERTY_HINT_RANGE, "0,180,0.01,radians_as_degrees"), "set_primary_negative_limit_angle", "get_primary_negative_limit_angle");
  398. ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "primary_negative_damp_threshold", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_primary_negative_damp_threshold", "get_primary_negative_damp_threshold");
  399. ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "secondary_limit_angle", PROPERTY_HINT_RANGE, "0,360,0.01,radians_as_degrees"), "set_secondary_limit_angle", "get_secondary_limit_angle");
  400. ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "secondary_damp_threshold", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_secondary_damp_threshold", "get_secondary_damp_threshold");
  401. ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "secondary_positive_limit_angle", PROPERTY_HINT_RANGE, "0,180,0.01,radians_as_degrees"), "set_secondary_positive_limit_angle", "get_secondary_positive_limit_angle");
  402. ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "secondary_positive_damp_threshold", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_secondary_positive_damp_threshold", "get_secondary_positive_damp_threshold");
  403. ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "secondary_negative_limit_angle", PROPERTY_HINT_RANGE, "0,180,0.01,radians_as_degrees"), "set_secondary_negative_limit_angle", "get_secondary_negative_limit_angle");
  404. ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "secondary_negative_damp_threshold", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_secondary_negative_damp_threshold", "get_secondary_negative_damp_threshold");
  405. BIND_ENUM_CONSTANT(ORIGIN_FROM_SELF);
  406. BIND_ENUM_CONSTANT(ORIGIN_FROM_SPECIFIC_BONE);
  407. BIND_ENUM_CONSTANT(ORIGIN_FROM_EXTERNAL_NODE);
  408. }
  409. void LookAtModifier3D::_process_modification(double p_delta) {
  410. if (!is_inside_tree()) {
  411. return;
  412. }
  413. Skeleton3D *skeleton = get_skeleton();
  414. if (!skeleton || bone < 0 || bone >= skeleton->get_bone_count()) {
  415. return;
  416. }
  417. // Calculate bone rest space in the world.
  418. Transform3D bone_rest_space;
  419. int parent_bone = skeleton->get_bone_parent(bone);
  420. if (parent_bone < 0) {
  421. bone_rest_space = skeleton->get_global_transform();
  422. bone_rest_space.translate_local(skeleton->get_bone_rest(bone).origin);
  423. } else {
  424. bone_rest_space = skeleton->get_global_transform() * skeleton->get_bone_global_pose(parent_bone);
  425. bone_rest_space.translate_local(skeleton->get_bone_rest(bone).origin);
  426. }
  427. // Calculate forward_vector and destination.
  428. is_within_limitations = true;
  429. Vector3 prev_forward_vector = forward_vector;
  430. Quaternion destination;
  431. Node3D *target = Object::cast_to<Node3D>(get_node_or_null(target_node));
  432. if (!target) {
  433. destination = skeleton->get_bone_pose_rotation(bone);
  434. } else {
  435. Transform3D origin_tr;
  436. if (origin_from == ORIGIN_FROM_SPECIFIC_BONE && origin_bone >= 0 && origin_bone < skeleton->get_bone_count()) {
  437. origin_tr = skeleton->get_global_transform() * skeleton->get_bone_global_pose(origin_bone);
  438. } else if (origin_from == ORIGIN_FROM_EXTERNAL_NODE) {
  439. Node3D *origin_src = Object::cast_to<Node3D>(get_node_or_null(origin_external_node));
  440. if (origin_src) {
  441. origin_tr = origin_src->get_global_transform();
  442. } else {
  443. origin_tr = bone_rest_space;
  444. }
  445. } else {
  446. origin_tr = bone_rest_space;
  447. }
  448. forward_vector = bone_rest_space.orthonormalized().basis.xform_inv(target->get_global_position() - origin_tr.translated_local(origin_offset).origin);
  449. forward_vector_nrm = forward_vector.normalized();
  450. if (forward_vector_nrm.abs().is_equal_approx(get_vector_from_axis(primary_rotation_axis))) {
  451. destination = skeleton->get_bone_pose_rotation(bone);
  452. forward_vector = Vector3(0, 0, 0); // The zero-vector to be used for checking in the line immediately below to avoid animation glitch.
  453. } else {
  454. destination = look_at_with_axes(skeleton->get_bone_rest(bone)).basis.get_rotation_quaternion();
  455. }
  456. }
  457. // Detect flipping.
  458. bool is_not_max_influence = influence < 1.0;
  459. bool is_flippable = use_angle_limitation || is_not_max_influence;
  460. Vector3::Axis current_forward_axis = get_axis_from_bone_axis(forward_axis);
  461. if (is_intersecting_axis(prev_forward_vector, forward_vector, current_forward_axis, secondary_rotation_axis) ||
  462. is_intersecting_axis(prev_forward_vector, forward_vector, primary_rotation_axis, primary_rotation_axis, true) ||
  463. is_intersecting_axis(prev_forward_vector, forward_vector, secondary_rotation_axis, current_forward_axis) ||
  464. (prev_forward_vector != Vector3(0, 0, 0) && forward_vector == Vector3(0, 0, 0)) ||
  465. (prev_forward_vector == Vector3(0, 0, 0) && forward_vector != Vector3(0, 0, 0))) {
  466. init_transition();
  467. } else if (is_flippable && std::signbit(prev_forward_vector[secondary_rotation_axis]) != std::signbit(forward_vector[secondary_rotation_axis])) {
  468. // Flipping by angle_limitation can be detected by sign of secondary rotation axes during forward_vector is rotated more than 90 degree from forward_axis (means dot production is negative).
  469. Vector3 prev_forward_vector_nrm = forward_vector.normalized();
  470. Vector3 rest_forward_vector = get_vector_from_bone_axis(forward_axis);
  471. if (symmetry_limitation) {
  472. if ((is_not_max_influence || !Math::is_equal_approx(primary_limit_angle, (float)Math::TAU)) &&
  473. prev_forward_vector_nrm.dot(rest_forward_vector) < 0 &&
  474. forward_vector_nrm.dot(rest_forward_vector) < 0) {
  475. init_transition();
  476. }
  477. } else {
  478. if ((is_not_max_influence || !Math::is_equal_approx(primary_positive_limit_angle + primary_negative_limit_angle, (float)Math::TAU)) &&
  479. prev_forward_vector_nrm.dot(rest_forward_vector) < 0 &&
  480. forward_vector_nrm.dot(rest_forward_vector) < 0) {
  481. init_transition();
  482. }
  483. }
  484. }
  485. // Do time-based interpolation.
  486. if (remaining > 0) {
  487. remaining = MAX(0, remaining - time_step * p_delta);
  488. if (is_flippable) {
  489. // Interpolate through the rest same as AnimationTree blending for preventing to penetrate the bone into the body.
  490. Quaternion rest = skeleton->get_bone_rest(bone).basis.get_rotation_quaternion();
  491. float weight = Tween::run_equation(transition_type, ease_type, 1 - remaining, 0.0, 1.0, 1.0);
  492. destination = rest * Quaternion().slerp(rest.inverse() * from_q, 1 - weight) * Quaternion().slerp(rest.inverse() * destination, weight);
  493. } else {
  494. destination = from_q.slerp(destination, Tween::run_equation(transition_type, ease_type, 1 - remaining, 0.0, 1.0, 1.0));
  495. }
  496. }
  497. skeleton->set_bone_pose_rotation(bone, destination);
  498. prev_q = destination;
  499. }
  500. bool LookAtModifier3D::is_intersecting_axis(const Vector3 &p_prev, const Vector3 &p_current, Vector3::Axis p_flipping_axis, Vector3::Axis p_check_axis, bool p_check_plane) const {
  501. // Prevent that the angular velocity does not become too large.
  502. // Check that is p_flipping_axis flipped nearby p_check_axis (close than origin_safe_margin) or not. If p_check_plane is true, check two axes of crossed plane.
  503. if (p_check_plane) {
  504. if (get_projection_vector(p_prev, p_check_axis).length() > origin_safe_margin && get_projection_vector(p_current, p_check_axis).length() > origin_safe_margin) {
  505. return false;
  506. }
  507. } else if (Math::abs(p_prev[p_check_axis]) > origin_safe_margin && Math::abs(p_current[p_check_axis]) > origin_safe_margin) {
  508. return false;
  509. }
  510. return std::signbit(p_prev[p_flipping_axis]) != std::signbit(p_current[p_flipping_axis]);
  511. }
  512. Vector3 LookAtModifier3D::get_basis_vector_from_bone_axis(const Basis &p_basis, BoneAxis p_axis) {
  513. Vector3 ret;
  514. switch (p_axis) {
  515. case BONE_AXIS_PLUS_X: {
  516. ret = p_basis.get_column(0);
  517. } break;
  518. case BONE_AXIS_MINUS_X: {
  519. ret = -p_basis.get_column(0);
  520. } break;
  521. case BONE_AXIS_PLUS_Y: {
  522. ret = p_basis.get_column(1);
  523. } break;
  524. case BONE_AXIS_MINUS_Y: {
  525. ret = -p_basis.get_column(1);
  526. } break;
  527. case BONE_AXIS_PLUS_Z: {
  528. ret = p_basis.get_column(2);
  529. } break;
  530. case BONE_AXIS_MINUS_Z: {
  531. ret = -p_basis.get_column(2);
  532. } break;
  533. }
  534. return ret;
  535. }
  536. Vector3::Axis LookAtModifier3D::get_secondary_rotation_axis(BoneAxis p_forward_axis, Vector3::Axis p_primary_rotation_axis) {
  537. Vector3 secondary_plane = get_vector_from_bone_axis(p_forward_axis) + get_vector_from_axis(p_primary_rotation_axis);
  538. return Math::is_zero_approx(secondary_plane.x) ? Vector3::AXIS_X : (Math::is_zero_approx(secondary_plane.y) ? Vector3::AXIS_Y : Vector3::AXIS_Z);
  539. }
  540. Vector2 LookAtModifier3D::get_projection_vector(const Vector3 &p_vector, Vector3::Axis p_axis) {
  541. // NOTE: axis is swapped between 2D and 3D.
  542. Vector2 ret;
  543. switch (p_axis) {
  544. case Vector3::AXIS_X: {
  545. ret = Vector2(p_vector.z, p_vector.y);
  546. } break;
  547. case Vector3::AXIS_Y: {
  548. ret = Vector2(p_vector.x, p_vector.z);
  549. } break;
  550. case Vector3::AXIS_Z: {
  551. ret = Vector2(p_vector.y, p_vector.x);
  552. } break;
  553. }
  554. return ret;
  555. }
  556. float LookAtModifier3D::remap_damped(float p_from, float p_to, float p_damp_threshold, float p_value) const {
  557. float sign = std::signbit(p_value) ? -1.0f : 1.0f;
  558. float abs_value = Math::abs(p_value);
  559. if (Math::is_equal_approx(p_damp_threshold, 1.0f) || Math::is_zero_approx(p_to)) {
  560. return sign * CLAMP(abs_value, p_from, p_to); // Avoid division by zero.
  561. }
  562. float value = Math::inverse_lerp(p_from, p_to, abs_value);
  563. if (value <= p_damp_threshold) {
  564. return sign * CLAMP(abs_value, p_from, p_to);
  565. }
  566. double limit = Math::PI;
  567. double inv_to = 1.0 / p_to;
  568. double end_x = limit * inv_to;
  569. double position = abs_value * inv_to;
  570. Vector2 start = Vector2(p_damp_threshold, p_damp_threshold);
  571. Vector2 mid = Vector2(1.0, 1.0);
  572. Vector2 end = Vector2(end_x, 1.0);
  573. value = get_bspline_y(start, mid, end, position);
  574. return sign * Math::lerp(p_from, p_to, value);
  575. }
  576. double LookAtModifier3D::get_bspline_y(const Vector2 &p_from, const Vector2 &p_control, const Vector2 &p_to, double p_x) const {
  577. double a = p_from.x - 2.0 * p_control.x + p_to.x;
  578. double b = -2.0 * p_from.x + 2.0 * p_control.x;
  579. double c = p_from.x - p_x;
  580. double t = 0.0;
  581. if (Math::is_zero_approx(a)) {
  582. t = -c / b; // Almost linear.
  583. } else {
  584. double discriminant = b * b - 4.0 * a * c;
  585. double sqrt_discriminant = Math::sqrt(discriminant);
  586. double e = 1.0 / (2.0 * a);
  587. double t1 = (-b + sqrt_discriminant) * e;
  588. t = (0.0 <= t1 && t1 <= 1.0) ? t1 : (-b - sqrt_discriminant) * e;
  589. }
  590. double u = 1.0 - t;
  591. double y = u * u * p_from.y + 2.0 * u * t * p_control.y + t * t * p_to.y;
  592. return y;
  593. }
  594. Transform3D LookAtModifier3D::look_at_with_axes(const Transform3D &p_rest) {
  595. // Primary rotation by projection to 2D plane by xform_inv and picking elements.
  596. Vector3 current_vector = get_basis_vector_from_bone_axis(p_rest.basis, forward_axis).normalized();
  597. Vector2 src_vec2 = get_projection_vector(p_rest.basis.xform_inv(forward_vector_nrm), primary_rotation_axis).normalized();
  598. Vector2 dst_vec2 = get_projection_vector(p_rest.basis.xform_inv(current_vector), primary_rotation_axis).normalized();
  599. real_t calculated_angle = src_vec2.angle_to(dst_vec2);
  600. Transform3D primary_result = p_rest.rotated_local(get_vector_from_axis(primary_rotation_axis), calculated_angle);
  601. Transform3D current_result = primary_result; // primary_result will be used by calculation of secondary rotation, current_result is rotated by that.
  602. float limit_angle = 0.0;
  603. float damp_threshold = 0.0;
  604. if (use_angle_limitation) {
  605. if (symmetry_limitation) {
  606. limit_angle = primary_limit_angle * 0.5f;
  607. damp_threshold = primary_damp_threshold;
  608. } else {
  609. if (std::signbit(calculated_angle)) {
  610. limit_angle = primary_negative_limit_angle;
  611. damp_threshold = primary_negative_damp_threshold;
  612. } else {
  613. limit_angle = primary_positive_limit_angle;
  614. damp_threshold = primary_positive_damp_threshold;
  615. }
  616. }
  617. if (Math::abs(calculated_angle) > limit_angle) {
  618. is_within_limitations = false;
  619. }
  620. calculated_angle = remap_damped(0, limit_angle, damp_threshold, calculated_angle);
  621. current_result = p_rest.rotated_local(get_vector_from_axis(primary_rotation_axis), calculated_angle);
  622. }
  623. // Needs for detecting flipping even if use_secondary_rotation is false.
  624. secondary_rotation_axis = get_secondary_rotation_axis(forward_axis, primary_rotation_axis);
  625. if (!use_secondary_rotation) {
  626. return current_result;
  627. }
  628. // Secondary rotation by projection to 2D plane by xform_inv and picking elements.
  629. current_vector = get_basis_vector_from_bone_axis(primary_result.basis, forward_axis).normalized();
  630. src_vec2 = get_projection_vector(primary_result.basis.xform_inv(forward_vector_nrm), secondary_rotation_axis).normalized();
  631. dst_vec2 = get_projection_vector(primary_result.basis.xform_inv(current_vector), secondary_rotation_axis).normalized();
  632. calculated_angle = src_vec2.angle_to(dst_vec2);
  633. if (use_angle_limitation) {
  634. if (symmetry_limitation) {
  635. limit_angle = secondary_limit_angle * 0.5f;
  636. damp_threshold = secondary_damp_threshold;
  637. } else {
  638. if (std::signbit(calculated_angle)) {
  639. limit_angle = secondary_negative_limit_angle;
  640. damp_threshold = secondary_negative_damp_threshold;
  641. } else {
  642. limit_angle = secondary_positive_limit_angle;
  643. damp_threshold = secondary_positive_damp_threshold;
  644. }
  645. }
  646. if (Math::abs(calculated_angle) > limit_angle) {
  647. is_within_limitations = false;
  648. }
  649. calculated_angle = remap_damped(0, limit_angle, damp_threshold, calculated_angle);
  650. }
  651. current_result = current_result.rotated_local(get_vector_from_axis(secondary_rotation_axis), calculated_angle);
  652. return current_result;
  653. }
  654. void LookAtModifier3D::init_transition() {
  655. if (Math::is_zero_approx(duration)) {
  656. return;
  657. }
  658. from_q = prev_q;
  659. remaining = 1.0;
  660. }