Trouble Rotating a Plane around an irregular axis in order to face the camera

I’m making a new spell-type for my game that works like a laser beam. I’ve managed to generate a flat plane between the start of the beam and the end of the beam, but now I’m having trouble getting the plane to rotate around its axis so that it faces the camera.

So far I’ve been trying to use the .fromAngleAxis();method - the only problem is I cannot seem to supply the correct degree value based on the current camera angle

             Vector3f dirToCam = app.getCamera().getLocation().subtract(beamLocation);
             float degrees;  //  =  ????;

        //some of my failed attempts at math....

       //    degrees = beamDir.dot(dirToCam); 

      //     Vector3f cross = beamDir.normalize().cross(dirToCam.normalize());
      //     tempQuat.lookAt(beamDir, upVec);
      //     degreese = tempQuat.toAngleAxis(cross);;              

       //   degrees = FastMath.pi * 3/2 ;  constant value to test a working rotation during my trial and error attempts

             beamGeometry.getLocalRotation().fromAngleAxis(degrees * FastMath.RAD_TO_DEG , beamDir);`

I found through trial and error that if I set a constant values for the degree parameter, then I can get my shape to face that direction. So I was able to find out that this method does what I want if I give it the right paramaters…

But I’m unable to find how I should calculate the proper degree value based on the beam direction and the camera angle.

The first thing I tried was crossing the beamDirection with the cameraDirection, but I don’t know how to get an angle value based on the crossed vector.

This is what the beam looks like when I set it to a constant 90 degrees with Fasmath.pi * 3/2 as the degrees paramater

Thanks in advance for any help :slightly_smiling_face:

Getting angles involved when you already have relative directions is almost never the answer. It’s three times the work and errors can creep in all over the place.

You know one axis: the beam

You need to find the other two.

One other axis will be the cross product of the camera-beamEndpoint vector and the beam vector. (Normalized of course.)

The third axis is the cross product of the first two.

Once you have three axes then you have a coordinate system. No reason to use angles.

https://javadoc.jmonkeyengine.org/com/jme3/math/Quaternion.html#fromAxes-com.jme3.math.Vector3f-com.jme3.math.Vector3f-com.jme3.math.Vector3f-

2 Likes

That smells a lot like an equation to calculate normals, too.

I tried your suggestion and it looks like I’m getting closer, but I can’t quite get things working entirely.

I’ve tried playing around with this code a bit, and at its best the beam will face the camera, but it also pivots in un-desirable directions, causing the start and end point of the Plane to rotate away from the actual start and end location of the Ray associated with the beam, so I think I’m still doing something wrong.

Here’s my updated code based on your suggestion. I’m calling this in my update loop for the duration of the laser beam spell - first the mesh gets updated based on the new start/end locations, then I’m trying to set the correct rotation.

         Vector3f end = target.getLocation();
         Vector3f start = caster.getHeadLocation();

         beamDir =  end.subtract(start);


         Vector3f meanLocation = updateBeamMesh(start, end);
         beamGeometry.setLocalTranslation(meanLocation); 
                    
          Vector3f axis1 = beamDir.clone();
          axis1.normalizeLocal();

           Vector3f camToBeamVector = end.subtract( app.getCamera().getLocation());
           camToBeamVector.normalizeLocal();
                    
           Vector3f axis2 = camToBeamVector.cross(axis1);
           axis2.normalizeLocal();
                       
            Vector3f axis3 = axis2.cross(axis1);
            axis3.normalizeLocal();
                    
            beamGeometry.getLocalRotation().fromAxes(axis1, axis2, axis3);

Any idea what I may be doing wrong still?

If it were me, I’d try visualizing the axes to see what’s wrong.

Edit: also, what you consider axis1, axis2, and axis3 in the fromAxes() will greatly depend on what the natural direction of your beam mesh is, etc… and this presumes are you creating the beam mesh in unrotated space, ie: it’s just the length you are getting from end1 and end2.

Edi2: also note: this is normally the kind of thing I’d do in a shader since it’s easier to project the corners along that first cross product.

1 Like

I think that I was creating the beam in rotated space and that was causing the problem. I went back to where I generate the flat mesh, and I noticed that it actually starts at a higher Y value than it ends, so it wasn’t necessarily flat I suppose.

I was going to generate the mesh entirely flat and try again, but instead I was able to take the first cross product Vector and use that as the offset for the corners of the mesh when its being generated, and it looks like its working now :slightly_smiling_face:

So I guess I could have solved this in a few different ways, but I ran into difficulties since I was doing some of the rotation in the mesh generation stage, and then I was attempting to do the rest of the rotation on the generated geometry in world space.

Thank you for your help and knowledge :slightly_smiling_face: this had me really confused at first but now I got it working, and I also learned a thing or two about Quaternions (at least more than I knew before :laughing:)

Yeah, it’s a little easier in the vert shader to do these things because you have all of the pieces and are just deciding which way to push each vertex. (Effectively what you are doing to the mesh now.)