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.
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
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.
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 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);
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);
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 !
[…] ShaderMaterial and GLSL – Our first Shader […]