How to change the shape of a model

Started by Eric, November 23, 2010, 05:00:33 AM

Previous topic - Next topic

Eric

Hi, I'm a beginner of JPCT-AE. And now I encountered a problem that how to change the shape of a 3D model. For example, there's a box loaded from a 3DS file in the scene. I'd like to change the "height" of the box by changing the position of its 4 top vertexes. I use GenericVertexController to do this, it works when I call it in onSurfaceCreated, but it doesn't work at all while it's running when I call it in onDrawFrame. I try to read out the position of the changed vertexes, they're changed but the look in the scene remains the same. I also tried to change the texture and the position of the vertexes dynamically at the same time, the texture changed but the look of the model didn't change at all. And if I call cloneObject to clone another model to the scene, the cloned one changed, but the origin remained the same. So, what's the problem of this, how can I change the vertex position dynamically? Thanks a lot!
Here's my code:

package com.censivn.weather;

import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.opengles.GL10;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PaintFlagsDrawFilter;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;

import android.app.Activity;
import android.content.res.Resources;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.os.Debug;
import android.util.FloatMath;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;

import com.threed.jpct.Camera;
import com.threed.jpct.Config;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.GenericVertexController;
import com.threed.jpct.IVertexController;
import com.threed.jpct.Light;
import com.threed.jpct.Loader;
import com.threed.jpct.Logger;
import com.threed.jpct.Mesh;
import com.threed.jpct.Object3D;
import com.threed.jpct.Primitives;

import com.threed.jpct.RGBColor;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.Texture;
import com.threed.jpct.TextureManager;
import com.threed.jpct.World;
import com.threed.jpct.Matrix;

import com.censivn.weather.R;
import com.junction.fire.Tween3DObject.*;

public class Demo extends Activity {

private GLSurfaceView mGLView;
private MyRenderer renderer = null;
private FrameBuffer fb = null;
private TweenWorld world = null;

private int move = 0;
private float turn = 0;

private boolean paused = false;

private float xDistance = 0;
private float yDistance = 0;

private float xpos = -1;
private float ypos = -1;

private boolean isFront = true;

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mGLView = new GLSurfaceView(getApplication());

mGLView.setEGLConfigChooser(new GLSurfaceView.EGLConfigChooser() {
public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
// Ensure that we get a 16bit framebuffer. Otherwise, we'll fall
// back to Pixelflinger on some device (read: Samsung I7500)

int[] attributes = new int[] { EGL10.EGL_DEPTH_SIZE, 16,
EGL10.EGL_NONE };

EGLConfig[] configs = new EGLConfig[1];
int[] result = new int[1];
egl.eglChooseConfig(display, attributes, configs, 1, result);
return configs[0];
}
});

renderer = new MyRenderer();
mGLView.setRenderer(renderer);
setContentView(mGLView);
}

protected void onPause() {
paused = true;
super.onPause();
mGLView.onPause();
}

protected void onResume() {
paused = false;
super.onResume();
mGLView.onResume();
}

protected void onStop() {
renderer.stop();
super.onStop();
}

public boolean onTouchEvent(MotionEvent me) {

if (me.getAction() == MotionEvent.ACTION_DOWN) {
xpos = me.getX();
ypos = me.getY();
return true;
}

if (me.getAction() == MotionEvent.ACTION_UP) {
xpos = -1;
ypos = -1;
return true;
}

if (me.getAction() == MotionEvent.ACTION_MOVE) {

float xd = me.getX() - xpos;
float yd = me.getY() - ypos;

xpos = me.getX();
ypos = me.getY();

xDistance = xd / 100f;
yDistance = yd / 100f;

return true;
}

return super.onTouchEvent(me);

}

public boolean onKeyDown(int keyCode, KeyEvent msg) {

if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
move = 2;
return true;
}

if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
move = -2;
return true;
}

if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
turn = 0.05f;
return true;
}

if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
turn = -0.05f;
return true;
}

return super.onKeyDown(keyCode, msg);
}

public boolean onKeyUp(int keyCode, KeyEvent msg) {
if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
move = 0;
return true;
}

if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
move = 0;
return true;
}

if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
turn = 0;
return true;
}

if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
turn = 0;
return true;
}

return super.onKeyUp(keyCode, msg);
}

protected boolean isFullscreenOpaque() {
return true;
}

class MyRenderer implements GLSurfaceView.Renderer {

private long time = System.currentTimeMillis();

private Object3D bottomModel = null;

private boolean stop = false;

public MyRenderer() {

Config.maxPolysVisible = 5000;

Config.farPlane = 1500;

}

public void stop() {
stop = true;
if (fb != null) {
fb.dispose();
fb = null;
}
}

public void onSurfaceChanged(GL10 gl, int w, int h) {
if (fb != null) {
fb.dispose();
}
fb = new FrameBuffer(gl, w, h);
}

public void onSurfaceCreated(GL10 gl, EGLConfig config) {

gl.glEnable(GL10.GL_BLEND);

gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA);

TextureManager.getInstance().flush();

world = new TweenWorld();

Resources res = getResources();

TextureManager tm = TextureManager.getInstance();

Texture barTexture = new Texture(res.openRawResource(R.raw.bar),
true);

Texture barTexture2 = new Texture(res.openRawResource(R.raw.bar2),
true);

tm.addTexture("barTexture", barTexture);

tm.addTexture("barTexture2", barTexture2);

bottomModel = Loader.load3DS(res.openRawResource(R.raw.bar_model),
1)[0];

bottomModel.setTexture("barTexture");

bottomModel.rotateX((float) Math.PI / 4);

world.addObject(bottomModel);

world.setAmbientLight(250, 250, 250);

world.buildAllObjects();

Camera cam = world.getCamera();

cam.moveCamera(Camera.CAMERA_MOVEOUT, 60);

cam.setFOV(1f);

//deformObject();

}

public void onDrawFrame(GL10 gl) {

try {

if (yDistance < 0) {

if (isFront) {

isFront = false;

bottomModel.setTexture("barTexture");

deformObject();

}

} else if (yDistance > 0) {

if (!isFront) {

isFront = true;

bottomModel.setTexture("barTexture2");

deformObject();

}

}

xDistance = 0;

yDistance = 0;

fb.clear();

world.renderScene(fb);

world.draw(fb);

fb.display();

} catch (Exception e) {
Logger.log("Drawing thread terminated!", Logger.MESSAGE);
}
}

public void deformObject(){

Mesh planeMesh = bottomModel.getMesh();

planeMesh.setVertexController(new Mod(),
IVertexController.PRESERVE_SOURCE_MESH);

planeMesh.applyVertexController();

planeMesh.removeVertexController();

}

}

public static class Mod extends GenericVertexController {
private static final long serialVersionUID = 1L;

public void apply() {

SimpleVector[] s = getSourceMesh();
SimpleVector[] d = getDestinationMesh();

d[4].y = -180;
d[5].y = -180;
d[6].y = -180;
d[7].y = -180;

Log.i("change point", "y:" + d[4].y);

this.updateMesh();

}
}

}

EgonOlsen

Assign the vertex controller once at startup and leave it assigned. Otherwise, jPCT-AE can't detect that this model is going to change at runtime and will do a static compile. Remember to call touch() after applying the vertex controller.

Eric

Quote from: EgonOlsen on November 23, 2010, 07:10:28 AM
Assign the vertex controller once at startup and leave it assigned. Otherwise, jPCT-AE can't detect that this model is going to change at runtime and will do a static compile. Remember to call touch() after applying the vertex controller.
Is it to say that I should add the follow red line ?
                        Mesh planeMesh = bottomModel.getMesh();

         planeMesh.setVertexController(new Mod(),
               IVertexController.PRESERVE_SOURCE_MESH);

         planeMesh.applyVertexController();

         planeMesh.removeVertexController();

                       bottomModel.touch();

EgonOlsen

No, not quite. Create your object, assign the controller and THEN call build(), render it, etc...don't remove the controller and don't assign it aftre the object has been rendered for the first time. In deformObject(), just do an apply... and a touch() afterwards.

Eric

OK, thanks a lot. I'll try it right away. :)