Friday Night Funkin' Cookbook
Friday Night Funkin' CookbookAdvancedScripted Shaders

Scripted Shaders

Reading time: 2 minutes

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.

// ...

Contributors:
Kade-gtihub
bobbyDX
Last modified:
Created:
Category:  Advanced
Tags: