Mathematics is very useful for drawing paths in space and so can be applied to ribbons.
NOTE - The examples on this page use the legacy method of creating ribbons
var ribbon = BABYLON.Mesh.CreateRibbon(name, pathArray, closeArray, closePath, offset, scene, updatable, sideOrientation);
rather then the newer options method.
var ribbon = BABYLON.MeshBuilder.CreateRibbon("ribbon", { pathArray: paths }, scene );
The Ribbon is very adapted to elaborated maths computed meshes.
You can easily start from an equation to get a full volumic complex shape.
There are many ways to do it.
If you don't feel at ease with maths, here is a way to start :
We just set points in space. These points have got each a set of three coordinates : x, y and z.
We call here these points Vector3.
When we want to design a curve or a path in space, we need to get a collection of successive Vector3.
We can't have an infinity of points.
So we define a path with a certain number of Vector3. The more Vector3, the more smooth the curve and the more computations too.
So when you want your path to follow a mathematical curve, you need to compute each path Vector3 coordinates.
You could choose a known math curve in wikipedia or dedicated sites (http://en.wikipedia.org/wiki/List_of_curves , http://www.mathcurve.com/courbes2d/courbes2d.shtml , http://www.uiowa.edu/~examserv/mathmatters/tutorial_quiz/geometry/commoncurves.html, etc) or, when you feel more comfortable, create you own.
As you can see, curve equations are often like this : f(x, y) = 0 or like this : y = f(x).
This means y is expressed in function of x.
This kind of equation is called a cartesian equation. It is probably the most used among mathematicians, but it won't help us a lot because we need to compute x and y (and z) simultaneously to set each Vector3.
So we will prefer the parametric equations.
In a parametric equation each different coordinate is defined in function of a parameter k :
x = fct1(k)
y = fct2(k)
z = fct3(k)
So if you are given a cartesian equation, it is quite almost possible to translate it in a parametric equation.
example with a parabola : y = x²
the cartesian equation y = x * x will give the parametric equation :
x = k
y = k * k
You then give k values from -20 to 20 for example and you get your 40 successive Vector3 on the parabola. Easy, isn't it ?
You now know the way to fill a path with successive Vector3 along a math curve.
Well, we just learnt how to fill a path but a Ribbon needs many paths (okay, we can still construct a ribbon with a single path too, but it's more complex), so how do we add different paths as there is no real interest to add many times the same path ?
It's quite easy once you've got your parametric equation.
Let's get into javascript now.
Your former parametric equation could be this way :
var path = [];
for (var k = -20; k <= 20; k++) {
var x = k;
var y = k * k;
var z = 0;
path.push(new BABYLON.Vector3(x, y, z));
}
Right ?
http://www.babylonjs-playground.com/#1HSC2O -
Let's now imagine, you create the same path array 10 times on the z-axis with z = t :
var paths = [];
for (var t = 0; t < 10; t++) {
var path = [];
for (var k = -20; k <= 20; k++) {
var x = k;
var y = k * k;
var z = t;
path.push(new BABYLON.Vector3(x, y, z));
}
paths.push(path);
}
What do we get now ?
http://www.babylonjs-playground.com/#1HSC2O#1 -
var paths = [];
for (var t = 1; t < 10; t++) {
var path = [];
for (var k = -20; k <= 20; k++) {
var x = k;
var y = k * k / t;
var z = t;
path.push(new BABYLON.Vector3(x, y, z));
}
paths.push(path);
}
You immediatly get a set of different paths along the z-axis : http://www.babylonjs-playground.com/#1HSC2O#8 -
At last, if we change a bit x and z variation to scale the curve, we can get a nice parabolic shape :
var paths = [];
for (var t = 1; t < 10; t++) {
var path = [];
for (var k = -20; k <= 20; k++) {
var x = k * 8;
var y = k * k / t;
var z = t * 50;
path.push(new BABYLON.Vector3(x, y, z));
}
paths.push(path);
}
http://www.babylonjs-playground.com/#1HSC2O#10 -
An easy way to create math computed shapes is so :
The Ribbon is very versatile. So you can redo every BabylonJS basic shapes.
Why would you want to do this ?
Well, you probably don't. There is no need to re-invent the wheel. But you could need to model your own shape which derivates from one of the basic shapes.
The main rule should be :
Let's try here to redo a sphere and then to modify it into something different.
As you've seen in the former part, you need to create many paths to build a ribbon. For a sphere, you can imagine that you stack many circles, each circle being a path.
To create a circle, you just set points at x = sin(angle) and z = cos(angle) and give angle some values between 0 and 2 x PI.
var pi2 = Math.PI * 2;
var step = pi2 / 60; // we want 60 points
for (var i = 0; i < pi2; i += step ) {
var x = radius * Math.sin(i);
var z = radius * Math.cos(i);
var y = 0;
path.push( new BABYLON.Vector3(x, y, z) );
}
path.push(path[0]); // to close the circle
demo : http://www.babylonjs-playground.com/#E6IX1#1 -
Now, you add circles along the y-axis, making the radius evolving with another angle p varying from the sphere south pole -PI / 2 to its north pole +PI /2. These circles (path) are stored in an array called paths :
var radius = 10;
var tes = 60;
var pi2 = Math.PI * 2;
var step = pi2 / tes;
var paths = [];
for (var p = -Math.PI / 2; p < Math.PI / 2; p += step / 2) {
var path = [];
for (var i = 0; i < pi2; i += step ) {
var x = radius * Math.sin(i) * Math.cos(p);
var z = radius * Math.cos(i) * Math.cos(p);
var y = radius * Math.sin(p);
path.push( new BABYLON.Vector3(x, y, z) );
}
path.push(path[0]);
paths.push(path);
}
demo : http://www.babylonjs-playground.com/#E6IX1 -
Let's apply a ribbon to these paths : http://www.babylonjs-playground.com/#E6IX1#2 -
var lastPath = [];
for (var j = 0; j < pi2; j += step ) {
lastPath.push( new BABYLON.Vector3(0, radius, 0) );
}
paths.push(lastPath);
var sphere = BABYLON.Mesh.CreateRibbon("sph", paths, false, true , 0, scene);
demo : http://www.babylonjs-playground.com/#E6IX1#3 -
But don't worry, all those efforts so far aren't vain. From now, let's the magic happens with only little changes ...
Remember : the for loop iterating on p is for the south to north pole angle. What if you don't increment p until PI / 2 but stop before, say at PI /2 - 1.5 :
for (var p = -Math.PI / 2; p < Math.PI / 2 - 1.5; p += step / 2) {
demo : http://www.babylonjs-playground.com/#E6IX1#4 -
Now, you can keep the original pole angle limit PI / 2 but add a new behavior : if a certain angle limit is reached, then inverse the y radius around this limit.
var yRadius;
var limit = Math.PI / 2 - 1;
for (var p = -Math.PI / 2; p < Math.PI / 2; p += step / 2) {
var path = [];
yRadius = p < limit ? Math.sin(p) : 2 * Math.sin(limit) - Math.sin(p) ;
for (var i = 0; i < pi2; i += step ) {
var x = radius * Math.sin(i) * Math.cos(p);
var z = radius * Math.cos(i) * Math.cos(p);
var y = radius * yRadius;
path.push( new BABYLON.Vector3(x, y, z) );
}
paths.push(path);
}
demo : http://www.babylonjs-playground.com/#E6IX1#5 -
Let's change the initial for loop limits now :
for (var p = -Math.PI / 2 + 0.5; p < Math.PI / 2 - 0.5; p += step / 2) {
demo : http://www.babylonjs-playground.com/#E6IX1#6 -
var sphere = BABYLON.Mesh.CreateRibbon("sph", paths, true, true , 0, scene);
demo : http://www.babylonjs-playground.com/#E6IX1#7 -
for (var i = 0; i < pi2; i += step ) {
var x = radius * Math.sin(i) * Math.cos(p) * Math.cos(i / 6);
var z = radius * Math.cos(i) * Math.cos(p);
var y = radius * yRadius;
path.push( new BABYLON.Vector3(x, y, z) );
}
demo : http://www.babylonjs-playground.com/#E6IX1#8 -
for (var i = 0; i < pi2; i += step ) {
var x = radius * Math.sin(i) * Math.cos(p) * Math.cos(i / 6);
var z = radius * Math.cos(i) * Math.cos(p) * 2;
var y = radius * yRadius * Math.cos(i * 2);
path.push( new BABYLON.Vector3(x, y, z) );
}
demo : http://www.babylonjs-playground.com/#E6IX1#9 -
Parametric Shapes
Polyhedra Shapes