Java libgdx如何缩放&;触摸旋转三维模型

Java libgdx如何缩放&;触摸旋转三维模型,java,libgdx,Java,Libgdx,我正在尝试创建一个简单的应用程序,允许您从.obj加载3d模型,并通过触摸屏幕进行缩放/旋转 我成功地编写了从文件中加载3d模型并检测手势的代码,但现在我不确定如何通过触摸屏幕来启用缩放/旋转功能 以下是我目前的代码: public class RenderObjApp implements ApplicationListener, GestureDetector.GestureListener { public static int SCREEN_WIDTH = 800; pu

我正在尝试创建一个简单的应用程序,允许您从.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;
    }
}

因此,我正在研究如何旋转透视摄影机和网格本身。

您需要旋转摄影机或旋转模型


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

请查看以下内容:

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

我一直在开发一款“Blender风格”相机,该相机具有收缩到缩放功能,并且(在桌面上)具有Blender相机的大部分功能。这是一项正在进行的工作——它还没有完全模仿Blender相机的行为。我想这会给你指明正确的方向。有些事情你应该知道:

  • 您可能需要转换模型,使其位于原点上。除非进行平移,否则摄影机将保持指向原点。(到目前为止,你只能在桌面上翻译,不能在android上翻译)

  • 我在这里获得了大部分缩放处理代码:

  • 对不起,这些神奇的数字。我将在将来制作这些常量

  • 如果您或其他任何人改进了此代码,我希望您能与我共享一份副本

  • 抽象类:

    /* 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);
            }
        }
    
    }
    
    /*作者:Christopher Grabowski,yourchristopher6334 gmail.com*/
    包裹
    导入com.badlogic.gdx.gdx;
    导入com.badlogic.gdx.Input.Keys;
    导入com.badlogic.gdx.math.Vector3;
    /*
    *pause、resize和render方法必须在其相应的
    *ApplicationListener中的方法
    */
    公共类BlenderStyleCamera扩展了ControllableCamera{
    公共静态最终矢量3原点=新矢量3(0,0,0);
    私有静态布尔值shiftIsPressed=false,controlIsPressed=false,
    IsCrollingup=false,IsCrollingDown=false,
    isSingleTouched=false,justSingleTouched=false;
    私有浮动方面;
    私有整数x=-1,y=-1;
    专用浮点数dx=0.0f,dy=0.0f;
    私有最终向量3 tmp=新向量3();
    //与“收缩到缩放”相关的字段
    私有int numberOfFingers=0;
    私有int fingerOnePointer;
    私有int-fingertwointer;
    私人浮动距离=0;
    私有最终向量3 fingerOne=新向量3();
    私有最终向量3 fingerTwo=新向量3();
    公共BlenderStyleCamera(整型视野、整型宽度、整型高度){
    super(视野、宽度、高度);
    aspectRatio=视口高度/视口宽度;
    Gdx.input.setInputProcessor(此);
    设置(0.0f,1.0f,0.0f);
    位置设置(0.0f、0.0f、30.0f);
    far=300.0f;
    注视(0,0,0);
    翻译(0.0f,0.0f,2.1f);
    注视(0,0,0);
    更新();
    }
    公共空间暂停(){
    手指数=0;
    }
    @凌驾
    公共空心调整大小(整型宽度、整型高度){
    视口宽度=宽度;
    视口高度=高度;
    aspectRatio=视口高度/视口宽度;
    更新();
    }
    @凌驾
    公共无效呈现(){
    如果(被触摸){
    //这将获得接触位置和位置的变化
    //补偿纵横比。
    如果(x==-1 | | y==-1 | | justsingletoucted){
    x=Gdx.input.getX();
    y=Gdx.input.getY();
    }否则{
    dx=(x-Gdx.input.getX());
    dy=(y-Gdx.input.getY())/aspectRatio;
    }
    //当按下控件时,此操作将缩放。
    如果(控件已压缩(&dy>0){
    滚动条();
    }else if(控件已压缩(&dy<0){
    滚动();
    }
    //这将转换相机混合器的样式
    //如果按下shift键。
    //请注意,使用
    //透视照相机。
    否则,如果(按下Shift键){
    翻译角度();
    }
    //默认设置为旋转对象
    //(实际绕球体旋转摄影机
    //它包围着物体)。
    否则{
    旅行社();
    }
    x=Gdx.input.getX();
    y=Gdx.input.getY();
    justsingletoucted=false;
    }
    //当鼠标滚轮旋转时,此操作将缩放
    如果(IsCrollingup){
    滚动条();
    IsCrollingup=假;
    }否则如果(IsCrollingdown){
    滚动();
    isScrollingDown=假;
    }
    //一些关键控件
    if(Gdx.input.isKeyPressed(Keys.LEFT)| | Gdx.input.isKeyPressed(Keys.A)){
    翻译角度(1,0);
    }else if(Gdx.input.iskeyspressed(Keys.RIGHT)
    ||Gdx.input.isKeyPressed(按键D)){
    翻译角度(-1,0);
    }
    if(Gdx.input.isKeyPressed(Keys.UP)| | Gdx.input.isKeyPressed(Keys.W)){
    翻译角度(0,1);
    }else if(Gdx.input.iskeys)按下(Keys.DOWN)
    ||Gdx.input.isKeyPressed(按键S)){
    平移角度(0,-1);
    }
    更新();
    }
    //这些方法可以创建收缩缩放
    //并在render方法中为逻辑设置一些标志。
    @凌驾
    公共布尔接地(整数x、整数y、整数指针、整数按钮){
    //从收缩到缩放
    numberOfFingers++;
    如果(numberOfFingers==1){
    Issingle=true;