Custom Materials

Bradley Griffith edited this page Feb 13, 2018 · 10 revisions

Blotter Materials describe how your texts will be rendered and provide the interface through which you can introduce variety in the characteristics of any effect. Blotter comes with a growing set of ready-to-use materials, but if you would like information on creating custom materials for private use, or for contributing new materials to Blotter, you should follow the guide below.

Note: I'll do my best to explain concepts here in a understandable way, but this guide is for those interested in supplying their own GLSL code to create new effects in Blotter. If you're new to GLSL, you may find starting with The Book of Shaders helpful, but dont be afraid to continue here. If you're experienced with GLSL, you may find this guide a little light, but feel free to ask any questions.

Custom Materials with Blotter.ShaderMaterial

Every Blotter material relies on its mainImage property for rendering its effect through a Fragment shader or, to put it more accurately, what is called a "Pixel Shader".

What are pixel shaders?
If you render a full screen quad, meaning that each of four points is placed in one of the four corners of the viewport, then the fragment shader for that quad is called pixel shader, because you could say that now each fragment corresponds to exactly one pixel of the screen. So a pixel shader is a fragment shader for a fullscreen quad.
- https://stackoverflow.com/a/19452805

The mainImage

When you create a new Blotter Material, you supply it with a Pixel Shader, in the form of a string, that must define a mainImage function. This function generates rendered texts by computing a color for each pixel, and is called once per pixel. It will receive a fragCoord and must set the value of the mainImage out argument.

The prototype is as follows. If you've used Shadertoy this should feel familiar.

void mainImage(out vec4 mainImage, in vec2 fragCoord);

Given this format, the following would define an acceptable program, implementing the mainImage function to return any text rendered through it in the color red.

var mainImageSource = [
  "void mainImage(out vec4 mainImage, in vec2 fragCoord) {",
  "    vec2 uv = fragCoord.xy / uResolution.xy;",
  "    vec3 red = vec3(1.0, 0.0, 0.0); // (R, G, B)",
  "    mainImage = vec4(red, textTexture(uv).a);",
  "}"
].join("\n");

Those familiar with GLSL may notice the call to textTexture here. Normally in Fragment shaders one will call texture2D(sampler2D sampler, vec2 coord) in order to retrieve texel information at a given texture coordinate. However, in Blotter texts that share a material are mapped into an atlas to be rendered together. In order to make Blotter's GLSL API function in a predictable way, the complexity around this logic is abstracted away from the developer. For example, for any given text, fragCoord's x or y values will range from 0 to the full width or height of the given text, rather than of the full atlas texture. This is also true for uResolution. As such, you should think of your mainImage functions as simply rendering any individual text, and sample that text using Blotter's GLSL textTexture(vec2 coord) function, which will retrieve the proper texture information for you.

Defining a Material

Once you have a mainImage definition, you can create a custom Blotter material by instantiating a new Blotter.ShaderMaterial object.

The following will create a new instance of Blotter.ShaderMaterial where mainImageSource is the string representation of your Pixel Shader, and the uniforms object is empty.

var mainImageSource = [
  "void mainImage(out vec4 mainImage, in vec2 fragCoord) {",
  "    vec2 uv = fragCoord.xy / uResolution.xy;",
  "    vec3 red = vec3(1.0, 0.0, 0.0); // (R, G, B)",
  "    mainImage = vec4(red, textTexture(uv).a);",
  "}"
].join("\n");

var material = new Blotter.ShaderMaterial(mainImageSource, { uniforms : {} }); 

Using Uniforms

In the example mainImage we have been using so far, we have hardcoded the function so that texts rendered through it are output in the color red. However, if we wanted to make this Material more flexible we could utilize "uniforms" in order to render the texts in any color the user chooses.

Note: For those unfamiliar with uniforms in GLSL, it may be helpful to reference the The Basics and the Documentation sections of Blotter's documentation site, or go over this section in the Book of Shaders.

var mainImageSource = [
  "void mainImage(out vec4 mainImage, in vec2 fragCoord) {",
  "    vec2 uv = fragCoord.xy / uResolution.xy;",
  "    mainImage = vec4(uColor, textTexture(uv).a);",
  "}"
].join("\n");

var material = new Blotter.ShaderMaterial(mainImageSource, {
  uniforms : {
    uColor : { type : "3f", value : [1.0, 0.0, 0.0] } // (R, G, B)
  }
});

Now, if we wanted to update all texts rendered through the material to render in the color green, we'd simply need to update the value of the uColor uniform on our Material's instance.

material.uniforms.uColor.value = [0.0, 1.0, 0.0];

More coming soon.

Clone this wiki locally
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.