The Wingnut Chronicles


That’s good to hear! Frosted bytes :joy:
I can barely stand when it starts hovering around 70 F here in California, I’d never be able to live over there!

@Rah Beat ya to it! 168 controls, that’s incredible! I don’t think that record is going anywhere any time soon :smile:


Hey Wingnut, lil’ help please.
A young woman is having a birthday. I asked what to get her. I was told, “something with her name on it”. So I got a domain and made this playground.

Wondering if you could help me tune it just a bit . . . A little brighter and the motion reduced by 80% or so.

. . . please . . . .


Hi TL! Glad to do it.

Line 120 refTexture.level can adjust texture “intensity” but I’m not sure that is “brighter”. Possibly lighting increase needed, and possibly a different texture.

All the animation happens in lines 155-182. In the original, I used one ‘addInPlace’ for position anim, and another for rotation anim. This one… has the position anim disabled, and TWO rotation addInPlaces… one doing Y (lines 168-172), another doing X (lines 174-178).

This is simple animation, but understand that EACH addInPlace could have its OWN timeline, its own step, and its own softener(s). And remember that you could do softener*2 or step/2 (or similar stuff) in any addInPlace section.

Lines 163, 170, 177… they are each vector3’s to be added-In-Place each frame, and they are essentially the “change since last frame” (sometimes called the ‘delta’).

And, you know sin and cos are cyclers… essentially back-n-forth oscillators. You can think of sin as ONE bike pedal, and cos as the other. :slight_smile:

Step is VERY important. Often, when you adjust step, you need to adjust other things, too. Step adjusts both speed and amount of effect. So, sometimes we adjust the speed of the animation, but then the amount of movement becomes too little or big, so the softeners need re-adjusting.

Softeners (attenuators) can be used as amplifiers, too… depending upon if you use them as a divisor or a multiplicand. (What the hell did he say?) (ie. You can sometimes divide-by softener, and sometimes multiply-by softener). I probably should have named it ‘scaler’ or ‘range’ or something like that.

And, camera angle is also important, esp .beta (the 1.8 seen in line 12).

This reflection version is still looking directly at the “pole” of the texture. You can see the texture’s pole… pass vertically thru the letter surfaces… twice per anim cycle… once going up, once going down.

If you would like to NOT see the texture pole pass thru the fonts, adjust that camera beta… OR… you can do what I did in the old forum post… where we changed line 91 ‘xyz’ into ‘zyx’. That might work.

Do you see how you could eliminate the 2nd rotation anim… by replacing the first zero in line 170… with the (Math.sin(timeline)/softener) from line 177? (add/remove parentheses as wanted). Then, line 170 would be animating both X and Y, and then lines 173-178 could be removed.

I turned OFF position animator… because… it gets to be too much, and also… it needs to be programmed more carefully than I have done, so far. Up in that section (lines 164/165)… you can see that I used the ‘i’ indexer variable in some of the calcs. That… is weird… and can have strange effects. Generally speaking, when using the i-indexer in calcs, left-most letters get little effect, right-most letters get LOTS of effect. This is not an overly-useful movement and can make words difficult to read.

Ok, I hope this helps. You should have some tools to cause trouble-with, now. :slight_smile: Don’t accidentally blow-up the planet. Perhaps someday, we will add pre-made MeshWriter “animation behaviors” that can be applied to a single letter, a single word, a single sentence, or an entire message. I am also hoping to apply path-following, soon, and have begun studies on paths. I’ve tested only camera-flying and single object-flying, so far. Thx to @JohnK and others… for helping me learn about paths.

This young birthday gal… umm… is she a California Girl? hmm. Can she… Does she… Would she… ahhh, never-mind. She wouldn’t know how to operate a snowblower. :smiley:


Hey TL… in this “reflection-texture” application (chrome fonts)… do you see why (blocky?) fonts with LOTS of surface area, work best? Yeah, sometimes “fat fonts” are difficult to read, because their “holes and slots” are small… but, if we could somehow activate one more set of fonts… big fat mamas… that would be great. The more surface area of the font faces, the better chance that the viewer can “make out” what the reflection texture is showing.

Let’s say the texture is a pano of the greater metro El Segundo skyline. The more surface area on the fonts, the more chance that viewers will recognize it as El Segundo… because more of the picture will be seen in the font faces.

HOW IMPORTANT is it… that viewers recognize the reflected picture? I dunno. :slight_smile: Depends upon the programmer/artist… and what is trying to be communicated, I guess. Brick patterns… easily recognized. “Where’s Waldo/Wally” pictures… perhaps more important. :slight_smile:

It takes a long time to tweak a fontFamily into being MeshWriter-tolerable, doesn’t it?

For those who don’t know, @TheLeftover is the original coder of the MeshWriter fonts/system… used in that demo. Attaboy to @jerome, too, for creating the Solid Particle System (SPS) used in MeshWriter ops. I think MeshWriter/similar… has a HUGE future… for reading ANYTHING while-within a virtual reality scene.

GUI textBlock controls have usage in VR, too… but there’s nothing prettier than 3D fonts, and they can do physics/collisions, can have on-font textures, be used as particle emitters, and they can pirouette. GUI textBlock controls will shatter, if they try a pirouette. :slight_smile:

And for teaching kids to read, there’s NOTHING like dancing fonts/words… keeps them wanting more and more sentences to pass-by.

Perhaps a pretty forest scene with text-paths winding out of the brush… passing-alongside the campfire. Kids would sit and read for HOURS and HOURS and HOURS. Pictures dance-by, among the words. 3D characters… too… “I’m a cone”… “I’m a parallelogram”… so much goooood stuff… to babysit those annoying kids-with. heh.

Parades. Sentence parades, newsfeed parades, mesh parades, sprite parades, anything that can follow a path… can be paraded. Everyone loves parades. Does anyone know what a Kerbal… is? How about Trolls? We need some cutesy 3D characters… tractors, lawnmowers, train locomotives, things that can path-pull a parade of MeshWriter words and assorted happy-stuff. Maybe some particle emitters to spray confetti, and maybe a little John Phillips Sousa marching music (calliope/bandwagon), etc. SO coooooool.

Parade Manager 1.0. :slight_smile: “Path-Wrangling and Media-Herding… done right.”


Well, the letters will always be flat on top, right? I make shapes in two dimensions and then it gets extruded, or whatever. That is the basic algorithm.

For my uses, I never notice. It is absolutely the most noticed when one does super-fat letters with a reflective texture. (hmmm . . . ) I remember looking at curving the 3rd dimension . . . and getting mental vapor lock. I am pretty sure it is beyond me unless I can get Archimedes in here to write that part of the code.

The two dimensions that are curved, are approximated, of course. The number of faces in a curve (say the outside of a ‘0’) is a function of a value embedded in the code and the way the font was originally written. The default value was intended to be pretty economical but look OK. I could incorporate a dialer to tune that to a couple different settings.

Yes. Putting a new font in MeshWriter is laborious. So is writing tools to speed font conversion. If we were producing more fonts, I would gradually tune up the tools – I thought.

I have zero information on usage. I am unaware of anyone taking anything to users using MeshWriter, besides me. (I will say this, there are frequent visits to the playgrounds you created that sport MeshWriter. I know this because they all source from my server.) I would expect that, if there was much usage (other than my friend Wingnut) I would hear about some deficiencies.


Yeah, like these, for example.

Little slots, little holes, lots of facial surface area. Super easy to see the image inside the fonts, but not very easy to read the words, unfortunately. Trade-off.

There’s probably 3-6 different font widths… involved in that font family. Compare the “I” to the “N”. 3 times wider? Maybe more? Might be a challenge to do auto-kerning, but boundingBox.extends.x might be able to measure each SPS-based character-mesh, and do the auto-kern. (for those in question, kern = letter-spacing, or X-spacing)

Those fonts are perhaps a little TOO “plump”, but you get the idea. Notice how the fonts are somewhat narrow, too, allowing them to be tightly kerned. These are all caps, so no descenders… allowing tight vertical stacking of words, too (line-spacing). Love it.

Later, we’ll actually run a movie inside the fonts. Wha-da-ya-think? Blazing Saddles? Top Secret? :slight_smile:

what video inside fonts looks-like


Its top-secret wingnut just stop doing secret projects =)


Ok, continuing from message #49… I used @JohnK’s #4 example from the path demo (line 69 formula)… in my other path demo… which we COULD call “The OT” (orthoganous tobogganous). Let’s have a look: (line 131 uses line 69 orthoganator formula) (disable line 105 to detach cam from car) (increase points in line 87… to slow the travel speed)

Just like Jerome’s rollercoaster, our “car” is staying reasonably heads-up (not much roll), while doing proper pitching and yawing to follow the path.

And just like Jerome’s rollercoaster, we have a “glitch” at one point in the track, probably where path-end meets path-start. hmm.

Draw Curves - Babylon.js Documentation (scroll down tiny bit)

While touring-around in Path3D docs and assorted related docs, I find this “Playground Example - Closed Joined Curves”.

That path has one SEVERE-angle place, and one pretty good bump… both along the upper right side… so I dunno if THAT method of closed-loop path-growing… is any different/better than what has been tried, so far.

I was just looking for a better “tie” point. (seam where start meets end). If we’re going to run a monorail system… we need good seams and smooth rail. MeshWriter fonts would get motion-sick when they hit that bump in the rail. And you KNOW those MeshWriter fonts - they BITCH about EVERYTHING. heh. If they don’t get a smooth ride along a path… we’re going to “hear about it.” :slight_smile:

I wonder what that “glitch” is. Quaternion spaz-out? Perhaps a bump where the rail was soldered/welded? Are we missing a path-point, and thus have a “gap” to jump?

Let’s do some more experiments. Here is a showNormals helper, or maybe better for us, a showBinormals helper.

Yep, I see an issue. Abnormal normals at the border. hmm. A wall will likely NOT improve anything. :open_mouth: Being a PathMaster is more complex than I first imagined.


As usual I like to simplify things so I can see what is going on, so goodbye skybox, extra meshes and the camera following the carBody and back to a plane for the carBody rather than a box. Also have cloned the carBody at its start position.
You can see that when the carBody approaches the end to restart its has rotated itself around the path. Checking out the console you can see that the final and first tangents are the same but not the normals and binormals. This will be down to the chooses made on how the normals and binormals are calculated going around the path and given for any point on the path there are an infinite number of vectors that can be chosen as a normal to the path the selection of a good method for a closed path is difficult. Will have another look to morrow.


Hi JK, thx for the response. I am not seeing that to be true, at console.

Object { x: 0.4448, y: 0.8858, z: 0.1314 }
Object { x: 0.4383, y: 0.8882, z: 0.1376 }

#60 pg has tangents start/end diff subtraction, and console log.

diff { x: 0.006593511346865366, y: -0.0023379251690160974, z: -0.006228536602425533 }

(Oddly, though, I THOUGHT I DID see them be identical numbers… ONCE. I could not make them be identical again, even after fresh re-loads. Maybe I hallucinated it.)

One more show-normals version: pg #62 I also played-with line 112 raw property. Improper usage. Better usage:

var path3d = new BABYLON.Path3D(points, BABYLON.Vector3.Up(), raw); // raw = bool

Not much affect.

I wonder if that seen angle-difference… is a 45 degree angle. hmm. (Wingy feels a brain tumor forming near his left temple.)

src for p3d

Yeah, not much roll, Wingy. Just enough to make your life miserable. :smiley: That’ll teach ya not-to “smack-talk” the Oimo plugin. heh


Cool topic, maybe here’s a view of the glitch:

It looks like the ends are combining at a tight angle?

Like a corner:


So, if join is on straight section of track maybe no glitch?

UPDATE: after re-reading I see you were joking about the angle, and looking into the challenge with the binormals not lining up…


Hiya aF! Yeah, that sort-of sounds correct… maybe. (I sound sure-of-myself, eh?)

A guy could ponder… “What IS the relationship of a pitch’n’yaw (x/y) rotation… to a direction/axis?”

Why did the car roll (z-rot) AT ALL? Probably something involving “goes-around, comes-around” :smiley: But, with a goes-around, comes-around issue (spirography), I would have expected the normals to be 180 degrees different, not 45± degrees different. hmm.

Axis IS a direction, though… I think. Or not. Directions need a magnitude, but so does an axis, I think. All-in-all, Mister Direction IS involved, here, somehow. Something… path-illogical. :slight_smile:


OK I really meant equal enough not to worry too much about it compared to the normals and binormals

Object { x: -0.8496, y: 0.4638, z: -0.2509 }

Object { x: -0.3619, y: 0.3145, z: -0.8774 }


Object { x: -0.2832, y: 0, z: 0.9590 }

Object { x: -0.8227, y: 0.3347, z: 0.4594 }

It is the normal and binormal that gives the rotation of the car body about the path.

Here is an interesting version This has a fixed normal all the way round. Sometimes the card appears to flick around, ie the rotation looks wrong. Focus on where this happens on the path and move the camera around to view that part of the path from different angles and at the appropriate angles you will see a smooth movement of the card. So in these cases it is to do with the viewing angle not the movement. (I am suggesting that even in the real world from some angles it would appear that the car would flick around). However there is one section of the curve I cannot find a smooth transition view - at a very kinky part of the path.


Nod. Thx John. An incorrect rotation that is eased-into… is fine, and perhaps understandable.

But “fast-jerk rotation-change” is not normal, and is not going to work for trains or parading of mesh or cameras. The #62 playground is perfect… except for where end meets start. It has only one fast-jerk rotation, where #63 has two.

I have a goofy idea. Let’s say we put a lookAT target in the middle of the circle-path. This lookAt target constantly moves up/down… to exactly match the worldSpace Y-height of the car, and the car constantly does car.lookAt(lookatTarget) with its RIGHT face (or left face if path travel is reversed). No rotation is ever set with code calculations. All rotation is done by right-side lookAt’s.

We could use the optional rotationOffset feature of lookAt… to make the car’s right-side… be the lookAt face.

This system is essentially a telephone pole in the center of the path-circle… that a lookAt target moves up/down along. This would also allow me to do banking. In our case, a hard-right banking could happen if lookAt target is lower than car.position.y.

One problem. LookAt likely affects car yaw and pitch, TOO. That… can’t be allowed to happen. It must ONLY affect car roll. AND… this is only ONE car. When we have 300 characters of MeshWriter fonts traveling the path… all characters will have a different ROLL-rotation than each other (because they are each at their own unique path-point and worldSpace altitude). That would mean that EACH character in the fonts-train… would need its OWN PERSONAL lookAt target moving up/down the center pole. OUCH!

What if I “hung” a disabled car-parented freeCam… from the BOTTOM-face of the car… and set freecam.applyGravity = true? heh. Should get good heads-up on the car, AND get some banking due-to… um… camera.inertia. heheh.

NOOOOO, that won’t work. But… yeah, physics-active “keel” hanging beneath the car(s)… would likely work pretty good… up-to-a point (ar ar) (a point of CPU bog due-to too many mesh on-the-path/in-frustum).

hmm. Just thinkin’. I don’t think the current method of controlling rotation… is going to work. Thx for your study and work, though. All comments/ideas welcome, always.

Perhaps I will try a playground, using the “variable-altitude lookAt target” (VALT) idea, unless someone beats me to it. I have some real-life junk to do first, but, it’s NOT snow-blowing! YAY!


Uses a hacked version, of the function used to compute the tangents, normals and binormals of a path, for the special case of a closed path.

BOTHERATIONS thought I had better look at the binormals and they go haywire.
Back to drawing board?:persevere:

More Editing
Turns out they do in #62 as well perhaps they do not matter so much!


“botherations”? haha. Funny word.

Babylon.js/math.ts at master · BabylonJS/Babylon.js · GitHub (a helper func for normals-calculations in BJS Path3D class)

if (!Scalar.WithinEpsilon(Math.abs(vt.y) / tgl, 1.0, Epsilon))

(My current brain tumor just had a baby brain tumor!)

If there were an “off-by-one” error in that Path3D code, who would ever know? It looks like a calculator exploded in there. :slight_smile: A guy could sink in all those floats! :wink:


Hi again, gang!

In the continuing story of our Path3d-playing, here’s a new version - #67.

In the source code for Path3d, there is MUCH talk about “first normal” which… is a user-settable parameter in the Path3d constructor. So, I set mine… to “up” vector… line 115.

Then… I put a sphere “atop” the carBody… to indicate which-way is UP, for IT. You can think of it as the head of a human, riding in our roller-coaster car.

Tests showed that the green Bi-Normals were aligned with the rider’s head. We ACTUALLY want the white Normals aligned with rider’s head… because… we set our “first normal” to v3.Up() in the Path3d constructor.

So… being the brave-but-blind explorer that I am… i re-arranged the ORDER of the arrays in our line 161 rotation formula. It WAS:
RotationFromAxis(normals[i], binormals[i], tangents[i]);

I eventually (trial’n’error-) found THIS order:
RotationFromAxis(tangents[i], normals[i], binormals[i]);

Now we have the white normals, passing thru the rider’s head… looking good. BiNormals are cross-product, as they should be (like I know what a cross-product is). I think all further experiments/playgrounds… should use this new formula-order.

If we look at (@JohnK’s?) playground example of the 6 path-following planes, examining lines 59-77, it is not unusual for tangents[i] to be the FIRST parameter. Case 0 and case 1 both have tangents as the first parameter. I chose to use case 3 (example 4) because the plane on the fourth “path follower”… stays orthoganous to its tobagganous.

In other words, the plane stays perpendicular to the path-line… all the time… exactly what I (and toboggan riders)… wish-for.

But maybe, case 3 (example 4) should be adjusted to match our NEW formula order.

Now that our formula “order” has changed, I decided to remove the optional BABYLON.Vector3.Up() “first normal” from the line 115 Path3d constructor, to see what the Path3d code uses as a default firstNormal value. Does Path3d set firstNormal as “up”, by default?

PG #68 tells us the answer, as does source code line 6974. It appears to set firstNormal = null, by default. And we can see a difference in #67 and #68 playgrounds, though BOTH (-erations?) have the white normals passing thru the rider’s head… properly.

If we want to follow firstNormal a bit… it is used again in source code line 6981, and arrives at the _compute function to be used in src line 7056.

From there, it arrives in the helper func called normalVector as 2nd parameter va. From there, it goes to line 7133 where it is tested for null-ness (its default value).

If null, it goes into that brain tumor epsilon stuff. I believe epsilon stuff is a type of “rounding”, and a mechanism to avoid a divide-by-zero error. In Star Trek lingo, it makes sure that the transporter places the human on ONE side of the wall, OR the OTHER side, but not “into” the wall. :slight_smile:

Anyway, I am simply telling of my experiments and things learned. No miraculous discoveries, but still better than accidentally peeing-on your own foot, right? :slight_smile:


A couple more to play with. Following your lead a swap in order of parameters (lines 12 and 34) can make major changes

Take a ride


You DID IT! Freakin’-A! (Wingy dances around like an idiot)

Hooray! Holy crap. 3-parameter call, eh?
this._normalVector(tg0, this._curve[0], firstNormal);

Interesting. This PG disables (overrides?) the optional firstNormal parameter for Path3d constructor, but who cares? No jerk-rotations. YAY!

I still like having the normals bisect our rider’s head, and not the binormals, so, I changed the formula order again. Later, if/when the optional firstNormal parameter is honored again, I might be able to return the formula order… to original order.

All in all, congrats, JK! Fantastic! We’re on our way, again. THANK YOU! Nice work!

I suppose, somehow, we’re still seeking a no-car-roll version… where the rider’s head stays as vertical as-possible, roll-wise. Natually, car pitch is going to affect rider UP-vector, but that’s fine. If we could accomplish growing paths that TRY to maintain rider head-up (roll-wise), that would be great.

That way, I get full-control of the banking (car z-rotation/roll), and NO control of banking is given to the path3d “grower” formula.

I’m not sure HOW I will manually program banking, but, physics is a possibility. By dangling/hanging/suspending a joint and pendulum-weight beneath each “train car”… and ONLY allowing carBodyImpostor ROLL… that might work. We cannot “lock” physics pitch and yaw. Instead, pitch and yaw must “free-wheel” - controlled only by path, not by physics. Only impostor roll… would be honored by our car. Weird thing, huh?

MAYBE…a special Path3d grower… COULD tilt the normals on the corners… by itself… and we would have a .bankingIntensity property. The amount of car upVector roll-tilt… would be based-upon the amount of x and z change… between current point and next point. Sideways (lateral) inertia calculations. Fancy. :slight_smile:


Wingnut your Chronicles are the best!

The solution above is cool. @Wingnut and @JohnK - thanks. Your writing on: normals, binormals, orthogonals, is a fun read. Highest honor: :black_heart:

UPDATE: followed through the experiment very interesting!

Seems like the SOLUTION was to reorder tangents and first normals!?! Interesting.

Catching up,