www.jpct.net
jPCT-AE - a 3d engine for Android => Support => Topic started by: Irony on December 29, 2013, 01:11:04 pm
-
From time to time, I will post a few code snippets that proved useful while working on Armada. Maybe someone can use something for their own projects.
One problem that I ran into was the limited viewing distance. I thought that just setting the farplane value high enough would solve it, but there is actually a hard limit given by the hardware and/or OpenGl (not sure about that).
I wanted to have a planet that is far away but still visible (and approachable). While it would be possible to fake something with billboards, I found a solution that uses real geometry and actually pretty simple.
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);
}
-
Added to the Wiki. I think we should still keep this thread open in case there any questions.
-
I think so. Could you also add a link there to this Topic? Then it would make a lot more sense ;) .
Nice code snippet, but don't forget that it is possible to determine a difference between a really far object and a not that far, scaled object. The really far object will look more flat than the other one (but I think nobody will ever notice that in a real program).
-
I think so. Could you also add a link there to this Topic? Then it would make a lot more sense ;) .
Nice code snippet, but don't forget that it is possible to determine a difference between a really far object and a not that far, scaled object. The really far object will look more flat than the other one (but I think nobody will ever notice that in a real program).
Thought it would be easy enough to find but here you go
http://www.jpct.net/wiki/index.php/Fake_unlimited_viewing_distance (http://www.jpct.net/wiki/index.php/Fake_unlimited_viewing_distance)
About your objection: Are you sure this effect isn't only present in stereoscopic (real) 3D?
-
I meant you could link from the wiki article to this Topic here ;) .
About your objection: Are you sure this effect isn't only present in stereoscopic (real) 3D?
I'm really sure. Look at this short sample:
world = new World();
piv = Object3D.createDummyObj();
camPiv = Object3D.createDummyObj();
camPiv.addParent(piv);
camPiv.translate(0, 0, -10);
Light light = new Light(world);
light.setPosition(new SimpleVector(-5, -5, -5));
TextureManager mgr = TextureManager.getInstance();
Resources res = getResources();
mgr.addTexture("texture", new Texture(res.openRawResource(R.raw.tex)));
SimpleVector vec;
Object3D sp1 = Primitives.getSphere(3.5f);
sp1.rotateY(0.4f);
sp1.rotateX(-0.1f);
vec = sp1.getZAxis();
vec.scalarMul(25f);
sp1.translate(vec);
sp1.calcTextureWrapSpherical();
sp1.setTexture("texture");
world.addObject(sp1);
Object3D sp2 = Primitives.getSphere(40f);
sp2.rotateY(-0.4f);
sp2.rotateX(-0.1f);
vec = sp2.getZAxis();
vec.scalarMul(400f);
sp2.translate(vec);
sp2.calcTextureWrapSpherical();
sp2.setTexture("texture");
world.addObject(sp2);
Which leads to this:
(https://dl.dropboxusercontent.com/u/1618711/web/Screenshot_2013-12-30-12-16-50.png)
It's a really extreme sample, but I think it's visible that the left sphere seems to be more flat.
-
It's different, because the scaling ignores the perspective projection. However, the farer away the object is, the less this counts. So for objects that are far away, this is a reasonable approach.
-
Thanks for the feedback guys ;)