Ok let’s get something out of the way, right out of the gate. This post is not for the faint of heart, we’re going to dive into something fairly mind-bending, but don’t give up…stay with me and I promise you’ll have some fun!
When Babylon.js introduced the Node Material Editor in version 4.1, it was a complete game changer for me. It’s like someone handed me a car when I had been crawling for my entire life.
It was a gift, a tool that allowed me to embark on an absolutely crazy journey, from overcoming some pretty crippling self-doubt, to attempting to recreate some of the earth’s most beautiful natural patterns.
You see, I like math. I like it a lot, but I’m also more ignorant on the subject than I’d care to admit.
Combine that ignorance with a relentless stubbornness for learning, and you end up with a strong drive to overcome what you don’t know. The Node Material Editor has empowered me to drive faster and further than I ever thought possible in the area of using math to drive visuals.
For anyone who isn’t familiar with the Node Material Editor in Babylon.js, it is an incredibly powerful node-based tool that allows you to visually assemble programs that run specifically on the GPU, or more commonly known as “shaders.” You can drag in a variety of different nodes, hook them together and turn something like this:
into something like this:
Most people use the Node Material by creating shaders by hand, dragging and connecting nodes inside of the editor. Many, however, don’t know that there is an entirely different way that you can do it as well. One that shifts into a whole new gear of power!
Imagine the possibilities if you could use the same system, but create node trees through code! Better yet, what if you could introduce randomization into the process to randomly generate different branches of your node trees. What if the number of branches, and the size of your tree was entirely randomly generated! The possibilities suddenly appear quite limitless!
Ok enough hyperbole, let’s do this!
This playground is going to serve as an example of this exact theory, and we’ll go over it together. Spoiler alert, it is NOT beautiful, but it does convey the idea well.
Here’s the idea at the highest level:
- Create a plane.
- Create a node material (from code) with a random number of branches.
- Each branch is a sin or cos wave of a number.
- Add those branches together to displace Y in the vertex shader.
- Apply the node material to the plane.
- Gui elements to reset the scene.
Did I lose you at step 2? Don’t worry, keep reading.
Here’s an example of what the node tree looks like for this particular instance of the playground:
Do you see each branch?
We loop through to create N number of branches, where N is a randomly chosen number between 1 and 50! In the case of this specific example of running the playground, it was 12 branches. Then we add each branch together to drive the height of each vertex of the plane based on the x position of each vertex.
How bonkers is that! It’s AMAZING! Because we’re constructing this node tree through code, we can introduce loops and randomization into its construction. This is SO COOL!!!!
Ok still with me? Ready to go another layer deeper? Let’s look at the branch again:
Notice the yellow-ish float node? Guess what…that’s ALSO randomly generated!
Want to go another layer deeper?
See that blue Cosine node? Yup…you guessed it, for every branch that’s created, we randomly choose a cosine or sine operation for the trigonometry node!
So when we create the node tree, we create a random number of branches, composed of a randomly chosen sine or cossine wave of a random number.
THIS IS AMAZING! IT’S NEXT LEVEL COOL RIGHT?!
Sure if you’re anything like me, your mind is probably melting right now, but this is just plain EPIC! Think of the possibilities. They are nearly limitless!
Ok so there are 2 main reasons I’m writing this post, first and foremost to introduce you to the idea that you can create node materials through code and unlock some incredible potential. Secondly, and perhaps most importantly, is to provide you with 3 very specific tips for getting started down this path.
- Start with the basics
- The MAGIC button
- Logging Nodes
Start with the basics
No wait! Hear me out. I literally mean start with the absolute base level of nodes necessary to properly build a Node Material. The Node Material documentation page already has the starting point written down for you.
That’s it! That’s the basics. This is the exact code you need to build the starting node tree that you might already be familiar with:
This base example is really important to wrap your head around for 3 reasons.
First it showcases that you MUST have both a VertexOutput node, AND a Fragment Output node to successfully build the node tree.
Secondly, in order for a tree to load, notice that every node has at least 1 input or output port (the colored bubbles) connected to the port of another node. This is really critical, because your node tree will not build unless all nodes are properly connected.
Thirdly, it showcases how to create a node, how to set properties of a node, and how to connect nodes to other nodes, all. All of these being critical things to understand if you want to construct node trees via code.
So while your instinct may be to skip this basic example, it’s WAY easier to get started by actually placing this in your code, and modifying it from there. Especially if you are just poking your head up into this brave new world.
The MAGIC Button
What if I told you that you could have the best of both worlds? You could connect nodes together into a tree or branch in the Node Material Editor by hand and then hit a magic button that would output the exact code necessary to recreate that tree or branch in your own project? Sound too good to be true?
Yup that’s right, sometimes it’s just faster to create the exact setup you want by hand, and then copy that into your code. Pressing the “Generate Code” button downloads a text file of the exact code you need to cut and paste that “tree” into your own project code. Remember the example playground from above with 12 branches? Try hitting the “Generate Code” button and look at the output. Pretty incredible right?
Keep in mind that Babylon.js is a incredibly rich platform with very thorough and robust documentation. The platform is so deep in fact, that sometimes there are properties and attributes that you can leverage that might not be immediately straight forward to find. This is why the following piece of code will unlock new doors for you:
It may seem really simple at first, but look at the output when you log a node to the browser’s console:
Isn’t that incredible? We don’t have time to go through all of this, but here’s the point, this output has EVERYTHING you could possibly want to know about your node. Inputs and outputs that are connected to other nodes, the nodes they are connected to, and many other properties and attributes of each node.
I won’t lie to you, as you embark down this journey, you’re going to run into some walls. I certainly have, but logging nodes along the way gives you incredible insight into the state of the tree you’re constructing and help you troubleshoot anything that may be going wrong. So don’t be shy about logging!
Ok, that’s it! We’re done! Welcome to the brand new world of creating procedural node material shaders from code! Now that you know, you can never un-know.
I truly hope you see the raw power and potential of this in the same way that I do. It really seems like the sky is the limit with procedural Node Materials!
If you can remember the three tips 1) Start with the Basics, 2) The MAGIC button, and 3) logging your nodes, then I am confident your journey into this space will start off on the right foot.
Thanks for reading!