Why not add a math class?

Started by AGP, September 06, 2008, 05:33:30 AM

Previous topic - Next topic

AGP

And include methods like static float calculateAngle(SimpleVector origin, SimpleVector p1, SimpleVector p2)? Until then, if somebody would tell me the code for that I'd be grateful! : -)

AGP

More specifically, I'm trying to calculate a 2D angle, so this method would only use the x and y components of the SimpleVector class. static float calculateAngle2D(SimpleVector origin, SimpleVector p1, SimpleVector p2) might be a better name!

EgonOlsen

The origin doesn't matter as long as p1 and p2 are direction vectors. If they aren't, simply calculate them from origin and p1 and p2 and feed them into this:


public static float calcAngle(SimpleVector s1, SimpleVector s2) {
s1=s1.normalize();
s2=s2.normalize();

float pa=s1.x*s2.x+s1.y*s2.y+s1.z*s2.z;

// Inaccuracies may cause NaN...fix this:
if (pa<-1) {
pa=-1;
}
if (pa>1) {
pa=1;
}
pa=(float) Math.acos(pa);
    return pa;
    }


This should give you the angle between them.

AGP

Thanks a lot. What about my suggestion of adding a Math class? Could be quite useful and wouldn't make jPCT cumbersome in any way.

EgonOlsen

I'll rather add this method to SimpleVector instead.

AGP

OK, but I still think that a Math class with all sorts of operations would be invaluable.

By the way, you know my problem and it didn't work for that one. I also tried the 2D variation that follows. Why doesn't it work?
      public float calculateAngle(SimpleVector s1, SimpleVector s2) {
s1=s1.normalize();//TRIED WITH AND WITHOUT THESE
s2=s2.normalize();
SimpleVector p13d = Interact2D.project3D2D(theCamera, buffer, s1);
Point p1 = new Point((int)p13d.x, (int)p13d.y);
SimpleVector p23d = Interact2D.project3D2D(theCamera, buffer, s2);
Point p2 = new Point((int)p23d.x, (int)p23d.y);

float pa=(float)p1.x*(float)p2.x+(float)p1.y*(float)p2.y;

// Inaccuracies may cause NaN...fix this:
if (pa<-1)
pa=-1;
else if (pa>1)
pa=1;
    return (float) Math.acos(pa);
      }

EgonOlsen

What should it do? If s1 and s2 are direction vectors in 3D, projecting them into 2D doesn't make any sense. If you want to calculate the angle in screen space, i.e. in 2D, you have to transform the origin and origin+s1 and origin+s2 (assuming that they ARE direction vectors. If not, it's just s1 and s2 and origin) from 3D into 2D, calculate the two direction vectors in 2d and feed those into the method.

AGP

OK, now I'm confused. My s1 was the hero's transformed center, and my s2 was the mouse click's position.

The hero''s transformed center is the origin. I have a direction vector for the keyboard that's always directly ahead of the hero, and I have the direction vector of the mouse click. What exactly should I feed into the method and for that matter, what version of the method? Yours?

EgonOlsen

What do you want to achieve? As far as i understand it, you have the origin, which is the position of the hero and you have two direction vectors (in 3d), one is always facing ahead of the hero, the other one is the vector from the hero to the point where the mouse click hits the plane (also in 3d). You angle is the angle between those two vectors (in 3d? or in 2d? If then 2d, then why?).
What do you need that angle for in the next step?

AGP

I need the hero to look in the direction of the mouse click. By the way, I could just use the original mouse coordinates which are already in 2D. So shouldn't converting the hero's center and the hero's direction vector (in front of him) to 2D and then calculate that angle make sense? And if you agree, tell me if my changes work and if not please make your own. Thanks a lot.

EgonOlsen

You want to rotate the hero in 3d, so you have to use the 3d coordinates. Doing it 2d doesn't cut it. But you don't really need the angle. a simple


hero.setRotationMatrix(yourClickDirectionVector.getRotationMatrix());


should rotate the hero correctly.

AGP

Oddly that works as often as it doesn't.

EgonOlsen

It should work as long the vectors are all correct. What happens instead in cases where it doesn't?

AGP

The hero doesn't rotate at all. And he sometimes rotates awkwardly.

EgonOlsen

I don't know your code, but the approach itself definitely works fine. Have a look at this modified mouse following example. Maybe it helps:


import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import com.threed.jpct.*;
import com.threed.jpct.util.*;

public class MouseFollower extends JFrame implements MouseMotionListener {

    private final static long serialVersionUID=1L;
 
    private Graphics g = null;
    private FrameBuffer fb = null;
    private World world = null;
    private Object3D plane = null;
    private Object3D cube = null;

    private boolean doloop = true;

    private int x=320;
    private int y=240;
   
    private SimpleVector target=new SimpleVector();

    public MouseFollower() {
        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(1, 400);
        plane.rotateX((float) Math.PI / 2f);

        // Not a cube anymore, but a cone...
        cube = Primitives.getCone(15);
        cube.rotateZ((float)Math.PI/2f);
        cube.rotateY((float)Math.PI/2f);
        cube.rotateMesh(); // Make the cone a pointer
        cube.setRotationMatrix(new Matrix());
       
        plane.setCollisionMode(Object3D.COLLISION_CHECK_OTHERS);
        plane.setVisibility(false);
       
        world.addObject(plane);
        world.addObject(cube);

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

        world.setAmbientLight(100, 100, 100);
       
        Light light = new Light(world);
        light.setPosition(new SimpleVector(0, -80, 0));
        light.setIntensity(150, 150, 150);

        world.buildAllObjects();
        target=cube.getTransformedCenter();
    }

    private void follow() {
        SimpleVector ray=Interact2D.reproject2D3D(world.getCamera(), fb, x, y);
       
        if (ray!=null) {
            SimpleVector norm=ray.normalize();
            Matrix mat=world.getCamera().getBack();
            mat=mat.invert3x3();
            norm.matMul(mat);

            SimpleVector ws=new SimpleVector(ray);
            ws.matMul(world.getCamera().getBack().invert3x3());
            ws.add(world.getCamera().getPosition());

            plane.setVisibility(true);
            float f=world.calcMinDistance(world.getCamera().getPosition(), norm, 1000);
            plane.setVisibility(false);
            if (f!=Object3D.COLLISION_NONE) {
                norm.scalarMul(f);
                SimpleVector mn=new SimpleVector(norm);
                mn.add(world.getCamera().getPosition());
                target=new SimpleVector(mn);
            }
        }
       
        SimpleVector m=new SimpleVector(target);
        m=m.calcSub(cube.getTransformedCenter());
       
        if (m.length()>0.5f) {
        cube.translate(m.normalize());
        cube.setRotationMatrix(m.getRotationMatrix());
        }
    }

    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 {
        MouseFollower cd = new MouseFollower();
        cd.initStuff();
        cd.doIt();
    }
}