Muzzle flash Z-axis billboard

Simple billboard shader that rotates the mesh around its local Z axis towards the camera, applies emission and hides it when the camera direction gets close to Z axis.

2 shaders are included:

  • First one is for side view of the muzzle flash. It rotates the mesh around local Z axis to face the camera. “Face threshold” parameter is used to hide the mesh when the camera faces Z axis.
  • Second shader is used for front/back view of the muzzle flash. “Face threshold” is instead used to reveal the texture when camera is facing the Z axis. I recommend using the same “face threshold” value selected for first shader.

Basic scene setup:

  1. Add MeshInstance3D node with “Quad Mesh” or AnimatedSprite3D node, depending if you want to use animation. This node will be used for side view of muzzle flash.
  2. Duplicate the created node. This second node will be used for front view.
  3. Create two “Shader Material” resources and assign “muzzle_flash_billboard_side.gdshader” to the first material and “muzzle_flash_billboard_face.gdshader” to the second one.
  4. Add textures to materials using “Main Tex” parameter.
  5. Assign created materials to nodes from steps 1 and 2.

Once the scene is set up, you should see the mesh rotate towards the camera.

If the rotation is wrong, you can rotate the meshes to change the billboard axis. Billboard axis follows the mesh local Z axis.

Feel free to copy, modify and use the code.

Shader code
/////////////////////// muzzle_flash_shader_side.gdshader /////////////////////////////
// Billboard muzzle flash shader (side view).
// Made by shadecore_dev, 2025.

shader_type spatial;

uniform float emission = 1.0; // Color multiplier
uniform sampler2D main_tex : filter_nearest; // Main texture

uniform float face_threshold = 0.1; // 0.0-1.0 Angle threshold for hiding the billboard when the camera gets close to Z axis.

void vertex() {
	vec3 side_vec3 = -MODEL_MATRIX[0].xyz;
	vec4 side_vec4 = -MODEL_MATRIX[0];
	
	float vec_dif = abs(dot(MODEL_MATRIX[0].xyz, CAMERA_DIRECTION_WORLD));
	
	MODELVIEW_MATRIX = VIEW_MATRIX * (
		mat4(
			vec4(normalize(cross(side_vec3, INV_VIEW_MATRIX[2].xyz)), 0.0),
			side_vec4,
			vec4(normalize(cross(INV_VIEW_MATRIX[0].xyz, side_vec3)), 0.0),
			MODEL_MATRIX[3]
		)
	);
}

void fragment() {
	float vec_dif = abs(dot(MODEL_MATRIX[0].xyz, CAMERA_DIRECTION_WORLD));
	vec4 color = texture(main_tex, UV);

    ALBEDO = color.rgb;
	EMISSION = color.rgb * emission;
	ALPHA = color.a * max(0.0, 1.0 - vec_dif - face_threshold);
}

///////////////////////////////////////////////////////////////////////////////////////

////////////////////////// muzzle_flash_shader_face.gdshader /////////////////////////
// Billboard muzzle flash shader (front/back view).
// Made by shadecore_dev, 2025.

shader_type spatial;

uniform float emission = 1.0; // Color multiplier
uniform sampler2D main_tex : filter_nearest; // Main texture

uniform float face_threshold = 0.1; // 0.0-1.0 Angle threshold for revealing the billboard when the camera gets close to Z axis.

void vertex() {
	vec3 face_vec3 = -MODEL_MATRIX[1].xyz;
	vec4 face_vec4 = -MODEL_MATRIX[1];
	
	float vec_dif = abs(dot(MODEL_MATRIX[0].xyz, CAMERA_DIRECTION_WORLD));
	
	MODELVIEW_MATRIX = VIEW_MATRIX * 
	mat4(
		vec4(normalize(cross(face_vec3, INV_VIEW_MATRIX[2].xyz)), 0.0),
		face_vec4,
		vec4(normalize(cross(INV_VIEW_MATRIX[0].xyz, face_vec3)), 0.0),
		MODEL_MATRIX[3]
	);
}

void fragment() {
	float vec_dif = abs(dot(MODEL_MATRIX[0].xyz, CAMERA_DIRECTION_WORLD));
	vec4 color = texture(main_tex, UV);

	ALBEDO = color.rgb;
	EMISSION = color.rgb * emission;
	ALPHA = color.a * max(0.0, 0.5 - max(0.0, 1.0 - vec_dif - face_threshold));
}

///////////////////////////////////////////////////////////////////////////////////////
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

Related shaders

World Space Gradient in Next-Pass (Y-Axis)

Billboard Sprite3D Sway (Godot 4.0)

Rotating Billboard Sprite 3D

Subscribe
Notify of
guest

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
nick
nick
3 days ago

Please give us the project file so we know how to set it up