我正在尝试创建一个简单的应用程序,它允许您从.obj加载3D模型,并通过触摸屏幕缩放/旋转它.
我设法编写了从文件中加载3d模型并检测手势的代码,但现在我不知道如何通过触摸屏幕来启用缩放/旋转功能.
这是我现在的代码:
public class RenderObjApp implements ApplicationListener,GestureDetector.GestureListener { public static int SCREEN_WIDTH = 800; public static int SCREEN_HEIGHT = 600; private static final String TAG = RenderObjApp.class.getSimpleName(); private Mesh model; private PerspectiveCamera camera; private float scale = 1f; @Override public void create() { model = ObjLoader.loadObj(Gdx.files.internal("data/cessna.obj").read(),true); Gdx.gl.glEnable(GL10.GL_DEPTH_TEST); Gdx.input.setInputProcessor(new GestureDetector(this)); } @Override public void dispose() { } @Override public void pause() { } @Override public void render() { Gdx.gl.glClearColor(0.0f,0.0f,1.0f); Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); camera.update(); camera.apply(Gdx.gl10); model.render(GL10.GL_TRIANGLES); } @Override public void resize(int arg0,int arg1) { float aspectRatio = (float) arg0 / (float) arg1; camera = new PerspectiveCamera(75,2f * aspectRatio,2f); camera.near = 0.1f; camera.translate(0,0); } @Override public void resume() { } @Override public boolean touchDown(float x,float y,int pointer) { Gdx.app.log(TAG,"touchDown: "); return false; } @Override public boolean tap(float x,int count,int pointer,int button) { Gdx.app.log(TAG,"tap: "); return false; } @Override public boolean longPress(float x,float y) { Gdx.app.log(TAG,"zoom: "); return false; } @Override public boolean fling(float velocityX,float velocityY,"fling: "); return false; } @Override public boolean pan(float x,float deltaX,float deltaY) { Gdx.app.log(TAG,"pan: "); return false; } @Override public boolean zoom(float initialDistance,float distance) { Gdx.app.log(TAG,"zoom: initialDistance=" + initialDistance + ",distance=" + distance); return false; } @Override public boolean pinch(Vector2 initialPointer1,Vector2 initialPointer2,Vector2 pointer1,Vector2 pointer2) { Gdx.app.log(TAG,"pinch: "); return false; } }
所以我正在寻找如何旋转PerspectiveCamera和Mesh本身.
解决方法
我一直致力于“Blender风格”相机,它具有捏合变焦功能以及(在桌面上)大多数Blender相机的功能.这是一项正在进行的工作 – 它并不完全模仿Blender相机的行为(尚未).我想这会让你指出正确的方向.你应该知道的一些事情:
>您可能需要翻译模型,使其位于原点.除非您翻译,否则相机仍然指向原点. (到目前为止,您只能在桌面上翻译而不是在Android上翻译);
>我在这里得到了大部分的缩放变焦处理代码:https://code.google.com/p/libgdx-users/wiki/PinchToZoom.
>抱歉有神奇的数字.我将在未来制作这些常数.
>如果您或其他任何人改进了此代码,我很乐意,如果您与我共享副本.
抽象类:
/* Author: Christopher Grabowski,yourchristopher6334 gmail.com */ package ...; import com.badlogic.gdx.InputProcessor; import com.badlogic.gdx.graphics.PerspectiveCamera; import com.badlogic.gdx.input.GestureDetector.GestureListener; import com.badlogic.gdx.math.Vector2; abstract public class ControllableCamera extends PerspectiveCamera implements InputProcessor{ abstract public void resize(int width,int height); abstract public void render(); public ControllableCamera(int fieldOfView,int width,int height) { super(fieldOfView,width,height); } @Override public boolean keyDown(int keyCode) { return false; } @Override public boolean keyTyped(char arg0) { return false; } @Override public boolean keyUp(int arg0) { return false; } @Override public boolean touchDown(int x,int y,int button) { return false; } @Override public boolean touchDragged(int screenX,int screenY,int pointer) { return false; } @Override public boolean touchUp(int x,int button) { return false; } @Override public boolean mouseMoved(int arg0,int arg1) { return false; } @Override public boolean scrolled(int direction) { return false; } }
具体课程:
/* Author: Christopher Grabowski,yourchristopher6334 gmail.com */ package ...; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input.Keys; import com.badlogic.gdx.math.Vector3; /* * the pause,resize,and render methods must be called within their corresponding * methods in the ApplicationListener */ public class BlenderStyleCamera extends ControllableCamera { public static final Vector3 ORIGIN = new Vector3(0,0); private static boolean shiftIsPressed = false,controlIsPressed = false,isScrollingUp = false,isScrollingDown = false,isSingleTouched = false,justSingleTouched = false; private float aspectRatio; private int x = -1,y = -1; private float dx = 0.0f,dy = 0.0f; private final Vector3 tmp = new Vector3(); // fields related to pinch-to-zoom private int numberOfFingers = 0; private int fingerOnePointer; private int fingerTwoPointer; private float lastDistance = 0; private final Vector3 fingerOne = new Vector3(); private final Vector3 fingerTwo = new Vector3(); public BlenderStyleCamera(int fieldOfView,height); aspectRatio = viewportHeight / viewportWidth; Gdx.input.setInputProcessor(this); up.set(0.0f,1.0f,0.0f); position.set(0.0f,30.0f); far = 300.0f; lookAt(0,0); translate(0.0f,2.1f); lookAt(0,0); update(); } public void pause() { numberOfFingers = 0; } @Override public void resize(int width,int height) { viewportWidth = width; viewportHeight = height; aspectRatio = viewportHeight / viewportWidth; update(); } @Override public void render() { if (isSingleTouched) { // This gets the change in touch position and // compensates for the aspect ratio. if (x == -1 || y == -1 || justSingleTouched) { x = Gdx.input.getX(); y = Gdx.input.getY(); } else { dx = (x - Gdx.input.getX()); dy = (y - Gdx.input.getY()) / aspectRatio; } // This zooms when control is pressed. if (controlIsPressed && dy > 0) { scrollIn(); } else if (controlIsPressed && dy < 0) { scrollOut(); } // This translates the camera blender-style // if shift is pressed. // Note that this will look weird with a // perspective camera. else if (shiftIsPressed) { translateTangentially(); } // Default is to rotate the object // (actually rotate the camera about a sphere // that surrounds the object). else { travelAround(); } x = Gdx.input.getX(); y = Gdx.input.getY(); justSingleTouched = false; } // this zooms when the mouse wheel is rotated if (isScrollingUp) { scrollIn(); isScrollingUp = false; } else if (isScrollingDown) { scrollOut(); isScrollingDown = false; } // Some key controls if (Gdx.input.isKeyPressed(Keys.LEFT) || Gdx.input.isKeyPressed(Keys.A)) { translateTangentially(1,0); } else if (Gdx.input.isKeyPressed(Keys.RIGHT) || Gdx.input.isKeyPressed(Keys.D)) { translateTangentially(-1,0); } if (Gdx.input.isKeyPressed(Keys.UP) || Gdx.input.isKeyPressed(Keys.W)) { translateTangentially(0,1); } else if (Gdx.input.isKeyPressed(Keys.DOWN) || Gdx.input.isKeyPressed(Keys.S)) { translateTangentially(0,-1); } update(); } // These methods create the pinch zoom // and set some flags for logic in render method. @Override public boolean touchDown(int x,int button) { // for pinch-to-zoom numberOfFingers++; if (numberOfFingers == 1) { isSingleTouched = true; justSingleTouched = true; fingerOnePointer = pointer; fingerOne.set(x,y,0); } else if (numberOfFingers == 2) { isSingleTouched = false; fingerTwoPointer = pointer; fingerTwo.set(x,0); float distance = fingerOne.dst(fingerTwo); lastDistance = distance; } return true; } @Override public boolean touchDragged(int x,int pointer) { if (numberOfFingers > 1) { if (pointer == fingerOnePointer) { fingerOne.set(x,0); } if (pointer == fingerTwoPointer) { fingerTwo.set(x,0); } float distance = fingerOne.dst(fingerTwo); if (lastDistance > distance) { scrollOut(); } else if (lastDistance < distance) { scrollIn(); } lastDistance = distance; update(); } return true; } @Override public boolean touchUp(int x,int button) { isSingleTouched = false; if (numberOfFingers == 1) { Vector3 touchPoint = new Vector3(x,0); unproject(touchPoint); } numberOfFingers--; // just some error prevention... clamping number of fingers (ouch! :-) if (numberOfFingers < 0) { numberOfFingers = 0; } lastDistance = 0; return false; } // These methods set flags for logic in render method. @Override public boolean keyDown(int keycode) { switch (keycode) { case (Keys.SHIFT_LEFT): case (Keys.SHIFT_RIGHT): shiftIsPressed = true; break; case (Keys.CONTROL_LEFT): case (Keys.CONTROL_RIGHT): controlIsPressed = true; break; case (Keys.O): this.up.set(0.0f,0.0f); this.position.set(0.0f,30.0f); this.lookAt(0,0); this.update(); } return true; } @Override public boolean keyUp(int arg0) { shiftIsPressed = controlIsPressed = false; return true; } @Override public boolean scrolled(int direction) { if (direction == -1) { isScrollingUp = true; } else if (direction == 1) { isScrollingDown = true; } return true; } // The rest of the methods translate the camera. public void scrollIn() { float magnitude = 1.0f; scrollIn(magnitude); } public void scrollIn(float magnitude) { if (position.dst2(ORIGIN) > 2.0f) { tmp.set(position); tmp.nor(); this.translate(-tmp.x * magnitude,-tmp.y * magnitude,-tmp.z * magnitude); update(); } } public void scrollOut() { float magnitude = 1.0f; scrollOut(magnitude); } public void scrollOut(float magnitude) { tmp.set(position); tmp.nor(); this.translate(tmp.x * magnitude,tmp.y * magnitude,tmp.z * magnitude); update(); } private void travelAround() { tmp.set(up); rotateAround(ORIGIN,tmp,dx); tmp.crs(position).nor(); rotateAround(ORIGIN,dy); } private void translateTangentially() { translateTangentially(dx,dy); } private void translateTangentially(float dx,float dy) { tmp.set(up); tmp.crs(position); if (dx > 0) { translate(tmp.x / 15.0f,tmp.y / 15.0f,tmp.z / 15.0f); } else if (dx < 0) { translate(-tmp.x / 15.0f,-tmp.y / 15.0f,-tmp.z / 15.0f); } if (dy > 0) { translate(-up.x,-up.y,-up.z); } else if (dy < 0) { translate(up); } } }