GrayFox

Cylinder between two points

Recommended Posts

Hello guys,

im trying to join two meshes (spheres) with a cylinder.( maybe basic but i'm having hard times as a beginner). The problem is that the default cylinder constructor leaves you with just the ability to only set the size , diameter of both top and bottom, and tessellation

 

·         Mesh.CreateCylinder(name, height, diameterTop, diameterBottom, tessellation, scene, updatable)

 

when i need to do something like 

·         New Cylinder(vectorStart, vectorEnd, scene) 

i've tried something like:

 

Cylinder = function(vstart,vend, scene){

  var HALF_PI = Math.PI/2 ;
  var distance = BABYLON.Vector3.Distance(vstart, vend);
  var position = vend.clone().add(vstart).divide(new BABYLON.Vector3(2,2,2));
 
  var material = new BABYLON.StandardMaterial("kosh", scene);
  var cylinder = BABYLON.Mesh.CreateCylinder("cylinder", distance, 1, 1, 36, scene, true);
 
   var orientation = new BABYLON.Matrix();
    var offsetRotation = new BABYLON.Matrix();
    orientation = BABYLON.Matrix.LookAtLH(vstart, vend, new BABYLON.Vector3(0,1,0));
    offsetRotation =BABYLON.Matrix.RotationX(HALF_PI);
    orientation.multiply(offsetRotation);
    cylinder.bakeTransformIntoVertices(orientation);;
    cylinder.position = position;; 
}

 

but it doesn't seem to work .

maybe i'm having a really bad approach of the problem but actually i really don't know what to do .

 

Can someone have any idea for me ? help will be so appreciated   :)

 

thanks in advance ! . 

Share this post


Link to post
Share on other sites

Can you create a playground sample? This way we will be able to help you debug your code :)

 

Sure @Deltakosh :) Thank you so much for spending your precious time on this.

 

Please find here http://www.babylonjs.com/playground/#1RWE59#9

 

As i don't know well about the playground and it's ability to parse and handle inner functions, i've just pasted an inline version of the initial function, assuming the result will be the same.  :)

 

Please, also bear in mind that i keep on searching too and stay open to any new idea. Maybe i'm doing it the wrong way  and  taking a bad approach to solve this problem.

 

will keep  you posted on any new updates.

 

Again, Thanks a lot. 

Share this post


Link to post
Share on other sites

And here is the result:

http://www.babylonjs.com/playground/#1RWE59#12

 

Code for reference:

    var vstart = whiteSphere.position;    var vend = redSphere.position;    var distance = BABYLON.Vector3.Distance(vstart,vend );        var material = new BABYLON.StandardMaterial("kosh", scene);    var cylinder = BABYLON.Mesh.CreateCylinder("cylinder", distance, 1, 1, 36, scene, true);        // First of all we have to set the pivot not in the center of the cylinder:    cylinder.setPivotMatrix(BABYLON.Matrix.Translation(0, -distance / 2, 0));     // Then move the cylinder to red sphere    cylinder.position = redSphere.position;    // Then find the vector between spheres    var v1 = vend.subtract(vstart);    v1.normalize();    var v2 = new BABYLON.Vector3(0, 1, 0);        // Using cross we will have a vector perpendicular to both vectors    var axis = BABYLON.Vector3.Cross(v1, v2);    axis.normalize();    console.log(axis);        // Angle between vectors    var angle = BABYLON.Vector3.Dot(v1, v2);    console.log(angle);        // Then using axis rotation the result is obvious    cylinder.rotationQuaternion = BABYLON.Quaternion.RotationAxis(axis, -Math.PI / 2 + angle);

Share this post


Link to post
Share on other sites

@DeltaKosh ... you my Hero !

 

 you pretty awesome :) !!!!  we are always told to keep things simple but  it seems to never stick in my that**head ! 

 

 i've made it a constructor because the cylinder which is in fact a molecular bound needs to manage itself depending the view mode (Balls, Sticks, Balls & Sticks) and it works like a charm ! 

 

Again, Big Thanks 

Share this post


Link to post
Share on other sites

Hey Deltakosh,

 

Thanks for the excellent post. I ran into a little bit of a problem when I lifted and reused it.

 

The situation happens when you run into the case where v1 = -v2. In my case, it happened with the two points (10, 20, -2) and (10, 2, -2) are input into your example code.

 

In this situation, the resultant cylinder is turned in the exact opposite direction from point A. This is apparently a common problem with this method of devising a quaternion based on a vector between two points.

 

The problem was exacerbated by the fact I couldn't just do an if(v1.equals(v2.negate()) statement. Because of numerical instability I ended up with v1 = (0, -0.9999999..., 0) and v2 = (0, 1, 0). I didn't see anything in the Babylon API that handles this case, so I wrote my own quick hack:

var vectorEqualsCloseEnough = function(v1, v2, tolerance) {  if(typeof(v2) !== 'object') { throw("v2 is supposed to be an object"); }  if(typeof(v1) !== 'object') { throw("v1 is supposed to be an object"); }  if(!tolerance) {    tolerance = 0.00002;  }  if(v1.x < v2.x - tolerance || v1.x > v2.x + tolerance ) {    return false;  }  if(v1.y < v2.y - tolerance || v1.y > v2.y + tolerance ) {    return false;  }  if(v1.z < v2.z - tolerance || v1.z > v2.z + tolerance ) {    return false;  }  return true;};

And this is my version of your function that calls it:

var createCylinderBetweenPoints = function(pointA, pointB, name, diameter, scene) {  var distance = BABYLON.Vector3.Distance(pointA, pointB);  var cylinder = BABYLON.Mesh.CreateCylinder(name, distance, diameter, diameter, 20, scene, true);  // Pivot from the end of the cylinder, not the centre  cylinder.setPivotMatrix(BABYLON.Matrix.Translation(0, -distance / 2, 0));  // Move the cylinder to start at pointB  cylinder.position = pointB;  // Find direction vector between points (v1) and cross it with a y-up vector (v2)  // to find the pivot axis for our quaternion  var v1 = pointB.subtract(pointA);  v1.normalize();  var v2 = new BABYLON.Vector3(0, 1, 0);  var axis = BABYLON.Vector3.Cross(v1, v2);  axis.normalize();  // Now figure out what the angle should be with a dot product  if(vectorEqualsCloseEnough(v1, v2.negate())) {    cylinder.position = pointA;    return;  }  var angle = BABYLON.Vector3.Dot(v1, v2);  // Generate the quaternion  cylinder.rotationQuaternion = BABYLON.Quaternion.RotationAxis(axis, -Math.PI / 2 + angle);};

Hope this helps! Thank you for the great original code, it really helped me out.

 

If you know of a function in the Babylon API that does "close enough" vector equality I'd love to replace my ugly hack with it.

Share this post


Link to post
Share on other sites

It didn't quite work as expected for me.

I altered the code a bit (converted the dot product to an angle using Math.acos)

This works great for me.

 

http://www.babylonjs-playground.com/#1RWE59#13

// You have to create a function called createScene. This function must return a BABYLON.Scene object// You can reference the following variables: scene, canvas// You must at least define a camera// More info here: https://github.com/BabylonJS/Babylon.js/wiki/The-Playgroundvar createScene = function () {    var scene = new BABYLON.Scene(engine);        var light = new BABYLON.PointLight("Omni", new BABYLON.Vector3(10, 50, 50), scene);    var camera = new BABYLON.ArcRotateCamera("Camera", 0, 1.2, 30, new BABYLON.Vector3(-10,0,0), scene);light.intensity = 1;    camera.attachControl(canvas, false);    var whiteSphere = BABYLON.Mesh.CreateSphere("sphere1", 16, 2, scene);    whiteSphere.position = new BABYLON.Vector3(-20,0,0);        var redSphere = BABYLON.Mesh.CreateSphere("sphere2", 16, 2, scene);    redSphere.position=  new BABYLON.Vector3(0,5,0);    var redMat = new BABYLON.StandardMaterial("kosh", scene);    redMat.diffuseColor = new BABYLON.Color3(1, 0, 0);    redSphere.material = redMat;          var vstart = whiteSphere.position;    var vend = redSphere.position;    var distance = BABYLON.Vector3.Distance(vstart,vend );        var material = new BABYLON.StandardMaterial("kosh", scene);    var cylinder = BABYLON.Mesh.CreateCylinder("cylinder", distance, 1, 1, 36, scene, true);        // First of all we have to set the pivot not in the center of the cylinder:    cylinder.setPivotMatrix(BABYLON.Matrix.Translation(0, -distance / 2, 0));     // Then move the cylinder to red sphere    cylinder.position = redSphere.position;    // Then find the vector between spheres    var v1 = vend.subtract(vstart);    v1.normalize();    var v2 = new BABYLON.Vector3(0, 1, 0);        // Using cross we will have a vector perpendicular to both vectors    var axis = BABYLON.Vector3.Cross(v1, v2);    axis.normalize();    console.log(axis);        // Angle between vectors    var angle = Math.acos(BABYLON.Vector3.Dot(v1, v2));    console.log(angle);        // Then using axis rotation the result is obvious    cylinder.rotationQuaternion = BABYLON.Quaternion.RotationAxis(axis, -angle);          scene.registerBeforeRender(function () {        light.position = camera.position;    });    return scene;};

Share this post


Link to post
Share on other sites

 

And here is the result:

http://www.babylonjs.com/playground/#1RWE59#12

 

Code for reference:

    var vstart = whiteSphere.position;    var vend = redSphere.position;    var distance = BABYLON.Vector3.Distance(vstart,vend );        var material = new BABYLON.StandardMaterial("kosh", scene);    var cylinder = BABYLON.Mesh.CreateCylinder("cylinder", distance, 1, 1, 36, scene, true);        // First of all we have to set the pivot not in the center of the cylinder:    cylinder.setPivotMatrix(BABYLON.Matrix.Translation(0, -distance / 2, 0));     // Then move the cylinder to red sphere    cylinder.position = redSphere.position;    // Then find the vector between spheres    var v1 = vend.subtract(vstart);    v1.normalize();    var v2 = new BABYLON.Vector3(0, 1, 0);        // Using cross we will have a vector perpendicular to both vectors    var axis = BABYLON.Vector3.Cross(v1, v2);    axis.normalize();    console.log(axis);        // Angle between vectors    var angle = BABYLON.Vector3.Dot(v1, v2);    console.log(angle);        // Then using axis rotation the result is obvious    cylinder.rotationQuaternion = BABYLON.Quaternion.RotationAxis(axis, -Math.PI / 2 + angle);

It seems there is a problem with the code here (http://www.babylonjs...ound/#1RWE59#12)

If I change the positions of the spheres then the cylinder would no longer connect

 

Like if i change this

whiteSphere.position = new BABYLON.Vector3(-20,0,0);

to

whiteSphere.position = new BABYLON.Vector3(-20,-20,0);

 

then then it will not work. Am I doing something wrong here. I took the code wrapped it up in a functions but for most of the cylinders one side would connect to one of the points but the other side one would not connect to the other point.

Share this post


Link to post
Share on other sites

Dear all.

I am also new to Babylon and need this functionality.

The above seems to rotate the link. You can see it using a box http://www.babylonjs-playground.com/#1RWE59#98

I need to keep them flat to the xz plane.

I have spent quite a bit of time trying to make this happen but its not happening. Any help would be appreciated.

Thanks in advance.

Share this post


Link to post
Share on other sites

Hi CLW, welcome to the forum.  How's this look...

https://www.babylonjs-playground.com/#1RWE59#101

Lines 35-87 is one big function, now.  In lines 90-93, that function is called 4 times.

Change the 'false' to 'true' in line 93, to see what that does.  (it is essentially addEndingSphere true/false)  :)

Notice that every Y value in the vector3's... in lines 90-93... are all set == 0.  No height.  All points are on the ground.

Hope this helps. 

Share this post


Link to post
Share on other sites

https://www.babylonjs-playground.com/#1RWE59#109

I suppose you want all the pieces... parented to  gizmo... so you can position/rotate/scale the skylight frame... easily?  (by moving the gizmo)

I haven't determined how to use a central parent on this, yet.  Shifted pivot-points are causing issues.

BUT, you want all the span-mesh... to lay flat, right?  Flat sides facing up.  Yep, bet so.  (You explained it perfectly... but I am slow, mentally.)  :)

I'll keep thinking.  Perhaps smarter people that I... will reply soon.

Sorry for misunderstanding.  I think I understand objective, now.  hmm.

The span-mesh (arms) in the picture... look somewhat triangular, eh?  Should be do-able, somehow.  Nice challenge!  ;o

Share this post


Link to post
Share on other sites

https://www.babylonjs-playground.com/#1RWE59#110

Another interesting kludge... using lookAt with offsets, and some tweaking (and no quaternion stuff other-than what comes with lookAt). 

Gruesome!  But all the triangular spans are rotated somewhat correctly.

Here's another, using 4-sided spans.  https://www.babylonjs-playground.com/#1RWE59#112

Just bad.  It has the precision and symmetry of a pile of mashed potatoes.  :D  hmm.   (Wingnut starts power-drinking, and thinks some more).   :)

https://www.babylonjs-playground.com/#1RWE59#116  (all parts parented to a 'gizmo')  (slightly raised all upper points except line 99 cross-bar)

Share this post


Link to post
Share on other sites

Nice one Wingnut you seem to have cracked it.

I didn't know about that lookAt. I was starting to go down the Path3D method with 

     var v1 = new BABYLON.Vector3.RotationFromAxis(binormals[0], normals[0], tangents[0]);
            polygon.rotation = v1;

But I couldn't get that to work.

 

Yes they are more like triangles. Hopefully I will be getting the shape data to make an extruded polygon.

How does that gizmo come into it?

I would have liked to lerp the spans to change the size of the roof but I will get to that later!

Thanks for your help.

Share this post


Link to post
Share on other sites

Cool!   The gizmo just makes it easier to position, rotate, and perhaps scale... the entire structure.  Consider it a "grouper".  If you need the structure to be 10 units off the ground, simply raise the gizmo.position.y, and entire structure rises.  A gizmo can also be called 'handle', 'proxy', and 'root', sometimes.  There are probably other names, too.

In my most-recent demo, I did a slow rotation of the gizmo (in the renderLoop), and the entire structure rotates.  All parts are parented to it.

It takes a certain kind of bravery to attempt to dynamically-generate this shape... with math/calculating.  I'm impressed with your adventuresome spirit!   The structure could be modeled in a modeller such as Blender or 3DsMax, too.

I like dynamic models, too.  I think they are sometimes called "parametric shapes".  I call it "manual plotting".  Here is one I did early in my BJS days (I call it "the plottery barn")... built when I was still learning how vertex data works (barely learned, now).  I use a little utility called 'boxify' to help me know which vertex... is located where.  Boxify sometimes needs mods... when flat-shaded mesh such as BJS boxes... is used.  More than one vert can be at the same location.  Here is a scene where stacked boxify was used to help me plot UVs for a woodgrain texture.  It turned out that the top piece's wood-grain was vertically flipped, and I never fixed it.  :)  User who I was helping... had needs for obtuse and acute angles in his hand railings, and I bailed due to being scared/stupid.  :D

Later I did an Air-Cooled High-Performance-Pointing Racing Arrow, which is pretty and fun.  I rarely take it out-of the garage, because it points TOO HARD and TOO FAST.  Children could get hurt.  heh

And even later, I built a "flying bobsled" using parametric shapes that were invented by our geometry God @jerome.  Its gizmo-box is physics-engine-active,  so it has "thrusting keys".  Press/hold shifted arrowkeys + pgUp/pgDown for translation, and control arrowkeys + pgUp/pgDown for rotation.

My age, and coding styles.... are pretty "old school", and I'm far from a math expert.  There are FAR better shape-plotters than I.  You could surely math-plot your skylight frame, using 'plottery barn' methods, if you enjoy that kind of pain. 

A nice chap named @Arte is also into parametric cabinets/shelving.  He showed us some movies of his project... here

A cool adventurer named @aFalcon is doing some mesh/terrain plotting here.

If you try plotting your skylight frame, could you share it with us? 

In fact, if you wish, show'n'tell (share) EVERYTHING that you do.  We love looking-at scenes around here, and especially if they are mad-scientist 'demented experiments'!   We love the BJS playground.  Demos put in there... can be messed-with by anyone, so everyone learns.   There are various ways to search the playground database... also handy and packed with learning.  (You probably know all this already - sorry if so).

Have you ever seen our 'spherical harmonics" demo?  Jerome has a nice version on his website... worth seeing.  Math gods - they are my heroes.  :)

YOU are probably a math God, too.  If you are willing to go LERPing, you are certainly math-brave to SOME degree.  :)  I look forward to your "stuff".  Party on!

PS: Wasn't there a children's song about LERP?  "Here we go LERP-dee-log(),  here we go LERP-dee-light.  Here we go SLERP-dee-LERP,  all on a Saturday night."  :D

Share this post


Link to post
Share on other sites

I've been using MeshBuilder.ExtrudePolygon because I thought I could update the depth later but this has not been added in Babylon.js.

So I looked at ExtrudeShape where I can have a 2 point path and modify the points.

This works but calling convertToFlatShadedMesh(); messes it up!

http://www.babylonjs-playground.com/#165IV6#163

Share this post


Link to post
Share on other sites

Hiya CLW!  Sorry for the slow response.

https://www.babylonjs-playground.com/#165IV6#164

Line 37 is an "updater" or "appender".  It adds more extrusion shape... to an already-existing extruded shape.

So, you need to wait until AFTER that line... to call your flat shader. 

Flat shading... adds vertices.  For example, if 3 "faces" intersect at a single vertex, flat shading will add 2 more verts atop the first one.   This is why BJS boxes are 24 verts, and not 8 verts.  They are flat-shaded by default.  Some mesh... when flat-shaded... go over 3 times their original vert-count.  :o

I don't think the extrude-appender... can handle those extra vertices.  So we wait until after the shape is completed, and then convert.

Party on!

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

  • Recently Browsing   0 members

    No registered users viewing this page.