Rotation Towards 3D Point

Started by AGP, March 07, 2017, 09:10:49 PM

Previous topic - Next topic

AGP

The following isn't working. How come?


     public void rotateTowards(SimpleVector towards) {
SimpleVector directionVector = new SimpleVector(towards.x -model.getTransformedCenter().x, towards.y -model.getTransformedCenter().y, towards.z -model.getTransformedCenter().z).normalize();//WON'T WORK WITH OR WITHOUT NORMALIZE()
Matrix rotationMatrix = directionVector.getRotationMatrix();
if (this instanceof Worker)
     ((Worker)this).setRotationMatrix(rotationMatrix);
else model.setRotationMatrix(rotationMatrix);
     }

EgonOlsen

"isn't working" doesn't really tell me much. You have to keep in mind that getRotationMatrix() gives you some rotation matrix that does the job, but it makes no assertion about the up-vector of the resulting matrix. If you need that, you would have to use the method that takes an additional up vector.

AGP

Most of the time it rotates in the wrong direction, sometimes it doesn't rotate at all. My game is on the x/z plane, but which method takes an up vector?

AGP

Oh, it should be noted that I already have both vectors in worldspace (my plane consists of multiple smaller planes that collide with the raycast mouse then just give me their transformed center).


AGP

If the characters are on the x/z plane and right side up, should I not do

Matrix rotationMatrix = directionVector.getRotationMatrix(new SimpleVector(0f, -1f, 0f));?

Because that didn't work.

EgonOlsen

Again, "didn't work" doesn't tell me much. What's the exact problem? And what does "right side up" mean in this context? It's either the right side or it's pointing up IMHO. How can a right side point upwards while still being on the right?

EgonOlsen

Here's a simple example. Maybe that helps:



import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;

import javax.swing.JFrame;

import com.threed.jpct.Camera;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.IRenderer;
import com.threed.jpct.Interact2D;
import com.threed.jpct.Lights;
import com.threed.jpct.Matrix;
import com.threed.jpct.Object3D;
import com.threed.jpct.Primitives;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.World;
import com.threed.jpct.util.Light;


public class MouseFollow
  extends JFrame
  implements MouseMotionListener
{

  private static final long serialVersionUID = 1L;

  private Graphics g = null;
  private FrameBuffer fb = null;
  private World world = null;
  private Object3D plane = null;
  private Object3D pointer = null;

  private boolean doloop = true;
  private SimpleVector target = new SimpleVector();

  private int x = 320;
  private int y = 240;


  public MouseFollow()
  {
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    pack();
    setSize(640, 480);
    setResizable(false);
    setLocationRelativeTo(null);
    setVisible(true);
    this.addMouseMotionListener(this);
    g = getGraphics();
  }


  public void mouseMoved(MouseEvent m)
  {
    x = m.getX();
    y = m.getY();
  }


  public void mouseDragged(MouseEvent m)
  {}


  private void initStuff()
  {
    fb = new FrameBuffer(640, 480, FrameBuffer.SAMPLINGMODE_NORMAL);
    world = new World();
    fb.enableRenderer(IRenderer.RENDERER_SOFTWARE);

    plane = Primitives.getPlane(20, 10);
    plane.setAdditionalColor(Color.GREEN);

    plane.rotateX((float) Math.PI / 2f);

    pointer = Primitives.getCone(20);
    pointer.rotateX((float) Math.PI / 2f);
    pointer.rotateMesh();
    pointer.clearRotation();

    plane.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
    Object3D cube = Primitives.getCube(5);
    cube.translate(0, -15, -15);
    cube.translateMesh();
    pointer = Object3D.mergeObjects(pointer, cube);

    world.addObject(plane);
    world.addObject(pointer);

    pointer.translate(-50, -10, -50);

    Light light = new Light(world);
    light.setPosition(new SimpleVector(0, -80, 0));
    light.setIntensity(40, 25, 22);

    world.buildAllObjects();
  }


  private void follow()
  {
    SimpleVector ray = Interact2D.reproject2D3DWS(world.getCamera(), fb, x, y);
    if (ray != null)
    {
      ray = ray.normalize();

      float f = world.calcMinDistance(world.getCamera().getPosition(), ray, 1000);
      if (f != Object3D.COLLISION_NONE)
      {
        SimpleVector offset = new SimpleVector(ray);
        ray.scalarMul(f);
        ray = ray.calcSub(offset);
        ray.add(world.getCamera().getPosition());
        target.set(ray);

        SimpleVector dir = target.calcSub(pointer.getTranslation());
        Matrix m = dir.getRotationMatrix(new SimpleVector(0, f - 1f, 0f));
        pointer.setRotationMatrix(m);
      }
    }

    if (pointer.getTranslation().calcSub(target).length() > 0.5f && target.length() > 0.01f)
    {
      pointer.translate(pointer.getZAxis());
    }
  }


  private void doIt()
    throws Exception
  {
    Camera cam = world.getCamera();
    cam.moveCamera(Camera.CAMERA_MOVEOUT, 100);
    cam.moveCamera(Camera.CAMERA_MOVEUP, 160);
    cam.lookAt(plane.getTransformedCenter());

    world.getLights().setOverbrightLighting(Lights.OVERBRIGHT_LIGHTING_DISABLED);

    while (doloop)
    {
      follow();
      fb.clear();
      world.renderScene(fb);
      world.draw(fb);

      fb.update();
      fb.display(g);
      Thread.sleep(10);
    }
    fb.disableRenderer(IRenderer.RENDERER_OPENGL);
    System.exit(0);
  }


  public static void main(String[] args)
    throws Exception
  {
    MouseFollow cd = new MouseFollow();
    cd.initStuff();
    cd.doIt();
  }
}




AGP

This is a language barrier. "Right side up" means "not upside down" (in this case, the model's up direction is aligned with jpct's world in that -y points up).

Your example works, but I should have clarified that the direction is stored in an array of ws SimpleVectors (as returned by the pathfinder), so your raycasting code won't apply. So how could I use it in this context?

AGP

I wasn't being lazy, FYI. But after several attempts based on yours, this is what worked:


     public void rotateTowards(SimpleVector towards) {
SimpleVector target = new SimpleVector(towards);
        SimpleVector dir = target.calcSub(model.getTranslation());
        Matrix rotationMatrix = dir.getRotationMatrix(new SimpleVector(0, 1f, 0f));
rotationMatrix.rotateY((float)Math.PI*-.5f);
if (this instanceof Worker)
     ((Worker)this).setRotationMatrix(rotationMatrix);
else model.setRotationMatrix(rotationMatrix);
     }

AGP

Update: sometimes the models are rotating in an axis other than the world's y. Is there  a way for me to limit the matrix's rotation to only the y axis?

EgonOlsen

That shouldn't happen, if you provide an up-vector. It might be a kind of distorted matrix because some input parameters are a bit off. Have you tried to normalize the direction vector?

AGP

It's normalized and it does frequently (say, 5% of the time) happen that the model get rotated 90 degrees on an axis other than the world's y.

EgonOlsen

No idea. It's impossible to tell without a test case. I've used this method in several applications, and never had a problem like this.