Skip to content

Latest commit

 

History

History
243 lines (160 loc) · 7.43 KB

RAYGL.md

File metadata and controls

243 lines (160 loc) · 7.43 KB

RayGL

RayGL makes use of special prefixes and directives. THe main script and all dependencies are composed in a single uber shader(Multi pass is controlled with conditional defines and the pass directive). If you want to debug the final glsl output, for now, just make a small typo and click "Apply"(Shortcuts are Alt-A and Alt-Enter). The side editor will show the final shader text along with the error message.

All scripts must use "$main(vec4 outputColor, vec2 fragCoords)" as the entry point for the shader execution(The one from the currently active script will be used). The use of the "$" character does the namespacing to prevent conflicts and allow for variable/function reuse in other scripts.

Code modularization is performed with the following directives:

#import

In a script we define eg a function

vec3 $myfunc(float myArg) {
    return vec3(myArg);
}

We get the editor state in a url from the Save link, and short url it to "someUrl"

We can then import it in another script and namespace it using the "@" prefix as follows.

#import myModule < http://someUrl >

$main(vec4 outputColor, vec3 fragCoords) 
{
    outputColor.rgb = @myModule.myfunc(123);
}

#export

Scripts can define special placeholders in a global namespace to allow for overridable behavior:

#export a_global_func < vec3 (vec3 col) >
#export a_global_var < vec3 = vec3(0.1, 0.3, 0.2) >
// We import the global namespace like this:
#import GLOBAL <>

vec3 $a_global_func( vec3 col )
{
    return col * @GLOBAL.a_global_var;
}

$main(vec4 outputColor, vec3 fragCoords) 
{
    outputColor.rgb = @GLOBAL.a_global_func(outputColor);
}

Functions must be defined but variables must not, they will be automatically added on the top of the shader using the configuration.

We then save/short url this script in someUrl and make a new one like:

#import myModule <someUrl>
#export a_global_func < vec3 (float myArg) >

vec3 $a_global_func( vec3 col )
{
    return col + vec3(0.1);
}

$main(vec4 outputColor, vec3 fragCoords) 
{   
    // the $main function from the previous script will use the a_global_func defined in this script
    @myModule.main(outputColor, fragCoords);
}

This way we can call code and override parts of it. Check the sdf module in the core lib for a more complex example.

#image

Fetch and use images from the web in sampler2D uniforms like this:

#import IMG < http://imageUrl >

vec4 texel = texture2D(@IMG.tex, uv);
vec4 infor = @IMG.inf.xyzw;

The "tex" property is a sampler2D and the inf property the following vec4:

{ x: imageWidth, y: imageHeight, z: 0.0, y:0.0 }

#cube

Fetch and use cubemaps in samplerCube uniforms. The image url provided must contain all six sides of the cube in 1x6, 6x1, 3x2 or 2x3 arrangement.

#import CUBE < http://imageUrl >

vec4 texel = textureCube(@CUBE.tex, dir.xyz);
vec4 infor = @CUBE.inf.xyzw;

The "tex" property is a samplerCube and the inf property the following vec4:

{ x: cubeSideWidth, y: cubeSideHeight, z: 0.0, y:0.0 }

#video

Fetch and use video frames in sampler2D uniforms. Videos are always muted and looping.

#import VID < http://videoUrl >

vec4 texel = texture2D(@VID.tex, dir.xyz);
vec4 infor = @VID.inf.xyzw;

The "tex" property is a sampler2D and the inf property the following vec4:

{ x: imageWidth, y: imageHeight, z: currentTime, y: videoDuration }

#net

Stream 2D textures from websockets. Servers just have to push arraybuffers of unsigned byte RGBA format prepended by a 2 Uint64s header width with the width/height of the current frame and a single float32 serverData which is accesible through the inf uniform for a fixed total of 8 header bytes.

#import NET < ws://serverUrl >

vec4 texel = texture2D(@NET.tex, dir.xyz);
vec4 infor = @NET.inf.xyzw;

The "tex" property is a sampler2D and the inf property the following vec4:

{ x: imageWidth, y: imageHeight, z: lastReceivedFrameTime, y: serverData }

#pass

Sets up multi pass.

// Pass textures are half the screen size
#pass MYPASS <view: 0.5 0.5; rel>

$main(vec4 outputColor, vec3 fragCoords) 
{

vec2 uv = fragCoords.xy / iResolution.xy;

#if defined @MYPASS.PASS
// This will run in the pass we defined

outputColor.rg = uv.xy;

#else
// This will run in the main pass, read  
// from the texture generated by MYPASS

outputColor.gbr = texture2D(@MYPASS.tex, uv).rgb;

#endif

}

Passes render directly to the screen or in framebuffer textures. Framebuffers exposed in the @PASSNAME.tex property and a .inf vec4 property like:

{ x: textureWidth, y: textureHeight, z: 0., y: 0. }

Framebuffers are paired so the last rendered frame can be accesed through the .tex property for implementing feedback effects.

Configuration of the pass is performed using a style parser in the directive text.

view - The first two numbers are used for the width and height of the viewport, the next two for the offset. These are interpreted as pixels by default and if the rel keyword is used, relative to the screen size.

The keywords supported are the following:

screen - Don't use framebuffers, output directly on screen

rel - Interpret provided coordinates as fractions of the screen size

func-xxx - Set the blendFunction like this:

#pass PASS1 < func: one msa >
#pass PASS2 < func: one msa one zero >

They keyword can be accompanied by 2 or 4 tokens, to use blendFunc or blendFuncSeparate respectively. Tokens are shortcuts for the following gl contants:

  • "one": "ONE", "zero": "ZERO", "src": "SRC_COLOR", "msc": "ONE_MINUS_SRC_COLOR", "dsc": "DST_COLOR", "mdc": "ONE_MINUS_DST_COLOR", "sra": "SRC_ALPHA", "msa": "ONE_MINUS_SRC_ALPHA", "dsa": "DST_ALPHA", "mda": "ONE_MINUS_DST_ALPHA", "sat": "SRC_ALPHA_SATURATE"

eq-xxx Like above, takes one or two tokens and passes them to blendEquation or blendEquationSeparate. Tokens are:

  • "add": "FUNC_ADD", "sub": "FUNC_SUBTRACT", "rev": "FUNC_REVERSE_SUBTRACT", "min": "MIN_EXT", "max": "MAX_EXT"

Mind that rayglider will try to enable the blend_minmax extension but it is not guaranteed that the min and max modes will actually be available.

wrap Sets the wrap options for the framebuffer textures:

#pass P1 <view: 1 1; rel; wrap: clamp repeat>
  • "mirror": "MIRRORED_REPEAT", "clamp": "CLAMP_TO_EDGE", "repeat": "REPEAT"

freq Controls how often this pass will be performed. Accepts an argument for the number of frames to skip between invocations.

#pass P1 <view: 1 1; rel; freq: 10>

mipmap Try to generate mipmaps for the framebuffer texture after render.

cube Render a cubemap texture. In this case the texture uniform for the pass will be a samplerCube. It will perform the pass 6 times during which iFace uniform will take the values 0-6 to configure each face accordingly.

map Reduce the texture. Will perform the number of passes provided with the second argument each time halving both dimensions. The texture exposed as the uniform for the pass will be the previous level while performing the reduce pass. For all other passes it will be the last level.

vmap Same as map but will reduce only the height, useful for physic collision calculations

rmap Same as map but will iterate the levels in reverse order, from smaller to bigger. Useful for implementing cone marching

#post

Sets up a render pass like #pass but post passes will run after all normal passes. Useful for making post process modules and gui elements

#midi

#track

#band

#boom