libgdx如何缩放&触摸旋转3d模型

时间:2012-11-16 16:42:26

标签: java libgdx

我正在尝试创建一个简单的应用程序,它允许您从.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, 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, 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, float y, 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, int pointer, int button) {
        Gdx.app.log(TAG, "fling: ");
        return false;
    }

    @Override
    public boolean pan(float x, float y, 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本身。

3 个答案:

答案 0 :(得分:2)

我一直致力于研发“Blender风格”相机,它具有捏合变焦功能以及(在桌面上)Blender相机的大部分功能。这是一项正在进行的工作 - 它并不完全模仿Blender相机的行为(尚未)。我想这会让你指出正确的方向。你应该知道的一些事情:

  1. 您可能需要翻译模型,使其位于原点。除非您翻译,否则相机仍然指向原点。 (到目前为止,您只能在桌面上翻译,而不能在Android上翻译);

  2. 我在这里获得了大部分捏缩变量处理代码:https://code.google.com/p/libgdx-users/wiki/PinchToZoom

  3. 很抱歉这些神奇的数字。我将在未来制作这些常数。

  4. 如果您或其他任何人改进了此代码,我很乐意与您共享副本。

  5. 抽象类:

    /* 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 pointer, int button) {
            return false;
        }
    
        @Override
        public boolean touchDragged(int screenX, int screenY, int pointer) {
            return false;
        }
    
        @Override
        public boolean touchUp(int x, int y, int pointer, 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, 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, int width, int height) {
            super(fieldOfView, width, height);
            aspectRatio = viewportHeight / viewportWidth;
            Gdx.input.setInputProcessor(this);
            up.set(0.0f, 1.0f, 0.0f);
            position.set(0.0f, 0.0f, 30.0f);
            far = 300.0f;
            lookAt(0, 0, 0);
            translate(0.0f, 0.0f, 2.1f);
            lookAt(0, 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 y, int pointer, 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, y, 0);
    
                float distance = fingerOne.dst(fingerTwo);
                lastDistance = distance;
            }
            return true;
        }
    
        @Override
        public boolean touchDragged(int x, int y, int pointer) {
            if (numberOfFingers > 1) {
                if (pointer == fingerOnePointer) {
                    fingerOne.set(x, y, 0);
                }
                if (pointer == fingerTwoPointer) {
                    fingerTwo.set(x, y, 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 y, int pointer, int button) {
            isSingleTouched = false;
            if (numberOfFingers == 1) {
                Vector3 touchPoint = new Vector3(x, y, 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, 1.0f, 0.0f);
                this.position.set(0.0f, 0.0f, 30.0f);
                this.lookAt(0, 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, tmp, 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);
            }
        }
    
    }
    

答案 1 :(得分:1)

请看一下:Mesh rendering issue libgdx

方法渲染包含您需要的代码。

答案 2 :(得分:0)

您需要旋转相机或旋转模型。

我相信libGDX Camera.rotateAround方法可以满足您的需求。将“点”保留为模型的中心,并根据用户投掷/平移的方式设置“轴”参数。 “角度”可以是固定值,也可以是相对于fling / pan的强度。