Create a Material For The Material Library

This tutorial will guide you through the process of creating a material for the materials library

Setting up environment

First of all, you need to create a folder for your shader in the /materialsLibrary/src folder. Let's call it diffuseEmissive. Then you need to create your files:

  • babylon.diffuseEmissiveMaterial.ts (just copy/paste from babylon.simpleMaterial.ts)
  • diffuseEmissive.vertex.fx (just copy/paste from simple.vertex.fx)
  • diffuseEmissive.fragment.fx (just copy/paste from simple.fragment.fx)

Then update the config.json file in the tools/gulp and add an entry in the "materialsLibrary/libraries" section of the file:

"libraries": [
...
{
"output": "babylon.triPlanarMaterial.min.js",
"entry": "./legacy/legacy-triPlanar.ts",
"preventLoadLibrary": true
}
...
]

To build all materials and generate the dist folder, just run from the tools/gulp folder:

gulp materialsLibrary

Update the shaders

Because we used the simple material as source, we already have everything required for a complete babylon.js material. The simple material already supports diffuse texture.

To add support for an emissive texture, let's add this code to the header of diffuseEmissive.vertex.fx file:

#ifdef EMISSIVE
varying vec2 vEmissiveUV;
uniform mat4 emissiveMatrix;
uniform vec2 vEmissiveInfos;
#endif

Then add this code in the main function:

#ifdef EMISSIVE
if (vEmissiveInfos.x == 0.)
{
vEmissiveUV = vec2(emissiveMatrix * vec4(uv, 1.0, 0.0));
}
else
{
vEmissiveUV = vec2(emissiveMatrix * vec4(uv2, 1.0, 0.0));
}
#endif

This code will generate the correct UV to read from emissive texture. Please note that we use #ifdef to take profit of the babylon.js smart shaders.

Then you have to update the fragment shader. First add this code to the header:

#ifdef EMISSIVE
varying vec2 vEmissiveUV;
uniform sampler2D emissiveSampler;
uniform vec2 vEmissiveInfos;
#endif

Then add this code at the end of the main function (just before the last line (gl_FragColor = ...):

#ifdef EMISSIVE
color.rgb += texture2D(emissiveSampler, vEmissiveUV) * vEmissiveInfos.y;
#endif

Update the material

First of all, rename all occurences of SimpleMaterialDefines to DiffuseEmissiveMaterialDefines and SimpleMaterial to DiffuseEmissiveMaterial.

Then add this property to SimpleMaterialDefines class:

public EMISSIVE = false;

Add this property to the DiffuseEmissiveMaterial class:

public emissiveTexture: BaseTexture;

Then go to isReady function and add this code in the if (scene.textureEnabled) block:

if (this.emissiveTexture && StandardMaterial.EmissiveTextureEnabled) {
if (!this.emissiveTexture.isReady()) {
return false;
} else {
needUVs = true;
this._defines.EMISSIVE = true;
}
}

The next function to update is bind. Add this code after the //Textures comment:

if (this.emissiveTexture && StandardMaterial.EmissiveTextureEnabled) {
this._effect.setTexture("emissiveSampler", this.emissiveTexture);
this._effect.setFloat2(
"vEmissiveInfos",
this.emissiveTexture.coordinatesIndex,
this.emissiveTexture.level
);
this._effect.setMatrix(
"emissiveMatrix",
this.emissiveTexture.getTextureMatrix()
);
}

You may also need to add this code to the clone function:

if (this.emissiveTexture && this.emissiveTexture.clone) {
newMaterial.emissiveTexture = this.emissiveTexture.clone();
}

For completeness, you will also have to complete the serialize and Parse functions (This is only required if you want to save/load your material to a .babylon file). Please note that serialize function needs to output the complete material name to the serializationObject like here:

serializationObject.customType = "BABYLON.SimplelMaterial";

And you're done for the material! Now it is time to test it.

Update the test page

To test your material, open the /materialsLibrary/index.html page. References are added automatically.

Then add the material at line 120:

var diffuseEmissive = new BABYLON.DiffuseEmissiveMaterial(
"diffuseEmissive",
scene
);
diffuseEmissive.diffuseTexture = new BABYLON.Texture(
"textures/amiga.jpg",
scene
);
diffuseEmissive.diffuseTexture.uScale = 5;
diffuseEmissive.diffuseTexture.vScale = 5;
diffuseEmissive.emissiveTexture = new BABYLON.Texture(
"textures/amiga.jpg",
scene
);
diffuseEmissive.emissiveTexture.uScale = 10;
diffuseEmissive.emissiveTexture.vScale = 10;

Finally update the UI control:

gui
.add(options, "material", ["standard", "simple", "diffuseEmissive"])
.onFinishChange(function() {
switch (options.material) {
case "diffuseEmissive":
currentMaterial = diffuseEmissive;
break;
case "simple":
currentMaterial = simple;
break;
default:
currentMaterial = std;
break;
}
currentMesh.material = currentMaterial;
});

Launch the test server

To Launch the server, you can start from the tools/gulp folder:

gulp webserver

Using the material with Babylon.js file loader

Babylon.js file format supports the use of custom material. You must provide a serialize() and a Parse() functions alongside with a getClassName() function. To let the loader knows about your material, you will also need to add the following line to the code using your material:

Tools.RegisteredExternalClasses["MyMaterial"] = MyMaterial;

This code will add your class to the list of supported external classes so that the loader will be able to instantiate it when loading a .babylon file with a reference to your material.