API

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 the environment

First of all, you need to create a folder for your shader in the /packages/dev/materials/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)

Update the shaders

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

To add support for an emissive texture, let's add this code to the header of the 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 the emissive texture. Please note that we use #ifdef to take advantage 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 occurrences of SimpleMaterialDefines to DiffuseEmissiveMaterialDefines and SimpleMaterial to DiffuseEmissiveMaterial.

Then add this property to the DiffuseEmissiveMaterialDefines 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 the bind function. 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 the serialize function needs to output the complete material name to the serializationObject, as shown here:

serializationObject.customType = "BABYLON.DiffuseEmissiveMaterial";

And you're done with 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:

const 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;
});

Testing your material

After adding the files, the material will be available in the local babylon server and the playground. If you use VSCode, select the task you want to start—if you want to edit code, run the local playground.

To start the babylon server, which will also track your changes and rebuild when needed, run npm start or use VSCode.

Using the material with Babylon.js file loader

The Babylon.js file format supports the use of custom materials. You must provide serialize(), Parse(), and getClassName() functions. To let the loader know 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.