How to draw a cylinder from one point to another?

I am trying to create a lser beam using a simple glowing cylinder put into the world for a short time.
I manages to get nearly everything right but somehow i can’t wrap my head arround how to rotate and move the cylinder so that it points the right way.
With the code i got so far i can determine where i click, calculate the point on the ground plane to get the direktion and now want to place the cylinder so that it shoots from my player towards this spot (horizontal to the groundplane). My player origin is at the groundplane, so i thought i can just moce the cylinder to the players origin, rotate it towards the point and move it half its length forward. When i shoot along the z axis it looks fine, but when i shoot somewhere else the laser is off its target. Things get even stranger when i fire behind the player (have a third person view with a bit of floor behind player visible).

My code so far:
[java]
public static final Quaternion PITCH090 = new Quaternion().fromAngleAxis(FastMath.PI / 2, new Vector3f(0, 1, 0));

public void onAction(String name, boolean isPressed, float tpf) {
    if (name.equals("Shoot") && isPressed) {


        if (laserBeam == null) {
            CollisionResults results = new CollisionResults();
            Vector2f click2d = inputManager.getCursorPosition();
            Vector3f click3d = cam.getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 0f).clone();
            Vector3f dir = cam.getWorldCoordinates(new Vector2f(click2d.x, click2d.y), 1f).subtractLocal(click3d).normalizeLocal();
            Ray ray = new Ray(click3d, dir);
            Plane ground = new Plane(Vector3f.UNIT_Y, 0);
            Vector3f groundpoint = new Vector3f();
            ray.intersectsWherePlane(ground, groundpoint);

            Sphere help = new Sphere(8, 8, 0.2f);
            helper = new Geometry("helper", help);
            Material mathelper = mat.clone();
            mathelper.setColor("Color", ColorRGBA.Red);
            mathelper.setColor("GlowColor", ColorRGBA.Magenta);
            helper.setMaterial(mathelper);
            helper.center().move(groundpoint);
            rootNode.attachChild(helper);

            Cylinder laser = new Cylinder(4, 8, 0.02f, 100);
            laserBeam = new Geometry("laserbeam", laser);
            Material matlaser = mat.clone();
            matlaser.setColor("Color", ColorRGBA.Orange);
            matlaser.setColor("GlowColor", ColorRGBA.Red);
            laserBeam.setMaterial(matlaser);
            laserBeam.center();
            laserBeam.move(player.getLocalTranslation());
            laserBeam.rotate(player.getLocalRotation());
            Quaternion rotation = laserBeam.getLocalRotation();
            rotation.lookAt(groundpoint, Vector3f.UNIT_Y);
            rotation = rotation.mult(PITCH090);
            laserBeam.rotate(rotation);
            laserBeam.move(new Vector3f(0, 3, 0));
            laserBeam.move(laserBeam.getLocalRotation().mult(new Vector3f(0, 0, 50)));
            rootNode.attachChild(laserBeam);
            laserlifetime = lasermaxlifetime;
        }
    }
}

@Override
public void simpleUpdate(float tpf) {
    if (laserlifetime  0 && laserBeam != null) {
        laserlifetime -= tpf;
    }

}

[/java]

I know it looks a bit messy, but thats from trying to figure it out, once i know how to do it i am going to tidy it up.

Anyone got a clue what i am doing wrong ?

Ok, solved it myself… lines 36 and 37 where total nonsense… that quaternion is the actual one used by the node so i manipulated it diretly.
Thought i was getting a new instance, but reading through math sheet got me on the right track.

Edit:
Mmh, now i get strange results still when i turn or move the player. Target of laser is not right then still.

I can’t understand lines 36 and 38.
Also line 35 seems to be off-topic. It computes an angle with respect to no position. Why don’t you use something like laserBeam.lookAt(groundPoint, Unit_Y) ?
You should also check which axis get rotated toward the target. Not sure this is the good one in your case.

I also don’t understand the line 39 for sure. Do you wan’t to translate the laser beam along its axis ?

Ok, missed the lookAt on the Spatial itself. But even using this it is fine when player is not rotated, but once the player rotetes it seems the rotation from player is added to the rotation of laser towards the groundpoint.

Line 38 moved the beam up from ground level so that it shoots from the player and not from between its feet.
Line 39 moved the beam forward because when creating the cylinder its center is at the origin, so i have to move it half its length forward.

Got this code now which works better but still has the player rotation problem:
[java] Cylinder laser = new Cylinder(4, 8, 0.02f, 100);
laserBeam = new Geometry(“laserbeam”, laser);
Material matlaser = mat.clone();
matlaser.setColor(“Color”, ColorRGBA.Orange);
matlaser.setColor(“GlowColor”, ColorRGBA.Red);
laserBeam.setMaterial(matlaser);
// attach laserbeam to player so it moves with player
player.attachChild(laserBeam);
// center laserbeam on players origin
laserBeam.center();
// make the laserbeam point towards clicked spot
laserBeam.lookAt(groundpoint, Vector3f.UNIT_Z);
// move laserbeam up so it does not shoot on ground level, but from player model
laserBeam.move(new Vector3f(0, 3, 0));
// move laserbeam forward because cylinder is created with center at player origin
laserBeam.move(laserBeam.getLocalRotation().mult(new Vector3f(0, 0, 50)));[/java]

Do you use the latest nightly ?
This trouble has been fixed a few weeks ago. (Rotation of the parent is now considered in the computation of lookat)

You should however first move the laser origin to the player-rifle and then only lookat. Otherwise, you will be offsight 3 units higher your target :wink:

No i am using latest stable build. Is it that outdated ?

For now i want the laser allways shooting parralel to the ground, so this way is fine. Otherwise you would be right :wink:

Depends what you mean by outdated. Stable is the one you should be using. The bugfix will push out to stable at some point.

Thats what i mean, how often are stable builds generated ? Or is there no usual timeframe for it ?
Switched to nightly and works like a charm now.
Still would like to understand the math that was missing. Tried to combine the player rotation with the rotation that the lookAt produced, but wasnt able to figure it out. Lacking a bit math skills with qaternions for that.

Well Maths are not that complicated.

  1. You take the rotation P of your parent
  2. You compute the rotation R needed toward your goal
  3. You prepend the inverse of the parent rotation to your rotation
    R* = P^-1 x R

Thus, when the final transform is computed, you have P x R* = R your desired rotation.

1 Like

So something like this:
[java]
Quaternion playerrot = player.getLocalRotation().clone();
playerrot.inverseLocal();
Quaternion laserrot = laserBeam.getLocalRotation().clone();
laserrot.lookAt(targetpoint, Vector3f.UNIT_Z);
laserrot.multLocal(playerrot);
laserBeam.rotate(player.getLocalRotation().mult(laserrot));
[/java]

?

Not this.

First you should not inverse the rotation of your parent !!! InverseLocal DO change the rotation of the parent !!!
Prefer something like playerRot = playerRot.inverse();

Next, you use lookAt on the spatial, so that it has a position.

Finally, you have to prepend not append the parent inverse rotation !
laserRot = playerRot.mult(laserBeam.getLocalRotation);

and at the end, you just have laserBeam.setLocalRotation(laserRot)

The renderer will compute the real final transform.

So in summary :
playerRot = playerRot.inverse();
laserBeam.lookAt(targetPoint, Vector3f.UNIT_Y); // Why Z here ?
laserRot = playerRot.mult(laserBeam.getLocalRotation);
laserBeam.setLocalRotation(laserRot);

But as I told you, this update already has been committed. At least to nightly.
If you apply this fix, it will cease working as soon as the fix comes in the stable build.

1 Like

I know that InverseLocal changes the qaternion its used on, thats why i cloned the player qaternion in the lines above.

Yes, with the niglty build it works. Just wanted to understand the procedure. I worked with vectors and qaternions a few years ago but forgot a lot of the math stuff that is involved by now, so i am trying to refresh my memory/knowledge. Think i understand it now, thanks!

Ok, sorry. I’ve read too quickly. Missed the clone. Mea culpa ;-).

Always good to have a fresh memory !