Smoke Shader
A (Billboard) Smoke Shader.
Shader code
/*
煙シェーダー by あるる(きのもと 結衣) @arlez80
Smoke Shader by Yui Kinomoto
MIT License
*/
shader_type spatial;
render_mode depth_draw_opaque;
// 煙の細かさ
uniform float scale = 1.0;
// 煙移動速度
uniform vec3 tex_speed = vec3( 0.0, -2.2, 0.5 );
// 煙もこもこ感
uniform vec2 mokomoko = vec2( 0.1, 0.1 );
// 煙の量
uniform float smoke_volume : hint_range( 0.0, 2.0 ) = 0.8;
// 穴開き具合
uniform float smoke_aperture : hint_range( 0.0, 3.0 ) = 0.28;
// 色
uniform vec4 smoke_color : hint_color = vec4( 0.185, 0.185, 0.185, 1.0 );
varying vec4 world_vertex;
float random( vec3 pos )
{
return fract(sin(dot(pos, vec3(12.9898,78.233,-3.532532))) * 43758.5453);
}
float value_noise( vec3 pos )
{
vec3 p = floor( pos );
vec3 f = fract( pos );
float v000 = random( p/*+ vec3( 0.0, 0.0, 0.0 )*/ );
float v100 = random( p + vec3( 1.0, 0.0, 0.0 ) );
float v010 = random( p + vec3( 0.0, 1.0, 0.0 ) );
float v110 = random( p + vec3( 1.0, 1.0, 0.0 ) );
float v001 = random( p + vec3( 0.0, 0.0, 1.0 ) );
float v101 = random( p + vec3( 1.0, 0.0, 1.0 ) );
float v011 = random( p + vec3( 0.0, 1.0, 1.0 ) );
float v111 = random( p + vec3( 1.0, 1.0, 1.0 ) );
vec3 u = f * f * ( 3.0 - 2.0 * f );
return mix(
mix(
mix( v000, v100, u.x )
, mix( v010, v110, u.x )
, u.y
)
, mix(
mix( v001, v101, u.x )
, mix( v011, v111, u.x )
, u.y
)
, u.z
);
}
float noise_tex( vec3 p )
{
return (
value_noise( p * 0.984864 ) * 0.5
+ value_noise( p * 2.543 ) * 0.25
+ value_noise( p * 9.543543 ) * 0.125
+ value_noise( p * 21.65436 ) * 0.0625
+ value_noise( p * 42.0 ) * 0.03125
+ value_noise( p * 87.135148 ) * 0.015625
+ value_noise( p * 340.66534654 ) * 0.0078125
);
}
void vertex( )
{
world_vertex = WORLD_MATRIX * vec4( VERTEX * scale, 1.0 );
}
void fragment( )
{
float p[9];
for( int y = 0; y < 3; y ++ ) {
for( int x = 0; x < 3; x ++ ) {
p[y*3 + x] = noise_tex( world_vertex.xyz + tex_speed * TIME + vec3( mokomoko * vec2( float(x - 1), float(y - 1) ), 0.0 ) );
}
}
float smoke = clamp( sin( UV.x * 3.1415926535 ) * smoke_volume, 0.0, 1.0 );
float smoke_noise = smoke * ( ( ( smoke + smoke_aperture ) * p[4] - smoke_aperture ) * 75.0 ) * UV.y;
vec2 sobel_filter = clamp(
vec2(
(
p[0] * -1.0
+ p[3] * -2.0
+ p[6] * -1.0
+ p[2] * 1.0
+ p[5] * 2.0
+ p[8] * 1.0
)
, (
p[0] * -1.0
+ p[1] * -2.0
+ p[2] * -1.0
+ p[6] * 1.0
+ p[7] * 2.0
+ p[8] * 1.0
)
)
, vec2( -1.0, -1.0 )
, vec2( 1.0, 1.0 )
) * 0.5;
NORMALMAP = normalize( vec3( sobel_filter.x + 0.5, -sobel_filter.y + 0.5, 1.0 ) );
ALBEDO = smoke_color.rgb;
ALPHA = clamp( smoke_noise, 0.0, 1.0 );
}
Wonderful smoke effect!
Can you give a bit more detail into how to use your shader? I’ve tried creating a ShaderMaterial loaded with “smoke.shader” and then use this material in a PlaneMesh (MeshInstance), but I couldn’t get it to work in billboard mode…
To get the billboard effect I ended up implementing a less than ideal solution – Attaching the following script to the node:
I’m positive there’s a much better solution out there though.
Oh, you can actually do the billboard from the shader itself.
In his shader, in the vertex function, put this line of code:
So the vertex function should look like this:
The code above is for a full billboard effect, taken straight from Godot’s spatial material code.
If you want just a Y-Billboard, you can use this:
So all in all, if you want Y-Billboard, the vertex function should look like this:
Hope that helps!
Thank you very much for your detailed answer, yours is a much more elegant solution than mine. The only problem I had with your Y-Billboard vertex function is that I can’t get it to look right when the player moves behind the smoke when I’m using
The shader goes upside down.
This is very well made, thanks!