Author Topic: Draw 3D Terrain with planes and change it on real time  (Read 1793 times)

Offline julycamara

  • byte
  • *
  • Posts: 10
    • View Profile
Draw 3D Terrain with planes and change it on real time
« on: July 07, 2013, 05:46:09 pm »
Hello,

I'm looking for the best way to draw a small grid of planes (for explample 10x10) that looks like a simple big rectangle with a texture from image, but i want to move it on real time, the vertex of each plane (join with nearest plane) would be move. I want to do an physical effect like waves or other over this grid.

¿how is the best way to implement this 3D objects and move it?

I try to create on each iteration all 100 planes, but it is very heavy, i'm seeing with ClientFactory to do like a 3d terrain, but ¿how can i move the vertex of planes on realtime, move deforming his form makes trapezoid and the plane doesn't keep the same size or square form.

i hope you can understand my english, sorry for that and thank you in advance.
« Last Edit: July 07, 2013, 05:52:00 pm by julycamara »

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: Draw 3D Terrain with planes and change it on real time
« Reply #1 on: July 08, 2013, 09:58:50 pm »
You could use OpenGL ES 2.0 mode and your own, custom shader. That's fast but more complicated. You could write a VertexController in Java and let it animate the plane. That's easier (at least IMHO), but slower. For the latter, i've this example for desktop jPCT, but it should be pretty easy to port it to jPCT-AE:

Code: [Select]
import com.threed.jpct.Config;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.GenericVertexController;
import com.threed.jpct.IRenderer;
import com.threed.jpct.Matrix;
import com.threed.jpct.Object3D;
import com.threed.jpct.Primitives;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.Texture;
import com.threed.jpct.TextureInfo;
import com.threed.jpct.TextureManager;
import com.threed.jpct.World;
import com.threed.jpct.util.Light;

public class CheapWater {

private World world;

private FrameBuffer buffer;

private Object3D water;

private WaterController wc = null;

public static void main(String[] args) throws Exception {
new CheapWater().loop();
}

public CheapWater() throws Exception {
world = new World();
world.setAmbientLight(100, 100, 100);

TextureManager tm = TextureManager.getInstance();
tm.addTexture("water", new Texture("water3.jpg"));

water = Primitives.getPlane(40, 1.5f);

water.setTexture("water");
water.rotateX((float) Math.PI / 2f);
water.rotateMesh();
water.clearRotation();
water.compile(true);
water.build();
water.setTransparency(2);
wc = new WaterController(water, 5, 10, false);
water.getMesh().setVertexController(wc, false);
world.addObject(water);

world.getCamera().setPosition(0, -50, -50);
world.getCamera().lookAt(water.getTransformedCenter());

Light light = new Light(world);
light.setAttenuation(-1);
light.setIntensity(255, 255, 255);
light.setPosition(new SimpleVector(100, -50, -20));
}

private void loop() throws Exception {
buffer = new FrameBuffer(800, 600, FrameBuffer.SAMPLINGMODE_GL_AA_2X);
buffer.disableRenderer(IRenderer.RENDERER_SOFTWARE);
buffer.enableRenderer(IRenderer.RENDERER_OPENGL);

long s = System.nanoTime() / 1000000L;
long ss = System.currentTimeMillis();
int fps = 0;

while (!org.lwjgl.opengl.Display.isCloseRequested()) {
buffer.clear(java.awt.Color.BLUE);

long ticks = ((System.nanoTime() / 1000000L) - s) / 10;

if (ticks > 0) {
s = System.nanoTime() / 1000000L;
wc.update(0.5f * (float) ticks);
water.getMesh().applyVertexController();
}

world.renderScene(buffer);
world.draw(buffer);
buffer.update();
buffer.displayGLOnly();
fps++;
if (System.currentTimeMillis() - ss >= 1000) {
System.out.println(fps + "fps");
fps = 0;
ss = System.currentTimeMillis();
}
}
buffer.disableRenderer(IRenderer.RENDERER_OPENGL);
buffer.dispose();
System.exit(0);
}

private static class WaterController extends GenericVertexController {

private float scale = 0;

private float damping = 0;

private SimpleVector[] preCalcNormals = null;

private SimpleVector[] preCalcNormalsNeg = null;

private float[] lastHeight = null;

private static final long serialVersionUID = 1L;

private float degreeAdd = 0;

private Object3D water = null;

private float lastUpdate = 0;

private boolean realNormals = false;

public WaterController(Object3D water, float scale, float damping, boolean realNormals) {
this.scale = scale;
this.water = water;
this.realNormals = realNormals;
this.damping = damping;
water.setTextureMatrix(new Matrix());
}

/**
* This calculates some normals...these are rather fake and in no way
* comparable to real surface normals. But they should do the trick...
*/
public boolean setup() {
SimpleVector ax = new SimpleVector(-1, 0, 1).normalize();
preCalcNormals = new SimpleVector[(int) (100f * scale)];
preCalcNormalsNeg = new SimpleVector[(int) (100f * scale)];
int end = preCalcNormals.length;
for (int i = 0; i < end; i++) {
float height = -1f + (((float) i) / (end / 2f));
SimpleVector n = new SimpleVector(0, -1, 0);
SimpleVector n2 = new SimpleVector(0, -1, 0);
Matrix m = new Matrix();
Matrix m2 = new Matrix();
if (height <= 0) {
float val = (float) Math.sqrt((height + 1) * (Math.PI / 7f));
m.rotateAxis(ax, val);
m2.rotateAxis(ax, -val);
} else {
float val = (float) Math.sqrt((1 - height) * (Math.PI / 7f));
m.rotateAxis(ax, val);
m2.rotateAxis(ax, -val);
}
n.rotate(m);
n2.rotate(m);
preCalcNormals[i] = n;
preCalcNormalsNeg[i] = n2;
}

SimpleVector[] source = this.getSourceMesh();
lastHeight = new float[source.length];

for (int i = 0; i < source.length; i++) {
lastHeight[i] = 0;
}

return true;
}

public void update(float inc) {
degreeAdd += inc;
lastUpdate = inc;
}

public void apply() {
SimpleVector[] source = this.getSourceMesh();
SimpleVector[] dest = this.getDestinationMesh();

SimpleVector[] destNormals = this.getDestinationNormals();

int end = source.length;
int nEnd = preCalcNormals.length;

for (int i = 0; i < end; i++) {
SimpleVector s = source[i];
SimpleVector d = dest[i];
float sin = (float) Math.sin((degreeAdd + s.x + s.z) / damping);
d.set(s.x, s.y + sin * scale, s.z);

int iHeight = (int) ((sin + 1) * (nEnd / 2));

if (lastHeight[i] > sin) {
destNormals[i].set(preCalcNormalsNeg[iHeight]);
} else {
destNormals[i].set(preCalcNormals[iHeight]);
}

lastHeight[i] = sin;
}

water.touch();
if (realNormals) {
water.calcNormals();
}
float tr = lastUpdate / 233f;
water.getTextureMatrix().translate(tr, -tr, 0);
}
}

}