Three.js GLSL ShaderMaterial Tuto 2

ShaderMaterial and GLSL – Our first Shader

This publication is the second part of the GLSL theme, I advise you to read the first part if you have not already done so :

The ShaderMaterial class

Constructor

Let’s start with ShaderMaterial : We use this class to create a material with a custom GLSL shader.

The constructor of ShaderMaterial accepts one parameter : A JavaScript object used to configure the class instance.

There are three main elements that make up a ShaderMaterial instance :

  • A Vertex Shader function ( GLSL Code )
  • A Fragment Shader function ( GLSL Code )
  • Uniforms ( JavaScript object )

Vertex and Fragment Shader – Introduction

As explained, a shader is composed of two main functions : Vertex Shader and Fragment Shader.

Vertex shader and fragment shader
The GLSL code for Vertex & Fragment Shaders

These two functions are written in GLSL, and manipulated in JavaScript Template formatted Strings.

Vertex and Fragment Shader – How to use

When we use ShaderMaterial with a Geometry to create a Mesh, the GLSL code of our shader will modify the final visual aspect of the 3D object.

Concretely:

  • The GLSL code of Vertex Shader is executed for each vertex of the 3D object’s structure
  • The GLSL code of Fragment Shader calculates the color of each pixel of the faces of the 3D object
Vertex Shader and Fragment Shader
Vertex Shader and Fragment Shader

Thus, it is possible to modify the shape of the 3D structure with Vertex Shader, and create color effects with Fragment Shader

The JavaScript Uniforms object

And finally, the JavaScript Uniforms object is the third element composing an instance of ShaderMaterial.

It is an optional element, structured with a key/value system, allowing to transfer data between JavaScript and GLSL.

ShaderMaterial Uniforms
ShaderMaterial Uniforms

Uniforms is an optional element, but very useful when making complex shaders ! We will not use it in this article.

Our first Shader

Setting up the bases

Let’s create our first shader with GLSL and ShaderMaterial!

Let’s start by creating a simple cube in a basic scene :

var boxGeo = new THREE.BoxGeometry(2,2,2);
var boxMat = new THREE.MeshPhongMaterial();
boxmesh = new THREE.Mesh(boxGeo, boxMat);
scene.add(boxmesh);
A basic cube
A basic cube

The Three.js materials classes offers a lot of customization options, but let’s imagine that we want to create our own visual effect !

To do this, let’s create an instance of ShaderMaterial :

var myshader =  new THREE.ShaderMaterial({
  uniforms         : uniforms,
  fragmentShader    : fragmentShader(),
  vertexShader        : vertexShader(),
});

Remember ! A ShaderMaterial instance is composed of three elements :

  • A Vertex Shader function ( GLSL Code )
  • A Fragment Shader function ( GLSL Code )
  • Uniforms ( JavaScript object )

Let’s continue by creating an ultra basic version of these three elements :

var uniforms = {};

function vertexShader()
{
    //GLSL Code
    return ` `;
}

function fragmentShader()
{
    //GLSL Code
    return ` `;
}  

Each vertexShader and fragmentShader function we just created returns a Template formated String : This string will contain our GLSL code.

Vertex Shader

Let’s start with vertexShader, the GLSL code that will be applied to each vertex of our 3D object structure :

function vertexShader()
{
    return `
    void main()
    {
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
    `;
}

GLSL is a very specific language, I will unfortunately not be able to teach it to you in a few lines haha !

But, we can still comment a bit on this minimalist code :

  • The main function will be the entry point of the GLSL shader
  • The syntax of GLSL is based on C
  • vec4 is a base type representing a four dimensional vector
  • gl_Position is a built-in shader variable representing the wanted position of the current vertex

Concretely, this line of code will simply draw each vertex of the 3D object according to the observation point, without modifying the global shape of the structure.

Fragment Shader

Let’s continue with fragmentShader, the GLSL code applied on each pixel of the faces of our 3D object :

function fragmentShader()
{
  return `
      void main()
      {
         gl_FragColor = vec4( 1.0, 1.0, 0.0, 1.0);
      }
  `;
}

As for vertexShader, I will comment a little on this minimalist code :

  • gl_FragColor is a built-in shader variable representing the color of the current pixel
  • The value of gl_FragColor is a vec4 whose first three values represent the desired RGB color
  • Each RGB value is between 0.0 and 1.0 ( For this example, I have chosen yellow )

Concretely, this basic GLSL code will define the color of each pixel of our 3D object by a raw yellow.

Final result

Our GLSL shader is finally ready, let’s replace the Material of our cube by our instance of ShaderMaterial :

var myshader =  new THREE.ShaderMaterial({
  uniforms         : uniforms,
  fragmentShader    : fragmentShader(),
  vertexShader        : vertexShader(),
});

var boxGeo = new THREE.BoxGeometry(2,2,2);
var boxMat = new THREE.MeshPhongMaterial();
boxmesh = new THREE.Mesh(boxGeo, myshader);
scene.add(boxmesh);
Our first ShaderMaterial
Our first ShaderMaterial !

As expected, the cube is colored with a yellow color !

GLSL offers almost infinite possibilities, to continue to discover this language, let’s continue in future publications !

One comment

Comments are closed.