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);
}
}
}
Do you have a screen shot of this?
here is a screenshot:
http://www.box.net/shared/pqrmulr8ap
That's not related to painter's algorithm, it's typical z-fighting (http://en.wikipedia.org/wiki/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.
:-\ 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
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.