From 363a1dec53f6785ee58a7b3f3b8407a48dcdd2c2 Mon Sep 17 00:00:00 2001 From: Tanasart Date: Wed, 31 Jul 2024 17:24:42 +0700 Subject: [PATCH] - New RM Cloud node. --- PixelComposer.resource_order | 3 + PixelComposer.yyp | 3 + scripts/node_mk_sparkle/node_mk_sparkle.gml | 149 ++++++++++- scripts/node_registry/node_registry.gml | 27 +- scripts/node_rm_cloud/node_outline.yy | 12 + scripts/node_rm_cloud/node_rm_cloud.gml | 87 +++++++ scripts/node_rm_cloud/node_rm_cloud.yy | 13 + shaders/sh_rm_cloud/sh_rm_cloud.fsh | 239 ++++++++++++++++++ shaders/sh_rm_cloud/sh_rm_cloud.vsh | 19 ++ shaders/sh_rm_cloud/sh_rm_cloud.yy | 12 + shaders/sh_simplex/sh_simplex.fsh | 43 ++-- .../bd43f5eb-ebb4-45a4-8041-a14c04348e64.png | Bin 0 -> 4016 bytes .../240a46bf-aeba-48c1-b99a-946637b25608.png | Bin 0 -> 4016 bytes sprites/s_node_RM_Cloud/s_node_RM_Cloud.yy | 90 +++++++ 14 files changed, 659 insertions(+), 38 deletions(-) create mode 100644 scripts/node_rm_cloud/node_outline.yy create mode 100644 scripts/node_rm_cloud/node_rm_cloud.gml create mode 100644 scripts/node_rm_cloud/node_rm_cloud.yy create mode 100644 shaders/sh_rm_cloud/sh_rm_cloud.fsh create mode 100644 shaders/sh_rm_cloud/sh_rm_cloud.vsh create mode 100644 shaders/sh_rm_cloud/sh_rm_cloud.yy create mode 100644 sprites/s_node_RM_Cloud/bd43f5eb-ebb4-45a4-8041-a14c04348e64.png create mode 100644 sprites/s_node_RM_Cloud/layers/bd43f5eb-ebb4-45a4-8041-a14c04348e64/240a46bf-aeba-48c1-b99a-946637b25608.png create mode 100644 sprites/s_node_RM_Cloud/s_node_RM_Cloud.yy diff --git a/PixelComposer.resource_order b/PixelComposer.resource_order index e7db69350..fd2050606 100644 --- a/PixelComposer.resource_order +++ b/PixelComposer.resource_order @@ -1053,6 +1053,7 @@ {"name":"node_rigid_variable","order":11,"path":"scripts/node_rigid_variable/node_rigid_variable.yy",}, {"name":"node_rigid_wall","order":12,"path":"scripts/node_rigid_wall/node_rigid_wall.yy",}, {"name":"node_rim","order":22,"path":"scripts/node_rim/node_rim.yy",}, + {"name":"node_rm_cloud","order":7,"path":"scripts/node_rm_cloud/node_rm_cloud.yy",}, {"name":"node_rm_combine","order":3,"path":"scripts/node_rm_combine/node_rm_combine.yy",}, {"name":"node_rm_primitive","order":1,"path":"scripts/node_rm_primitive/node_rm_primitive.yy",}, {"name":"node_rm_render","order":6,"path":"scripts/node_rm_render/node_rm_render.yy",}, @@ -1597,6 +1598,7 @@ {"name":"sh_remove_black","order":17,"path":"shaders/sh_remove_black/sh_remove_black.yy",}, {"name":"sh_replace_color","order":4,"path":"shaders/sh_replace_color/sh_replace_color.yy",}, {"name":"sh_rim","order":39,"path":"shaders/sh_rim/sh_rim.yy",}, + {"name":"sh_rm_cloud","order":2,"path":"shaders/sh_rm_cloud/sh_rm_cloud.yy",}, {"name":"sh_rm_terrain","order":1,"path":"shaders/sh_rm_terrain/sh_rm_terrain.yy",}, {"name":"sh_rsh_erode","order":2,"path":"shaders/sh_rsh_erode/sh_rsh_erode.yy",}, {"name":"sh_rsh_rotate","order":1,"path":"shaders/sh_rsh_rotate/sh_rsh_rotate.yy",}, @@ -2329,6 +2331,7 @@ {"name":"s_node_rigidSim_render_output","order":10,"path":"sprites/s_node_rigidSim_render_output/s_node_rigidSim_render_output.yy",}, {"name":"s_node_rigidSim_renderer","order":1,"path":"sprites/s_node_rigidSim_renderer/s_node_rigidSim_renderer.yy",}, {"name":"s_node_rigidSim_wall","order":11,"path":"sprites/s_node_rigidSim_wall/s_node_rigidSim_wall.yy",}, + {"name":"s_node_RM_Cloud","order":33,"path":"sprites/s_node_RM_Cloud/s_node_RM_Cloud.yy",}, {"name":"s_node_rm_combine","order":26,"path":"sprites/s_node_rm_combine/s_node_rm_combine.yy",}, {"name":"s_node_rm_primitive","order":27,"path":"sprites/s_node_rm_primitive/s_node_rm_primitive.yy",}, {"name":"s_node_rm_render","order":29,"path":"sprites/s_node_rm_render/s_node_rm_render.yy",}, diff --git a/PixelComposer.yyp b/PixelComposer.yyp index 77cdcd062..304a36264 100644 --- a/PixelComposer.yyp +++ b/PixelComposer.yyp @@ -1631,6 +1631,7 @@ {"id":{"name":"node_rigid_variable","path":"scripts/node_rigid_variable/node_rigid_variable.yy",},}, {"id":{"name":"node_rigid_wall","path":"scripts/node_rigid_wall/node_rigid_wall.yy",},}, {"id":{"name":"node_rim","path":"scripts/node_rim/node_rim.yy",},}, + {"id":{"name":"node_rm_cloud","path":"scripts/node_rm_cloud/node_rm_cloud.yy",},}, {"id":{"name":"node_rm_combine","path":"scripts/node_rm_combine/node_rm_combine.yy",},}, {"id":{"name":"node_rm_primitive","path":"scripts/node_rm_primitive/node_rm_primitive.yy",},}, {"id":{"name":"node_rm_render","path":"scripts/node_rm_render/node_rm_render.yy",},}, @@ -2266,6 +2267,7 @@ {"id":{"name":"sh_remove_black","path":"shaders/sh_remove_black/sh_remove_black.yy",},}, {"id":{"name":"sh_replace_color","path":"shaders/sh_replace_color/sh_replace_color.yy",},}, {"id":{"name":"sh_rim","path":"shaders/sh_rim/sh_rim.yy",},}, + {"id":{"name":"sh_rm_cloud","path":"shaders/sh_rm_cloud/sh_rm_cloud.yy",},}, {"id":{"name":"sh_rm_primitive","path":"shaders/sh_rm_primitive/sh_rm_primitive.yy",},}, {"id":{"name":"sh_rm_terrain","path":"shaders/sh_rm_terrain/sh_rm_terrain.yy",},}, {"id":{"name":"sh_rsh_corner","path":"shaders/sh_rsh_corner/sh_rsh_corner.yy",},}, @@ -3051,6 +3053,7 @@ {"id":{"name":"s_node_rigidSim_renderer","path":"sprites/s_node_rigidSim_renderer/s_node_rigidSim_renderer.yy",},}, {"id":{"name":"s_node_rigidSim_wall","path":"sprites/s_node_rigidSim_wall/s_node_rigidSim_wall.yy",},}, {"id":{"name":"s_node_rigidSim","path":"sprites/s_node_rigidSim/s_node_rigidSim.yy",},}, + {"id":{"name":"s_node_RM_Cloud","path":"sprites/s_node_RM_Cloud/s_node_RM_Cloud.yy",},}, {"id":{"name":"s_node_rm_combine","path":"sprites/s_node_rm_combine/s_node_rm_combine.yy",},}, {"id":{"name":"s_node_rm_primitive","path":"sprites/s_node_rm_primitive/s_node_rm_primitive.yy",},}, {"id":{"name":"s_node_rm_render","path":"sprites/s_node_rm_render/s_node_rm_render.yy",},}, diff --git a/scripts/node_mk_sparkle/node_mk_sparkle.gml b/scripts/node_mk_sparkle/node_mk_sparkle.gml index 1d98d6474..883a1684a 100644 --- a/scripts/node_mk_sparkle/node_mk_sparkle.gml +++ b/scripts/node_mk_sparkle/node_mk_sparkle.gml @@ -8,6 +8,150 @@ function Node_MK_Sparkle(_x, _y, _group = noone) : Node_Processor(_x, _y, _group inputs[| 0] = nodeValue("Size", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 5); + inputs[| 1] = nodeValueSeed(self, VALUE_TYPE.float); + + inputs[| 2] = nodeValue("Speed", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 1) + .setDisplay(VALUE_DISPLAY.slider) + + inputs[| 3] = nodeValue("Shade", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false); + + inputs[| 4] = nodeValue("Amount", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0.5) + .setDisplay(VALUE_DISPLAY.slider) + + inputs[| 5] = nodeValue("Scatter", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0.5) + .setDisplay(VALUE_DISPLAY.slider) + + inputs[| 6] = nodeValue("Colors", self, JUNCTION_CONNECT.input, VALUE_TYPE.color, [ cola(c_black), cola(c_white) ]) + .setDisplay(VALUE_DISPLAY.palette) + + inputs[| 7] = nodeValue("Additive", self, JUNCTION_CONNECT.input, VALUE_TYPE.boolean, false) + + inputs[| 8] = nodeValue("Diagonal", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0.2) + .setDisplay(VALUE_DISPLAY.slider) + + outputs[| 0] = nodeValue("Surface out", self, JUNCTION_CONNECT.output, VALUE_TYPE.surface, noone); + + input_display_list = [ new Inspector_Sprite(s_MKFX), 1, + ["Surfaces", false], 0, + ["Sparkle", false], 2, 4, 5, 8, + ["Render", false, 3], 6, 7, + ] + + temp_surface = array_create(3); + + static processData = function(_outSurf, _data, _output_index, _array_index) { + var _seed = _data[1]; + + var _size = _data[0]; + + var _sped = _data[2]; + var _amou = _data[4]; + var _scat = _data[5]; + var _diag = _data[8]; + + var _shad = _data[3]; + var _palt = _data[6]; + var _badd = _data[7]; + + _outSurf = surface_verify(_outSurf, _size, _size); + random_set_seed(_seed); + + var st_sz = ceil( _size / 2); + var st_ps = floor(_size / 2); + temp_surface[0] = surface_verify(temp_surface[0], st_sz, st_sz); + temp_surface[1] = surface_verify(temp_surface[1], _size, _size); + temp_surface[2] = surface_verify(temp_surface[2], _size, _size); + + var f = CURRENT_FRAME * _sped; + + surface_set_target(temp_surface[0]); + DRAW_CLEAR + + var _amo = 3 + irandom(st_ps * _amou); + var _ind = 0; + var _sct = lerp(25, 1, power(_scat, 0.1)); + var _pal_sz = array_length(_palt); + + draw_set_color(c_white); + if(_badd) BLEND_ADD + + repeat(_amo) { + if(_shad) { + var _in = _ind / (_amo - 1); + draw_set_color(_palt[(_pal_sz - 1) * _in]); + } + _ind++; + + var dy = power(random(1), _sct) * (st_ps / 2); + var dx = power(random(1), _sct) * (st_ps / 2); + + var sx = irandom_range(1, st_ps / 4); + var sl = irandom_range(1, st_ps / 4) * -1; + var ll = irandom_range(1, st_ps / 2); + + var len = max(0, ll + f * sl); + var diam = random(1) < _diag * 0.2; + var diag = random(1) < _diag; + + if(len <= 0) continue; + + if(diam) { + var lx = -1 + dx - f * sx; + var ly = st_sz - 1 - dy - f * sx; + + draw_line(lx, ly, lx - len, ly - len); + + } else if(diag) { + var lx = -1 + dx + f * sx; + var ly = st_sz - 1 - dy - f * sx; + + draw_line(lx, ly, lx + len, ly - len); + + } else { + var ly = st_sz - 1 - dy; + var lx0 = -1 + f * sx + dx; + var lx1 = lx0 + len; + + draw_line(lx0, ly, lx1, ly); + } + } + surface_reset_target(); + BLEND_NORMAL + + surface_set_target(temp_surface[1]); + DRAW_CLEAR + + draw_surface_ext(temp_surface[0], st_ps, 0, 1, 1, 0, c_white, 1); + draw_surface_ext(temp_surface[0], st_sz, 0, -1, 1, 0, c_white, 1); + surface_reset_target(); + + surface_set_target(temp_surface[2]); + DRAW_CLEAR + + draw_surface_ext(temp_surface[1], 0, 0, 1, 1, 0, c_white, 1); + draw_surface_ext(temp_surface[1], 0, _size, 1, -1, 0, c_white, 1); + surface_reset_target(); + + surface_set_target(_outSurf); + DRAW_CLEAR + + draw_surface_ext(temp_surface[2], 0, 0, 1, 1, 0, c_white, 1); + draw_surface_ext(temp_surface[2], 0, _size, 1, 1, 90, c_white, 1); + surface_reset_target(); + + return _outSurf; + } +} + +/* Old sparkle, dunno why but I don't want to remove it yet + +function __Node_MK_Sparkle(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) constructor { + name = "MK Sparkle"; + dimension_index = -1; + update_on_frame = true; + + inputs[| 0] = nodeValue("Size", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 5); + inputs[| 1] = nodeValue("Sparkle", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ [ MKSPARK_DIRR.main, 0, 0, 2, 1, 0, 0 ], [ MKSPARK_DIRR.main, 0, -1, 1, 1, 0, 0 ], @@ -32,7 +176,7 @@ function Node_MK_Sparkle(_x, _y, _group = noone) : Node_Processor(_x, _y, _group editor_timer_mx = 0; editor_timer_sx = 0; - sparkleEditor = new Inspector_Custom_Renderer(function(_x, _y, _w, _m, _hover, _focus) { #region + sparkleEditor = new Inspector_Custom_Renderer(function(_x, _y, _w, _m, _hover, _focus) { var _size = inputs[| 0].getValue(); var _sprk = inputs[| 1].getValue(); @@ -208,7 +352,7 @@ function Node_MK_Sparkle(_x, _y, _group = noone) : Node_Processor(_x, _y, _group } return _h; - }); #endregion + }); input_display_list = [ new Inspector_Sprite(s_MKFX), ["Sparkle", false], 0, 2, 3, @@ -265,6 +409,7 @@ function Node_MK_Sparkle(_x, _y, _group = noone) : Node_Processor(_x, _y, _group if(lng == 0) draw_point(_lx, _ly); else draw_line(_lx, _ly, _lx + lng, _ly); + } else if(dr == MKSPARK_DIRR.diag) { var _l0 = _c - 1 + sp * ff; var _l1 = _l0 + lng; diff --git a/scripts/node_registry/node_registry.gml b/scripts/node_registry/node_registry.gml index cd02b0678..60f27e4a9 100644 --- a/scripts/node_registry/node_registry.gml +++ b/scripts/node_registry/node_registry.gml @@ -700,6 +700,7 @@ function __initNodes() { addNodeObject(d3d, "RM Terrain", s_node_rm_terrain, "Node_RM_Terrain", [1, Node_RM_Terrain], ["ray marching"]).setVersion(11720); addNodeObject(d3d, "RM Combine", s_node_rm_combine, "Node_RM_Combine", [1, Node_RM_Combine], ["ray marching", "rm boolean"]).setVersion(11740); addNodeObject(d3d, "RM Render", s_node_rm_render, "Node_RM_Render", [1, Node_RM_Render], ["ray marching"]).setVersion(11740); + addNodeObject(d3d, "RM Cloud", s_node_RM_Cloud, "Node_RM_Cloud", [1, Node_RM_Cloud],, "Generate distance field cloud.").patreonExtra(); #endregion @@ -778,19 +779,19 @@ function __initNodes() { addNodeObject(generator, "Flood Fill", s_node_flood_fill, "Node_Flood_Fill", [1, Node_Flood_Fill],, "Filled connected pixel given position and color.").setVersion(1133); ds_list_add(generator, "MK Effects"); - addNodeObject(generator, "MK Rain", s_node_mk_rain, "Node_MK_Rain", [1, Node_MK_Rain],, "Generate deterministic rain.").setVersion(11600); - addNodeObject(generator, "MK GridBalls", s_node_mk_ball_grid, "Node_MK_GridBalls", [1, Node_MK_GridBalls],, "Generate controllable grid of spheres.").setVersion(11600); - addNodeObject(generator, "MK GridFlip", s_node_mk_flip_grid, "Node_MK_GridFlip", [1, Node_MK_GridFlip],, "Generate controllable grid of planes.").setVersion(11600); - addNodeObject(generator, "MK Saber", s_node_mk_saber, "Node_MK_Saber", [1, Node_MK_Saber],, "Generate glowing saber from 2 points.").setVersion(11600); - addNodeObject(generator, "MK Tile", s_node_mk_tile, "Node_MK_Tile", [1, Node_MK_Tile],, "Generate game engines-ready tileset.").setVersion(11600); - addNodeObject(generator, "MK Flag", s_node_mk_flag, "Node_MK_Flag", [1, Node_MK_Flag],, "Generate waving flag.").setVersion(11600); - addNodeObject(generator, "MK Brownian", s_node_mk_brownian, "Node_MK_Brownian", [1, Node_MK_Brownian],, "Generate random particle.").setVersion(11630); - addNodeObject(generator, "MK Fall", s_node_mk_fall, "Node_MK_Fall", [1, Node_MK_Fall], ["Leaf", "Leaves"], "Generate leaves falling effects.").setVersion(11630); - addNodeObject(generator, "MK Blinker", s_node_mk_blinker, "Node_MK_Blinker", [1, Node_MK_Blinker],, "Flicker regions of the selected colors randomly.").setVersion(11630); - addNodeObject(generator, "MK Lens Flare", s_node_mk_flare, "Node_MK_Flare", [1, Node_MK_Flare],, "Generate lens flare.").setVersion(11630); - addNodeObject(generator, "MK Delay Machine", s_node_mk_delay_machine, "Node_MK_Delay_Machine", [1, Node_MK_Delay_Machine],, "Combines multiple frames of animation into one.").setVersion(11680); - addNodeObject(generator, "MK Fracture", s_node_mk_fracture, "Node_MK_Fracture", [1, Node_MK_Fracture],, "Deterministically fracture and image and apply basic physics.").patreonExtra(); - //addNodeObject(generator, "MK Sparkle", s_node_mk_sparkle, "Node_MK_Sparkle", [1, Node_MK_Sparkle]).patreonExtra(); + addNodeObject(generator, "MK Rain", s_node_mk_rain, "Node_MK_Rain", [1, Node_MK_Rain],, "Generate deterministic rain.").setVersion(11600); + addNodeObject(generator, "MK GridBalls", s_node_mk_ball_grid, "Node_MK_GridBalls", [1, Node_MK_GridBalls],, "Generate controllable grid of spheres.").setVersion(11600); + addNodeObject(generator, "MK GridFlip", s_node_mk_flip_grid, "Node_MK_GridFlip", [1, Node_MK_GridFlip],, "Generate controllable grid of planes.").setVersion(11600); + addNodeObject(generator, "MK Saber", s_node_mk_saber, "Node_MK_Saber", [1, Node_MK_Saber],, "Generate glowing saber from 2 points.").setVersion(11600); + addNodeObject(generator, "MK Tile", s_node_mk_tile, "Node_MK_Tile", [1, Node_MK_Tile],, "Generate game engines-ready tileset.").setVersion(11600); + addNodeObject(generator, "MK Flag", s_node_mk_flag, "Node_MK_Flag", [1, Node_MK_Flag],, "Generate waving flag.").setVersion(11600); + addNodeObject(generator, "MK Brownian", s_node_mk_brownian, "Node_MK_Brownian", [1, Node_MK_Brownian],, "Generate random particle.").setVersion(11630); + addNodeObject(generator, "MK Fall", s_node_mk_fall, "Node_MK_Fall", [1, Node_MK_Fall], ["Leaf", "Leaves"], "Generate leaves falling effects.").setVersion(11630); + addNodeObject(generator, "MK Blinker", s_node_mk_blinker, "Node_MK_Blinker", [1, Node_MK_Blinker],, "Flicker regions of the selected colors randomly.").setVersion(11630); + addNodeObject(generator, "MK Lens Flare", s_node_mk_flare, "Node_MK_Flare", [1, Node_MK_Flare],, "Generate lens flare.").setVersion(11630); + addNodeObject(generator, "MK Delay Machine", s_node_mk_delay_machine, "Node_MK_Delay_Machine", [1, Node_MK_Delay_Machine],, "Combines multiple frames of animation into one.").setVersion(11680); + addNodeObject(generator, "MK Fracture", s_node_mk_fracture, "Node_MK_Fracture", [1, Node_MK_Fracture],, "Deterministically fracture and image and apply basic physics.").patreonExtra(); + addNodeObject(generator, "MK Sparkle", s_node_mk_sparkle, "Node_MK_Sparkle", [1, Node_MK_Sparkle],, "Generate random star animation.").patreonExtra(); #endregion var compose = ds_list_create(); #region //compose diff --git a/scripts/node_rm_cloud/node_outline.yy b/scripts/node_rm_cloud/node_outline.yy new file mode 100644 index 000000000..86468bc09 --- /dev/null +++ b/scripts/node_rm_cloud/node_outline.yy @@ -0,0 +1,12 @@ +{ + "isDnD": false, + "isCompatibility": false, + "parent": { + "name": "process", + "path": "folders/nodes/data/process.yy", + }, + "resourceVersion": "1.0", + "name": "node_outline", + "tags": [], + "resourceType": "GMScript", +} \ No newline at end of file diff --git a/scripts/node_rm_cloud/node_rm_cloud.gml b/scripts/node_rm_cloud/node_rm_cloud.gml new file mode 100644 index 000000000..1e4cc106f --- /dev/null +++ b/scripts/node_rm_cloud/node_rm_cloud.gml @@ -0,0 +1,87 @@ +function Node_RM_Cloud(_x, _y, _group = noone) : Node_Processor(_x, _y, _group) constructor { + name = "RM CLoud"; + + inputs[| 0] = nodeValue("Dimension", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, DEF_SURF) + .setDisplay(VALUE_DISPLAY.vector); + + inputs[| 1] = nodeValue("Position", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 0, 0 ]) + .setDisplay(VALUE_DISPLAY.vector); + + inputs[| 2] = nodeValue("Rotation", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 0, 0 ]) + .setDisplay(VALUE_DISPLAY.vector); + + inputs[| 3] = nodeValue("Scale", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 1) + .setDisplay(VALUE_DISPLAY.slider, { range: [ 0, 4, 0.01 ] }); + + inputs[| 4] = nodeValue("FOV", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 30) + .setDisplay(VALUE_DISPLAY.slider, { range: [ 0, 90, 1 ] }); + + inputs[| 5] = nodeValue("View Range", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, [ 0, 6 ]) + .setDisplay(VALUE_DISPLAY.vector); + + inputs[| 6] = nodeValue("Density", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0.5) + .setDisplay(VALUE_DISPLAY.slider); + + inputs[| 7] = nodeValue("Detail", self, JUNCTION_CONNECT.input, VALUE_TYPE.integer, 8); + + inputs[| 8] = nodeValue("Threshold", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0.5) + .setDisplay(VALUE_DISPLAY.slider); + + inputs[| 9] = nodeValue("Detail Scaling", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 2.); + + inputs[| 10] = nodeValue("Detail Attenuation", self, JUNCTION_CONNECT.input, VALUE_TYPE.float, 0.5) + .setDisplay(VALUE_DISPLAY.slider); + + outputs[| 0] = nodeValue("Surface Out", self, JUNCTION_CONNECT.output, VALUE_TYPE.surface, noone); + + input_display_list = [ 0, + ["Transform", false], 1, 2, 3, + ["Camera", false], 4, 5, + ["Cloud", false], 6, 8, 7, 9, 10, + ]; + + static drawOverlay = function(hover, active, _x, _y, _s, _mx, _my, _snx, _sny) {} + + static step = function() { + + } + + static processData = function(_outSurf, _data, _output_index, _array_index = 0) { + var _dim = _data[0]; + + var _pos = _data[1]; + var _rot = _data[2]; + var _sca = _data[3]; + + var _fov = _data[4]; + var _rng = _data[5]; + + var _dens = _data[6]; + var _itrr = _data[7]; + var _thrs = _data[8]; + var _dsca = _data[9]; + var _datt = _data[10]; + + _outSurf = surface_verify(_outSurf, _dim[0], _dim[1]); + + surface_set_shader(_outSurf, sh_rm_cloud); + + shader_set_3("position", _pos); + shader_set_3("rotation", _rot); + shader_set_f("objectScale", _sca * 4); + + shader_set_f("fov", _fov); + shader_set_2("viewRange", _rng); + + shader_set_i("iteration", _itrr); + shader_set_f("density", _dens); + shader_set_f("threshold", _thrs); + shader_set_f("detailScale", _dsca); + shader_set_f("detailAtten", _datt); + + draw_sprite_stretched(s_fx_pixel, 0, 0, 0, _dim[0], _dim[1]); + surface_reset_shader(); + + return _outSurf; + } +} diff --git a/scripts/node_rm_cloud/node_rm_cloud.yy b/scripts/node_rm_cloud/node_rm_cloud.yy new file mode 100644 index 000000000..970792377 --- /dev/null +++ b/scripts/node_rm_cloud/node_rm_cloud.yy @@ -0,0 +1,13 @@ +{ + "$GMScript":"", + "%Name":"node_rm_cloud", + "isCompatibility":false, + "isDnD":false, + "name":"node_rm_cloud", + "parent":{ + "name":"raymarching", + "path":"folders/nodes/data/3D/raymarching.yy", + }, + "resourceType":"GMScript", + "resourceVersion":"2.0", +} \ No newline at end of file diff --git a/shaders/sh_rm_cloud/sh_rm_cloud.fsh b/shaders/sh_rm_cloud/sh_rm_cloud.fsh new file mode 100644 index 000000000..bd89fe1a8 --- /dev/null +++ b/shaders/sh_rm_cloud/sh_rm_cloud.fsh @@ -0,0 +1,239 @@ +//Inigo Quilez +//Oh where would I be without you. + +varying vec2 v_vTexcoord; +varying vec4 v_vColour; + +const int MAX_MARCHING_STEPS = 512; +const float EPSILON = 1e-6; +const float PI = 3.14159265358979323846; + +uniform vec3 position; +uniform vec3 rotation; +uniform float objectScale; + +uniform float fov; +uniform vec2 viewRange; + +uniform float density; +uniform int iteration; +uniform float threshold; + +uniform int adaptiveIteration; +uniform float detailScale; +uniform float detailAtten; + +mat3 rotMatrix, irotMatrix; +vec3 eye, dir; + +#region ////========== Transform ============ + mat3 rotateX(float dg) { + float c = cos(radians(dg)); + float s = sin(radians(dg)); + return mat3( + vec3(1, 0, 0), + vec3(0, c, -s), + vec3(0, s, c) + ); + } + + mat3 rotateY(float dg) { + float c = cos(radians(dg)); + float s = sin(radians(dg)); + return mat3( + vec3( c, 0, s), + vec3( 0, 1, 0), + vec3(-s, 0, c) + ); + } + + mat3 rotateZ(float dg) { + float c = cos(radians(dg)); + float s = sin(radians(dg)); + return mat3( + vec3(c, -s, 0), + vec3(s, c, 0), + vec3(0, 0, 1) + ); + } + + mat3 inverse(mat3 m) { + float a00 = m[0][0], a01 = m[0][1], a02 = m[0][2]; + float a10 = m[1][0], a11 = m[1][1], a12 = m[1][2]; + float a20 = m[2][0], a21 = m[2][1], a22 = m[2][2]; + + float b01 = a22 * a11 - a12 * a21; + float b11 = -a22 * a10 + a12 * a20; + float b21 = a21 * a10 - a11 * a20; + + float det = a00 * b01 + a01 * b11 + a02 * b21; + + return mat3(b01, (-a22 * a01 + a02 * a21), (a12 * a01 - a02 * a11), + b11, (a22 * a00 - a02 * a20), (-a12 * a00 + a02 * a10), + b21, (-a21 * a00 + a01 * a20), (a11 * a00 - a01 * a10)) / det; + } +#endregion + +#region ////============= Noise ============== + + vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } + vec4 mod289(vec4 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; } + vec4 permute(vec4 x) { return mod289(((x * 34.0) + 10.0) * x); } + vec4 taylorInvSqrt(vec4 r) { return 1.79284291400159 - 0.85373472095314 * r; } + + float snoise(vec3 vec) { + vec3 v = vec * 4.; + + const vec2 C = vec2(1.0 / 6.0, 1.0 / 3.0); + const vec4 D = vec4(0.0, 0.5, 1.0, 2.0); + + // First corner + vec3 i = floor(v + dot(v, C.yyy)); + vec3 x0 = v - i + dot(i, C.xxx); + + // Other corners + vec3 g = step(x0.yzx, x0.xyz); + vec3 l = 1.0 - g; + vec3 i1 = min( g.xyz, l.zxy ); + vec3 i2 = max( g.xyz, l.zxy ); + + // x0 = x0 - 0.0 + 0.0 * C.xxx; + // x1 = x0 - i1 + 1.0 * C.xxx; + // x2 = x0 - i2 + 2.0 * C.xxx; + // x3 = x0 - 1.0 + 3.0 * C.xxx; + vec3 x1 = x0 - i1 + C.xxx; + vec3 x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y + vec3 x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y + + // Permutations + i = mod289(i); + vec4 p = permute( permute( permute( + i.z + vec4(0.0, i1.z, i2.z, 1.0 )) + + i.y + vec4(0.0, i1.y, i2.y, 1.0 )) + + i.x + vec4(0.0, i1.x, i2.x, 1.0 )); + + // Gradients: 7x7 points over a square, mapped onto an octahedron. + // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294) + float n_ = 0.142857142857; // 1.0/7.0 + vec3 ns = n_ * D.wyz - D.xzx; + + vec4 j = p - 49.0 * floor(p * ns.z * ns.z); // mod(p,7*7) + + vec4 x_ = floor(j * ns.z); + vec4 y_ = floor(j - 7.0 * x_ ); // mod(j,N) + + vec4 x = x_ * ns.x + ns.yyyy; + vec4 y = y_ * ns.x + ns.yyyy; + vec4 h = 1.0 - abs(x) - abs(y); + + vec4 b0 = vec4( x.xy, y.xy ); + vec4 b1 = vec4( x.zw, y.zw ); + + //vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0; + //vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0; + vec4 s0 = floor(b0) * 2.0 + 1.0; + vec4 s1 = floor(b1) * 2.0 + 1.0; + vec4 sh = -step(h, vec4(0.0)); + + vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy ; + vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww ; + + vec3 p0 = vec3(a0.xy, h.x); + vec3 p1 = vec3(a0.zw, h.y); + vec3 p2 = vec3(a1.xy, h.z); + vec3 p3 = vec3(a1.zw, h.w); + + //Normalise gradients + vec4 norm = taylorInvSqrt(vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3))); + p0 *= norm.x; + p1 *= norm.y; + p2 *= norm.z; + p3 *= norm.w; + + // Mix final noise value + vec4 m = max(0.5 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0); + m = m * m; + + float n = 105.0 * dot( m * m, vec4( dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3) ) ); + n = mix(0.0, 0.5 + 0.5 * n, smoothstep(0.0, 0.003, vec.z)); + return n; + } + + float simplex(in vec3 pos, in int itr) { + vec3 xyz = vec3(pos); + xyz.z = abs(xyz.z); + + float amp = 1.; + float n = 0.; + float acc = 0.; + + for(int i = 0; i < itr; i++) { + n += snoise(xyz) * amp; + acc += amp; + + amp *= detailAtten; + xyz *= detailScale; + } + + return n / acc; + } + +#endregion + +float volume(vec3 pos, float ratio) { + int it = adaptiveIteration == 1? int(max(1., ratio * float(iteration))) : iteration; + float ss = simplex(pos * 0.5, it / 2); + float sp = simplex(pos, it); + + float thr = threshold; + + float d1 = clamp(max(0., ss - thr) / (1. - thr), 0., 1.); + d1 = smoothstep(.2, .8, d1); + d1 *= clamp(1. - distance(pos, eye) / 16., 0., 1.); + + float ds = clamp(max(0., sp - thr) / (1. - thr), 0., 1.); + + ds *= d1; + + return ds; +} + +float marchDensity(vec3 camera, vec3 direction) { + float maxx = float(MAX_MARCHING_STEPS); + float st = 1. / maxx; + float _densi = 0.; + float dens = pow(2., 10. * density - 10.); + + for (float i = 0.; i <= maxx; i++) { + float depth = mix(viewRange.x, viewRange.y, i * st); + vec3 pos = camera + depth * direction; + float mden = volume(pos, 1. - i * st); + _densi += dens * mden; + } + + return _densi; +} + +void main() { + mat3 rx = rotateX(rotation.x); + mat3 ry = rotateY(rotation.y); + mat3 rz = rotateZ(rotation.z); + rotMatrix = rx * ry * rz; + irotMatrix = inverse(rotMatrix); + + float z = 1. / tan(radians(fov) / 2.); + dir = normalize(vec3((v_vTexcoord - .5) * 2., -z)); + eye = vec3(0., 0., 5.); + + // vec2 cps = (v_vTexcoord - .5) * 2.; + // dir = vec3(0., 0., -1.); + // eye = vec3(cps, 5.); + + dir = normalize(irotMatrix * dir) / objectScale; + eye = irotMatrix * eye; + eye /= objectScale; + eye -= position; + + float dens = marchDensity(eye, dir); + gl_FragColor = vec4(vec3(dens), 1.); +} \ No newline at end of file diff --git a/shaders/sh_rm_cloud/sh_rm_cloud.vsh b/shaders/sh_rm_cloud/sh_rm_cloud.vsh new file mode 100644 index 000000000..3900c20f4 --- /dev/null +++ b/shaders/sh_rm_cloud/sh_rm_cloud.vsh @@ -0,0 +1,19 @@ +// +// Simple passthrough vertex shader +// +attribute vec3 in_Position; // (x,y,z) +//attribute vec3 in_Normal; // (x,y,z) unused in this shader. +attribute vec4 in_Colour; // (r,g,b,a) +attribute vec2 in_TextureCoord; // (u,v) + +varying vec2 v_vTexcoord; +varying vec4 v_vColour; + +void main() +{ + vec4 object_space_pos = vec4( in_Position.x, in_Position.y, in_Position.z, 1.0); + gl_Position = gm_Matrices[MATRIX_WORLD_VIEW_PROJECTION] * object_space_pos; + + v_vColour = in_Colour; + v_vTexcoord = in_TextureCoord; +} diff --git a/shaders/sh_rm_cloud/sh_rm_cloud.yy b/shaders/sh_rm_cloud/sh_rm_cloud.yy new file mode 100644 index 000000000..a23ba5589 --- /dev/null +++ b/shaders/sh_rm_cloud/sh_rm_cloud.yy @@ -0,0 +1,12 @@ +{ + "$GMShader":"", + "%Name":"sh_rm_cloud", + "name":"sh_rm_cloud", + "parent":{ + "name":"ray march", + "path":"folders/shader/ray march.yy", + }, + "resourceType":"GMShader", + "resourceVersion":"2.0", + "type":1, +} \ No newline at end of file diff --git a/shaders/sh_simplex/sh_simplex.fsh b/shaders/sh_simplex/sh_simplex.fsh index 0ec5b9e7d..d7f57172e 100644 --- a/shaders/sh_simplex/sh_simplex.fsh +++ b/shaders/sh_simplex/sh_simplex.fsh @@ -39,13 +39,13 @@ uniform vec2 colorRanB; vec2 sca; float itrMax, itr; -vec3 hsv2rgb(vec3 c) { #region +vec3 hsv2rgb(vec3 c) { vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); -} #endregion +} -float snoise(vec3 vec) { #region +float snoise(vec3 vec) { vec3 v = vec * 4.; const vec2 C = vec2(1.0 / 6.0, 1.0 / 3.0); @@ -121,9 +121,9 @@ float snoise(vec3 vec) { #region float n = 105.0 * dot( m * m, vec4( dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3) ) ); n = mix(0.0, 0.5 + 0.5 * n, smoothstep(0.0, 0.003, vec.z)); return n; -} #endregion +} -float simplex(in vec2 st) { #region +float simplex(in vec2 st) { vec2 p = st; float _z = 1. + position.z; vec3 xyz = vec3(p, _z); @@ -144,24 +144,21 @@ float simplex(in vec2 st) { #region } return n; -} #endregion +} -void main() { #region - #region params - sca = scale; - if(scaleUseSurf == 1) { - vec4 _vMap = texture2D( scaleSurf, v_vTexcoord ); - sca = vec2(mix(scale.x, scale.y, (_vMap.r + _vMap.g + _vMap.b) / 3.)); - } - - itr = iteration.x; - itrMax = max(iteration.x, iteration.y); - if(iterationUseSurf == 1) { - vec4 _vMap = texture2D( iterationSurf, v_vTexcoord ); - itr = mix(iteration.x, iteration.y, (_vMap.r + _vMap.g + _vMap.b) / 3.); - } - - #endregion +void main() { + sca = scale; + if(scaleUseSurf == 1) { + vec4 _vMap = texture2D( scaleSurf, v_vTexcoord ); + sca = vec2(mix(scale.x, scale.y, (_vMap.r + _vMap.g + _vMap.b) / 3.)); + } + + itr = iteration.x; + itrMax = max(iteration.x, iteration.y); + if(iterationUseSurf == 1) { + vec4 _vMap = texture2D( iterationSurf, v_vTexcoord ); + itr = mix(iteration.x, iteration.y, (_vMap.r + _vMap.g + _vMap.b) / 3.); + } vec2 pos = position.xy / dimension; float ang = rotation; @@ -182,4 +179,4 @@ void main() { #region gl_FragColor = vec4(hsv2rgb(vec3(randH, randS, randV)), 1.0); } -} #endregion \ No newline at end of file +} \ No newline at end of file diff --git a/sprites/s_node_RM_Cloud/bd43f5eb-ebb4-45a4-8041-a14c04348e64.png b/sprites/s_node_RM_Cloud/bd43f5eb-ebb4-45a4-8041-a14c04348e64.png new file mode 100644 index 0000000000000000000000000000000000000000..eb7e42bbf4acf4da71e23c70c68c854d12737ece GIT binary patch literal 4016 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":"", + "Keyframes":[], + "resourceType":"KeyframeStore", + "resourceVersion":"2.0", + }, + "eventStubScript":null, + "eventToFunction":{}, + "length":1.0, + "lockOrigin":false, + "moments":{ + "$KeyframeStore":"", + "Keyframes":[], + "resourceType":"KeyframeStore", + "resourceVersion":"2.0", + }, + "name":"s_node_RM_Cloud", + "playback":1, + "playbackSpeed":30.0, + "playbackSpeedType":0, + "resourceType":"GMSequence", + "resourceVersion":"2.0", + "showBackdrop":true, + "showBackdropImage":false, + "timeUnits":1, + "tracks":[ + {"$GMSpriteFramesTrack":"","builtinName":0,"events":[],"inheritsTrackColour":true,"interpolation":1,"isCreationTrack":false,"keyframes":{"$KeyframeStore":"","Keyframes":[ + {"$Keyframe":"","Channels":{ + "0":{"$SpriteFrameKeyframe":"","Id":{"name":"bd43f5eb-ebb4-45a4-8041-a14c04348e64","path":"sprites/s_node_RM_Cloud/s_node_RM_Cloud.yy",},"resourceType":"SpriteFrameKeyframe","resourceVersion":"2.0",}, + },"Disabled":false,"id":"96cbfdeb-c359-48b2-ba78-897a8a58e2b8","IsCreationKey":false,"Key":0.0,"Length":1.0,"resourceType":"Keyframe","resourceVersion":"2.0","Stretch":false,}, + ],"resourceType":"KeyframeStore","resourceVersion":"2.0",},"modifiers":[],"name":"frames","resourceType":"GMSpriteFramesTrack","resourceVersion":"2.0","spriteId":null,"trackColour":0,"tracks":[],"traits":0,}, + ], + "visibleRange":null, + "volume":1.0, + "xorigin":32, + "yorigin":32, + }, + "swatchColours":null, + "swfPrecision":0.5, + "textureGroupId":{ + "name":"Default", + "path":"texturegroups/Default", + }, + "type":0, + "VTile":false, + "width":64, +} \ No newline at end of file