Fake unlimited viewing distance

From JPCT
Jump to: navigation, search

One problem that you may run into is limited viewing distance. Setting the farplane value very high does not solve it, because there is actually a hard limit given by the hardware and/or OpenGl. For example, imagine that for a space game, you want to have a planet that is far away but still visible (and approachable). You have to fake a little bit by scaling the object and putting it closer to the camera than it actually is. The player should not be able to see this little cheat.

public class Planet extends Object3D { //It's better to not use Object3D directly for your game objects, but I do it here for simplicity

  private SimpleVector realPosition, camPos = new SimpleVector();
  private SimpleVector v = new SimpleVector; // temporary vector
  private final static MAX_VIEWING_DISTANCE = 5000; //this should be a safe value for most devices; make sure your farplane value is higher than this

  public Planet(SimpleVector position) {
      ... // init Object3D here

     translate(position);
     realPosition = new SimpleVector(position); //Save "real" position of planet in another vector as the object's physical position will change 
  }

  // this is called in every frame update
  public void update() {
    
    world.getCamera().getPosition(camPos); //position of used camera

    float dist = realPosition.distance(camPos);  //calculate distance camera<->Planet

    if (dist>MAX_VIEWING_DISTANCE) { //outside of the viewing distance -> do projection magic

	setScale(MAX_VIEWING_DISTANCE / dist);    //shrink the object

     // Now that we made the object smaller, put it closer to the camera

	 v.set(realPosition); //Set helper vector to planet position 
	v.sub(camPos); //calculate direction vector from camera to planet
	v.normalize(v); //and normalize it
	v.scalarMul(MAX_VIEWING_DISTANCE); // Calculate new position within viewing distance
        v.add(camPos);  // add camera vector to get final object position

  	//Move it!
        clearTranslation();
        translate(v);
   } 

   else { //planet is within viewing distance; reset size and position to real values
	setScale(1); 
        clearTranslation();
	translate(realPosition);
  }