Vintage Flight-Simulator

Started by tom3001, September 29, 2009, 02:02:04 PM

Previous topic - Next topic

tom3001

Hi.

I improved my Flight-Sim Project a bit. The Horizon is working well now. I'm using a big plane, rotating dynamically with the camera. That solution is IMHO better and simpler than the one with two domes...

You can look around with arrowkeys, and move around with w,a,s,d keys.

One problem is, when you move high above the ground, the landing-pad isn't drawn properly. I suppose it's a math-rounding issue of the painter-algorithm; I tried to lower the ground-plane a little bit, to avoid this problem, but if you fly far away from ground, this "little bit" gets too small...
I tried to play around with the setSortOffset() method on the ground-plane, but it didn't chance anything... do you have any suggestions??

Here is my code:



import com.threed.jpct.*;

import javax.swing.*;



import java.awt.Color;

import java.awt.event.KeyEvent;

import java.awt.event.KeyListener;



public class HorizonTest implements KeyListener {



private static float PI = (float) Math.PI;



private World world = null;

private FrameBuffer buffer = null;

private Object3D box = null;

private Object3D plane = null;

private Object3D[] grid = null;

private Object3D[] wobjects = null;

private JFrame frame = null;



// half size of the grid

int gridsize_x = 6;

int gridsize_z = 6;



// Rotation control variables

private boolean doLeftRotation = false;

private boolean doRightRotation = false;

private boolean doUpRotation = false;

private boolean doDownRotation = false;

private boolean doMoveForward = false;

private boolean doMoveBackward = false;

private boolean doRollLeft = false;

private boolean doRollRight = false;



float xpos=-200, ypos=-50, zpos=0;

float xangle=0, yangle=0, zangle=0;

int oldcx=0, oldcz=0;



public static void main(String[] args) throws Exception {

new HorizonTest().loop();

}



public HorizonTest() throws Exception {



// Setup the frame

frame = new JFrame("Horizon Test");

frame.setSize(800, 600);

frame.setVisible(true);

frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);

frame.addKeyListener(this);



Config.farPlane = 1700;



// Set up the worlds

world = new World();



//world.setAmbientLight(127, 127, 127);

world.setAmbientLight(255, 255, 255);



// Define textures

TextureManager.getInstance().addTexture("earth", new Texture(16,16,new Color(0,170,0)));

TextureManager.getInstance().addTexture("sky", new Texture(16,16,new Color(85,255,255)));

TextureManager.getInstance().addTexture("red", new Texture(16,16,new Color(255,0,0)));

TextureManager.getInstance().addTexture("grid", new Texture(16,16,new Color(85,85,85)));

TextureManager.getInstance().addTexture("landingpad", new Texture(16,16,new Color(200,200,200)));



// Some box somewhere else

box = Primitives.getBox(10f, 1f);

box.translate(0, -10f, -100f); // Place it on the ground

box.getPolygonManager().setPolygonTexture(8, 3);

box.rotateY(PI / 4f);

world.addObject(box);



// Add ground-grid

int count = 0;

grid = new Object3D[gridsize_x*gridsize_z*4];

for (int z=-gridsize_z; z<gridsize_z; z++) {

for (int x=-gridsize_x; x<gridsize_x; x++) {

grid[count] = Primitives.getBox(1f, 1f);

grid[count].setTexture("grid");

grid[count].translate(200 * x, -1f, 200 * z); // Place it on the ground

world.addObject(grid[count]);

count++;



}

}



// Horizon plane

plane = Primitives.getPlane(1, 10000);

plane.setTexture("earth");

plane.translate(0, 1f, 0);

plane.rotateX(PI / 2f);

world.addObject(plane);



addLandingPad();



world.buildAllObjects();



// View

Camera cam = world.getCamera();

cam.setFOV(1.5f);

}



private void loop() throws Exception {

buffer = new FrameBuffer(800, 600, FrameBuffer.SAMPLINGMODE_NORMAL);



while (frame.isShowing()) {

doMovementUpdate();

buffer.clear(new Color(85,255,255));

world.renderScene(buffer);

world.draw(buffer);

buffer.update();

buffer.display(frame.getGraphics(),0,0);

Thread.sleep(10);

}

buffer.disableRenderer(IRenderer.RENDERER_OPENGL);

buffer.dispose();

frame.dispose();

System.exit(0);

}



private void addLandingPad() {

int numobjects = 1;

wobjects = new Object3D[numobjects];

wobjects[0] = new Object3D(2);

wobjects[0].addTriangle(new SimpleVector(0,0,0),new SimpleVector(100,0,0),new SimpleVector(0,0,1000));

wobjects[0].addTriangle(new SimpleVector(100,0,1000),new SimpleVector(100,0,0),new SimpleVector(0,0,1000));

wobjects[0].rotateY(PI / 2f);

wobjects[0].translate(100,0,-450);

wobjects[0].setTexture("landingpad");

wobjects[0].setCulling(false);



world.addObject(wobjects[0]);

}



private void updateGrid() {

SimpleVector v = world.getCamera().getPosition();



int cx = Math.round(v.x / 200) * 200;

int cz = Math.round(v.z / 200) * 200;



int dx = cx - oldcx;

int dz = cz - oldcz;



for (int i=0; i<grid.length; i++) {

grid[i].translate(dx, 0, dz);

}



plane.translate(dx, 0, dz);



oldcx = cx;

oldcz = cz;

}





// Rotates the horizon plane with the camera

private void updateHorizon(float angle) {

plane.rotateY(angle);

}



private void doMovementUpdate() {



float rotval= 0.01f;

float speed = 1.3f;   // default = 1.3f



if (doLeftRotation) {

yangle -= rotval;

updateHorizon(-rotval);

}

if (doRightRotation) {

yangle += rotval;

updateHorizon(rotval);

}

if (doUpRotation) {

xangle -= rotval;

}

if (doDownRotation) {

xangle += rotval;

}

if (doMoveForward) {

if (ypos > -4) {

world.getCamera().rotateX(xangle);

world.getCamera().rotateZ(zangle);

xangle=0;

zangle=0;

world.getCamera().moveCamera(Camera.CAMERA_MOVEUP, 1);

}

world.getCamera().moveCamera(Camera.CAMERA_MOVEIN, speed);

SimpleVector v = world.getCamera().getPosition();

xpos = v.x;

ypos = v.y;

zpos = v.z;

updateGrid();

}

if (doMoveBackward) {

if (ypos > -4) {

world.getCamera().rotateX(xangle);

world.getCamera().rotateZ(zangle);

xangle=0;

zangle=0;

world.getCamera().moveCamera(Camera.CAMERA_MOVEUP, 1);

}

world.getCamera().moveCamera(Camera.CAMERA_MOVEOUT, speed);

SimpleVector v = world.getCamera().getPosition();

xpos = v.x;

ypos = v.y;

zpos = v.z;

updateGrid();

}

if (doRollLeft) {

zangle += rotval;

}

if (doRollRight) {

zangle -= rotval;

}



world.getCamera().setPosition(xpos,ypos,zpos);

world.getCamera().lookAt(new SimpleVector(xpos+1,ypos,zpos));

world.getCamera().rotateY(-yangle);

world.getCamera().rotateX(-xangle);

world.getCamera().rotateZ(-zangle);



System.out.println("pos(" + Math.round(xpos/100) + "," + Math.round(zpos/100) + ")");

}



@Override

public void keyPressed(KeyEvent e) {



int keyCode = e.getKeyCode();

//System.out.println("key code : " + keyCode);



if (keyCode == 37) { // left arrow

doLeftRotation = true;

}

else if (keyCode == 39) { // right arrow

doRightRotation = true;

}

else if (keyCode == 38) { // up arrow

doUpRotation = true;

}

else if (keyCode == 40) { // down arrow

doDownRotation = true;

}

else if (keyCode == 87) { // "w"

doMoveForward = true;

}

else if (keyCode == 83) { // "s"

doMoveBackward = true;

}

else if (keyCode == 65) { // "a"

doRollLeft = true;

}

else if (keyCode == 68) { // "d"

doRollRight = true;

}

}



@Override

public void keyReleased(KeyEvent e) {

int keyCode = e.getKeyCode();

//System.out.println("key code : " + keyCode);



if (keyCode == 37) { // left arrow

doLeftRotation = false;

}

else if (keyCode == 39) { // right arrow

doRightRotation = false;

}

else if (keyCode == 38) { // up arrow

doUpRotation = false;

}

else if (keyCode == 40) { // down arrow

doDownRotation = false;

}

else if (keyCode == 87) { // "w"

doMoveForward = false;

}

else if (keyCode == 83) { // "s"

doMoveBackward = false;

}

else if (keyCode == 65) { // "a"

doRollLeft = false;

}

else if (keyCode == 68) { // "d"

doRollRight = false;

}

}



@Override

public void keyTyped(KeyEvent e) {

}



private void tileTexture(Object3D obj, float tileFactor) {

PolygonManager pm = obj.getPolygonManager();



int end = pm.getMaxPolygonID();

for (int i = 0; i < end; i++) {

SimpleVector uv0 = pm.getTextureUV(i, 0);

SimpleVector uv1 = pm.getTextureUV(i, 1);

SimpleVector uv2 = pm.getTextureUV(i, 2);



uv0.scalarMul(tileFactor);

uv1.scalarMul(tileFactor);

uv2.scalarMul(tileFactor);



int id = pm.getPolygonTexture(i);



TextureInfo ti = new TextureInfo(id, uv0.x, uv0.y, uv1.x, uv1.y,

uv2.x, uv2.y);

pm.setPolygonTexture(i, ti);

}

}

}


EgonOlsen

Do you have a screen shot of this?


EgonOlsen

That's not related to painter's algorithm, it's typical z-fighting (http://en.wikipedia.org/wiki/Z-fighting) which happens if the precision of the depth buffer isn't sufficient to distinguish correctly between polygons that are pretty close. The only solution is to increase the distance between the two. The sort offset is for sorting only. Would it have it influence on the actual depth, it wouldn't be any different from changing the actual depth coordiantes of the polygons themselves.

tom3001

#4
 :-\ I see.... is it possible to increase the z-buffers precision instead of increasing the distance between the planes?

I just tried another approach... I put the ground-plane into a new world object. Then, after drawing that world I'm clearing the z-buffer with clearZBufferOnly(). It works quite good, and I don't need to do any spacing anymore to avoid Z-Fighting. But clearZBufferOnly() seems to slow down the whole thing a little bit, right?

Regards

EgonOlsen

#5
That's a solution that i wanted to mention too...but you came first... ;D

Yes, clearZBufferOnly will slow it down a little bit, because it's an additional operation that takes at least half the time the normal clear() takes. But it shouldn't be too much of a problem.

Edit: Upcoming 1.19 can do that operation in multiple threads when running the software renderer.