HISE Docs

ScriptShader


A shader is a small program that will run natively on the GPU and allows very complex animation / textures. There is a whole universe of different shaders available.

In order to use it, create a shader object using Content.createShader(fileName) and then render the shader on any ScriptPanel using Graphics.applyShader() .

There are a few limitations to the shader support in HISE:

and obviously the support of different shaders depend on the hardware on the end user system.

How to use existing shaders in HISE

Check out shadertoy.com for a vast gallery of shaders. Unfortunately there is not a 100% clean API so you will need to adjust the shader code a bit in order to run inside HISE (I tried to make it as compatible as possible so the amount of tweaking is the absolute minimum).
Below you can see the Hello world of shaders on shadertoy.com:

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // Normalized pixel coordinates (from 0 to 1)
    vec2 uv = fragCoord/iResolution.xy;

    // Time varying pixel color
    vec3 col = 0.5 + 0.5*cos(iTime+uv.xyx+vec3(0,2,4));

    // Output to screen
    fragColor = vec4(col,1.0);
}

In order to use this shader in HISE you will have to do two steps:

  1. modify the main function signature
  2. multiply the output colour with pixelAlpha

If you do these two steps, you will end up with this code:

void main() // must be named `main()` without parameters
{
    // Normalized pixel coordinates (from 0 to 1)
    vec2 uv = fragCoord/iResolution.xy;

    // Time varying pixel color
    vec3 col = 0.5 + 0.5*cos(iTime+uv.xyx+vec3(0,2,4));

    // Output to screen
    fragColor = pixelAlpha * vec4(col,1.0);
}

As soon as there is an image or something in the iChannel boxes on the shadertoy website, the shader will not work, so make sure that you only use shaders without external textures.

How to declare constants

You can define constants or declare them above the main function like so:

#define PI 3.14159265359

const float myFloat = 2.35468;

const vec2 myVector = vec2(0.6546, 0.9512);

Arrays cannot be declared as constants as it is not supported by this version of GLSL.

So this won't work:

// this doesn't work
const vec2 myArray1[2] = vec2[2] (vec2( 0.4657,  0.2149), vec2( 0.5536,  0.1345));

But instead, you can declare arrays inside the main function like so:

void main()
{
	vec2 myArray1[2]; 
    myArray1[0] = vec2( 0.4657,  0.2149);
    myArray1[1] = vec2( 0.5536,  0.1345);
    
    vec2 myArray2[64];
    for (int i=0; i < 64; i++) // myArray2.length() isn't supported by the current GLSL version
    {
	    myArray2[i] = vec2(0.);
    }
    
    // Note that this won't work either:
    //vec2 myArray1[2] = vec2[3] (vec2( 0.4657,  0.2149), vec2( 0.5536,  0.1345));
}

Learn to write shaders

If you want to do more than pasting shaders from shadertoy.com and look at it in awe, you will need to learn how to write shaders. OpenGL shaders use a specific language called GLSL which is similar to C / C++. There are lots of useful resources on the web,

I can recommend this Youtube channel. Start with the basic introduction and watch the time pass by as you click the next video over and over again.

Class methods

fromBase64

Compiles the code from the given base64 string.

ScriptShader.fromBase64(String b64)


During development it's highly recommended to use human readable GLSL text files in the script repository, however there are a few use cases where you need to dynamically load new shaders:

  1. If you ship new shaders with expansions
  2. If you want a monolithic patch (for pasting the HiseSnippet to the forum).

This method can be used to give the shader a base64 encoded string that was created with the ScriptShader.toBase64() method.

getOpenGLStatistics

Returns a JSON object with the current OpenGL statistics.

ScriptShader.getOpenGLStatistics()



setBlendFunc

Sets the blend mode for the shader.

ScriptShader.setBlendFunc(bool enabled, int sFactor, int dFactor)


This sets the blending mode for the shader. The first parameter enables / disables blending all together and the other two parameters need to be OpenGL constants (which are defined as constants of the shader object).

There are plenty of options available in order to define the blending. Take a look at eg. this website for a detailed explanation.

This is a small cheat sheet for the most useful combinations:

const var shader = Content.createShader("myShader");

// No blending
shader.setBlendFunc(false, shader.GL_ZERO , shader.GL_ZERO);

// Additive blending with alpha
shader.setBlendFunc(true, shader.GL_SRC_ALPHA , shader.GL_ONE);

// Default blending based on alpha value:
shader.setBlendFunc(true, shader.GL_SRC_ALPHA, shader.GL_ONE_MINUS_SRC_ALPHA);

// Additive blending without alpha
shader.setBlendFunc(true, shader.GL_ONE, shader.GL_ONE);

// Additive blending with alpha
shader.setBlendFunc(true, shader.GL_SRC_ALPHA , shader.GL_ONE);


setEnableCachedBuffer

If this is enabled, the shader will create a buffered image of the last rendering result.

ScriptShader.setEnableCachedBuffer(bool shouldEnableBuffer)



setFragmentShader

Loads a .glsl file from the script folder.

ScriptShader.setFragmentShader(String shaderFile)


Normally you don't need to use this method because the shader input will be defined when you create this object, but you can opt to use the same shader object but with a different input file if that suits your workflow.

The input parameter is the shader file name (without the .glsl extension and the file must be inside the Scripts folder of your project (it will be embedded like any other script file when you export the project).

As soon as you added a shader, you can select the file in the drop down menu to get the code editor that you can use to modify the shader.

setPreprocessor

Adds a preprocessor definition before the code and recompiles the shader (Empty string removes all preprocessors).

ScriptShader.setPreprocessor(String preprocessorString, var value)



setUniformData

Sets an uniform variable to be used in the shader code.

ScriptShader.setUniformData( String id, var data)


This function can be used to pass around data from the HiseScript world to GLSL. It just needs two steps:

  1. Define the variable in your GLSL code (with the uniform keyword).
  2. Call this method.

So this is the example code for the GLSL part:

// GLSL side

uniform float myValue;
uniform vec3 myColour;
uniform float myBuffer[128];

void main()
{
    fragColor = pixelAlpha * vec4(myColour, myValue);
}

From the script you need to call this:

// Javascript side:

const var shader = Content.createShader("MyShader");

// a single number will be parsed as float
shader.setUniformData("myValue", 0.8);

// an array with three elements will be interpreted as vec3 type.
shader.setUniformData("myColour", [0.0, 1.0, 0.0]);

const var buffer = Buffer.create(128);

// A Buffer object (a float array) will be passed on to the GPU as read only
shader.setUniformData("myBuffer", buffer);

Make sure that the types match (or the behaviour will be undefined). Also be aware that you will need to pass in the buffer data when it changes (the GPU doesn't reference the actual buffer data but takes a copy when you call this method).

toBase64

Compresses the GLSL code and returns a encoded string snippet.

ScriptShader.toBase64()


If you want to use dynamic shaders, you can call this method to get a compressed version of the current shader code which you then can pass into ScriptShader.fromBase64()

The most efficient workflow is to use Console.print() with this method, then copy & paste the output as string literal.

Note that this string will include all files that are imported in the main shader using #include so it's guaranteed to work without relying on any dependency.