Author Topic: How to rotate and move 3D object in world space by 2D mouse coordinaes?  (Read 5922 times)

Offline marat

  • byte
  • *
  • Posts: 6
    • View Profile
Hallo!

I want to solve the following problems:
1) How to rotateY() 3D object in world space by 2D mouse coordinates? // 3D object must follow mouse movements
2) How to move 3D object in world space by 2D mouse cooridnates? // 3D object must move in world by mouse click

//Solution 1
SimpleVector mouse3D = Interract2D.reproject2D3DWS(camera, xMouse, yMose).normalize();
float angel = mouse3D.calcAngel(my3Dobject);
my3Dobject.clerRotation();
my3Dobject.rotaYAxis(new SimpleVector(0,1,0), angel);

//Solution 2
SimpleVector mouse3D = Interract2D.reproject2D3DWS(camera, xMouse, yMose).normalize();
Simple direction = mouse3D.calcSub(my3Dobject.getTranslation()); // get direction of 3Dobject
my3Dobject.translate(direction.x+1, 0, direction.z+1);

Maybe similar topics already exist? (please can send the links)

Sorry for my english.

Thanks!


[attachment deleted by admin]
« Last Edit: June 29, 2011, 10:51:54 am by marat »

Offline Nemetz

  • int
  • **
  • Posts: 53
    • View Profile
Hi!
I'm simply made it in Android version with
   my3Dobjct.rotateY(turnRad);
where turnRad - is in angle in Radians.

Offline marat

  • byte
  • *
  • Posts: 6
    • View Profile
So the solutins is?
SimpleVector mouse3D = Interract2D.reproject2D3DWS(camera, xMouse, yMose).normalize(); // Am correctly use  method to convert 2D mouse coordinates from screen to 3D?
float angel = mouse3D.calcAngel(my3Dobject);
my3Dobject.clerRotation();
my3Dobject.rotaY(Math.toRadian(angel));

i always got positive angel...

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 11776
    • View Profile
    • http://www.jpct.net
I'm not sure, if this is what you mean, but here's an old and hacky test case of mine. It's for desktop jPCT, but it can easily be ported.

Code: [Select]
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import javax.swing.JFrame;

import com.threed.jpct.*;
import com.threed.jpct.util.Light;


public class MouseFollowDemo
  extends JFrame
  implements MouseMotionListener, MouseListener
{

  private static final long serialVersionUID = 1L;
  private Graphics g = null;
  private FrameBuffer fb = null;
  private World world = null;
  private Object3D plane = null;
  private Object3D ramp = null;
  private Object3D player = null;
  private Object3D cube2 = null;
  private Object3D sphere = null;

  private boolean doloop = true;
  private boolean pressed = false;

  private int mouseX = 320;
  private int mouseY = 240;


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


  @Override
  public void mouseMoved(MouseEvent m)
  {
    mouseX = m.getX();
    mouseY = m.getY();
  }


  @Override
  public void mouseDragged(MouseEvent m)
  {}


  @Override
  public void mouseClicked(MouseEvent e)
  {}


  @Override
  public void mouseEntered(MouseEvent e)
  {}


  @Override
  public void mouseExited(MouseEvent e)
  {}


  @Override
  public void mousePressed(MouseEvent e)
  {
    pressed = true;
  }


  @Override
  public void mouseReleased(MouseEvent e)
  {}


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

    ramp = Primitives.getCube(20);
    ramp.setAdditionalColor(Color.red);
    plane = Primitives.getPlane(20, 10);
    plane.setAdditionalColor(Color.GREEN);
    sphere = Primitives.getSphere(30);
    sphere.setAdditionalColor(Color.CYAN);
    sphere.translate(-50, 10, 50);
    cube2 = Primitives.getCube(20);
    cube2.setAdditionalColor(Color.ORANGE);
    cube2.translate(60, -20, 60);

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

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

    plane.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
    ramp.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
    sphere.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
    cube2.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);

    world.addObject(plane);
    world.addObject(ramp);
    world.addObject(sphere);
    world.addObject(cube2);
    world.addObject(player);

    player.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 lookAt()
  {
    SimpleVector mousePos = getWorldPosition();
    if (mousePos != null)
    {
      SimpleVector curPos = player.getTranslation();
      mousePos = mousePos.calcSub(curPos);
      player.setRotationMatrix(mousePos.getRotationMatrix());
    }
  }


  private void relocate()
  {
    SimpleVector pos = getWorldPosition();
    if (pos != null)
    {
      player.clearTranslation();
      player.translate(pos);
    }
  }


  private SimpleVector getWorldPosition()
  {
    SimpleVector pos = null;
    SimpleVector ray = Interact2D.reproject2D3DWS(world.getCamera(), fb, mouseX, mouseY);
    if (ray != null)
    {
      SimpleVector norm = ray.normalize();

      float f = world.calcMinDistance(world.getCamera().getPosition(), norm, 1000);
      if (f != Object3D.COLLISION_NONE)
      {
        pos = new SimpleVector();
        SimpleVector offset = new SimpleVector(norm);
        norm.scalarMul(f);
        norm = norm.calcSub(offset);
        pos.add(norm);
        pos.add(world.getCamera().getPosition());
      }
    }
    return pos;
  }


  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)
    {
      lookAt();
      if (pressed)
      {
        relocate();
        pressed = false;
      }
      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
  {
    MouseFollowDemo cd = new MouseFollowDemo();
    cd.initStuff();
    cd.doIt();
  }
}


Offline marat

  • byte
  • *
  • Posts: 6
    • View Profile
Thanks EgonOlsen!
It's work 100% very well..

Thanks again...


Offline marat

  • byte
  • *
  • Posts: 6
    • View Profile
Hm!
I still have problems, this example work fine on desktop systems, but on android system emulator it's work not exactly, differences in the mouse coordinates..
Problems with movements,  object does not move exactly (always a distance) when you mouse click.
I don't undesrtand why.

Offline Nemetz

  • int
  • **
  • Posts: 53
    • View Profile
Which code do you use for handling touch events?

Offline Edak

  • byte
  • *
  • Posts: 14
    • View Profile
Here's a method out of my 'directional pad' class, you'll have to edit the centerX and Y accordingly, but given an X and a Y (and the correct center) this will compute a radian to rotate a model by.

Code: [Select]
public float computeRadian(float x, float y) {
       
        float touchPointX = x - centerX;
        float touchPointY = centerY - y;

        double a = Math.sqrt(Math.pow(touchPointX, 2) + Math.pow(touchPointY, 2));
        double b = a;
        double c = Math.sqrt(Math.pow(touchPointX, 2) + Math.pow(touchPointY - a, 2));

        Double torsoRotate = new Double(Math.acos((Math.pow(a, 2) + Math.pow(b, 2) - Math.pow(c, 2)) / (2 * a * b)));
        //Logger.log("a: "+a+" c: "+c+" Degree: "+Degree);
        //Degree *= 0.0174532925; // Number to put in rotateY()
        //cos-1((P122 + P132 - P232)/(2 * P12 * P13))
        //where P12 is the length of the segment from P1 to P2, calculated by
        //sqrt((P1x - P2x)2 + (P1y - P2y)2)

        if (x < centerX) {
            torsoRotate *= -1;
        }
        return torsoRotate.floatValue();
    }

So for touch events I do this:

Code: [Select]
@Override
    public boolean onTouchEvent(MotionEvent me) {
        if (me.getAction() == MotionEvent.ACTION_DOWN) {
            holdType = 0;
            windowX = me.getX();
            windowY = me.getY();
            if (inGame) {
                ///If it's in the dpad
                //
                if (dpadShoot.touched(windowX, windowY)) {
                    holdType = 1;
                }
            }
            return true;
        }

        if (me.getAction() == MotionEvent.ACTION_UP) {
           
            return true;
        }

        if (me.getAction() == MotionEvent.ACTION_MOVE) {
            if (holdType == 1) {
                    Object3D.clearRotation(); //clear the rotation of the model
                    Object3D.rotateY(computeRadian(me.getX(), me.getY())); //compute the rotation based on the X and Y given from the touchpad
            }
            return true;
        }
        try {
            Thread.sleep(15);
        } catch (Exception e) {
        }
        return super.onTouchEvent(me);
    }


Please note, the second bit of code won't work, I just pulled what I have, removed most of it, and put in some sample code. But the first method I posted took me a good solid two days and no sleep to figure out, and it's flawless, so enjoy.
« Last Edit: July 01, 2011, 10:56:55 am by Edak »

Offline marat

  • byte
  • *
  • Posts: 6
    • View Profile
I use this

setOnTouchListener(new View.OnTouchListener() {
    public boolean onTouch(View v, MotionEvent e) {
 
           switch(e.getAction()) {
               case ACTION_MOVE:
                   xMouse = e.getX();
                   yMose = e.getY();
               break;
           }

       return true;
    }
});


Maybe i should override? ->
@Override  public boolean onTouchEvent
« Last Edit: July 01, 2011, 11:00:46 am by marat »

Offline Edak

  • byte
  • *
  • Posts: 14
    • View Profile
Hey if what you have works so far why change it eh?

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 11776
    • View Profile
    • http://www.jpct.net
Hm!
I still have problems, this example work fine on desktop systems, but on android system emulator it's work not exactly, differences in the mouse coordinates..
Problems with movements,  object does not move exactly (always a distance) when you mouse click.
I don't undesrtand why.
Because your mouse coordinates are off? Might be that the status bar sets them off by some amount. Given that the mouse coordinates match the frame buffer coordinates, the collision system is pixel perfect. So it have to be your mouse coordinates (or you did some porting error).

Offline marat

  • byte
  • *
  • Posts: 6
    • View Profile
Hm!
Problem is solved, thanks to everybody

//correct
class X extends activity  {

myGLView.setOnTouchListener(new View.OnTouchListener() {
}

}

//wrong
class X extends activity  {

@Oeverride
public boolean onTouch() {
}

}



 :)

Offline Edak

  • byte
  • *
  • Posts: 14
    • View Profile
You say my method is wrong, but why does it work on my phone? I  don't have my code in front of me but could it be variations in phones?