Author Topic: A Little Trigonometry  (Read 17735 times)

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 11745
    • View Profile
    • http://www.jpct.net
Re: A Little Trigonometry
« Reply #45 on: June 05, 2009, 09:50:36 am »
I tried this:

Code: [Select]
DataInputStream dir=new DataInputStream(new FileInputStream("tracks.rac"));
List<SimpleVector> markers=new ArrayList<SimpleVector>();
while (dir.available()>0) {
      SimpleVector s=new SimpleVector(dir.readFloat(), dir.readFloat(), dir.readFloat());
      System.out.println(s+"/"+dir.available());
      markers.add(s);
}
...it doesn't work. At the end of the file, 4 bytes remain, the loop tries to read them into 3 floats and crashes...

Offline AGP

  • quad
  • ******
  • Posts: 1516
    • View Profile
Re: A Little Trigonometry
« Reply #46 on: June 05, 2009, 09:56:03 am »
Sorry, I forgot to tell you that the first 4 bytes are an int that informs us how many SimpleVectors (not floats) are stored.

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 11745
    • View Profile
    • http://www.jpct.net
Re: A Little Trigonometry
« Reply #47 on: June 05, 2009, 10:02:46 am »
OK...and the track lies within the X-Y-plane? When looking at the values, x and y differ and z doesn't. Seems a bit strange to me!?
« Last Edit: June 05, 2009, 10:04:34 am by EgonOlsen »

Offline AGP

  • quad
  • ******
  • Posts: 1516
    • View Profile
Re: A Little Trigonometry
« Reply #48 on: June 05, 2009, 10:07:02 am »
No, that's what it ought to look like. The cars are moving on the X/Y plane with +Z going up. And, like I said, the car is following the tracks nicely.

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 11745
    • View Profile
    • http://www.jpct.net
Re: A Little Trigonometry
« Reply #49 on: June 05, 2009, 10:22:04 am »
The car is following nicely...so what doesn't work actually? Just the rotation?

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 11745
    • View Profile
    • http://www.jpct.net
Re: A Little Trigonometry
« Reply #50 on: June 05, 2009, 03:19:03 pm »
This seems to work...:

Code: [Select]
import java.io.*;
import java.util.*;

import org.lwjgl.opengl.Display;

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

public class OnTrackZ
{
  public static void main(String[] args) throws Exception
  {
    Config.farPlane=60000;
    
    DataInputStream di=new DataInputStream(new FileInputStream("tracks.rac"));
    List<SimpleVector> markers=new ArrayList<SimpleVector>();
    di.readInt();
    while (di.available()>0) {
      SimpleVector s=new SimpleVector(di.readFloat(), di.readFloat(), di.readFloat());
      float y=s.y;
      s.y=-s.z;
      s.z=-y;
      markers.add(s);
    }
    
    FrameBuffer buffer=new FrameBuffer(800,600,FrameBuffer.SAMPLINGMODE_HARDWARE_ONLY);
    buffer.disableRenderer(IRenderer.RENDERER_SOFTWARE);
    buffer.enableRenderer(IRenderer.RENDERER_OPENGL);
    
    World world=new World();
    
    Object3D car=Primitives.getCone(5, 2000);
    car.rotateX((float)Math.PI/2f);
    car.rotateMesh();
    car.setRotationMatrix(new Matrix());
    
    car.compile();
    car.translate(markers.get(0));
    
    SimpleVector initTrs=markers.get(1).calcSub(markers.get(0)).normalize();
    car.setRotationMatrix(initTrs.getRotationMatrix());
    
    world.addObject(car);
    world.setAmbientLight(100, 100, 100);
    world.buildAllObjects();
    
    Light light=new Light(world);
    light.setPosition(new SimpleVector(0,-1000,0));
    light.setAttenuation(-1);
    light.setIntensity(255, 0, 0);
    
    Camera cam=world.getCamera();
    cam.setPosition(car.getTranslation());
    cam.moveCamera(Camera.CAMERA_MOVEUP, 50000);
    cam.rotateX(-(float)Math.PI/2f);
    
    Matrix lastRot=car.getRotationMatrix();
    
    long start=0;
    int fps=0;
    
    int pos=0;
    while (!Display.isCloseRequested()) {
      int next=(pos+1)%markers.size();
      
      SimpleVector cur=car.getTranslation();
      SimpleVector dir=markers.get(next).calcSub(cur);
      SimpleVector trs=dir.normalize();
      
      if (trs.length()!=0) {
        Matrix softMat=trs.getRotationMatrix();
        lastRot.interpolate(lastRot, softMat, 0.008f);
        car.setRotationMatrix(lastRot);
      }
      
      trs.scalarMul(5);
      car.translate(trs);
      
      if (car.getTranslation().calcSub(markers.get(next)).length()<5.5f) {
        lastRot=trs.getRotationMatrix();
        car.setTranslationMatrix(new Matrix());
        car.translate(markers.get(next));
        pos++;
        pos%=markers.size();
        System.out.println("Switching to: "+pos);
      }
      
      buffer.clear();
      world.renderScene(buffer);
      world.draw(buffer);
      buffer.update();
      buffer.displayGLOnly();
      
      fps++;
      if (System.currentTimeMillis()-start>=1000) {
        start=System.currentTimeMillis();
        System.out.println(fps+" fps");
        fps=0;
      }
    }
    buffer.dispose();
    System.exit(0);
  }
}

...BUT: As said, this method relies on getRotationMatrix() of SimpleVector. getRotationMatrix() is very similar to the usual lookAt-method, which means that its outcome is correct in terms of what the Javadoc states that it does, but it depends on the internal command order how the result looks like. In other words: There are millions of ways to look at something from a given position because you can always turn yourself around your own z-axis. The method works fine for the usual x-z-plane worlds, but when used in the y-x-plane, it creates wrap-arounds at the poles. Again, this is correct in terms of what it is supposed to do, but its not what you want in this case.
This is why my test code transforms the markers from the x-y-plane to the x-z-plane. It seems to work much better that way. Give it a try, maybe it helps somehow...
« Last Edit: June 05, 2009, 03:20:45 pm by EgonOlsen »

Offline AGP

  • quad
  • ******
  • Posts: 1516
    • View Profile
Re: A Little Trigonometry
« Reply #51 on: June 05, 2009, 06:38:07 pm »
I understand so little of this code it's hard to plug it into my program. Let's start with what part of this converts between X/Z and X/Y?

Offline AGP

  • quad
  • ******
  • Posts: 1516
    • View Profile
Re: A Little Trigonometry
« Reply #52 on: June 05, 2009, 07:02:55 pm »
Never mind my question, I can see it in your loading code. So then, can you explain the rest to me?

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 11745
    • View Profile
    • http://www.jpct.net
Re: A Little Trigonometry
« Reply #53 on: June 05, 2009, 07:03:20 pm »
That happens right where i load the SimpleVectors by simply swapping z and y (with an additional sign change). The actual move/rotation code is pretty simple: It has a current pos and a next pos into the marker list and creates a direction vector from the current translation of the car to the next marker. It gets the rotation matrix from this vector and interpolates between this matrix and the current rotation matrix (lastRot) to get a smooth transition between them. If the car is located close to the next marker, it increases the pos and goes ahead.
It should be possible to do the calculations even when remaining in the y-x-plane, but you would have to do some conversions from y-x-plane to the x-z-plane, do the calulations and revert the transform....i tried that, but did something wrong, because it didn't work. So i decided to transform the track instead. It's more intuitive this way anyway IMHO.

Offline AGP

  • quad
  • ******
  • Posts: 1516
    • View Profile
Re: A Little Trigonometry
« Reply #54 on: June 05, 2009, 07:13:28 pm »
Yeah, but it's not like I rotated any of the models. X/Y is just what I ended up with when I loaded them. Anyway, of my Quest for Glory you wrote the opposite, because I have an X/Z plane and I remember you saying that the mouse-walking method had been meant for X/Y. So should I rotate everything -90 degrees along their x-axis?

Offline AGP

  • quad
  • ******
  • Posts: 1516
    • View Profile
Re: A Little Trigonometry
« Reply #55 on: June 05, 2009, 07:41:58 pm »
Rotating obviously messed everything up. What about world.rotateAxis(world.getXAxis(), float) methods? I think it would be very handy.

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 11745
    • View Profile
    • http://www.jpct.net
Re: A Little Trigonometry
« Reply #56 on: June 05, 2009, 07:59:20 pm »
Yeah, but it's not like I rotated any of the models. X/Y is just what I ended up with when I loaded them. Anyway, of my Quest for Glory you wrote the opposite, because I have an X/Z plane and I remember you saying that the mouse-walking method had been meant for X/Y. So should I rotate everything -90 degrees along their x-axis?
Mouse picking in jPCT usually happens in camera space, where even your X/Y-plane is transformed into X/Z, because that's what is going to be rendered. The picking plane itself lies within X/Y (aka screen space)...maybe that was, what i was writing about...i can't remember it.

About the rotation: Yes, i suggest to do this. It's something that i'm doing with every model i'm loading from 3ds, because 3ds simply uses another coordinate system. World.rotateAxis() doesn't make much sense, because the world's rotation actually is the inverted camera rotation...but that doesn't help in this case. What i suggest is to rotate your loaded models by -90 around x right after loading them and make this rotation permanent (i.e. apply rotateMesh() on them and reset the rotation matrix afterwards). You may have to adjust some things in your code, but it should be worth the effort.

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 11745
    • View Profile
    • http://www.jpct.net
Re: A Little Trigonometry
« Reply #57 on: June 05, 2009, 08:03:34 pm »
Rotating obviously messed everything up.
I'll invest some time and try to make the transformations work even with your X/Y-plane...shouldn't be too hard, but i failed once so maybe it's harder then i think it is...

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 11745
    • View Profile
    • http://www.jpct.net
Re: A Little Trigonometry
« Reply #58 on: June 05, 2009, 08:57:41 pm »
This one works with everything left in the X/Y-plane. I'm not sure about the initial rotation of the car...maybe it needs some tweaking depending on how you load your model. You'll find my test model here: http://www.jpct.net/download/misc/droid3.3DS

The basic idea of this thing is, that everything graphics related happen in the X/Y-plane (as in your code), but the actual rotation calculation and interpolation happens in the X/Z-plane. Some rotates are used to convert between the two.

Code: [Select]
import java.io.*;
import java.util.*;

import org.lwjgl.opengl.Display;

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

public class OnTrackZ {
public static void main(String[] args) throws Exception {
float rot = (float) Math.PI / 2f;

Config.farPlane = 60000;

DataInputStream di = new DataInputStream(new FileInputStream(
"tracks.rac"));
List<SimpleVector> markers = new ArrayList<SimpleVector>();
di.readInt();
while (di.available() > 0) {
SimpleVector s = new SimpleVector(di.readFloat(), di.readFloat(), di.readFloat());
markers.add(s);
}

FrameBuffer buffer = new FrameBuffer(800, 600, FrameBuffer.SAMPLINGMODE_HARDWARE_ONLY);
buffer.disableRenderer(IRenderer.RENDERER_SOFTWARE);
buffer.enableRenderer(IRenderer.RENDERER_OPENGL);

World world = new World();

Object3D car = Object3D.mergeAll(Loader.load3DS("droid3.3DS", 80));
car.rotateX(rot);
car.rotateMesh();
car.setRotationMatrix(new Matrix());

car.compile();
car.translate(markers.get(0));

// Set the cars initial rotation rotation matrix and lastRot.
// The inital rotation is in the X/Y-plane while lastRot is actually
// the same thing but transformed into the X/Z-plane.
SimpleVector initTrs = markers.get(1).calcSub(markers.get(0)).normalize();
car.setRotationMatrix(initTrs.getRotationMatrix()); // X/Y-plane...
initTrs.rotateX(rot);
Matrix lastRot = initTrs.getRotationMatrix(); // X/Z-plane

world.addObject(car);
world.setAmbientLight(100, 100, 100);
world.buildAllObjects();

Light light = new Light(world);
light.setPosition(new SimpleVector(0, -1000, 0));
light.setAttenuation(-1);
light.setIntensity(255, 0, 0);

Camera cam = world.getCamera();
cam.setPosition(car.getTranslation());
cam.moveCamera(Camera.CAMERA_MOVEOUT, 50000);

long start = 0;
int fps = 0;

int pos = 0;
while (!Display.isCloseRequested()) {
int next = (pos + 1) % markers.size();

// Get the current position
SimpleVector cur = car.getTranslation();

// Get the direction vector from "current" to the next marker
SimpleVector dir = markers.get(next).calcSub(cur);

// Normalize that...
SimpleVector trs = dir.normalize();

// Make a copy of the direction vector for matrix generation
SimpleVector tr = new SimpleVector(trs);

// Rotate the copy into the X/Z-plane
tr.rotateX(rot);

// Is there any length? (Should always be the case, but you never
// know...)
if (trs.length() != 0) {
// Create a rotation matrix out of the tranformed direction
// vector
Matrix softMat = tr.getRotationMatrix();
// interpolate between the matrices
lastRot.interpolate(lastRot, softMat, 0.008f);
// make a copy of lastRot...
Matrix mr = new Matrix(lastRot);
// ...and transform it back into X/Y-plane...
mr.rotateX(rot);
// ...to use it as an actual rotation matrix for the car!
car.setRotationMatrix(mr);
}

// apply the translation (in X/Y)
trs.scalarMul(5f);
car.translate(trs);

// A marker has been reached?
if (car.getTranslation().calcSub(markers.get(next)).length() < 5.5f) {
// Fix lastRot. This prevents rounding and accuracy errors.
lastRot = tr.getRotationMatrix();
// The same for the car's position...
car.setTranslationMatrix(new Matrix());
car.translate(markers.get(next));

// Next marker, please...
pos++;
pos %= markers.size();
}

// Render that thing
buffer.clear();
world.renderScene(buffer);
world.draw(buffer);
buffer.update();
buffer.displayGLOnly();

// Simple fps counter
fps++;
if (System.currentTimeMillis() - start >= 1000) {
start = System.currentTimeMillis();
System.out.println(fps + " fps");
fps = 0;
}
}
buffer.dispose();
System.exit(0);
}
}

Edit: Fixed a flaw in the code, added some comments.
« Last Edit: June 05, 2009, 09:10:39 pm by EgonOlsen »

Offline AGP

  • quad
  • ******
  • Posts: 1516
    • View Profile
Re: A Little Trigonometry
« Reply #59 on: June 06, 2009, 10:33:05 pm »
Egon, THANKS A WHOLE LOT. Works great. I'll try and get the applet up and running by tonight to show it to you. It's a good lesson, too, this doing it by matrices, for future programs. I appreciate it, pal.