How to recreate PBR with the NodeMaterial

Hey,

I have a model and it has 12 meshes in it. All the meshes material are made of PBR material. I m trying to recreate the PBR material with nodeMaterial. Any help how to map from PBR to NodeMaterial?

@Deltakosh - When I search on the forum if there is similar question, I found this question -
Cast from nodematerial to PBRMaterial - Questions - Babylon.js (babylonjs.com) and you mentioned a suggestion on the question, what I needed now. Can you give me a hint how I can implement it?

Thanks in advance.

It is all in the doc Node Material | Babylon.js Documentation

2 Likes

@sebavan Thanks for the link.

Some of the mapping I tried works → albedoColor to baseColor, metallicTexture to metallic & Roughness, abmientTexture to ambientColor from PRBMaterial to PBRMetallicRoughnessMaterial.
But I m a kind of lost where/how to map albedoTexture, reflectionTexture, reflectionColor, and bumpTexture values of PBRMaterial on PBRMetallicRoughnessMaterial?

thanks

albedoTexture, you need to multiply with your albedoColor before placing inside of the baseColor node.

reflectionnTexture is using the reflection block


which either use the environmentTexture or your own defined ones

reflectionColor is indeed defined on the previous block

bumpTexture is used through the perturb normal block:

2 Likes

@sebavan Thank you so much. Let me try to implement it and if I have a question, I will come back again. :slight_smile:

1 Like

@sebavan I would like to thank you so much again. Every thing works. I have one minor question - I can’t open the node material editor from Inspector.

The node material build successfully and gives me the expected output. And also I was able to generate the code using nodeMaterial.generateCode(); from the function. I get the texture file from the back-end API, does that create an issue?

Here is the error message I get

NodeMaterialError

Here is the graph I constructed based on the generated code.

Here is the generated code

var nodeMaterial = new BABYLON.NodeMaterial("NM_plasticsFoot");

// InputBlock
var position = new BABYLON.InputBlock("position");
position.setAsAttribute("position");

// TransformBlock
var WorldPos = new BABYLON.TransformBlock("WorldPos");
WorldPos.complementZ = 0;
WorldPos.complementW = 1;

// InputBlock
var World = new BABYLON.InputBlock("World");
World.setAsSystemValue(BABYLON.NodeMaterialSystemValues.World);

// TransformBlock
var Worldnormal = new BABYLON.TransformBlock("World normal");
Worldnormal.complementZ = 0;
Worldnormal.complementW = 0;

// InputBlock
var normal = new BABYLON.InputBlock("normal");
normal.setAsAttribute("normal");

// PBRMetallicRoughnessBlock
var PBRMetallicRoughness = new BABYLON.PBRMetallicRoughnessBlock("PBRMetallicRoughness");
PBRMetallicRoughness.lightFalloff = 0;
PBRMetallicRoughness.useAlphaTest = false;
PBRMetallicRoughness.alphaTestCutoff = 0.5;
PBRMetallicRoughness.useAlphaBlending = false;
PBRMetallicRoughness.useRadianceOverAlpha = true;
PBRMetallicRoughness.useSpecularOverAlpha = true;
PBRMetallicRoughness.enableSpecularAntiAliasing = false;
PBRMetallicRoughness.realTimeFiltering = false;
PBRMetallicRoughness.realTimeFilteringQuality = 8;
PBRMetallicRoughness.useEnergyConservation = true;
PBRMetallicRoughness.useRadianceOcclusion = true;
PBRMetallicRoughness.useHorizonOcclusion = true;
PBRMetallicRoughness.unlit = false;
PBRMetallicRoughness.forceNormalForward = false;
PBRMetallicRoughness.debugMode = 0;
PBRMetallicRoughness.debugLimit = 0;
PBRMetallicRoughness.debugFactor = 1;

// InputBlock
var view = new BABYLON.InputBlock("view");
view.setAsSystemValue(BABYLON.NodeMaterialSystemValues.View);

// InputBlock
var cameraPosition = new BABYLON.InputBlock("cameraPosition");
cameraPosition.setAsSystemValue(BABYLON.NodeMaterialSystemValues.CameraPosition);

// InputBlock
var baseColorFactor = new BABYLON.InputBlock("baseColorFactor");
baseColorFactor.value = new BABYLON.Color3(0.04026846, 0.04026846, 0.04026846);
baseColorFactor.isConstant = false;

// TextureBlock
var MetallicRoughnessTexture = new BABYLON.TextureBlock("MetallicRoughnessTexture");
MetallicRoughnessTexture.texture = new BABYLON.Texture("api_url_to get_the_texture", null);
MetallicRoughnessTexture.texture.wrapU = 1;
MetallicRoughnessTexture.texture.wrapV = 1;
MetallicRoughnessTexture.texture.uAng = 0;
MetallicRoughnessTexture.texture.vAng = 0;
MetallicRoughnessTexture.texture.wAng = 0;
MetallicRoughnessTexture.texture.uOffset = 0;
MetallicRoughnessTexture.texture.vOffset = 0;
MetallicRoughnessTexture.texture.uScale = 1;
MetallicRoughnessTexture.texture.vScale = 1;
MetallicRoughnessTexture.convertToGammaSpace = false;
MetallicRoughnessTexture.convertToLinearSpace = true;

// InputBlock
var uv = new BABYLON.InputBlock("uv");
uv.setAsAttribute("uv");

// TextureBlock
var AmbientTexture = new BABYLON.TextureBlock("AmbientTexture");
AmbientTexture.texture = new BABYLON.Texture("api_url_to get_the_texture", null);
AmbientTexture.texture.wrapU = 1;
AmbientTexture.texture.wrapV = 1;
AmbientTexture.texture.uAng = 0;
AmbientTexture.texture.vAng = 0;
AmbientTexture.texture.wAng = 0;
AmbientTexture.texture.uOffset = 0;
AmbientTexture.texture.vOffset = 0;
AmbientTexture.texture.uScale = 1;
AmbientTexture.texture.vScale = 1;
AmbientTexture.convertToGammaSpace = false;
AmbientTexture.convertToLinearSpace = true;

// ScaleBlock
var Scale = new BABYLON.ScaleBlock("Scale");
Scale.visibleInInspector = false;

// InputBlock
var Vector = new BABYLON.InputBlock("Vector3");
Vector.value = new BABYLON.Vector3(0.76, 0.76, 0.76);
Vector.isConstant = false;

// ColorSplitterBlock
var ColorSplitter = new BABYLON.ColorSplitterBlock("ColorSplitter");
ColorSplitter.visibleInInspector = false;

// ReflectionBlock
var Reflection = new BABYLON.ReflectionBlock("Reflection");
Reflection.useSphericalHarmonics = true;
Reflection.forceIrradianceInFragment = false;

// FragmentOutputBlock
var FragmentOutput = new BABYLON.FragmentOutputBlock("FragmentOutput");
FragmentOutput.visibleInInspector = false;

// TransformBlock
var WorldPosViewProjectionTransform = new BABYLON.TransformBlock("WorldPos * ViewProjectionTransform");
WorldPosViewProjectionTransform.complementZ = 0;
WorldPosViewProjectionTransform.complementW = 1;

// InputBlock
var ViewProjection = new BABYLON.InputBlock("ViewProjection");
ViewProjection.setAsSystemValue(BABYLON.NodeMaterialSystemValues.ViewProjection);

// VertexOutputBlock
var VertexOutput = new BABYLON.VertexOutputBlock("VertexOutput");
VertexOutput.visibleInInspector = false;

// Connections
position.output.connectTo(WorldPos.vector);
World.output.connectTo(WorldPos.transform);
WorldPos.output.connectTo(WorldPosViewProjectionTransform.vector);
ViewProjection.output.connectTo(WorldPosViewProjectionTransform.transform);
WorldPosViewProjectionTransform.output.connectTo(VertexOutput.vector);

WorldPos.output.connectTo(PBRMetallicRoughness.worldPosition);
normal.output.connectTo(Worldnormal.vector);
World.output.connectTo(Worldnormal.transform);
Worldnormal.output.connectTo(PBRMetallicRoughness.worldNormal);

view.output.connectTo(PBRMetallicRoughness.view);
cameraPosition.output.connectTo(PBRMetallicRoughness.cameraPosition);
baseColorFactor.output.connectTo(PBRMetallicRoughness.baseColor);

uv.output.connectTo(MetallicRoughnessTexture.uv);
MetallicRoughnessTexture.b.connectTo(PBRMetallicRoughness.metallic);
Vector.output.connectTo(Scale.input);
MetallicRoughnessTexture.g.connectTo(Scale.factor);
Scale.output.connectTo(ColorSplitter.rgbIn);
ColorSplitter.g.connectTo(PBRMetallicRoughness.roughness);

uv.output.connectTo(AmbientTexture.uv);
AmbientTexture.rgb.connectTo(PBRMetallicRoughness.ambientColor);

position.output.connectTo(Reflection.position);
World.output.connectTo(Reflection.world);
Reflection.reflection.connectTo(PBRMetallicRoughness.reflection);

PBRMetallicRoughness.lighting.connectTo(FragmentOutput.rgb);

// Output nodes
nodeMaterial.addOutputNode(VertexOutput);
nodeMaterial.addOutputNode(FragmentOutput);
nodeMaterial.build();

Thanks in advance. :slight_smile:

Could you repro in the playgound? So that @Evgeni_Popov may have a look :wink:

I reproduced the material here: Babylon.js Playground (babylonjs-playground.com)

and I can open it in nme from the inspector:

Do you mind updating that PG so we can have a look?

3 Likes

@Deltakosh Thank you for the playground. Here is my update - NodeMaterial_generation_from_code | Babylon.js Playground (babylonjs-playground.com)

I tried to apply the general framework of my project code base with a test data on the playground and I am able to open the node material editor. I can’t reproduce the error I m facing on my end. My project is based on typescript, hopefully that wouldn’t cause the problem.

I will keep looking and post my update.

Thanks again!

1 Like

No TS cannot cause that issue for sure (we are also developing with TS)

Please keep us updated if you find what is the culprit :wink:

1 Like

@Deltakosh I come back after long time and many trial. I hope this will explain my issue well.

Here is what I found. I tried to implement the same code using javascript and typescript. And the JS worked but TypeScript doesn’t.

Here is my javascript code

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Node Material Test</title>

    <script src="https://cdn.babylonjs.com/babylon.js"></script>
    <script src="https://cdn.babylonjs.com/loaders/babylonjs.loaders.min.js"></script>
</head>
<body>
    <canvas id='canvas' style="width: 100%; height: 100hv;"></canvas>
    <script>
        var canvas = document.getElementById('canvas');
        var engine = new BABYLON.Engine(canvas, true);
        var scene = new BABYLON.Scene(engine);
        scene.debugLayer.show();
        var camera = new BABYLON.FreeCamera("camera1", new BABYLON.Vector3(0, 5, -10), scene);
        camera.setTarget(BABYLON.Vector3.Zero());
        camera.attachControl(canvas, true);

        var light = new BABYLON.HemisphericLight("light", new BABYLON.Vector3(0, 1, 0), scene);
        light.intensity = 0.7;

        var sphere = BABYLON.MeshBuilder.CreateSphere("sphere", {diameter: 2, segments: 32}, scene);
        sphere.position.y = 1;
        sphere.material = getNodeMaterial();

        var ground = BABYLON.MeshBuilder.CreateGround("ground", {width: 6, height: 6}, scene);

        engine.runRenderLoop(function () {
            scene.render();
        });

        function getNodeMaterial() {
            var nodeMaterial = new BABYLON.NodeMaterial("node");

            // InputBlock
            var position = new BABYLON.InputBlock("position");
            position.visibleInInspector = false;
            position.target = 1;
            position.setAsAttribute("position");

            // TransformBlock
            var WorldPos = new BABYLON.TransformBlock("WorldPos");
            WorldPos.visibleInInspector = false;
            WorldPos.target = 1;
            WorldPos.complementZ = 0;
            WorldPos.complementW = 1;

            // InputBlock
            var World = new BABYLON.InputBlock("World");
            World.visibleInInspector = false;
            World.target = 1;
            World.setAsSystemValue(BABYLON.NodeMaterialSystemValues.World);

            // TransformBlock
            var WorldPosViewProjectionTransform = new BABYLON.TransformBlock("WorldPos * ViewProjectionTransform");
            WorldPosViewProjectionTransform.visibleInInspector = false;
            WorldPosViewProjectionTransform.target = 1;
            WorldPosViewProjectionTransform.complementZ = 0;
            WorldPosViewProjectionTransform.complementW = 1;

            // InputBlock
            var ViewProjection = new BABYLON.InputBlock("ViewProjection");
            ViewProjection.visibleInInspector = false;
            ViewProjection.target = 1;
            ViewProjection.setAsSystemValue(BABYLON.NodeMaterialSystemValues.ViewProjection);

            // VertexOutputBlock
            var VertexOutput = new BABYLON.VertexOutputBlock("VertexOutput");
            VertexOutput.visibleInInspector = false;
            VertexOutput.target = 1;

            // InputBlock
            var color = new BABYLON.InputBlock("color");
            color.visibleInInspector = false;
            color.target = 1;
            color.value = new BABYLON.Color4(0.8, 0.8, 0.8, 1);
            color.isConstant = false;

            // FragmentOutputBlock
            var FragmentOutput = new BABYLON.FragmentOutputBlock("FragmentOutput");
            FragmentOutput.visibleInInspector = false;
            FragmentOutput.target = 2;

            // Connections
            position.output.connectTo(WorldPos.vector);
            World.output.connectTo(WorldPos.transform);
            WorldPos.output.connectTo(WorldPosViewProjectionTransform.vector);
            ViewProjection.output.connectTo(WorldPosViewProjectionTransform.transform);
            WorldPosViewProjectionTransform.output.connectTo(VertexOutput.vector);
            color.output.connectTo(FragmentOutput.rgba);

            // Output nodes
            nodeMaterial.addOutputNode(VertexOutput);
            nodeMaterial.addOutputNode(FragmentOutput);
            nodeMaterial.build();

            return nodeMaterial;
        }
    </script>
</body>
</html>

Here is the result I get

For TypeScript I tried to using babylonjs-typescript-starter-master ( GitHub - oktinaut/babylonjs-typescript-starter: Sample BABYLON.js application using Typescript and Webpack) and update the index.ts page. It looks like this

import "@babylonjs/core/Debug/debugLayer";
import "@babylonjs/inspector";

import * as BABYLON from '@babylonjs/core';
import { ArcRotateCamera } from "@babylonjs/core/Cameras/arcRotateCamera"
import { Engine } from "@babylonjs/core/Engines/engine"
import { HemisphericLight } from "@babylonjs/core/Lights/hemisphericLight"
import { MeshBuilder } from "@babylonjs/core/Meshes/meshBuilder"
import { Scene } from "@babylonjs/core/scene"
import { Vector3 } from "@babylonjs/core/Maths/math.vector"

import { SampleMaterial } from "./Materials/SampleMaterial"

const view = document.getElementById("view") as HTMLCanvasElement
const engine = new Engine(view, true)

let scene = new Scene(engine);
scene.debugLayer.show();

const camera = new ArcRotateCamera(
    "camera",
    Math.PI / 2,
    Math.PI / 3.2,
    2,
    Vector3.Zero(),
    scene)

camera.attachControl(view)

const light = new HemisphericLight(
    "light",
    new Vector3(0, 1, 0),
    scene)

const mesh = MeshBuilder.CreateGround("mesh", {}, scene)

// const material =  new SampleMaterial("material", scene)
// mesh.material = material;
mesh.material = getNodeMaterial();

engine.runRenderLoop(() => {
    scene.render();
});

function getNodeMaterial() {
    var nodeMaterial = new BABYLON.NodeMaterial("node");

    // InputBlock
    var position = new BABYLON.InputBlock("position");
    position.visibleInInspector = false;
    position.target = 1;
    position.setAsAttribute("position");

    // TransformBlock
    var WorldPos = new BABYLON.TransformBlock("WorldPos");
    WorldPos.visibleInInspector = false;
    WorldPos.target = 1;
    WorldPos.complementZ = 0;
    WorldPos.complementW = 1;

    // InputBlock
    var World = new BABYLON.InputBlock("World");
    World.visibleInInspector = false;
    World.target = 1;
    World.setAsSystemValue(BABYLON.NodeMaterialSystemValues.World);

    // TransformBlock
    var WorldPosViewProjectionTransform = new BABYLON.TransformBlock("WorldPos * ViewProjectionTransform");
    WorldPosViewProjectionTransform.visibleInInspector = false;
    WorldPosViewProjectionTransform.target = 1;
    WorldPosViewProjectionTransform.complementZ = 0;
    WorldPosViewProjectionTransform.complementW = 1;

    // InputBlock
    var ViewProjection = new BABYLON.InputBlock("ViewProjection");
    ViewProjection.visibleInInspector = false;
    ViewProjection.target = 1;
    ViewProjection.setAsSystemValue(BABYLON.NodeMaterialSystemValues.ViewProjection);

    // VertexOutputBlock
    var VertexOutput = new BABYLON.VertexOutputBlock("VertexOutput");
    VertexOutput.visibleInInspector = false;
    VertexOutput.target = 1;

    // InputBlock
    var color = new BABYLON.InputBlock("color");
    color.visibleInInspector = false;
    color.target = 1;
    color.value = new BABYLON.Color4(0.8, 0.8, 0.8, 1);
    color.isConstant = false;

    // FragmentOutputBlock
    var FragmentOutput = new BABYLON.FragmentOutputBlock("FragmentOutput");
    FragmentOutput.visibleInInspector = false;
    FragmentOutput.target = 2;

    // Connections
    position.output.connectTo(WorldPos.vector);
    World.output.connectTo(WorldPos.transform);
    WorldPos.output.connectTo(WorldPosViewProjectionTransform.vector);
    ViewProjection.output.connectTo(WorldPosViewProjectionTransform.transform);
    WorldPosViewProjectionTransform.output.connectTo(VertexOutput.vector);
    color.output.connectTo(FragmentOutput.rgba);

    // Output nodes
    nodeMaterial.addOutputNode(VertexOutput);
    nodeMaterial.addOutputNode(FragmentOutput);
    nodeMaterial.build();

    return nodeMaterial;
}

And here is what I get when I tried to open Node Material Editor

Please let me know if I need to test it more or do something. :slight_smile:

Thanks,

Can you try renaming import * as BABYLON from ‘@babylonjs/core’; to import * as TEST from ‘@babylonjs/core’; for instance ?

@sebavan thanks for the reply. I tried what you suggest and I get the same error.

maybe @RaananW could help with this part of the setup ?

Sure!!

@Yofetahe_Habtu - if I missed it I am sorry, but - can you share the project you are using so I can understand the scenario better?

@RaananW Sorry I can’t share my project, the policy prohibited me to do that. But the issue is, as I tried to put in the previous sample codes, I get an error when I tried to open the NodeMaterial Editor. If you try to open the editor from this -

import "@babylonjs/core/Debug/debugLayer";
import "@babylonjs/inspector";

import * as BABYLON from '@babylonjs/core';
import { ArcRotateCamera } from "@babylonjs/core/Cameras/arcRotateCamera"
import { Engine } from "@babylonjs/core/Engines/engine"
import { HemisphericLight } from "@babylonjs/core/Lights/hemisphericLight"
import { MeshBuilder } from "@babylonjs/core/Meshes/meshBuilder"
import { Scene } from "@babylonjs/core/scene"
import { Vector3 } from "@babylonjs/core/Maths/math.vector"

import { SampleMaterial } from "./Materials/SampleMaterial"

const view = document.getElementById("view") as HTMLCanvasElement
const engine = new Engine(view, true)

let scene = new Scene(engine);
scene.debugLayer.show();

const camera = new ArcRotateCamera(
    "camera",
    Math.PI / 2,
    Math.PI / 3.2,
    2,
    Vector3.Zero(),
    scene)

camera.attachControl(view)

const light = new HemisphericLight(
    "light",
    new Vector3(0, 1, 0),
    scene)

const mesh = MeshBuilder.CreateGround("mesh", {}, scene)

// const material =  new SampleMaterial("material", scene)
// mesh.material = material;
mesh.material = getNodeMaterial();

engine.runRenderLoop(() => {
    scene.render();
});

function getNodeMaterial() {
    var nodeMaterial = new BABYLON.NodeMaterial("node");

    // InputBlock
    var position = new BABYLON.InputBlock("position");
    position.visibleInInspector = false;
    position.target = 1;
    position.setAsAttribute("position");

    // TransformBlock
    var WorldPos = new BABYLON.TransformBlock("WorldPos");
    WorldPos.visibleInInspector = false;
    WorldPos.target = 1;
    WorldPos.complementZ = 0;
    WorldPos.complementW = 1;

    // InputBlock
    var World = new BABYLON.InputBlock("World");
    World.visibleInInspector = false;
    World.target = 1;
    World.setAsSystemValue(BABYLON.NodeMaterialSystemValues.World);

    // TransformBlock
    var WorldPosViewProjectionTransform = new BABYLON.TransformBlock("WorldPos * ViewProjectionTransform");
    WorldPosViewProjectionTransform.visibleInInspector = false;
    WorldPosViewProjectionTransform.target = 1;
    WorldPosViewProjectionTransform.complementZ = 0;
    WorldPosViewProjectionTransform.complementW = 1;

    // InputBlock
    var ViewProjection = new BABYLON.InputBlock("ViewProjection");
    ViewProjection.visibleInInspector = false;
    ViewProjection.target = 1;
    ViewProjection.setAsSystemValue(BABYLON.NodeMaterialSystemValues.ViewProjection);

    // VertexOutputBlock
    var VertexOutput = new BABYLON.VertexOutputBlock("VertexOutput");
    VertexOutput.visibleInInspector = false;
    VertexOutput.target = 1;

    // InputBlock
    var color = new BABYLON.InputBlock("color");
    color.visibleInInspector = false;
    color.target = 1;
    color.value = new BABYLON.Color4(0.8, 0.8, 0.8, 1);
    color.isConstant = false;

    // FragmentOutputBlock
    var FragmentOutput = new BABYLON.FragmentOutputBlock("FragmentOutput");
    FragmentOutput.visibleInInspector = false;
    FragmentOutput.target = 2;

    // Connections
    position.output.connectTo(WorldPos.vector);
    World.output.connectTo(WorldPos.transform);
    WorldPos.output.connectTo(WorldPosViewProjectionTransform.vector);
    ViewProjection.output.connectTo(WorldPosViewProjectionTransform.transform);
    WorldPosViewProjectionTransform.output.connectTo(VertexOutput.vector);
    color.output.connectTo(FragmentOutput.rgba);

    // Output nodes
    nodeMaterial.addOutputNode(VertexOutput);
    nodeMaterial.addOutputNode(FragmentOutput);
    nodeMaterial.build();

    return nodeMaterial;
}

it will give you the same error I m getting on my project.

thanks in advance.

Understandable, will be a little harder to help though :slight_smile:

Are you including the node material editor package in your project? can you start it manually, or is it a global project issue?

@RaananW hmm… my previous project was javascript base and we included core, loaders, validators and gui libraries and I can start/open the node material editor. We are switching to typescript and we includes core, inspector, loaders and also I tried to include node-editor ‘4.2.0’ libraries now. But I can’t start/open the node material editor with the same code.

I tried to look at the list of packages ( npm (npmjs.com) ) and tried to include node-editor. is there other package I need to install?

Since you are using the es6 packages you will need this - @babylonjs/node-editor - npm (npmjs.com).

I know you can’t share the project, can you reproduce is with a simple project (just a sphere) so I can understand what is happening there?

@RaananW, the code that I shared on our chat earlier was a sample project. I tried to using babylonjs-typescript-starter-master ( GitHub - oktinaut/babylonjs-typescript-starter: Sample BABYLON.js application using Typescript and Webpack) and update the index.ts page with this

import "@babylonjs/core/Debug/debugLayer";
import "@babylonjs/inspector";

import * as BABYLON from '@babylonjs/core';
import { ArcRotateCamera } from "@babylonjs/core/Cameras/arcRotateCamera"
import { Engine } from "@babylonjs/core/Engines/engine"
import { HemisphericLight } from "@babylonjs/core/Lights/hemisphericLight"
import { MeshBuilder } from "@babylonjs/core/Meshes/meshBuilder"
import { Scene } from "@babylonjs/core/scene"
import { Vector3 } from "@babylonjs/core/Maths/math.vector"

import { SampleMaterial } from "./Materials/SampleMaterial"

const view = document.getElementById("view") as HTMLCanvasElement
const engine = new Engine(view, true)

let scene = new Scene(engine);
scene.debugLayer.show();

const camera = new ArcRotateCamera(
    "camera",
    Math.PI / 2,
    Math.PI / 3.2,
    2,
    Vector3.Zero(),
    scene)

camera.attachControl(view)

const light = new HemisphericLight(
    "light",
    new Vector3(0, 1, 0),
    scene)

const mesh = MeshBuilder.CreateGround("mesh", {}, scene)

// const material =  new SampleMaterial("material", scene)
// mesh.material = material;
mesh.material = getNodeMaterial();

engine.runRenderLoop(() => {
    scene.render();
});

function getNodeMaterial() {
    var nodeMaterial = new BABYLON.NodeMaterial("node");

    // InputBlock
    var position = new BABYLON.InputBlock("position");
    position.visibleInInspector = false;
    position.target = 1;
    position.setAsAttribute("position");

    // TransformBlock
    var WorldPos = new BABYLON.TransformBlock("WorldPos");
    WorldPos.visibleInInspector = false;
    WorldPos.target = 1;
    WorldPos.complementZ = 0;
    WorldPos.complementW = 1;

    // InputBlock
    var World = new BABYLON.InputBlock("World");
    World.visibleInInspector = false;
    World.target = 1;
    World.setAsSystemValue(BABYLON.NodeMaterialSystemValues.World);

    // TransformBlock
    var WorldPosViewProjectionTransform = new BABYLON.TransformBlock("WorldPos * ViewProjectionTransform");
    WorldPosViewProjectionTransform.visibleInInspector = false;
    WorldPosViewProjectionTransform.target = 1;
    WorldPosViewProjectionTransform.complementZ = 0;
    WorldPosViewProjectionTransform.complementW = 1;

    // InputBlock
    var ViewProjection = new BABYLON.InputBlock("ViewProjection");
    ViewProjection.visibleInInspector = false;
    ViewProjection.target = 1;
    ViewProjection.setAsSystemValue(BABYLON.NodeMaterialSystemValues.ViewProjection);

    // VertexOutputBlock
    var VertexOutput = new BABYLON.VertexOutputBlock("VertexOutput");
    VertexOutput.visibleInInspector = false;
    VertexOutput.target = 1;

    // InputBlock
    var color = new BABYLON.InputBlock("color");
    color.visibleInInspector = false;
    color.target = 1;
    color.value = new BABYLON.Color4(0.8, 0.8, 0.8, 1);
    color.isConstant = false;

    // FragmentOutputBlock
    var FragmentOutput = new BABYLON.FragmentOutputBlock("FragmentOutput");
    FragmentOutput.visibleInInspector = false;
    FragmentOutput.target = 2;

    // Connections
    position.output.connectTo(WorldPos.vector);
    World.output.connectTo(WorldPos.transform);
    WorldPos.output.connectTo(WorldPosViewProjectionTransform.vector);
    ViewProjection.output.connectTo(WorldPosViewProjectionTransform.transform);
    WorldPosViewProjectionTransform.output.connectTo(VertexOutput.vector);
    color.output.connectTo(FragmentOutput.rgba);

    // Output nodes
    nodeMaterial.addOutputNode(VertexOutput);
    nodeMaterial.addOutputNode(FragmentOutput);
    nodeMaterial.build();

    return nodeMaterial;
}

It will reproduce the same issue.