5

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

4

3 回答 3

2

我一直在研究一种“Blender 风格”的相机,它具有捏合缩放功能以及(在桌面上)您使用 Blender 相机获得的大部分功能。这是一项正在进行的工作——它还不能完美地模仿 Blender 相机的行为。我认为这会让你指出正确的方向。你应该知道的一些事情:

  1. 您可能必须翻译您的模型,使其位于原点。除非您翻译它,否则相机将始终指向原点。(目前只能在台式机上翻译,不能在安卓上翻译);

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

  3. 对不起魔术数字。我将在未来制作这些常量。

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

抽象类:

/* 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);
        }
    }

}
于 2013-03-04T19:21:33.830 回答
1

请看一下:网格渲染问题 libgdx

方法render包含您需要的代码。

于 2012-11-23T18:34:16.630 回答
0

您要么需要旋转相机,要么旋转模型。

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

于 2012-11-22T04:29:57.460 回答