Skip to content

Commit

Permalink
Merge pull request gdquest-demos#23 from QbieShay/stylized-fire
Browse files Browse the repository at this point in the history
Add stylized fire shader
  • Loading branch information
NathanLovato authored Jan 21, 2021
2 parents dcf2b04 + b2bbcca commit 4370662
Show file tree
Hide file tree
Showing 15 changed files with 395 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Here's a list of available shaders:
- 2D x-ray (masking)
- Force field
- 2D palette swap
- 3D stylized fire

![2D water shader with light support](./img/water2d.png)

Expand Down
127 changes: 127 additions & 0 deletions godot/Demos/StylizedFire.tscn
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
[gd_scene load_steps=17 format=2]

[ext_resource path="res://Shared/DemoInterface.tscn" type="PackedScene" id=1]
[ext_resource path="res://Demos/StylizedFire/FireMask.png" type="Texture" id=2]
[ext_resource path="res://Demos/StylizedFire/HoleNoise.png" type="Texture" id=3]
[ext_resource path="res://Demos/StylizedFire/GreenFireGradient.tres" type="Texture" id=4]
[ext_resource path="res://Shaders/stylized_fire.shader" type="Shader" id=5]
[ext_resource path="res://Shared/Demo3DEnvironmentDark.tscn" type="PackedScene" id=6]
[ext_resource path="res://Demos/StylizedFire/BlueFireGradient.tres" type="Texture" id=7]

[sub_resource type="ShaderMaterial" id=1]
shader = ExtResource( 5 )
shader_param/emission_intensity = 2.0
shader_param/time_scale = 3.0
shader_param/texture_scale = Vector2( 1, 1 )
shader_param/edge_softness = 0.1
shader_param/noise_texture = ExtResource( 3 )
shader_param/texture_mask = ExtResource( 2 )

[sub_resource type="Gradient" id=2]
colors = PoolColorArray( 0.980957, 0.801817, 0, 1, 1, 0, 0.447059, 0 )

[sub_resource type="GradientTexture" id=3]
gradient = SubResource( 2 )
width = 128

[sub_resource type="Curve" id=4]
_data = [ Vector2( 0, 0 ), 0.0, 3.65289, 0, 0, Vector2( 0.556561, 1 ), 0.0, 0.0, 0, 0 ]

[sub_resource type="CurveTexture" id=5]
width = 128
curve = SubResource( 4 )

[sub_resource type="ParticlesMaterial" id=6]
lifetime_randomness = 0.81
direction = Vector3( 0, 1, 0 )
spread = 0.0
gravity = Vector3( 0, 0, 0 )
initial_velocity = 0.5
linear_accel = 4.0
scale = 2.0
scale_random = 1.0
scale_curve = SubResource( 5 )
color_ramp = SubResource( 3 )

[sub_resource type="QuadMesh" id=7]
size = Vector2( 0.5, 0.5 )

[sub_resource type="ParticlesMaterial" id=8]
lifetime_randomness = 0.81
direction = Vector3( 0, 1, 0 )
spread = 0.0
gravity = Vector3( 0, 0, 0 )
initial_velocity = 0.5
linear_accel = 4.0
scale = 2.0
scale_random = 1.0
scale_curve = SubResource( 5 )
color_ramp = ExtResource( 7 )

[sub_resource type="ParticlesMaterial" id=9]
lifetime_randomness = 0.81
direction = Vector3( 0, 1, 0 )
spread = 0.0
gravity = Vector3( 0, 0, 0 )
initial_velocity = 0.5
linear_accel = 4.0
scale = 2.0
scale_random = 1.0
scale_curve = SubResource( 5 )
color_ramp = ExtResource( 4 )

[node name="RootNode" type="Spatial"]

[node name="Fire" type="Particles" parent="."]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.26708, 0 )
material_override = SubResource( 1 )
cast_shadow = 0
amount = 50
randomness = 0.74
local_coords = false
draw_order = 1
process_material = SubResource( 6 )
draw_pass_1 = SubResource( 7 )

[node name="OmniLight" type="OmniLight" parent="Fire"]
light_color = Color( 1, 0.901961, 0.560784, 1 )
light_energy = 2.0

[node name="BlueFire" type="Particles" parent="."]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -1.78327, 1.26708, 0 )
material_override = SubResource( 1 )
cast_shadow = 0
amount = 50
randomness = 0.74
local_coords = false
draw_order = 1
process_material = SubResource( 8 )
draw_pass_1 = SubResource( 7 )

[node name="OmniLight" type="OmniLight" parent="BlueFire"]
light_color = Color( 0.560784, 0.752941, 1, 1 )
light_energy = 2.0

[node name="GreenFire" type="Particles" parent="."]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 1.66113, 1.26708, 0 )
material_override = SubResource( 1 )
cast_shadow = 0
amount = 50
randomness = 0.74
local_coords = false
draw_order = 1
process_material = SubResource( 9 )
draw_pass_1 = SubResource( 7 )

[node name="OmniLight" type="OmniLight" parent="GreenFire"]
light_color = Color( 0.560784, 0.752941, 1, 1 )
light_energy = 2.0

[node name="DemoInterface" parent="." instance=ExtResource( 1 )]
text_bbcode = "A particle system with a custom world coordinate, noise based, alpha erosion."

[node name="Camera" type="Camera" parent="."]
transform = Transform( 1, 0, 0, 0, 0.950814, 0.309764, 0, -0.309764, 0.950814, 0, 2.58946, 2.17295 )

[node name="Demo3DEnvironmentDark" parent="." instance=ExtResource( 6 )]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0.0586119, 0.168849, 0.13654 )
8 changes: 8 additions & 0 deletions godot/Demos/StylizedFire/BlueFireGradient.tres
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[gd_resource type="GradientTexture" load_steps=2 format=2]

[sub_resource type="Gradient" id=1]
colors = PoolColorArray( 0, 0.976562, 1, 1, 0.335327, 0, 0.640625, 0 )

[resource]
gradient = SubResource( 1 )
width = 128
9 changes: 9 additions & 0 deletions godot/Demos/StylizedFire/CloudNoise.tres
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[gd_resource type="NoiseTexture" load_steps=2 format=2]

[sub_resource type="OpenSimplexNoise" id=1]
period = 119.4
persistence = 0.449

[resource]
seamless = true
noise = SubResource( 1 )
8 changes: 8 additions & 0 deletions godot/Demos/StylizedFire/FireGradient.tres
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[gd_resource type="GradientTexture" load_steps=2 format=2]

[sub_resource type="Gradient" id=1]
colors = PoolColorArray( 1, 0.890625, 0, 1, 1, 0, 0.447059, 0 )

[resource]
gradient = SubResource( 1 )
width = 128
Binary file added godot/Demos/StylizedFire/FireMask.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 36 additions & 0 deletions godot/Demos/StylizedFire/FireMask.png.import
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[remap]

importer="texture"
type="StreamTexture"
path.s3tc="res://.import/FireMask.png-449a5975d3ec46a30137f9c77f5aac15.s3tc.stex"
path.etc2="res://.import/FireMask.png-449a5975d3ec46a30137f9c77f5aac15.etc2.stex"
metadata={
"imported_formats": [ "s3tc", "etc2" ],
"vram_texture": true
}

[deps]

source_file="res://Demos/StylizedFire/FireMask.png"
dest_files=[ "res://.import/FireMask.png-449a5975d3ec46a30137f9c77f5aac15.s3tc.stex", "res://.import/FireMask.png-449a5975d3ec46a30137f9c77f5aac15.etc2.stex" ]

[params]

compress/mode=2
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=true
flags/filter=true
flags/mipmaps=true
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
stream=false
size_limit=0
detect_3d=false
svg/scale=1.0
8 changes: 8 additions & 0 deletions godot/Demos/StylizedFire/GreenFireGradient.tres
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[gd_resource type="GradientTexture" load_steps=2 format=2]

[sub_resource type="Gradient" id=1]
colors = PoolColorArray( 0.21875, 1, 0, 1, 0, 0.640625, 0.145142, 0 )

[resource]
gradient = SubResource( 1 )
width = 128
Binary file added godot/Demos/StylizedFire/HoleNoise.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 36 additions & 0 deletions godot/Demos/StylizedFire/HoleNoise.png.import
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[remap]

importer="texture"
type="StreamTexture"
path.s3tc="res://.import/HoleNoise.png-4463c65817ac6974adf95590921ef8c1.s3tc.stex"
path.etc2="res://.import/HoleNoise.png-4463c65817ac6974adf95590921ef8c1.etc2.stex"
metadata={
"imported_formats": [ "s3tc", "etc2" ],
"vram_texture": true
}

[deps]

source_file="res://Demos/StylizedFire/HoleNoise.png"
dest_files=[ "res://.import/HoleNoise.png-4463c65817ac6974adf95590921ef8c1.s3tc.stex", "res://.import/HoleNoise.png-4463c65817ac6974adf95590921ef8c1.etc2.stex" ]

[params]

compress/mode=2
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=true
flags/filter=true
flags/mipmaps=true
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
stream=false
size_limit=0
detect_3d=false
svg/scale=1.0
Binary file added godot/Demos/StylizedFire/WispyNoise.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 36 additions & 0 deletions godot/Demos/StylizedFire/WispyNoise.png.import
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[remap]

importer="texture"
type="StreamTexture"
path.s3tc="res://.import/WispyNoise.png-51c0c348937110df7c2bdbd4e9b46669.s3tc.stex"
path.etc2="res://.import/WispyNoise.png-51c0c348937110df7c2bdbd4e9b46669.etc2.stex"
metadata={
"imported_formats": [ "s3tc", "etc2" ],
"vram_texture": true
}

[deps]

source_file="res://Demos/StylizedFire/WispyNoise.png"
dest_files=[ "res://.import/WispyNoise.png-51c0c348937110df7c2bdbd4e9b46669.s3tc.stex", "res://.import/WispyNoise.png-51c0c348937110df7c2bdbd4e9b46669.etc2.stex" ]

[params]

compress/mode=2
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=true
flags/filter=true
flags/mipmaps=true
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
stream=false
size_limit=0
detect_3d=false
svg/scale=1.0
79 changes: 79 additions & 0 deletions godot/Shaders/stylized_fire.shader
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// This shader is based on Minionsart's stylized fire
// https://twitter.com/minionsart/status/1132593681452683264?s=20

shader_type spatial;
render_mode blend_mix;

// This texture must be seamless!
// Experiment with the different noises provided in the res://Demos/StylizedFire/ folder
uniform sampler2D noise_texture;

uniform sampler2D texture_mask;
uniform float emission_intensity = 2.0;
uniform float time_scale = 3.0;
uniform vec2 texture_scale = vec2(1.0);
uniform float edge_softness = 0.1;

varying vec3 world_coord;
varying float world_x_dot;


void vertex() {
// Billboard code, taken directly from a spatial material
// create a spatial material, enable billboard with billboard keep scale, and then convert
// to shader material, and it will create a shader with this code.
mat4 mat_world = mat4(normalize(CAMERA_MATRIX[0])*length(WORLD_MATRIX[0]),normalize(CAMERA_MATRIX[1])*length(WORLD_MATRIX[0]),normalize(CAMERA_MATRIX[2])*length(WORLD_MATRIX[2]),WORLD_MATRIX[3]);
mat_world = mat_world * mat4( vec4(cos(INSTANCE_CUSTOM.x),-sin(INSTANCE_CUSTOM.x), 0.0, 0.0), vec4(sin(INSTANCE_CUSTOM.x), cos(INSTANCE_CUSTOM.x), 0.0, 0.0),vec4(0.0, 0.0, 1.0, 0.0),vec4(0.0, 0.0, 0.0, 1.0));
MODELVIEW_MATRIX = INV_CAMERA_MATRIX * mat_world;

// We map the coordinates on the vertical planes xy and zy
// we also calculate how to blend between the two based on where the world space normal
// is pointing.
world_coord = (mat_world * vec4(VERTEX, 1.0)).rgb;
vec4 world_normal = (mat_world * vec4(NORMAL, 0.0));
world_x_dot = abs(dot(normalize(world_normal.rgb), vec3(1.0,0.0,0.0)));
}


void fragment() {

// We sample the mask texture based on regular UV
// We don't want the particles to show their square shape
// so we use a round, black and white, mask texture
float mask = texture(texture_mask, UV).r;

// We sample the noise both from the xy plane and from the zy plane, adding a time-based
// panning. If we didn't do this, we would see the holes of the noise will always be in the
// same space in global coordinates. Set the time_scale to zero to see how it would look like.
// To add more variation, we could sample from another noise that has a different scale and panning speed.
// The additional offset on the zy noise is to avoid mirroring effects when
// the view vector is between same-sign x and z axes
vec2 time_based_pan = vec2(0.2, 1.0) * (- TIME * time_scale);
float noise_xy = texture(noise_texture, world_coord.xy * texture_scale + time_based_pan).r;
float noise_zy = texture(noise_texture, world_coord.zy * texture_scale + time_based_pan + vec2(0.7, 0.3)).r;

// We blend the noise based on world_x_dot, which is the dot product between
// the normal of the billboard plane, and the global x axis. If we face the global
// x axis, then we sample from the xy plane, otherwise, we sample from the zy plane
float noise = mix(noise_xy, noise_zy, clamp(world_x_dot, 0.0, 1.0));

// The particle color is assigned to the vertex color, which is called COLOR
ALBEDO = COLOR.rgb;
// Assign the same color for emission, multiplied by the emission intensity
EMISSION = ALBEDO * emission_intensity;

// Instead of blending out the particle, we apply a technique called alpha erosion, where we
// subtract an erosion amount from the alpha.
float erosion_amount = (1.0 - COLOR.a);
float alpha = (noise * mask) - erosion_amount;

// Because we perform a subtraction, we ensure that the alpha is always between 0 and 1.
// If the alpha goes negative or above 1, a number of visual artifacts appear.
alpha = clamp(alpha, 0.0, 1.0);

// In order to give this fire a stylized vibe, we use smoothstep to remap the alpha value
// We could use step(0.1, alpha), but then there would be an abrupt cut between transparent and
// non transparent (exactly as if we discarded the fragment with discard)
// smoothstep gives a nice blend on the edges instead
ALPHA = smoothstep(0.0, edge_softness, alpha);
}
15 changes: 15 additions & 0 deletions godot/Shared/Demo3DEnvironmentDark.tscn
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[gd_scene load_steps=4 format=2]

[ext_resource path="res://Shared/environments/level_environment_dark.tres" type="Environment" id=1]
[ext_resource path="res://Shared/Demo3DEnvironment.tscn" type="PackedScene" id=2]

[sub_resource type="SpatialMaterial" id=1]
albedo_color = Color( 0.188235, 0.188235, 0.188235, 1 )

[node name="Demo3DEnvironmentDark" instance=ExtResource( 2 )]

[node name="BaseWorldEnvironment" parent="." index="0"]
environment = ExtResource( 1 )

[node name="Ground" parent="." index="2"]
material_override = SubResource( 1 )
Loading

0 comments on commit 4370662

Please sign in to comment.