Android 3D jpct-ae 一個場景小例子
阿新 • • 發佈:2019-02-15
jpct-ae 一個場景小例子,載入了一些3ds模型,並且實現了手指觸控移動,實現了上下左右鍵。但是,此處有兩個3ds模型在最終的畫面裡面沒有顯示,程式也沒有報錯,不知道是為什麼,這一點讓我很納悶。
注意:1,Loader.load3DS返回的是Object3D[],是一個數組,一般選擇陣列的第一項。
2,jpct-ae 裡面rotate()預設的是逆時針方向旋轉,若要順時針方向旋轉,則rotate(負數);
程式碼:
package com.je; import java.lang.reflect.Field; 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 com.threed.jpct.Camera; import com.threed.jpct.Config; import com.threed.jpct.FrameBuffer; import com.threed.jpct.Light; import com.threed.jpct.Loader; import com.threed.jpct.Logger; import com.threed.jpct.Object3D; 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.util.MemoryHelper; import android.app.Activity; import android.content.res.AssetManager; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.opengl.GLSurfaceView; import android.os.Bundle; import android.util.Log; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.Window; import android.view.WindowManager; public class JpctExampleActivity extends Activity { //JpctAdvancedExampleActivity物件用來處理activity的onPause和onResume public static JpctExampleActivity master=null; private GLSurfaceView mGLView; private MRenderer mRenderer=null; private float touchTurn = 0; private float touchTurnUp = 0; private float xpos = -1; private float ypos = -1; private int move=0; private float turn=0; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub // 如果本類物件不為NULL,將從Object中所有屬性裝入該類 if(master!=null) copy(master); super.onCreate(savedInstanceState); mGLView=new GLSurfaceView(getApplication()); // 使用自己實現的 EGLConfigChooser,該實現必須在setRenderer(renderer)之前 // 如果沒有setEGLConfigChooser方法被呼叫,則預設情況下, // 檢視將選擇一個與當前android.view.Surface相容至少16位深度緩衝深度EGLConfig。 mGLView.setEGLConfigChooser(new GLSurfaceView.EGLConfigChooser() { @Override public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { // TODO Auto-generated method stub int[] att=new int[]{EGL10.EGL_DEPTH_SIZE,16,EGL10.EGL_NONE}; EGLConfig[] config=new EGLConfig[1]; int[] result = new int[1]; egl.eglChooseConfig(display, att, config, 1, result); return config[0]; } }); mRenderer=new MRenderer(); mGLView.setRenderer(mRenderer); setContentView(mGLView); } @Override protected void onPause() { // TODO Auto-generated method stub super.onPause(); mGLView.onPause(); } @Override protected void onResume() { // TODO Auto-generated method stub super.onResume(); mGLView.onResume(); } @Override protected void onStop() { // TODO Auto-generated method stub super.onStop(); } //實現手勢觸控移動 @Override public boolean onTouchEvent(MotionEvent event) { // TODO Auto-generated method stub //按下手指 if(event.getAction()==MotionEvent.ACTION_DOWN){ xpos=event.getX(); ypos=event.getY(); return true; } //擡起手指 if (event.getAction() == MotionEvent.ACTION_UP) { xpos = -1; ypos = -1; touchTurn = 0; touchTurnUp = 0; return true; } //移動 if (event.getAction() == MotionEvent.ACTION_MOVE) { float xd = event.getX() - xpos; float yd = event.getY() - ypos; xpos = event.getX(); ypos = event.getY(); touchTurn = xd / 100f; touchTurnUp = yd / 100f; return true; } try { Thread.sleep(15); } catch (Exception e) { } return super.onTouchEvent(event); } //實現上下左右鍵 @Override public boolean onKeyDown(int keyCode, KeyEvent event) { // TODO Auto-generated method stub 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, event); } @Override public boolean onKeyUp(int keyCode, KeyEvent event) { // TODO Auto-generated method stub 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, event); } private void copy(Object src) { try { // 列印日誌 Logger.log("Copying data from master Activity!"); // 返回一個數組,其中包含目前這個類的的所有欄位的Filed物件 Field[] fs = src.getClass().getDeclaredFields(); // 遍歷fs陣列 for (Field f : fs) { // 嘗試設定無障礙標誌的值。標誌設定為false將使訪問檢查,設定為true,將其禁用。 f.setAccessible(true); // 將取到的值全部裝入當前類中 f.set(this, f.get(src)); } } catch (Exception e) { // 丟擲執行時異常 throw new RuntimeException(e); } } class MRenderer implements GLSurfaceView.Renderer { private FrameBuffer fb=null; private World world=null; private RGBColor back=new RGBColor(100,100,100); private Object3D plane=null;//平面 private Object3D tree1=null;//樹 private Object3D tree2=null; private Object3D rock=null;//石頭 private Object3D grass=null;//草 private Object3D cube=null;//長方體 private Object3D house=null;//房子 private Object3D head=null;//一個骷髏頭 private Light light=null; private long time=System.currentTimeMillis();//返回的是以毫秒為單位的當前時間 private SimpleVector lightRot=new SimpleVector(-100,-100f,100); public MRenderer(){ //此程式碼在下一個例子中會解釋 Config.maxPolysVisible = 500; Config.farPlane = 1500; Config.glTransparencyMul = 0.1f; Config.glTransparencyOffset = 0.1f; Texture.defaultToMipmapping(true); Texture.defaultTo4bpp(true); } @Override public void onDrawFrame(GL10 gl) { // TODO Auto-generated method stub try { if (true) { Camera cam = world.getCamera(); if (turn != 0) { world.getCamera().rotateY(-turn); } if (touchTurn != 0) { world.getCamera().rotateY(touchTurn); touchTurn = 0; } if (touchTurnUp != 0) { world.getCamera().rotateX(touchTurnUp); touchTurnUp = 0; } if (move != 0) { world.getCamera().moveCamera(cam.getDirection(), move); } fb.clear(back); world.renderScene(fb);//轉換燈光和所有的多邊形 world.draw(fb); fb.display();//顯示 if (light != null) { light.rotate(lightRot, plane.getTransformedCenter()); } } else { if (fb != null) { fb.dispose(); fb = null; } } } catch (Exception e) { e.printStackTrace(); Logger.log("Drawing thread terminated!", Logger.MESSAGE); } } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { // TODO Auto-generated method stub if(fb!=null) fb.dispose();//清理緩衝器 fb=new FrameBuffer(gl,width,height); } @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { // TODO Auto-generated method stub if(JpctExampleActivity.master==null){ world=new World(); Resources res = getResources(); //取得材質管理器 TextureManager tm=TextureManager.getInstance(); //取得紋理 Texture grass2 = new Texture(res.openRawResource(R.raw.grassy)); Texture leaves = new Texture(res.openRawResource(R.raw.tree2y)); Texture leaves2 = new Texture(res.openRawResource(R.raw.tree3y)); Texture rocky = new Texture(res.openRawResource(R.raw.rocky)); Texture planetex = new Texture(res.openRawResource(R.raw.planetex)); Texture housey2 = new Texture(res.openRawResource(R.raw.photo)); Texture heady=new Texture(res.openRawResource(R.raw.photo)); //將紋理新增到材質管理器裡面 tm.addTexture("grass2", grass2); tm.addTexture("leaves", leaves); tm.addTexture("leaves2", leaves2); tm.addTexture("rock", rocky); tm.addTexture("grassy", planetex); tm.addTexture("housey2",housey2); tm.addTexture("heady",heady); //構造平面,該出用的是經過處理的資料 plane = Loader.loadSerializedObject(res.openRawResource(R.raw.serplane)); //載入岩石,樹,草,房子,骷髏頭的3ds模型 //檢視API文件可知,Loader.load3DS返回的是Object3D[],是一個數組,這裡選擇陣列的第一項 //陣列第一項就是我們需要的模型,所以寫為Loader.load3DS( )[0]; rock=Loader.load3DS(res.openRawResource(R.raw.rock), 30f)[0]; tree1=Loader.load3DS(res.openRawResource(R.raw.tree2), 5f)[0]; tree2=Loader.load3DS(res.openRawResource(R.raw.tree3), 5f)[0]; grass=Loader.load3DS(res.openRawResource(R.raw.grass), 2f)[0]; cube=Loader.load3DS(res.openRawResource(R.raw.cube), 1f)[0]; //?????????? 在這裡有些問題,house和head這兩個3ds模型載入不進去????????? house=Loader.load3DS(res.openRawResource(R.raw.house1), 1f)[0]; head=Loader.load3DS(res.openRawResource(R.raw.head), 1f)[0]; //上面的house和head兩個模型在最終的畫面裡面看不到,沒有出現,筆者也不知道是為什麼?????????????? grass.translate(-45, -17, -50);//平移 grass.rotateZ((float) Math.PI); rock.translate(0, 0, -90); //繞X軸旋轉90度,注意:rotateX()預設的是逆時針方向旋轉 rock.rotateX(-(float) Math.PI / 2); tree1.translate(-50, -100, -50); tree1.rotateZ((float) Math.PI); tree2.translate(60, -95, -10); tree2.rotateZ((float) Math.PI); plane.rotateX((float) Math.PI / 2f); cube.translate(-80, 0, -110); cube.rotateX((float)Math.PI/2f); head.translate(-45, -17, -50); head.rotateZ((float) Math.PI); house.translate(-70, 0, -110); house.rotateX((float)Math.PI/2f); //下面的可要可不要 house.setName("house"); plane.setName("plane"); tree1.setName("tree1"); tree2.setName("tree2"); grass.setName("grass"); rock.setName("rock"); //設定紋理方式 house.calcTextureWrapSpherical(); head.calcTextureWrapSpherical(); cube.calcTextureWrapSpherical(); //設定紋理 house.setTexture("housey2"); head.setTexture("heady"); cube.setTexture("housey2"); tree1.setTexture("leaves"); tree2.setTexture("leaves2"); rock.setTexture("rock"); grass.setTexture("grass2"); //加入到world裡面 world.addObject(plane); world.addObject(tree1); world.addObject(tree2); world.addObject(grass); world.addObject(rock); world.addObject(house); world.addObject(head); world.addObject(cube); //釋放記憶體 plane.strip(); tree1.strip(); tree2.strip(); grass.strip(); rock.strip(); house.strip(); head.strip(); cube.strip(); world.setAmbientLight(250, 250, 250);//設定光環境光 world.buildAllObjects();//Calls build() for every object in the world. light = new Light(world);//設定光照 light.setIntensity(250, 250, 0);//設定光顏色 Camera cam = world.getCamera(); cam.moveCamera(Camera.CAMERA_MOVEOUT, 250); cam.moveCamera(Camera.CAMERA_MOVEUP, 100); //相機的在plane的中心 cam.lookAt(plane.getTransformedCenter()); SimpleVector sv = new SimpleVector(); sv.set(plane.getTransformedCenter()); Log.e("X:", plane.getTransformedCenter().toString()); sv.y -= 500; sv.x -= 300; sv.z += 200; //設定光照的位置,此處的sv為plane的中心 light.setPosition(sv); //釋放記憶體 MemoryHelper.compact(); if (master == null) { Logger.log("Saving master Activity!"); master = JpctExampleActivity.this; } } } } }