This chapter will walk you through the process of using a custom runtime shader to alter the appearance of a given sprite or camera using GLSL.
Setup
To get started, let's set up a fragment shader, with the .frag extension, in the mods/mymod/shaders folder. For example, let's set up a solid color shader, appropriately titled solidColor.frag:
#pragma header
uniform vec4 color;
void main()
{
gl_FragColor = color;
}
Loading and Applying the Shader
You can register a variable to hold your shader using FlxRuntimeShader. Here's an example applying the shader to the boyfriend sprite in a stage script:
Shader application is most common in stage scripts, but you can also apply them in other scripts as needed.
import funkin.play.stage.Stage; import flixel.addons.display.FlxRuntimeShader; import funkin.play.PlayState; class TemplateStage extends Stage { function new() { super('template'); } var colorShader:FlxRuntimeShader; function onCreate(event:ScriptEvent):Void { super.onCreate(event); colorShader = new FlxRuntimeShader(Assets.getText(Paths.frag('solidColor'))); PlayState.instance.currentStage.getBoyfriend().shader = colorShader; } }
A shader is registered, and to edit the effect, you'll need to update the shader's uniform values.
// in hscript, some function... colorShader.setFloatArray("color", [1.0,1.0,1.0,1.0]); // pure white
Below is a list of methods available for setting uniform values on a FlxRuntimeShader:
setFloat(name:String, value:Float)setFloatArray(name:String, value:Array<Float>)setInt(name:String, value:Int)setIntArray(name:String, value:Array<Int>)setBool(name:String, value:Bool)setBoolArray(name:String, value:Array<Bool>)setBitmapData(name:String, value:openfl.display.BitmapData)
There are also corresponding get methods for each of these to retrieve the current uniform values.
Custom Shader Classes
For more complex shaders, you might want to create a custom shader class that extends FlxRuntimeShader. Here's an example of how to create a custom shader class:
import flixel.addons.display.FlxRuntimeShader; class SolidColorShader extends FlxRuntimeShader { // notice how we have a function that sets the shader's color uniform when we set the color variable public var color(default, set):Array<Float>; public function new() { super(Assets.getText(Paths.frag('solidColor'))); this.color = [0.0, 0.0, 0.0, 0.0]; } function set_color(value:Array<Float>):Array<Float> { this.setFloatArray('color', value); this.color = value; return this.color; } }
You can then use this custom shader class in your stage script like so:
colorShader = new SolidColorShader(); colorShader.color = [1.0, 0.0, 0.0, 1.0]; // Set the color to red PlayState.instance.currentStage.getBoyfriend().shader = colorShader;
Applying shaders to a camera
To apply the shader to the camera (effecting the overall picture of the stage), which is useful if you would like to apply effects to:
- Everything
- Texture Atlas' Sprites
- A specific portion of the stage/menu/etc
// ... import flixel.addons.display.FlxRuntimeShader; import openfl.filters.ShaderFilter; // ... // You have a FlxRuntimeShader called 'bevel' FlxG.camera.filters = [new ShaderFilter(bevel)]; // You can also stack these if you have another shader, say 'adjustColor' FlxG.camera.filters = [new ShaderFilter(adjustColor), new ShaderFilter(bevel)]; // It will follow order of operations! // First: apply adjust color, than apply the bevel shader on top of that output. // ...