tutorials

Parametric Shapes


Introduction

The basic meshes you've seen up until now have an expected shape : when you create a sphere mesh, you expect to see a spherical shape. The same goes for a box mesh, a torus, a cylinder, etc.

There is another kind of mesh whose final shapes aren't fixed. Their final shape depends upon some parameters. So we call these meshes "Parametric Shapes".

The Ribbon

The ribbon is a very simple and versatile shape. As it is very elementary, you can model almost any shape using a ribbon or many merged ribbons.

Ribbon

CreateRibbon(name, pathArray, closeArray, closePath, offset, scene, updatable, sideOrientation);
  • name : string.
  • pathArray : an array of paths.
    As explained in the Basic Elements section, the ribbon is the surface between two, or more, paths.
    A path is a series of successive points in space (Vector3).
    So a path can be designed by many ways : you can set points manually, import them from some set of data (json, etc), compute them with some maths function ... or even a bit of all of this.
    The javascript representation of a path is simply an array of Vector3.
    A path must have at least two points (four points if you provide a single path). In order to create a ribbon, you just have to pass an array of paths. This array can contain only one path and in this case, the offset parameter is used.

  • closeArray : default False boolean, if true an extra set of triangles is constructed between the last path and the first path of pathArray. example : http://www.babylonjs-playground.com/#295H7U -



    Here we populate an array called paths with many path arrays.
    Each path array is populated itself with Vector3 along a B├ęzier curve. Anything else could have been chosen for this example, but I love this strange shape.
    Before dealing with the ribbon, we just display each path with the CreateLines() method so we can figure out what these paths look like. As we can see, the curves are side by side around an incomplete circle.
    If we apply this paths array to a ribbon mesh, we get this : http://www.babylonjs-playground.com/#295H7U#1 -


    You can see that a surface is constructed between each path as expected.
    Here is the same with a plain material ans still the paths displayed : http://www.babylonjs-playground.com/#295H7U#2 -


    If we set closeArray to true, the missing surface between the first and the last paths is then constructed : http://www.babylonjs-playground.com/#295H7U#3 -


    The mesh becomes then a real closed volume and the light reflects in a continuous way along its surface.

  • closePath : default False boolean, if true the last point of each path of pathArray is joined to the first point of this same path.
    example : http://www.babylonjs-playground.com/#1TDTHJ -



    Here is some kind of unclosed tubular ribbon. It is made with only two paths path1 and path2 each following an incomplete circle.
    If we set the closePath to true (http://www.babylonjs-playground.com/#1TDTHJ#1 -

    ), you can notice that path1 and path2 are now closed and two triangles are added between the beginning and the end of each path.
    If we give this ribbon a plain material, you can then notice it is really closed as the normals are computed to reflect the light in a continuous way : http://www.babylonjs-playground.com/#1TDTHJ#2 -


    Here is the example of the former closeArray parameter with closeArray and closePath set to true : http://www.babylonjs-playground.com/#295H7U#4 -

  • offset : default half size of the pathArray length, mandatory only for pathArray containing a single path.
    example : http://www.babylonjs-playground.com/#1W5VJN#14 -


    Here is a single path path1, a simple helix. It is just shown with CreateLines().
    We can populate the pathArray with this single path : [path1]
    In this case, the ribbon will be constructed by joining each point of the path to another point located offset positions further in the path. Example : offset = 10, the point 1 will be joined to the point 11, the point 2 to the point 12, etc.
    If you don't provide an offset value, or if you provide a value greater than half of_path1 length, the offset will be set by default to half of path1 length.
    Back to our example : http://www.babylonjs-playground.com/#1W5VJN#15 -


    Offset is set to 20 here.
    Let's change it to 5 : http://www.babylonjs-playground.com/#1W5VJN#16 -


    So this parameter allows you to construct different meshes from a same single path.
    So playing with offset, closeArray, or other parameters, you can easily get volumic shapes, even with a single path : http://www.babylonjs-playground.com/#1W5VJN#17 -

  • updatable : boolean, true if the ribbon could updated after creation

  • sideOrientation : default DEFAULTSIDE possible other values :

    • BABYLON.Mesh.FRONTSIDE
    • BABYLON.Mesh.BACKSIDE
    • BABYLON.Mesh.DOUBLESIDE
      see full explanation about sideOrientation parameter in Basic elements

If you need more details about ribbon uses, you might want to read the Ribbon Tutorial part.

The Tube

Basically a tube is just a curved (or not) cylinder.
However it can be far more than just a cylinder if you consider it as a parametric shape.
Example with a simple cos/sin path : http://www.babylonjs-playground.com/#LG3GS#8 -


var tube =  BABYLON.Mesh.CreateTube(name, path, radius, tessellation, radiusFunction, cap, scene, updatable?, sideOrientation);
  • name : string.
  • path : an array of successive Vector3. It represents the path the tube will be constructed along. This path is the central axis of the tube. This array must have at least two Vector3. The first point is the start of the tube and the last point is the end of the tube. So having only two points, you get a simple cylinder.
    This path can be filled as you like : manually, by importing Vector3 from a data set, with some maths function or even a bit of all of this. It's just an array filled with Vector3 to set where the tube axis goes into space.
  • radius : a radius number value. This is the constant radius value applied along the tube. This value is taken into account only if the radiusFunction parameter is null.
  • tessellation : the number of radial segments. If you set it to 3 you get a triangular tube section, if you set to 4 you get a squared section, and so on. So set it to what level of precision you need, just keep in mind the more segments, the heavier your mesh.
  • cap : BABYLON.Mesh.NO_CAP, BABYLON.Mesh.CAP_START, BABYLON.Mesh.CAP_END, BABYLON.Mesh.CAP_ALL.
  • radiusFunction : a custom javascript function.
    If you pass this parameter to the CreateTube() method, then the radius parameter value will be ignored.
    Your custom function will be called at each point of the path while constructing the tube.
    It will then be passed two arguments : the position of the current point i and the distance of this i-th point from the beginnig of the tube.
    Your function must just return a radius value.
    Example :
    var myFunction = function(i, distance) {
    var radius = 3 * Math.cos(distance / 5);
    return radius;
    };
    var tube = BABYLON.Mesh.CreateTube("lumps", path, null, 20, myFunction, scene);
    

Here is an example with both an i sinusoidal radius function and x sinusoidal incrementing path : http://www.babylonjs-playground.com/#LG3GS#9 -



Here's another example with a circular path and varying radius : http://www.babylonjs-playground.com/#LG3GS#10 -

Extrusion

What is extrusion ?
Extrusion is the way to transform a 2D shape into a volumic shape.
Let's imagine that you define a star shape by filling an array with successive Vector3. In order to have a 2D shape, you only set these points in the xOy plane, so every z coordinate is zero.
ex : http://www.babylonjs-playground.com/#RF9W9 -



Let's show the World axis so it is clearer : http://www.babylonjs-playground.com/#RF9W9#1 -


Let's now imagine you could stretch this 2D shape along the Z-axis to give it some volume... this is extrusion : http://www.babylonjs-playground.com/#RF9W9#30 -

Let's now imagine you can extrude your star along a 3D path in space, a sinus curve for example, and not only along the z-axis.
http://www.babylonjs-playground.com/#RF9W9#31 -


Extrusion can be accomplished with two different methods. A basic one and an advanced or custom one.

BASIC METHOD

BABYLON.Mesh.ExtrudeShape(name, shape, path, scale, rotation, cap, scene, updatable?, sideOrientation)
  • name : the extruded mesh name.
  • shape : the shape to be extruded, an array of successive Vector3.
  • path : the path to extrude the shape along, an array of successive Vector3.
  • scale : default 1, the value to scale the initial shape.
  • rotation : default 0, the step value to rotate the shape at each path point.
  • cap : BABYLON.Mesh.NO_CAP, BABYLON.Mesh.CAP_START, BABYLON.Mesh.CAP_END, BABYLON.Mesh.CAP_ALL.
  • scene : the current scene.
  • updatable? : if the mesh is updatable.
  • sideOrientation : the side orientation - front, back or double.

If we change the scale value from 1 to 3 for example (line 84), the initial star is scaled to 3 along the curve : http://www.babylonjs-playground.com/#RF9W9#526 -


If we now change the rotation step value from 0 to PI / 24 for example, the curve is twisted this angle at each curve point : http://www.babylonjs-playground.com/#RF9W9#218 -

Of course, even if you define your 2D shape in the xOy plane as described, the extrusion still works along any path direction : http://www.babylonjs-playground.com/#RF9W9#32 -


Moreover, the shape doesn't need to be closed. You can have a simple (or complex) open shape : http://www.babylonjs-playground.com/#RF9W9#7 -



Extrusion : http://www.babylonjs-playground.com/#RF9W9#33 -


Extrusion with rotation : http://www.babylonjs-playground.com/#RF9W9#34 -

Remember that your shape doesn't need to be centered on the coordinate system either. Here is an offset simple shape : http://www.babylonjs-playground.com/#RF9W9#10 -



Extrusion (the extrusion path is shown in magenta so the offset is visible) : http://www.babylonjs-playground.com/#RF9W9#35 -


Now rotation... around the path axis : http://www.babylonjs-playground.com/#RF9W9#36 -


As you can see, this is a way to build complex curved helix meshes without handling maths or simpler ones : http://www.babylonjs-playground.com/#RF9W9#37 -


As the shape to be extruded is unpredictable, it is assumed that the cap, if want to add it one or two to your extruded mesh, is computed with its center set to the shape barycenter.

ADVANCED METHOD

BABYLON.Mesh.ExtrudeShapeCustom(name, shape, path, scaleFunction, rotateFunction, ribbonCloseArray, ribbonClosePath, cap, scene)
  • name : the extruded mesh name,
  • shape : the shape to be extruded, an array of successive Vector3.
  • path : the path to extrude the shape along, an array of successive Vector3.
  • scaleFunction : a custom javascript function. This function is called on each path point and is given the i position of the point in the path and its distance from the begining of the path. It must return a scale numeric value. This value will be the scaling applied to the shape drawn at the i-th point.
  • rotationFunction : a custom javascript function. This function is called on each path point and is given the i position of the point in the path and its distance from the begining of the path. It must return a rotation numeric value. This value will be the rotation applied to the shape drawn at the i-th point.
  • ribbonCloseArray : default false, boolean. The underlying ribbon closeArray parameter. This can be used to automatically close a path with right normals computation.
  • ribbonClosePath : default false, boolean. The underlying ribbon closePath parameter. This can be used to automatically close a shape with right normals computation.
  • cap : BABYLON.Mesh.NO_CAP, BABYLON.Mesh.CAP_START, BABYLON.Mesh.CAP_END, BABYLON.Mesh.CAP_ALL.
  • scene : the current scene.
  • updatable? : if the mesh is updatable.
  • sideOrientation : the side orientation - front, back or double.

In this advanced method, the scale and rotation parameters are replaced by custom functions.

scaleFunction
This javascript function will be called on each path point iteration when extruding. It will be passed two parameters : i and distance.

  • i is the point position in the path, starting from zero for the first point.
  • distance is the current point distance from the begining of the path.

This custom function must return a scale numeric value which will be applied to the shape on the i-th point.
Example :

var myScale = function(i, distance) {
  var scale = 2 * Math.sin(i / 5);
  return scale;
};

Here is an example with an unclosed un-centered simple shape whose scale evolves linearly along the path : http://www.babylonjs-playground.com/#RF9W9#38 -



Now if we use a sinus scaling function instead and as the shape isn't centered, we get interesting results : http://www.babylonjs-playground.com/#RF9W9#39 -


We can even emulate rotation by alternately scaling positive/negative : http://www.babylonjs-playground.com/#RF9W9#40 -

rotateFunction
This javascript function will be called on each path point iteration when extruding. It will be passed two parameters : i and distance.

  • i is the point position in the path, starting from zero for the first point.
  • distance is the current point distance from the begining of the path.

This custom function must return a rotation numeric value which will be applied to the shape on the i-th point.
Example :

var myRotation = function(i, distance) {
  var rotation = distance / 20;
  return rotation;
};

Here is an example of constant scale and rotation evolving with the distance : http://www.babylonjs-playground.com/#RF9W9#41 -



You can set a non-linear rotation function of course, sinus here : http://www.babylonjs-playground.com/#RF9W9#42 -

Fixed values

This advanced method needs two custom functions. But you may want to use a custom scale function with a fixed (or no) rotation function, for example. In this case, just pass a custom rotation function returning a fixed value :
Example :

var noRotation = function(i, distance) {
  return 0;
};

If you carefully read the code of this previous example, you can see in line 41 that the scaleFunction returns the constant 1 value : http://www.babylonjs-playground.com/#RF9W9#41 -


ribbonCloseXXX parameters

The extruded mesh is based on an underlying ribbon. When you extrude a shape, you actually make a particular ribbon.
This means you can also set this ribbon closeArray and closePath parameter if you need to automatically close the extruded shape.
NOTE : the closeXXX names are the ribbon ones. Not the extruded shape ones.
So it may be confusing because :

  • ribbonCloseArray set to true will close your shape extrusion path,
  • ribbonClosePath set to true will close your shape itself (if unclosed).

Let's now do this unclosed, un-centered extruded shape : http://www.babylonjs-playground.com/#RF9W9#20 -



And this almost circular path : http://www.babylonjs-playground.com/#RF9W9#21 -


Extrusion with constant scale and no rotation : http://www.babylonjs-playground.com/#RF9W9#43 -


Now let's set the ribbonCloseArray to true :http://www.babylonjs-playground.com/#RF9W9#44 -


As you can see, it closes the extrusion path. Let's set it back to false and let's set the ribbonClosePath to true instead : http://www.babylonjs-playground.com/#RF9W9#45 -


Now the shape is closed.
Both together : http://www.babylonjs-playground.com/#RF9W9#46 -

Summary
At last, the extrude custom function call would be, for example:

BABYLON.Mesh.ExtrudeShapeCustom("extruded", shape, path, myScale, myRotation, false, true, scene)

A shape is an array of successive Vector3. This means 2D or 3D shapes can be extruded as well.
The shape is to be designed in the local coordinate system knowing that the z-axis will be the extrusion path axis.
Finally, shapes don't have to be centered in the local coordinate system.
A centered shape will be extruded symmetrically centered along the path axis. An un-centered shape will be extruded offset from the path axis.

Easy way to generate strange shapes : http://www.babylonjs-playground.com/#RF9W9#47 -