【问题标题】:Move camera around using touch event in CardBoard and Rajawali VR Android在 CardBoard 和 Rajawali VR Android 中使用触摸事件移动相机
【发布时间】:2015-09-28 16:13:36
【问题描述】:

目前,我正在开发使用 google CardBoard 和 Rajawali 播放 360 度视频的 Android 虚拟现实应用程序。传感器运行良好,但我无法使用触摸来正确拖动场景或相机。有什么方法可以在这个应用中启用触控模式吗?

非常感谢任何帮助! 谢谢。

【问题讨论】:

    标签: android touch google-cardboard rajawalivr


    【解决方案1】:

    我做过同样的事情,这就是我使用的:

    首先,看看 Rajawali 的 ArcballCamera 课程。您可以在那里看到如何处理触摸事件以使用触摸事件旋转相机。

    问题是我不喜欢用户在屏幕上移动时的默认旋转行为,所以我自己做了另一个实现,基于前一个实现,并直接旋转我正在寻找的球体,而不是相机,就这样(所有这些都在我的 Renderer 类中,顺便说一句):

    首先,声明:

    private GestureDetector detector;           //gesture detector
    private ScaleGestureDetector scaleDetector; //scale detector (for zooming)
    private GestureListener gListener;          //gesture listener
    private ScaleListener sListener;            //scale listener
    private View.OnTouchListener touchListener; //touch events listener
    private boolean isRotating;                 //true if the sphere is rotating
    private boolean isScaling;                  //true if the sphere is scaling
    private float xInicial,yInicial;            //inicial touch point
    //sphere's yaw and pitch, used for rotation
    private double yaw,pitch, yawAcumulado=0, pitchAcumulado=0, yawAcumuladoR=0, pitchAcumuladoR=0;
    //physical to logical (in 3D world) conversion: screen scroll to sphere rotation
    private final double gradosPorBarridoX=120, gradosPorBarridoY=90;
    private final double gradosPorPixelYaw, gradosPorPixelPitch;
    

    在渲染器的构造函数中,我启动了初始化(定时器和控件用于视频控制视图,所以不要关注这些):

        DisplayMetrics outMetrics = new DisplayMetrics();
        ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics(outMetrics);
        gradosPorPixelPitch = gradosPorBarridoY / outMetrics.heightPixels;
        gradosPorPixelYaw = gradosPorBarridoX / outMetrics.widthPixels;
        addListeners();
        ...
        //from Rajawali ArcballCamera class
    private void addListeners(){
        ((Activity)context).runOnUiThread(new Runnable() {
            @Override
            public void run() {
                gListener = new GestureListener();
                sListener = new ScaleListener();
                detector = new GestureDetector(context, gListener);
                scaleDetector = new ScaleGestureDetector(context, sListener);
                touchListener = new View.OnTouchListener() {
                    @Override
                    public boolean onTouch(View v, MotionEvent event) {
                        scaleDetector.onTouchEvent(event); //see if it is a scale event
                        //if not, check whether it is a scroll
                        if (!isScaling) {
                            detector.onTouchEvent(event);
                            //or an up motion
                            if (event.getAction() == MotionEvent.ACTION_UP) {
                                if (!isRotating) {
                                    //change video control view's visibility
                                    TouchActivity.timer.cancel();
                                    if (TouchActivity.control.getVisibility() == View.INVISIBLE) {
                                        TouchActivity.control.setVisibility(View.VISIBLE);
                                        TouchActivity.timer.start(); //timer is restarted
                                    } else {
                                        TouchActivity.control.setVisibility(View.INVISIBLE);
                                    }
                                } else {
                                    isRotating = false;   //cancel rotation
                                }
                            }
                        }
                        return true;
                    }
                };
                TouchActivity.principal.setOnTouchListener(touchListener);
            }
        });
    }
    

    最后但同样重要的是,事件监听(缩放和旋转):

    /**
     * called when the rotation starts
     * @param x
     * @param y
     */
    private void startRotation(float x, float y){
        xInicial = x;
        yInicial = y;
    }
    
    /**
     * called during the consecutive events of a rotation movement
     * @param x
     * @param y
     */
    private void updateRotation(float x, float y){
        float difX = xInicial - x;
        float difY = yInicial - y;
        yaw= difX * gradosPorPixelYaw;
        pitch = difY * gradosPorPixelPitch;
        yawAcumulado+=yaw;
        pitchAcumulado+=pitch;
    }
    
    /**
     * event listener. if the user scrolls his finger through the screen, it sends the
     * touch event to calculate the sphere's rotation
     */
    private class GestureListener extends GestureDetector.SimpleOnGestureListener{
        @Override
        public boolean onScroll(MotionEvent event1, MotionEvent event2, float distanceX, float distanceY) {
            //starts or updates the rotation with the upcoming event x and y screen values
            if(!isRotating) {
                startRotation(event2.getX(), event2.getY());
                isRotating=true;
                return false;
            }else{
                isRotating = true;
                updateRotation(event2.getX(), event2.getY());
                return false;
            }
        }
    }
    
    /**
     * event listener. Zooms in or out depending on the user's action
     */
    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener{
        //zooms in or out according to the scale detector value
        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            if(detector.getScaleFactor()>1){
                if(earthSphere.getScaleX()*1.1<120){
                    earthSphere.setScaleX(earthSphere.getScaleX()*1.1);
                    earthSphere.setScaleY(earthSphere.getScaleY() * 1.1);
                    earthSphere.setScaleZ(earthSphere.getScaleZ() * 1.1);
                }
            }else{
                if(earthSphere.getScaleX()*0.9>0.95) {
                    earthSphere.setScaleX(earthSphere.getScaleX() * 0.9);
                    earthSphere.setScaleY(earthSphere.getScaleY() * 0.9);
                    earthSphere.setScaleZ(earthSphere.getScaleZ() * 0.9);
                }
            }
            return true;
        }
    
        //the zoom begins
        @Override
        public boolean onScaleBegin (ScaleGestureDetector detector) {
            isScaling = true;
            isRotating = false;
            return super.onScaleBegin(detector);
        }
    
        //the zoom ends
        @Override
        public void onScaleEnd (ScaleGestureDetector detector) {
            isRotating = false;
            isScaling = false;
        }
    }
    

    所有这些都解决了,您只需要在每个渲染上设置方向,如下所示:

        yawAcumuladoR = (yawAcumulado) * 0.04;
        pitchAcumuladoR = (pitchAcumulado) * 0.04;
        Quaternion q = new Quaternion();
        q.fromEuler(yawAcumuladoR, pitchAcumuladoR, 0);
        earthSphere.setOrientation(q);
    

    正如我所说,这对我有用,但我只是在旋转球体。将其添加到您的需求中应该不难,除了您拥有作为相机的 Arcball 类并且可能更适合您想要的东西。无论如何,我希望这对你有用。

    【讨论】:

    • 谢谢,我先试试这个。 :)
    • 什么是 TouchActivity?
    • TouchActivity 是我创建渲染器和 surfaceView 的 Activity,我有一个浮动视图充当视频控件,以及一个使该视图不可见的计时器经过 7 秒的时间。正如我所说,您不必针对这个特定问题考虑它们
    • 那么,我可以删除 TouchActivity 吗?
    • 是的,当你有 MOTION_UP 事件时,唯一需要做的就是将 isRotating 设置为 false
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多