visual_shader_particle_nodes.cpp 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048
  1. /*************************************************************************/
  2. /* visual_shader_particle_nodes.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
  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 "visual_shader_particle_nodes.h"
  31. // VisualShaderNodeParticleEmitter
  32. int VisualShaderNodeParticleEmitter::get_output_port_count() const {
  33. return 1;
  34. }
  35. VisualShaderNodeParticleEmitter::PortType VisualShaderNodeParticleEmitter::get_output_port_type(int p_port) const {
  36. return PORT_TYPE_VECTOR;
  37. }
  38. String VisualShaderNodeParticleEmitter::get_output_port_name(int p_port) const {
  39. if (p_port == 0) {
  40. return "position";
  41. }
  42. return String();
  43. }
  44. bool VisualShaderNodeParticleEmitter::has_output_port_preview(int p_port) const {
  45. return false;
  46. }
  47. VisualShaderNodeParticleEmitter::VisualShaderNodeParticleEmitter() {
  48. }
  49. // VisualShaderNodeParticleSphereEmitter
  50. String VisualShaderNodeParticleSphereEmitter::get_caption() const {
  51. return "SphereEmitter";
  52. }
  53. int VisualShaderNodeParticleSphereEmitter::get_input_port_count() const {
  54. return 2;
  55. }
  56. VisualShaderNodeParticleSphereEmitter::PortType VisualShaderNodeParticleSphereEmitter::get_input_port_type(int p_port) const {
  57. return PORT_TYPE_SCALAR;
  58. }
  59. String VisualShaderNodeParticleSphereEmitter::get_input_port_name(int p_port) const {
  60. if (p_port == 0) {
  61. return "radius";
  62. } else if (p_port == 1) {
  63. return "inner_radius";
  64. }
  65. return String();
  66. }
  67. String VisualShaderNodeParticleSphereEmitter::generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
  68. String code;
  69. code += "vec3 __get_random_point_in_sphere(inout uint seed, float radius, float inner_radius) {\n";
  70. code += " return __get_random_unit_vec3(seed) * __randf_range(seed, inner_radius, radius);\n";
  71. code += "}\n\n";
  72. return code;
  73. }
  74. String VisualShaderNodeParticleSphereEmitter::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
  75. String code;
  76. code += " " + p_output_vars[0] + " = __get_random_point_in_sphere(__seed, " + (p_input_vars[0].is_empty() ? (String)get_input_port_default_value(0) : p_input_vars[0]) + ", " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ");\n";
  77. return code;
  78. }
  79. VisualShaderNodeParticleSphereEmitter::VisualShaderNodeParticleSphereEmitter() {
  80. set_input_port_default_value(0, 10.0);
  81. set_input_port_default_value(1, 0.0);
  82. }
  83. // VisualShaderNodeParticleBoxEmitter
  84. String VisualShaderNodeParticleBoxEmitter::get_caption() const {
  85. return "BoxEmitter";
  86. }
  87. int VisualShaderNodeParticleBoxEmitter::get_input_port_count() const {
  88. return 1;
  89. }
  90. VisualShaderNodeParticleBoxEmitter::PortType VisualShaderNodeParticleBoxEmitter::get_input_port_type(int p_port) const {
  91. if (p_port == 0) {
  92. return PORT_TYPE_VECTOR;
  93. }
  94. return PORT_TYPE_SCALAR;
  95. }
  96. String VisualShaderNodeParticleBoxEmitter::get_input_port_name(int p_port) const {
  97. if (p_port == 0) {
  98. return "extents";
  99. }
  100. return String();
  101. }
  102. String VisualShaderNodeParticleBoxEmitter::generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
  103. String code;
  104. code += "vec3 __get_random_point_in_box(inout uint seed, vec3 extents) {\n";
  105. code += " vec3 half_extents = extents / 2.0;\n";
  106. code += " return vec3(__randf_range(seed, -half_extents.x, half_extents.x), __randf_range(seed, -half_extents.y, half_extents.y), __randf_range(seed, -half_extents.z, half_extents.z));\n";
  107. code += "}\n\n";
  108. return code;
  109. }
  110. String VisualShaderNodeParticleBoxEmitter::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
  111. String code;
  112. code += " " + p_output_vars[0] + " = __get_random_point_in_box(__seed, " + (p_input_vars[0].is_empty() ? (String)get_input_port_default_value(0) : p_input_vars[0]) + ");\n";
  113. return code;
  114. }
  115. VisualShaderNodeParticleBoxEmitter::VisualShaderNodeParticleBoxEmitter() {
  116. set_input_port_default_value(0, Vector3(1.0, 1.0, 1.0));
  117. }
  118. // VisualShaderNodeParticleRingEmitter
  119. String VisualShaderNodeParticleRingEmitter::get_caption() const {
  120. return "RingEmitter";
  121. }
  122. int VisualShaderNodeParticleRingEmitter::get_input_port_count() const {
  123. return 3;
  124. }
  125. VisualShaderNodeParticleRingEmitter::PortType VisualShaderNodeParticleRingEmitter::get_input_port_type(int p_port) const {
  126. return PORT_TYPE_SCALAR;
  127. }
  128. String VisualShaderNodeParticleRingEmitter::get_input_port_name(int p_port) const {
  129. if (p_port == 0) {
  130. return "radius";
  131. } else if (p_port == 1) {
  132. return "inner_radius";
  133. } else if (p_port == 2) {
  134. return "height";
  135. }
  136. return String();
  137. }
  138. String VisualShaderNodeParticleRingEmitter::generate_global_per_node(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
  139. String code;
  140. code += "vec3 __get_random_point_on_ring(inout uint seed, float radius, float inner_radius, float height) {\n";
  141. code += " float angle = __rand_from_seed(seed) * PI * 2.0;\n";
  142. code += " vec2 ring = vec2(sin(angle), cos(angle)) * __randf_range(seed, inner_radius, radius);\n";
  143. code += " return vec3(ring.x, __randf_range(seed, min(0.0, height), max(0.0, height)), ring.y);\n";
  144. code += "}\n\n";
  145. return code;
  146. }
  147. String VisualShaderNodeParticleRingEmitter::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
  148. String code;
  149. code = " " + p_output_vars[0] + " = __get_random_point_on_ring(__seed, " + (p_input_vars[0].is_empty() ? (String)get_input_port_default_value(0) : p_input_vars[0]) + ", " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ", " + (p_input_vars[2].is_empty() ? (String)get_input_port_default_value(2) : p_input_vars[2]) + ");\n";
  150. return code;
  151. }
  152. VisualShaderNodeParticleRingEmitter::VisualShaderNodeParticleRingEmitter() {
  153. set_input_port_default_value(0, 10.0);
  154. set_input_port_default_value(1, 0.0);
  155. set_input_port_default_value(2, 0.0);
  156. }
  157. // VisualShaderNodeParticleMultiplyByAxisAngle
  158. void VisualShaderNodeParticleMultiplyByAxisAngle::_bind_methods() {
  159. ClassDB::bind_method(D_METHOD("set_degrees_mode", "enabled"), &VisualShaderNodeParticleMultiplyByAxisAngle::set_degrees_mode);
  160. ClassDB::bind_method(D_METHOD("is_degrees_mode"), &VisualShaderNodeParticleMultiplyByAxisAngle::is_degrees_mode);
  161. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "degrees_mode"), "set_degrees_mode", "is_degrees_mode");
  162. }
  163. String VisualShaderNodeParticleMultiplyByAxisAngle::get_caption() const {
  164. return "MultiplyByAxisAngle";
  165. }
  166. int VisualShaderNodeParticleMultiplyByAxisAngle::get_input_port_count() const {
  167. return 3;
  168. }
  169. VisualShaderNodeParticleMultiplyByAxisAngle::PortType VisualShaderNodeParticleMultiplyByAxisAngle::get_input_port_type(int p_port) const {
  170. if (p_port == 0 || p_port == 1) { // position, rotation_axis
  171. return PORT_TYPE_VECTOR;
  172. }
  173. return PORT_TYPE_SCALAR; // angle (degrees/radians)
  174. }
  175. String VisualShaderNodeParticleMultiplyByAxisAngle::get_input_port_name(int p_port) const {
  176. if (p_port == 0) {
  177. return "position";
  178. }
  179. if (p_port == 1) {
  180. return "axis";
  181. }
  182. if (p_port == 2) {
  183. if (degrees_mode) {
  184. return "angle (degrees)";
  185. } else {
  186. return "angle (radians)";
  187. }
  188. }
  189. return String();
  190. }
  191. bool VisualShaderNodeParticleMultiplyByAxisAngle::is_show_prop_names() const {
  192. return true;
  193. }
  194. int VisualShaderNodeParticleMultiplyByAxisAngle::get_output_port_count() const {
  195. return 1;
  196. }
  197. VisualShaderNodeParticleMultiplyByAxisAngle::PortType VisualShaderNodeParticleMultiplyByAxisAngle::get_output_port_type(int p_port) const {
  198. return PORT_TYPE_VECTOR;
  199. }
  200. String VisualShaderNodeParticleMultiplyByAxisAngle::get_output_port_name(int p_port) const {
  201. return "position";
  202. }
  203. String VisualShaderNodeParticleMultiplyByAxisAngle::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
  204. String code;
  205. if (degrees_mode) {
  206. code += " " + p_output_vars[0] + " = __build_rotation_mat3(" + (p_input_vars[1].is_empty() ? ("vec3" + (String)get_input_port_default_value(1)) : p_input_vars[1]) + ", radians(" + (p_input_vars[2].is_empty() ? (String)get_input_port_default_value(2) : p_input_vars[2]) + ")) * " + (p_input_vars[0].is_empty() ? "vec3(0.0)" : p_input_vars[0]) + ";\n";
  207. } else {
  208. code += " " + p_output_vars[0] + " = __build_rotation_mat3(" + (p_input_vars[1].is_empty() ? ("vec3" + (String)get_input_port_default_value(1)) : p_input_vars[1]) + ", " + (p_input_vars[2].is_empty() ? (String)get_input_port_default_value(2) : p_input_vars[2]) + ") * " + (p_input_vars[0].is_empty() ? "vec3(0.0)" : p_input_vars[0]) + ";\n";
  209. }
  210. return code;
  211. }
  212. void VisualShaderNodeParticleMultiplyByAxisAngle::set_degrees_mode(bool p_enabled) {
  213. degrees_mode = p_enabled;
  214. emit_changed();
  215. }
  216. bool VisualShaderNodeParticleMultiplyByAxisAngle::is_degrees_mode() const {
  217. return degrees_mode;
  218. }
  219. Vector<StringName> VisualShaderNodeParticleMultiplyByAxisAngle::get_editable_properties() const {
  220. Vector<StringName> props;
  221. props.push_back("degrees_mode");
  222. props.push_back("axis_amount");
  223. return props;
  224. }
  225. bool VisualShaderNodeParticleMultiplyByAxisAngle::has_output_port_preview(int p_port) const {
  226. return false;
  227. }
  228. VisualShaderNodeParticleMultiplyByAxisAngle::VisualShaderNodeParticleMultiplyByAxisAngle() {
  229. set_input_port_default_value(1, Vector3(1, 0, 0));
  230. set_input_port_default_value(2, 0.0);
  231. }
  232. // VisualShaderNodeParticleConeVelocity
  233. String VisualShaderNodeParticleConeVelocity::get_caption() const {
  234. return "ConeVelocity";
  235. }
  236. int VisualShaderNodeParticleConeVelocity::get_input_port_count() const {
  237. return 2;
  238. }
  239. VisualShaderNodeParticleConeVelocity::PortType VisualShaderNodeParticleConeVelocity::get_input_port_type(int p_port) const {
  240. if (p_port == 0) {
  241. return PORT_TYPE_VECTOR;
  242. } else if (p_port == 1) {
  243. return PORT_TYPE_SCALAR;
  244. }
  245. return PORT_TYPE_SCALAR;
  246. }
  247. String VisualShaderNodeParticleConeVelocity::get_input_port_name(int p_port) const {
  248. if (p_port == 0) {
  249. return "direction";
  250. } else if (p_port == 1) {
  251. return "spread(degrees)";
  252. }
  253. return String();
  254. }
  255. int VisualShaderNodeParticleConeVelocity::get_output_port_count() const {
  256. return 1;
  257. }
  258. VisualShaderNodeParticleConeVelocity::PortType VisualShaderNodeParticleConeVelocity::get_output_port_type(int p_port) const {
  259. return PORT_TYPE_VECTOR;
  260. }
  261. String VisualShaderNodeParticleConeVelocity::get_output_port_name(int p_port) const {
  262. if (p_port == 0) {
  263. return "velocity";
  264. }
  265. return String();
  266. }
  267. bool VisualShaderNodeParticleConeVelocity::has_output_port_preview(int p_port) const {
  268. return false;
  269. }
  270. String VisualShaderNodeParticleConeVelocity::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
  271. String code;
  272. code += " __radians = radians(" + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ");\n";
  273. code += " __scalar_buff1 = __rand_from_seed_m1_p1(__seed) * __radians;\n";
  274. code += " __scalar_buff2 = __rand_from_seed_m1_p1(__seed) * __radians;\n";
  275. code += " __vec3_buff1 = " + (p_input_vars[0].is_empty() ? "vec3" + (String)get_input_port_default_value(0) : p_input_vars[0]) + ";\n";
  276. code += " __scalar_buff1 += __vec3_buff1.z != 0.0 ? atan(__vec3_buff1.x, __vec3_buff1.z) : sign(__vec3_buff1.x) * (PI / 2.0);\n";
  277. code += " __scalar_buff2 += __vec3_buff1.z != 0.0 ? atan(__vec3_buff1.y, abs(__vec3_buff1.z)) : (__vec3_buff1.x != 0.0 ? atan(__vec3_buff1.y, abs(__vec3_buff1.x)) : sign(__vec3_buff1.y) * (PI / 2.0));\n";
  278. code += " __vec3_buff1 = vec3(sin(__scalar_buff1), 0.0, cos(__scalar_buff1));\n";
  279. code += " __vec3_buff2 = vec3(0.0, sin(__scalar_buff2), cos(__scalar_buff2));\n";
  280. code += " __vec3_buff2.z = __vec3_buff2.z / max(0.0001, sqrt(abs(__vec3_buff2.z)));\n";
  281. code += " " + p_output_vars[0] + " = normalize(vec3(__vec3_buff1.x * __vec3_buff2.z, __vec3_buff2.y, __vec3_buff1.z * __vec3_buff2.z));\n";
  282. return code;
  283. }
  284. VisualShaderNodeParticleConeVelocity::VisualShaderNodeParticleConeVelocity() {
  285. set_input_port_default_value(0, Vector3(1, 0, 0));
  286. set_input_port_default_value(1, 45.0);
  287. }
  288. // VisualShaderNodeParticleRandomness
  289. void VisualShaderNodeParticleRandomness::_bind_methods() {
  290. ClassDB::bind_method(D_METHOD("set_op_type", "type"), &VisualShaderNodeParticleRandomness::set_op_type);
  291. ClassDB::bind_method(D_METHOD("get_op_type"), &VisualShaderNodeParticleRandomness::get_op_type);
  292. ADD_PROPERTY(PropertyInfo(Variant::INT, "op_type", PROPERTY_HINT_ENUM, "Scalar,Vector"), "set_op_type", "get_op_type");
  293. BIND_ENUM_CONSTANT(OP_TYPE_SCALAR);
  294. BIND_ENUM_CONSTANT(OP_TYPE_VECTOR);
  295. BIND_ENUM_CONSTANT(OP_TYPE_MAX);
  296. }
  297. Vector<StringName> VisualShaderNodeParticleRandomness::get_editable_properties() const {
  298. Vector<StringName> props;
  299. props.push_back("op_type");
  300. return props;
  301. }
  302. String VisualShaderNodeParticleRandomness::get_caption() const {
  303. return "ParticleRandomness";
  304. }
  305. int VisualShaderNodeParticleRandomness::get_output_port_count() const {
  306. return 1;
  307. }
  308. VisualShaderNodeParticleRandomness::PortType VisualShaderNodeParticleRandomness::get_output_port_type(int p_port) const {
  309. if (op_type == OP_TYPE_VECTOR) {
  310. return PORT_TYPE_VECTOR;
  311. }
  312. return PORT_TYPE_SCALAR;
  313. }
  314. String VisualShaderNodeParticleRandomness::get_output_port_name(int p_port) const {
  315. return "random";
  316. }
  317. int VisualShaderNodeParticleRandomness::get_input_port_count() const {
  318. return 2;
  319. }
  320. VisualShaderNodeParticleRandomness::PortType VisualShaderNodeParticleRandomness::get_input_port_type(int p_port) const {
  321. if (op_type == OP_TYPE_VECTOR) {
  322. return PORT_TYPE_VECTOR;
  323. }
  324. return PORT_TYPE_SCALAR;
  325. }
  326. String VisualShaderNodeParticleRandomness::get_input_port_name(int p_port) const {
  327. if (p_port == 0) {
  328. return "min";
  329. } else if (p_port == 1) {
  330. return "max";
  331. }
  332. return String();
  333. }
  334. String VisualShaderNodeParticleRandomness::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
  335. String code;
  336. if (op_type == OP_TYPE_SCALAR) {
  337. code += vformat(" %s = __randf_range(__seed, %s, %s);\n", p_output_vars[0], p_input_vars[0].is_empty() ? (String)get_input_port_default_value(0) : p_input_vars[0], p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]);
  338. } else if (op_type == OP_TYPE_VECTOR) {
  339. code += vformat(" %s = __randv_range(__seed, %s, %s);\n", p_output_vars[0], p_input_vars[0].is_empty() ? (String)get_input_port_default_value(0) : p_input_vars[0], p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]);
  340. }
  341. return code;
  342. }
  343. void VisualShaderNodeParticleRandomness::set_op_type(OpType p_op_type) {
  344. ERR_FAIL_INDEX(int(p_op_type), int(OP_TYPE_MAX));
  345. if (op_type == p_op_type) {
  346. return;
  347. }
  348. if (p_op_type == OP_TYPE_SCALAR) {
  349. set_input_port_default_value(0, 0.0);
  350. set_input_port_default_value(1, 1.0);
  351. } else {
  352. set_input_port_default_value(0, Vector3(-1.0, -1.0, -1.0));
  353. set_input_port_default_value(1, Vector3(1.0, 1.0, 1.0));
  354. }
  355. op_type = p_op_type;
  356. emit_changed();
  357. }
  358. VisualShaderNodeParticleRandomness::OpType VisualShaderNodeParticleRandomness::get_op_type() const {
  359. return op_type;
  360. }
  361. bool VisualShaderNodeParticleRandomness::has_output_port_preview(int p_port) const {
  362. return false;
  363. }
  364. VisualShaderNodeParticleRandomness::VisualShaderNodeParticleRandomness() {
  365. set_input_port_default_value(0, 0.0);
  366. set_input_port_default_value(1, 1.0);
  367. }
  368. // VisualShaderNodeParticleAccelerator
  369. void VisualShaderNodeParticleAccelerator::_bind_methods() {
  370. ClassDB::bind_method(D_METHOD("set_mode", "mode"), &VisualShaderNodeParticleAccelerator::set_mode);
  371. ClassDB::bind_method(D_METHOD("get_mode"), &VisualShaderNodeParticleAccelerator::get_mode);
  372. ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Linear,Radial,Tangential"), "set_mode", "get_mode");
  373. BIND_ENUM_CONSTANT(MODE_LINEAR);
  374. BIND_ENUM_CONSTANT(MODE_RADIAL)
  375. BIND_ENUM_CONSTANT(MODE_TANGENTIAL);
  376. BIND_ENUM_CONSTANT(MODE_MAX);
  377. }
  378. Vector<StringName> VisualShaderNodeParticleAccelerator::get_editable_properties() const {
  379. Vector<StringName> props;
  380. props.push_back("mode");
  381. return props;
  382. }
  383. String VisualShaderNodeParticleAccelerator::get_caption() const {
  384. return "ParticleAccelerator";
  385. }
  386. int VisualShaderNodeParticleAccelerator::get_output_port_count() const {
  387. return 1;
  388. }
  389. VisualShaderNodeParticleAccelerator::PortType VisualShaderNodeParticleAccelerator::get_output_port_type(int p_port) const {
  390. return PORT_TYPE_VECTOR;
  391. }
  392. String VisualShaderNodeParticleAccelerator::get_output_port_name(int p_port) const {
  393. return String();
  394. }
  395. int VisualShaderNodeParticleAccelerator::get_input_port_count() const {
  396. return 3;
  397. }
  398. VisualShaderNodeParticleAccelerator::PortType VisualShaderNodeParticleAccelerator::get_input_port_type(int p_port) const {
  399. if (p_port == 0) {
  400. return PORT_TYPE_VECTOR;
  401. } else if (p_port == 1) {
  402. return PORT_TYPE_SCALAR;
  403. } else if (p_port == 2) {
  404. return PORT_TYPE_VECTOR;
  405. }
  406. return PORT_TYPE_SCALAR;
  407. }
  408. String VisualShaderNodeParticleAccelerator::get_input_port_name(int p_port) const {
  409. if (p_port == 0) {
  410. return "amount";
  411. } else if (p_port == 1) {
  412. return "randomness";
  413. } else if (p_port == 2) {
  414. return "axis";
  415. }
  416. return String();
  417. }
  418. String VisualShaderNodeParticleAccelerator::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
  419. String code;
  420. switch (mode) {
  421. case MODE_LINEAR:
  422. code += " " + p_output_vars[0] + " = length(VELOCITY) > 0.0 ? " + "normalize(VELOCITY) * " + (p_input_vars[0].is_empty() ? "vec3" + (String)get_input_port_default_value(0) : p_input_vars[0]) + " * mix(1.0, __rand_from_seed(__seed), " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ") : vec3(0.0);\n";
  423. break;
  424. case MODE_RADIAL:
  425. code += " " + p_output_vars[0] + " = length(__diff) > 0.0 ? __ndiff * " + (p_input_vars[0].is_empty() ? "vec3" + (String)get_input_port_default_value(0) : p_input_vars[0]) + " * mix(1.0, __rand_from_seed(__seed), " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ") : vec3(0.0);\n";
  426. break;
  427. case MODE_TANGENTIAL:
  428. code += " __vec3_buff1 = cross(__ndiff, normalize(" + (p_input_vars[2].is_empty() ? "vec3" + (String)get_input_port_default_value(2) : p_input_vars[2]) + "));\n";
  429. code += " " + p_output_vars[0] + " = length(__vec3_buff1) > 0.0 ? normalize(__vec3_buff1) * (" + (p_input_vars[0].is_empty() ? "vec3" + (String)get_input_port_default_value(0) : p_input_vars[0]) + " * mix(1.0, __rand_from_seed(__seed), " + (p_input_vars[1].is_empty() ? (String)get_input_port_default_value(1) : p_input_vars[1]) + ")) : vec3(0.0);\n";
  430. break;
  431. default:
  432. break;
  433. }
  434. return code;
  435. }
  436. void VisualShaderNodeParticleAccelerator::set_mode(Mode p_mode) {
  437. ERR_FAIL_INDEX(int(p_mode), int(MODE_MAX));
  438. if (mode == p_mode) {
  439. return;
  440. }
  441. mode = p_mode;
  442. emit_changed();
  443. }
  444. VisualShaderNodeParticleAccelerator::Mode VisualShaderNodeParticleAccelerator::get_mode() const {
  445. return mode;
  446. }
  447. bool VisualShaderNodeParticleAccelerator::has_output_port_preview(int p_port) const {
  448. return false;
  449. }
  450. VisualShaderNodeParticleAccelerator::VisualShaderNodeParticleAccelerator() {
  451. set_input_port_default_value(0, Vector3(1, 1, 1));
  452. set_input_port_default_value(1, 0.0);
  453. set_input_port_default_value(2, Vector3(0, -9.8, 0));
  454. }
  455. // VisualShaderNodeParticleOutput
  456. String VisualShaderNodeParticleOutput::get_caption() const {
  457. if (shader_type == VisualShader::TYPE_START) {
  458. return "StartOutput";
  459. } else if (shader_type == VisualShader::TYPE_PROCESS) {
  460. return "ProcessOutput";
  461. } else if (shader_type == VisualShader::TYPE_COLLIDE) {
  462. return "CollideOutput";
  463. } else if (shader_type == VisualShader::TYPE_START_CUSTOM) {
  464. return "CustomStartOutput";
  465. } else if (shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
  466. return "CustomProcessOutput";
  467. }
  468. return String();
  469. }
  470. int VisualShaderNodeParticleOutput::get_input_port_count() const {
  471. if (shader_type == VisualShader::TYPE_START) {
  472. return 8;
  473. } else if (shader_type == VisualShader::TYPE_COLLIDE) {
  474. return 5;
  475. } else if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
  476. return 6;
  477. } else { // TYPE_PROCESS
  478. return 7;
  479. }
  480. return 0;
  481. }
  482. VisualShaderNodeParticleOutput::PortType VisualShaderNodeParticleOutput::get_input_port_type(int p_port) const {
  483. switch (p_port) {
  484. case 0:
  485. if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
  486. return PORT_TYPE_VECTOR; // custom.rgb
  487. }
  488. return PORT_TYPE_BOOLEAN; // active
  489. case 1:
  490. if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
  491. break; // custom.a (scalar)
  492. }
  493. return PORT_TYPE_VECTOR; // velocity
  494. case 2:
  495. return PORT_TYPE_VECTOR; // color & velocity
  496. case 3:
  497. if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
  498. return PORT_TYPE_VECTOR; // color
  499. }
  500. break; // alpha (scalar)
  501. case 4:
  502. if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
  503. break; // alpha
  504. }
  505. if (shader_type == VisualShader::TYPE_PROCESS) {
  506. break; // scale
  507. }
  508. if (shader_type == VisualShader::TYPE_COLLIDE) {
  509. return PORT_TYPE_TRANSFORM; // transform
  510. }
  511. return PORT_TYPE_VECTOR; // position
  512. case 5:
  513. if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
  514. return PORT_TYPE_TRANSFORM; // transform
  515. }
  516. if (shader_type == VisualShader::TYPE_PROCESS) {
  517. return PORT_TYPE_VECTOR; // rotation_axis
  518. }
  519. break; // scale (scalar)
  520. case 6:
  521. if (shader_type == VisualShader::TYPE_START) {
  522. return PORT_TYPE_VECTOR; // rotation_axis
  523. }
  524. break;
  525. case 7:
  526. break; // angle (scalar)
  527. }
  528. return PORT_TYPE_SCALAR;
  529. }
  530. String VisualShaderNodeParticleOutput::get_input_port_name(int p_port) const {
  531. String port_name;
  532. switch (p_port) {
  533. case 0:
  534. if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
  535. port_name = "custom";
  536. break;
  537. }
  538. port_name = "active";
  539. break;
  540. case 1:
  541. if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
  542. port_name = "custom_alpha";
  543. break;
  544. }
  545. port_name = "velocity";
  546. break;
  547. case 2:
  548. if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
  549. port_name = "velocity";
  550. break;
  551. }
  552. port_name = "color";
  553. break;
  554. case 3:
  555. if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
  556. port_name = "color";
  557. break;
  558. }
  559. port_name = "alpha";
  560. break;
  561. case 4:
  562. if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
  563. port_name = "alpha";
  564. break;
  565. }
  566. if (shader_type == VisualShader::TYPE_PROCESS) {
  567. port_name = "scale";
  568. break;
  569. }
  570. if (shader_type == VisualShader::TYPE_COLLIDE) {
  571. port_name = "transform";
  572. break;
  573. }
  574. port_name = "position";
  575. break;
  576. case 5:
  577. if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
  578. port_name = "transform";
  579. break;
  580. }
  581. if (shader_type == VisualShader::TYPE_PROCESS) {
  582. port_name = "rotation_axis";
  583. break;
  584. }
  585. port_name = "scale";
  586. break;
  587. case 6:
  588. if (shader_type == VisualShader::TYPE_PROCESS) {
  589. port_name = "angle_in_radians";
  590. break;
  591. }
  592. port_name = "rotation_axis";
  593. break;
  594. case 7:
  595. port_name = "angle_in_radians";
  596. break;
  597. default:
  598. break;
  599. }
  600. if (!port_name.is_empty()) {
  601. return port_name.capitalize();
  602. }
  603. return String();
  604. }
  605. bool VisualShaderNodeParticleOutput::is_port_separator(int p_index) const {
  606. if (shader_type == VisualShader::TYPE_START || shader_type == VisualShader::TYPE_PROCESS) {
  607. String name = get_input_port_name(p_index);
  608. return bool(name == "Scale");
  609. }
  610. if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
  611. String name = get_input_port_name(p_index);
  612. return bool(name == "Velocity");
  613. }
  614. return false;
  615. }
  616. String VisualShaderNodeParticleOutput::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
  617. String code;
  618. String tab = " ";
  619. if (shader_type == VisualShader::TYPE_START_CUSTOM || shader_type == VisualShader::TYPE_PROCESS_CUSTOM) {
  620. if (!p_input_vars[0].is_empty()) { // custom.rgb
  621. code += tab + "CUSTOM.rgb = " + p_input_vars[0] + ";\n";
  622. }
  623. if (!p_input_vars[1].is_empty()) { // custom.a
  624. code += tab + "CUSTOM.a = " + p_input_vars[1] + ";\n";
  625. }
  626. if (!p_input_vars[2].is_empty()) { // velocity
  627. code += tab + "VELOCITY = " + p_input_vars[2] + ";\n";
  628. }
  629. if (!p_input_vars[3].is_empty()) { // color.rgb
  630. code += tab + "COLOR.rgb = " + p_input_vars[3] + ";\n";
  631. }
  632. if (!p_input_vars[4].is_empty()) { // color.a
  633. code += tab + "COLOR.a = " + p_input_vars[4] + ";\n";
  634. }
  635. if (!p_input_vars[5].is_empty()) { // transform
  636. code += tab + "TRANSFORM = " + p_input_vars[5] + ";\n";
  637. }
  638. } else {
  639. if (!p_input_vars[0].is_empty()) { // active (begin)
  640. code += tab + "ACTIVE = " + p_input_vars[0] + ";\n";
  641. code += tab + "if(ACTIVE) {\n";
  642. tab += " ";
  643. }
  644. if (!p_input_vars[1].is_empty()) { // velocity
  645. code += tab + "VELOCITY = " + p_input_vars[1] + ";\n";
  646. }
  647. if (!p_input_vars[2].is_empty()) { // color
  648. code += tab + "COLOR.rgb = " + p_input_vars[2] + ";\n";
  649. }
  650. if (!p_input_vars[3].is_empty()) { // alpha
  651. code += tab + "COLOR.a = " + p_input_vars[3] + ";\n";
  652. }
  653. // position
  654. if (shader_type == VisualShader::TYPE_START) {
  655. code += tab + "if (RESTART_POSITION) {\n";
  656. if (!p_input_vars[4].is_empty()) {
  657. code += tab + " TRANSFORM = mat4(vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(" + p_input_vars[4] + ", 1.0));\n";
  658. } else {
  659. code += tab + " TRANSFORM = mat4(vec4(1.0, 0.0, 0.0, 0.0), vec4(0.0, 1.0, 0.0, 0.0), vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0));\n";
  660. }
  661. code += tab + " if (RESTART_VELOCITY) {\n";
  662. code += tab + " VELOCITY = (EMISSION_TRANSFORM * vec4(VELOCITY, 0.0)).xyz;\n";
  663. code += tab + " }\n";
  664. code += tab + " TRANSFORM = EMISSION_TRANSFORM * TRANSFORM;\n";
  665. code += tab + "}\n";
  666. } else if (shader_type == VisualShader::TYPE_COLLIDE) { // position
  667. if (!p_input_vars[4].is_empty()) {
  668. code += tab + "TRANSFORM = " + p_input_vars[4] + ";\n";
  669. }
  670. }
  671. if (shader_type == VisualShader::TYPE_START || shader_type == VisualShader::TYPE_PROCESS) {
  672. int scale = 5;
  673. int rotation_axis = 6;
  674. int rotation = 7;
  675. if (shader_type == VisualShader::TYPE_PROCESS) {
  676. scale = 4;
  677. rotation_axis = 5;
  678. rotation = 6;
  679. }
  680. String op;
  681. if (shader_type == VisualShader::TYPE_START) {
  682. op = "*=";
  683. } else {
  684. op = "=";
  685. }
  686. if (!p_input_vars[rotation].is_empty()) { // rotation_axis & angle_in_radians
  687. String axis;
  688. if (p_input_vars[rotation_axis].is_empty()) {
  689. axis = "vec3(0, 1, 0)";
  690. } else {
  691. axis = p_input_vars[rotation_axis];
  692. }
  693. code += tab + "TRANSFORM " + op + " __build_rotation_mat4(" + axis + ", " + p_input_vars[rotation] + ");\n";
  694. }
  695. if (!p_input_vars[scale].is_empty()) { // scale
  696. code += tab + "TRANSFORM " + op + " mat4(vec4(" + p_input_vars[scale] + ", 0, 0, 0), vec4(0, " + p_input_vars[scale] + ", 0, 0), vec4(0, 0, " + p_input_vars[scale] + ", 0), vec4(0, 0, 0, 1));\n";
  697. }
  698. }
  699. if (!p_input_vars[0].is_empty()) { // active (end)
  700. code += " }\n";
  701. }
  702. }
  703. return code;
  704. }
  705. VisualShaderNodeParticleOutput::VisualShaderNodeParticleOutput() {
  706. }
  707. // EmitParticle
  708. Vector<StringName> VisualShaderNodeParticleEmit::get_editable_properties() const {
  709. Vector<StringName> props;
  710. props.push_back("flags");
  711. return props;
  712. }
  713. void VisualShaderNodeParticleEmit::_bind_methods() {
  714. ClassDB::bind_method(D_METHOD("set_flags", "flags"), &VisualShaderNodeParticleEmit::set_flags);
  715. ClassDB::bind_method(D_METHOD("get_flags"), &VisualShaderNodeParticleEmit::get_flags);
  716. ADD_PROPERTY(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Position,RotScale,Velocity,Color,Custom"), "set_flags", "get_flags");
  717. BIND_ENUM_CONSTANT(EMIT_FLAG_POSITION);
  718. BIND_ENUM_CONSTANT(EMIT_FLAG_ROT_SCALE);
  719. BIND_ENUM_CONSTANT(EMIT_FLAG_VELOCITY);
  720. BIND_ENUM_CONSTANT(EMIT_FLAG_COLOR);
  721. BIND_ENUM_CONSTANT(EMIT_FLAG_CUSTOM);
  722. }
  723. String VisualShaderNodeParticleEmit::get_caption() const {
  724. return "EmitParticle";
  725. }
  726. int VisualShaderNodeParticleEmit::get_input_port_count() const {
  727. return 7;
  728. }
  729. VisualShaderNodeParticleEmit::PortType VisualShaderNodeParticleEmit::get_input_port_type(int p_port) const {
  730. switch (p_port) {
  731. case 0:
  732. return PORT_TYPE_BOOLEAN;
  733. case 1:
  734. return PORT_TYPE_TRANSFORM;
  735. case 2:
  736. return PORT_TYPE_VECTOR;
  737. case 3:
  738. return PORT_TYPE_VECTOR;
  739. case 4:
  740. return PORT_TYPE_SCALAR;
  741. case 5:
  742. return PORT_TYPE_VECTOR;
  743. case 6:
  744. return PORT_TYPE_SCALAR;
  745. }
  746. return PORT_TYPE_SCALAR;
  747. }
  748. String VisualShaderNodeParticleEmit::get_input_port_name(int p_port) const {
  749. switch (p_port) {
  750. case 0:
  751. return "condition";
  752. case 1:
  753. return "transform";
  754. case 2:
  755. return "velocity";
  756. case 3:
  757. return "color";
  758. case 4:
  759. return "alpha";
  760. case 5:
  761. return "custom";
  762. case 6:
  763. return "custom_alpha";
  764. }
  765. return String();
  766. }
  767. int VisualShaderNodeParticleEmit::get_output_port_count() const {
  768. return 0;
  769. }
  770. VisualShaderNodeParticleEmit::PortType VisualShaderNodeParticleEmit::get_output_port_type(int p_port) const {
  771. return PORT_TYPE_SCALAR;
  772. }
  773. String VisualShaderNodeParticleEmit::get_output_port_name(int p_port) const {
  774. return String();
  775. }
  776. void VisualShaderNodeParticleEmit::add_flag(EmitFlags p_flag) {
  777. flags |= p_flag;
  778. emit_changed();
  779. }
  780. bool VisualShaderNodeParticleEmit::has_flag(EmitFlags p_flag) const {
  781. return flags & p_flag;
  782. }
  783. void VisualShaderNodeParticleEmit::set_flags(EmitFlags p_flags) {
  784. flags = (int)p_flags;
  785. emit_changed();
  786. }
  787. VisualShaderNodeParticleEmit::EmitFlags VisualShaderNodeParticleEmit::get_flags() const {
  788. return EmitFlags(flags);
  789. }
  790. bool VisualShaderNodeParticleEmit::is_show_prop_names() const {
  791. return true;
  792. }
  793. bool VisualShaderNodeParticleEmit::is_generate_input_var(int p_port) const {
  794. if (p_port == 0) {
  795. if (!is_input_port_connected(0)) {
  796. return false;
  797. }
  798. }
  799. return true;
  800. }
  801. String VisualShaderNodeParticleEmit::get_input_port_default_hint(int p_port) const {
  802. switch (p_port) {
  803. case 1:
  804. return "default";
  805. case 2:
  806. return "default";
  807. case 3:
  808. return "default";
  809. case 4:
  810. return "default";
  811. case 5:
  812. return "default";
  813. case 6:
  814. return "default";
  815. }
  816. return String();
  817. }
  818. String VisualShaderNodeParticleEmit::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
  819. String code;
  820. String tab;
  821. bool default_condition = false;
  822. if (!is_input_port_connected(0)) {
  823. default_condition = true;
  824. if (get_input_port_default_value(0)) {
  825. tab = " ";
  826. } else {
  827. return code;
  828. }
  829. } else {
  830. tab = " ";
  831. }
  832. String transform;
  833. if (p_input_vars[1].is_empty()) {
  834. transform = "TRANSFORM";
  835. } else {
  836. transform = p_input_vars[1];
  837. }
  838. String velocity;
  839. if (p_input_vars[2].is_empty()) {
  840. velocity = "VELOCITY";
  841. } else {
  842. velocity = p_input_vars[2];
  843. }
  844. String color;
  845. if (p_input_vars[3].is_empty()) {
  846. color = "COLOR.rgb";
  847. } else {
  848. color = p_input_vars[3];
  849. }
  850. String alpha;
  851. if (p_input_vars[4].is_empty()) {
  852. alpha = "COLOR.a";
  853. } else {
  854. alpha = p_input_vars[4];
  855. }
  856. String custom;
  857. if (p_input_vars[5].is_empty()) {
  858. custom = "CUSTOM.rgb";
  859. } else {
  860. custom = p_input_vars[5];
  861. }
  862. String custom_alpha;
  863. if (p_input_vars[6].is_empty()) {
  864. custom_alpha = "CUSTOM.a";
  865. } else {
  866. custom_alpha = p_input_vars[6];
  867. }
  868. List<String> flags_arr;
  869. if (has_flag(EmitFlags::EMIT_FLAG_POSITION)) {
  870. flags_arr.push_back("FLAG_EMIT_POSITION");
  871. }
  872. if (has_flag(EmitFlags::EMIT_FLAG_ROT_SCALE)) {
  873. flags_arr.push_back("FLAG_EMIT_ROT_SCALE");
  874. }
  875. if (has_flag(EmitFlags::EMIT_FLAG_VELOCITY)) {
  876. flags_arr.push_back("FLAG_EMIT_VELOCITY");
  877. }
  878. if (has_flag(EmitFlags::EMIT_FLAG_COLOR)) {
  879. flags_arr.push_back("FLAG_EMIT_COLOR");
  880. }
  881. if (has_flag(EmitFlags::EMIT_FLAG_CUSTOM)) {
  882. flags_arr.push_back("FLAG_EMIT_CUSTOM");
  883. }
  884. String flags;
  885. for (int i = 0; i < flags_arr.size(); i++) {
  886. if (i > 0) {
  887. flags += "|";
  888. }
  889. flags += flags_arr[i];
  890. }
  891. if (flags.is_empty()) {
  892. flags = "uint(0)";
  893. }
  894. if (!default_condition) {
  895. code += " if (" + p_input_vars[0] + ") {\n";
  896. }
  897. code += tab + "emit_subparticle(" + transform + ", " + velocity + ", vec4(" + color + ", " + alpha + "), vec4(" + custom + ", " + custom_alpha + "), " + flags + ");\n";
  898. if (!default_condition) {
  899. code += " }\n";
  900. }
  901. return code;
  902. }
  903. VisualShaderNodeParticleEmit::VisualShaderNodeParticleEmit() {
  904. set_input_port_default_value(0, true);
  905. }