| … | … | @@ -0,0 +1,52 @@ |
| 1 | [gd_scene load_steps=10 format=2] | |
| 2 | ||
| 3 | [ext_resource path="res://assets/shaders/FireMask.png" type="Texture" id=1] | |
| 4 | [ext_resource path="res://assets/shaders/HoleNoise.png" type="Texture" id=2] | |
| 5 | [ext_resource path="res://assets/shaders/stylized_fire.shader" type="Shader" id=3] | |
| 6 | [ext_resource path="res://assets/shaders/BlueFireGradient.tres" type="Texture" id=4] | |
| 7 | ||
| 8 | [sub_resource type="ShaderMaterial" id=1] | |
| 9 | shader = ExtResource( 3 ) | |
| 10 | shader_param/emission_intensity = 2.0 | |
| 11 | shader_param/time_scale = 3.0 | |
| 12 | shader_param/texture_scale = Vector2( 1, 1 ) | |
| 13 | shader_param/edge_softness = 0.1 | |
| 14 | shader_param/noise_texture = ExtResource( 2 ) | |
| 15 | shader_param/texture_mask = ExtResource( 1 ) | |
| 16 | ||
| 17 | [sub_resource type="Curve" id=4] | |
| 18 | _data = [ Vector2( 0.0108696, 0.0090909 ), 0.0, -0.418182, 0, 0, Vector2( 1, 1 ), 1.27656, 0.0, 0, 0 ] | |
| 19 | ||
| 20 | [sub_resource type="CurveTexture" id=5] | |
| 21 | width = 128 | |
| 22 | curve = SubResource( 4 ) | |
| 23 | ||
| 24 | [sub_resource type="ParticlesMaterial" id=8] | |
| 25 | emission_shape = 1 | |
| 26 | emission_sphere_radius = 1.0 | |
| 27 | direction = Vector3( 0, 1, 0 ) | |
| 28 | spread = 0.0 | |
| 29 | gravity = Vector3( 0, 0, 0 ) | |
| 30 | initial_velocity = 0.5 | |
| 31 | linear_accel = 4.0 | |
| 32 | scale_random = 1.0 | |
| 33 | scale_curve = SubResource( 5 ) | |
| 34 | color_ramp = ExtResource( 4 ) | |
| 35 | ||
| 36 | [sub_resource type="QuadMesh" id=7] | |
| 37 | size = Vector2( 0.5, 0.5 ) | |
| 38 | ||
| 39 | [node name="BlueFire" type="Particles"] | |
| 40 | transform = Transform( 0.996392, 0, 0, 0, 0.996392, 0, 0, 0, 0.996392, -1.78327, 1.26708, 0 ) | |
| 41 | material_override = SubResource( 1 ) | |
| 42 | cast_shadow = 0 | |
| 43 | amount = 20 | |
| 44 | explosiveness = 0.45 | |
| 45 | randomness = 0.74 | |
| 46 | draw_order = 1 | |
| 47 | process_material = SubResource( 8 ) | |
| 48 | draw_pass_1 = SubResource( 7 ) | |
| 49 | ||
| 50 | [node name="OmniLight" type="OmniLight" parent="."] | |
| 51 | light_color = Color( 0.560784, 0.752941, 1, 1 ) | |
| 52 | light_energy = 2.0 |
| … | … | @@ -0,0 +1,8 @@ |
| 1 | [gd_resource type="GradientTexture" load_steps=2 format=2] | |
| 2 | ||
| 3 | [sub_resource type="Gradient" id=1] | |
| 4 | colors = PoolColorArray( 0, 0.941406, 1, 1, 0.335327, 0, 0.640625, 0 ) | |
| 5 | ||
| 6 | [resource] | |
| 7 | gradient = SubResource( 1 ) | |
| 8 | width = 128 |
| … | … | @@ -0,0 +1,9 @@ |
| 1 | [gd_resource type="NoiseTexture" load_steps=2 format=2] | |
| 2 | ||
| 3 | [sub_resource type="OpenSimplexNoise" id=1] | |
| 4 | period = 119.4 | |
| 5 | persistence = 0.449 | |
| 6 | ||
| 7 | [resource] | |
| 8 | seamless = true | |
| 9 | noise = SubResource( 1 ) |
| … | … | @@ -0,0 +1,8 @@ |
| 1 | [gd_resource type="GradientTexture" load_steps=2 format=2] | |
| 2 | ||
| 3 | [sub_resource type="Gradient" id=1] | |
| 4 | colors = PoolColorArray( 1, 0.890625, 0, 1, 1, 0, 0.447059, 0 ) | |
| 5 | ||
| 6 | [resource] | |
| 7 | gradient = SubResource( 1 ) | |
| 8 | width = 128 |
| … | … | @@ -0,0 +1,35 @@ |
| 1 | [remap] | |
| 2 | ||
| 3 | importer="texture" | |
| 4 | type="CompressedTexture2D" | |
| 5 | uid="uid://d4ejlwj2m2rct" | |
| 6 | path.s3tc="res://.godot/imported/FireMask.png-553f87899aee20cf715415b16d244fb2.s3tc.ctex" | |
| 7 | path.etc2="res://.godot/imported/FireMask.png-553f87899aee20cf715415b16d244fb2.etc2.ctex" | |
| 8 | metadata={ | |
| 9 | "imported_formats": ["s3tc", "etc2"], | |
| 10 | "vram_texture": true | |
| 11 | } | |
| 12 | ||
| 13 | [deps] | |
| 14 | ||
| 15 | source_file="res://assets/particles/FireMask.png" | |
| 16 | dest_files=["res://.godot/imported/FireMask.png-553f87899aee20cf715415b16d244fb2.s3tc.ctex", "res://.godot/imported/FireMask.png-553f87899aee20cf715415b16d244fb2.etc2.ctex"] | |
| 17 | ||
| 18 | [params] | |
| 19 | ||
| 20 | compress/mode=2 | |
| 21 | compress/lossy_quality=0.7 | |
| 22 | compress/hdr_compression=1 | |
| 23 | compress/bptc_ldr=0 | |
| 24 | compress/normal_map=0 | |
| 25 | compress/channel_pack=0 | |
| 26 | mipmaps/generate=true | |
| 27 | mipmaps/limit=-1 | |
| 28 | roughness/mode=0 | |
| 29 | roughness/src_normal="" | |
| 30 | process/fix_alpha_border=true | |
| 31 | process/premult_alpha=false | |
| 32 | process/normal_map_invert_y=false | |
| 33 | process/hdr_as_srgb=false | |
| 34 | process/size_limit=0 | |
| 35 | detect_3d/compress_to=0 |
| … | … | @@ -0,0 +1,8 @@ |
| 1 | [gd_resource type="GradientTexture" load_steps=2 format=2] | |
| 2 | ||
| 3 | [sub_resource type="Gradient" id=1] | |
| 4 | colors = PoolColorArray( 0.21875, 1, 0, 1, 0, 0.640625, 0.145142, 0 ) | |
| 5 | ||
| 6 | [resource] | |
| 7 | gradient = SubResource( 1 ) | |
| 8 | width = 128 |
| … | … | @@ -0,0 +1,33 @@ |
| 1 | [remap] | |
| 2 | ||
| 3 | importer="texture" | |
| 4 | type="CompressedTexture2D" | |
| 5 | uid="uid://cm3pm6yiceahb" | |
| 6 | path="res://.godot/imported/HoleNoise.png-9d1e8c57751bc4c582a578c9feb378c0.ctex" | |
| 7 | metadata={ | |
| 8 | "vram_texture": false | |
| 9 | } | |
| 10 | ||
| 11 | [deps] | |
| 12 | ||
| 13 | source_file="res://assets/particles/HoleNoise.png" | |
| 14 | dest_files=["res://.godot/imported/HoleNoise.png-9d1e8c57751bc4c582a578c9feb378c0.ctex"] | |
| 15 | ||
| 16 | [params] | |
| 17 | ||
| 18 | compress/mode=0 | |
| 19 | compress/lossy_quality=0.7 | |
| 20 | compress/hdr_compression=1 | |
| 21 | compress/bptc_ldr=0 | |
| 22 | compress/normal_map=0 | |
| 23 | compress/channel_pack=0 | |
| 24 | mipmaps/generate=false | |
| 25 | mipmaps/limit=-1 | |
| 26 | roughness/mode=0 | |
| 27 | roughness/src_normal="" | |
| 28 | process/fix_alpha_border=true | |
| 29 | process/premult_alpha=false | |
| 30 | process/normal_map_invert_y=false | |
| 31 | process/hdr_as_srgb=false | |
| 32 | process/size_limit=0 | |
| 33 | detect_3d/compress_to=1 |
| … | … | @@ -0,0 +1,68 @@ |
| 1 | [gd_scene load_steps=11 format=2] | |
| 2 | ||
| 3 | [ext_resource path="res://assets/shaders/HoleNoise.png" type="Texture" id=1] | |
| 4 | [ext_resource path="res://assets/shaders/FireMask.png" type="Texture" id=2] | |
| 5 | [ext_resource path="res://assets/shaders/stylized_fire.shader" type="Shader" id=4] | |
| 6 | ||
| 7 | [sub_resource type="ShaderMaterial" id=1] | |
| 8 | shader = ExtResource( 4 ) | |
| 9 | shader_param/emission_intensity = 10.0 | |
| 10 | shader_param/time_scale = 1.0 | |
| 11 | shader_param/texture_scale = Vector2( 1, 1 ) | |
| 12 | shader_param/edge_softness = 0.4 | |
| 13 | shader_param/noise_texture = ExtResource( 1 ) | |
| 14 | shader_param/texture_mask = ExtResource( 2 ) | |
| 15 | ||
| 16 | [sub_resource type="Gradient" id=9] | |
| 17 | colors = PoolColorArray( 0, 0.941406, 1, 1, 0.335327, 0, 0.640625, 0 ) | |
| 18 | ||
| 19 | [sub_resource type="GradientTexture" id=10] | |
| 20 | gradient = SubResource( 9 ) | |
| 21 | width = 128 | |
| 22 | ||
| 23 | [sub_resource type="Curve" id=4] | |
| 24 | _data = [ Vector2( 0.0108696, 0.0090909 ), 0.0, -0.418182, 0, 0, Vector2( 1, 1 ), 1.27656, 0.0, 0, 0 ] | |
| 25 | ||
| 26 | [sub_resource type="CurveTexture" id=5] | |
| 27 | width = 128 | |
| 28 | curve = SubResource( 4 ) | |
| 29 | ||
| 30 | [sub_resource type="ParticlesMaterial" id=8] | |
| 31 | render_priority = 1 | |
| 32 | emission_shape = 2 | |
| 33 | emission_box_extents = Vector3( 1, 1, 1 ) | |
| 34 | direction = Vector3( 0, 1, 0 ) | |
| 35 | spread = 0.0 | |
| 36 | gravity = Vector3( 0, 0, 0 ) | |
| 37 | initial_velocity = 0.5 | |
| 38 | angular_velocity_random = 1.0 | |
| 39 | linear_accel = 4.0 | |
| 40 | radial_accel = -68.63 | |
| 41 | tangential_accel = -7.77 | |
| 42 | tangential_accel_random = 0.83 | |
| 43 | damping = 58.82 | |
| 44 | damping_random = 0.85 | |
| 45 | angle = -564.7 | |
| 46 | scale = 15.0 | |
| 47 | scale_random = 1.0 | |
| 48 | scale_curve = SubResource( 5 ) | |
| 49 | color_ramp = SubResource( 10 ) | |
| 50 | ||
| 51 | [sub_resource type="QuadMesh" id=7] | |
| 52 | size = Vector2( 0.5, 0.5 ) | |
| 53 | ||
| 54 | [node name="RedFire" type="Particles"] | |
| 55 | transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -1.78327, 1.26708, 0 ) | |
| 56 | material_override = SubResource( 1 ) | |
| 57 | cast_shadow = 0 | |
| 58 | amount = 20 | |
| 59 | explosiveness = 0.45 | |
| 60 | randomness = 0.74 | |
| 61 | draw_order = 1 | |
| 62 | process_material = SubResource( 8 ) | |
| 63 | draw_pass_1 = SubResource( 7 ) | |
| 64 | ||
| 65 | [node name="OmniLight" type="OmniLight" parent="."] | |
| 66 | light_color = Color( 0.14902, 0.921569, 1, 1 ) | |
| 67 | light_energy = 2.0 | |
| 68 | omni_attenuation = 7.46425 |
| … | … | @@ -0,0 +1,33 @@ |
| 1 | [remap] | |
| 2 | ||
| 3 | importer="texture" | |
| 4 | type="CompressedTexture2D" | |
| 5 | uid="uid://bnuyfp5ju72wd" | |
| 6 | path="res://.godot/imported/WispyNoise.png-48a0fd4bd5fc8ff1f1b280d16213ca41.ctex" | |
| 7 | metadata={ | |
| 8 | "vram_texture": false | |
| 9 | } | |
| 10 | ||
| 11 | [deps] | |
| 12 | ||
| 13 | source_file="res://assets/particles/WispyNoise.png" | |
| 14 | dest_files=["res://.godot/imported/WispyNoise.png-48a0fd4bd5fc8ff1f1b280d16213ca41.ctex"] | |
| 15 | ||
| 16 | [params] | |
| 17 | ||
| 18 | compress/mode=0 | |
| 19 | compress/lossy_quality=0.7 | |
| 20 | compress/hdr_compression=1 | |
| 21 | compress/bptc_ldr=0 | |
| 22 | compress/normal_map=0 | |
| 23 | compress/channel_pack=0 | |
| 24 | mipmaps/generate=false | |
| 25 | mipmaps/limit=-1 | |
| 26 | roughness/mode=0 | |
| 27 | roughness/src_normal="" | |
| 28 | process/fix_alpha_border=true | |
| 29 | process/premult_alpha=false | |
| 30 | process/normal_map_invert_y=false | |
| 31 | process/hdr_as_srgb=false | |
| 32 | process/size_limit=0 | |
| 33 | detect_3d/compress_to=1 |
| … | … | @@ -0,0 +1,51 @@ |
| 1 | [gd_scene load_steps=9 format=3 uid="uid://cdhytj7hq0otb"] | |
| 2 | ||
| 3 | [ext_resource type="Texture2D" uid="uid://d4ejlwj2m2rct" path="res://assets/particles/FireMask.png" id="1_41t08"] | |
| 4 | ||
| 5 | [sub_resource type="Gradient" id="Gradient_uumr1"] | |
| 6 | colors = PackedColorArray(0, 0, 0, 1, 1, 1, 1, 0) | |
| 7 | ||
| 8 | [sub_resource type="GradientTexture1D" id="GradientTexture1D_duqqp"] | |
| 9 | gradient = SubResource( "Gradient_uumr1" ) | |
| 10 | ||
| 11 | [sub_resource type="Curve" id="Curve_jl5ig"] | |
| 12 | _data = [Vector2(0, 0), 0.0, 3.05455, 0, 0, Vector2(1, 1), 0.298004, 0.0, 0, 0] | |
| 13 | ||
| 14 | [sub_resource type="CurveTexture" id="CurveTexture_ejl88"] | |
| 15 | curve = SubResource( "Curve_jl5ig" ) | |
| 16 | ||
| 17 | [sub_resource type="ParticlesMaterial" id="ParticlesMaterial_288xr"] | |
| 18 | emission_shape = 6 | |
| 19 | emission_ring_axis = Vector3(0, 90, 1) | |
| 20 | emission_ring_height = 0.1 | |
| 21 | emission_ring_radius = 1.0 | |
| 22 | emission_ring_inner_radius = 0.5 | |
| 23 | direction = Vector3(0, 0, 0) | |
| 24 | gravity = Vector3(0, 0, 0) | |
| 25 | tangential_accel_max = 1.23 | |
| 26 | scale_min = 0.1 | |
| 27 | scale_max = 0.5 | |
| 28 | scale_curve = SubResource( "CurveTexture_ejl88" ) | |
| 29 | color = Color(0.501961, 0.501961, 0.501961, 1) | |
| 30 | color_ramp = SubResource( "GradientTexture1D_duqqp" ) | |
| 31 | ||
| 32 | [sub_resource type="ORMMaterial3D" id="ORMMaterial3D_yuhto"] | |
| 33 | transparency = 1 | |
| 34 | blend_mode = 1 | |
| 35 | no_depth_test = true | |
| 36 | albedo_texture = ExtResource( "1_41t08" ) | |
| 37 | billboard_mode = 3 | |
| 38 | particles_anim_h_frames = 1 | |
| 39 | particles_anim_v_frames = 1 | |
| 40 | particles_anim_loop = false | |
| 41 | ||
| 42 | [sub_resource type="QuadMesh" id="QuadMesh_i58mu"] | |
| 43 | material = SubResource( "ORMMaterial3D_yuhto" ) | |
| 44 | ||
| 45 | [node name="Node3D" type="Node3D"] | |
| 46 | ||
| 47 | [node name="GPUParticles3D" type="GPUParticles3D" parent="."] | |
| 48 | amount = 200 | |
| 49 | explosiveness = 1.0 | |
| 50 | process_material = SubResource( "ParticlesMaterial_288xr" ) | |
| 51 | draw_pass_1 = SubResource( "QuadMesh_i58mu" ) |
| … | … | @@ -0,0 +1,105 @@ |
| 1 | // ANCHOR: all | |
| 2 | // This shader is based on Minionsart's stylized fire | |
| 3 | // https://twitter.com/minionsart/status/1132593681452683264?s=20 | |
| 4 | shader_type spatial; | |
| 5 | render_mode blend_mix; | |
| 6 | ||
| 7 | // This texture must be seamless! | |
| 8 | // Experiment with the different noises provided in the res://Demos/StylizedFire/ folder | |
| 9 | uniform sampler2D noise_texture; | |
| 10 | ||
| 11 | uniform sampler2D texture_mask; | |
| 12 | uniform float emission_intensity = 2.0; | |
| 13 | uniform float time_scale = 3.0; | |
| 14 | uniform vec2 texture_scale = vec2(1.0); | |
| 15 | uniform float edge_softness = 0.1; | |
| 16 | ||
| 17 | // ANCHOR: varying | |
| 18 | varying vec3 world_coord; | |
| 19 | varying float world_x_dot; | |
| 20 | // END: varying | |
| 21 | ||
| 22 | void vertex() { | |
| 23 | // ANCHOR: matworld_1 | |
| 24 | // Billboard code, taken directly from a spatial material | |
| 25 | // create a spatial material, enable billboard with billboard keep scale, and then convert | |
| 26 | // to shader material, and it will create a shader with this code. | |
| 27 | mat4 mat_world = mat4( | |
| 28 | normalize(CAMERA_MATRIX[0]) * length(WORLD_MATRIX[0]), | |
| 29 | normalize(CAMERA_MATRIX[1]) * length(WORLD_MATRIX[0]), | |
| 30 | normalize(CAMERA_MATRIX[2]) * length(WORLD_MATRIX[2]), | |
| 31 | WORLD_MATRIX[3]); | |
| 32 | // END: matworld_1 | |
| 33 | // ANCHOR: matworld_2 | |
| 34 | mat_world *= mat4( | |
| 35 | vec4(cos(INSTANCE_CUSTOM.x), -sin(INSTANCE_CUSTOM.x), 0.0, 0.0), | |
| 36 | vec4(sin(INSTANCE_CUSTOM.x), cos(INSTANCE_CUSTOM.x), 0.0, 0.0), | |
| 37 | vec4(0.0, 0.0, 1.0, 0.0), | |
| 38 | vec4(0.0, 0.0, 0.0, 1.0)); | |
| 39 | // END: matworld_2 | |
| 40 | // ANCHOR: modelview | |
| 41 | MODELVIEW_MATRIX = INV_CAMERA_MATRIX * mat_world; | |
| 42 | // END: modelview | |
| 43 | // ANCHOR: varying_calculations | |
| 44 | // We map the coordinates on the vertical planes xy and zy | |
| 45 | // we also calculate how to blend between the two based on where the world space normal | |
| 46 | // is pointing. | |
| 47 | world_coord = (mat_world * vec4(VERTEX, 1.0)).xyz; | |
| 48 | vec4 world_normal = (mat_world * vec4(NORMAL, 0.0)); | |
| 49 | world_x_dot = abs(dot(normalize(world_normal.xyz), vec3(1.0, 0.0, 0.0))); | |
| 50 | // END: varying_calculations | |
| 51 | } | |
| 52 | ||
| 53 | void fragment() { | |
| 54 | // ANCHOR: mask | |
| 55 | // We sample the mask texture based on regular UV | |
| 56 | // We don't want the particles to show their square shape | |
| 57 | // so we use a round, black and white, mask texture | |
| 58 | float mask = texture(texture_mask, UV).r; | |
| 59 | // END: mask | |
| 60 | // ANCHOR: pan | |
| 61 | vec2 time_based_pan = vec2(0.2, 1.0) * (-TIME * time_scale); | |
| 62 | // END: pan | |
| 63 | // ANCHOR: noise_planes | |
| 64 | // We sample the noise both from the xy plane and from the zy plane, adding a time-based | |
| 65 | // panning. If we didn't do this, we would see the holes of the noise will always be in the | |
| 66 | // same space in global coordinates. Set the time_scale to zero to see how it would look like. | |
| 67 | // To add more variation, we could sample from another noise that has a different scale and panning speed. | |
| 68 | // The additional offset on the zy noise is to avoid mirroring effects when | |
| 69 | // the view vector is between same-sign x and z axes | |
| 70 | float noise_xy = texture(noise_texture, world_coord.xy * texture_scale + time_based_pan).r; | |
| 71 | float noise_zy = texture(noise_texture, | |
| 72 | world_coord.zy * texture_scale + time_based_pan + vec2(0.7, 0.3)).r; | |
| 73 | // END: noise_planes | |
| 74 | // ANCHOR: noise_mix | |
| 75 | // We blend the noise based on world_x_dot, which is the dot product between | |
| 76 | // the normal of the billboard plane, and the global x axis. If we face the global | |
| 77 | // x axis, then we sample from the xy plane, otherwise, we sample from the zy plane | |
| 78 | float noise = mix(noise_xy, noise_zy, clamp(world_x_dot, 0.0, 1.0)); | |
| 79 | // END: noise_mix | |
| 80 | // The particle color is assigned to the vertex color, which is called COLOR | |
| 81 | ALBEDO = COLOR.rgb; | |
| 82 | // ANCHOR: emission | |
| 83 | // Assign the same color for emission, multiplied by the emission intensity | |
| 84 | EMISSION = ALBEDO * emission_intensity; | |
| 85 | // END: emission | |
| 86 | // ANCHOR: alpha_erosion | |
| 87 | // Instead of blending out the particle, we apply a technique called alpha erosion, where we | |
| 88 | // subtract an erosion amount from the alpha. | |
| 89 | float alpha = noise * mask; | |
| 90 | alpha += COLOR.a - 1.0; | |
| 91 | // END: alpha_erosion | |
| 92 | // ANCHOR: alpha_clamp | |
| 93 | // Because we perform a subtraction, we ensure that the alpha is always between 0 and 1. | |
| 94 | // If the alpha goes negative or above 1, a number of visual artifacts appear. | |
| 95 | alpha = clamp(alpha, 0.0, 1.0); | |
| 96 | // END: alpha_clamp | |
| 97 | // ANCHOR: smoothstep | |
| 98 | // In order to give this fire a stylized vibe, we use smoothstep to remap the alpha value | |
| 99 | // We could use step(0.1, alpha), but then there would be an abrupt cut between transparent and | |
| 100 | // non transparent (exactly as if we discarded the fragment with discard) | |
| 101 | // smoothstep gives a nice blend on the edges instead | |
| 102 | ALPHA = smoothstep(0.0, edge_softness, alpha); | |
| 103 | // END: smoothstep | |
| 104 | } | |
| 105 | // END: all |