Created
February 21, 2019 02:52
-
-
Save sigmaxipi/b9d4cbfb3410e5be6c5279f56c09b391 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/samples/sdk-video360/src/main/java/com/google/vr/sdk/samples/video360/MonoscopicView.java b/samples/sdk-video360/src/main/java/com/google/vr/sdk/samples/video360/MonoscopicView.java | |
index 19ebd03..cb1b577 100644 | |
--- a/samples/sdk-video360/src/main/java/com/google/vr/sdk/samples/video360/MonoscopicView.java | |
+++ b/samples/sdk-video360/src/main/java/com/google/vr/sdk/samples/video360/MonoscopicView.java | |
@@ -30,8 +30,12 @@ import android.support.annotation.AnyThread; | |
import android.support.annotation.BinderThread; | |
import android.support.annotation.UiThread; | |
import android.util.AttributeSet; | |
+import android.view.Display; | |
import android.view.MotionEvent; | |
+import android.view.OrientationEventListener; | |
+import android.view.Surface; | |
import android.view.View; | |
+import android.view.WindowManager; | |
import com.google.vr.sdk.base.Eye.Type; | |
import com.google.vr.sdk.samples.video360.rendering.SceneRenderer; | |
import javax.microedition.khronos.egl.EGLConfig; | |
@@ -52,6 +56,8 @@ public final class MonoscopicView extends GLSurfaceView { | |
private SensorManager sensorManager; | |
private Sensor orientationSensor; | |
private PhoneOrientationListener phoneOrientationListener; | |
+ private DisplayOrientationListener displayOrientationListener; | |
+ private int displayRotationDegrees; | |
private MediaLoader mediaLoader; | |
private Renderer renderer; | |
@@ -88,6 +94,12 @@ public final class MonoscopicView extends GLSurfaceView { | |
orientationSensor = sensorManager.getDefaultSensor(Sensor.TYPE_GAME_ROTATION_VECTOR); | |
phoneOrientationListener = new PhoneOrientationListener(); | |
+ // When a phone rotates from portrait <-> landscape or portrait <-> reverse landscape, this flow | |
+ // is used. However, this flow isn't used for landscape <-> reverse landscape changes. For that | |
+ // case, displayOrientationListener's onOrientationChanged callback is used. | |
+ displayOrientationListener = new DisplayOrientationListener(getContext()); | |
+ displayOrientationListener.recomputeDisplayOrientation(); | |
+ | |
touchTracker = new TouchTracker(renderer); | |
setOnTouchListener(touchTracker); | |
} | |
@@ -99,6 +111,7 @@ public final class MonoscopicView extends GLSurfaceView { | |
// Use the fastest sensor readings. | |
sensorManager.registerListener( | |
phoneOrientationListener, orientationSensor, SensorManager.SENSOR_DELAY_FASTEST); | |
+ displayOrientationListener.enable(); | |
mediaLoader.resume(); | |
} | |
@@ -107,6 +120,7 @@ public final class MonoscopicView extends GLSurfaceView { | |
public void onPause() { | |
mediaLoader.pause(); | |
sensorManager.unregisterListener(phoneOrientationListener); | |
+ displayOrientationListener.disable(); | |
super.onPause(); | |
} | |
@@ -121,11 +135,11 @@ public final class MonoscopicView extends GLSurfaceView { | |
mediaLoader.handleIntent(intent, uiView); | |
} | |
- /** Detects sensor events and saves them as a matrix. */ | |
+ /** Detects fine-grained sensor events and saves them as a matrix. */ | |
private class PhoneOrientationListener implements SensorEventListener { | |
private final float[] phoneInWorldSpaceMatrix = new float[16]; | |
private final float[] remappedPhoneMatrix = new float[16]; | |
- private final float[] angles = new float[3]; | |
+ private final float[] anglesRadians = new float[3]; | |
@Override | |
@BinderThread | |
@@ -140,9 +154,9 @@ public final class MonoscopicView extends GLSurfaceView { | |
phoneInWorldSpaceMatrix, | |
SensorManager.AXIS_X, SensorManager.AXIS_MINUS_Z, | |
remappedPhoneMatrix); | |
- SensorManager.getOrientation(remappedPhoneMatrix, angles); | |
- float roll = angles[2]; | |
- touchTracker.setRoll(roll); | |
+ SensorManager.getOrientation(remappedPhoneMatrix, anglesRadians); | |
+ float roll = anglesRadians[2]; | |
+ touchTracker.setRoll((float) (roll - Math.toRadians(displayRotationDegrees))); | |
// Rotate from Android coordinates to OpenGL coordinates. Android's coordinate system | |
// assumes Y points North and Z points to the sky. OpenGL has Y pointing up and Z pointing | |
@@ -155,6 +169,51 @@ public final class MonoscopicView extends GLSurfaceView { | |
public void onAccuracyChanged(Sensor sensor, int accuracy) {} | |
} | |
+ /** Detects coarse-grained sensor events and saves them as a matrix. */ | |
+ private class DisplayOrientationListener extends OrientationEventListener { | |
+ public DisplayOrientationListener(Context context) { | |
+ super(context); | |
+ } | |
+ | |
+ /** | |
+ * This is called when Android's sensors detect rotation of the screen. It is specifically | |
+ * | |
+ * @param orientationDegrees the current orientation with a precision of single digit degrees. | |
+ * This is clockwise with respect to the device's natural orientation. | |
+ */ | |
+ @Override | |
+ @BinderThread | |
+ public void onOrientationChanged(int orientationDegrees) { | |
+ int counterClockwiseOrientation = 360 - orientationDegrees; | |
+ int roundedOrientation = (((counterClockwiseOrientation + 45) % 360) / 90) * 90; | |
+ if (Math.abs(displayRotationDegrees - roundedOrientation) > 90) { | |
+ recomputeDisplayOrientation(); | |
+ } | |
+ } | |
+ | |
+ @AnyThread | |
+ public void recomputeDisplayOrientation() { | |
+ WindowManager windowManager = | |
+ (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); | |
+ Display display = windowManager.getDefaultDisplay(); | |
+ switch (display.getRotation()) { | |
+ case Surface.ROTATION_90: | |
+ displayRotationDegrees = 90; | |
+ break; | |
+ case Surface.ROTATION_180: | |
+ displayRotationDegrees = 180; | |
+ break; | |
+ case Surface.ROTATION_270: | |
+ displayRotationDegrees = 270; | |
+ break; | |
+ default: | |
+ displayRotationDegrees = 0; | |
+ } | |
+ | |
+ renderer.setDisplayRotation(displayRotationDegrees); | |
+ } | |
+ }; | |
+ | |
/** | |
* Basic touch input system. | |
* | |
@@ -189,7 +248,7 @@ public final class MonoscopicView extends GLSurfaceView { | |
private final PointF accumulatedTouchOffsetDegrees = new PointF(); | |
// The conversion from touch to yaw & pitch requires compensating for device roll. This is set | |
// on the sensor thread and read on the UI thread. | |
- private volatile float roll; | |
+ private volatile float rollRadians; | |
private final Renderer renderer; | |
@@ -215,7 +274,7 @@ public final class MonoscopicView extends GLSurfaceView { | |
float touchY = (event.getY() - previousTouchPointPx.y) / PX_PER_DEGREES; | |
previousTouchPointPx.set(event.getX(), event.getY()); | |
- float r = roll; // Copy volatile state. | |
+ float r = rollRadians; // Copy volatile state. | |
float cr = (float) Math.cos(r); | |
float sr = (float) Math.sin(r); | |
// To convert from screen space to the 3D space, we need to adjust the drag vector based | |
@@ -226,8 +285,8 @@ public final class MonoscopicView extends GLSurfaceView { | |
// Handle pitch and limit it to 45 degrees. | |
accumulatedTouchOffsetDegrees.y += sr * touchX + cr * touchY; | |
accumulatedTouchOffsetDegrees.y = | |
- Math.max(-MAX_PITCH_DEGREES, | |
- Math.min(MAX_PITCH_DEGREES, accumulatedTouchOffsetDegrees.y)); | |
+ Math.max( | |
+ -MAX_PITCH_DEGREES, Math.min(MAX_PITCH_DEGREES, accumulatedTouchOffsetDegrees.y)); | |
renderer.setPitchOffset(accumulatedTouchOffsetDegrees.y); | |
renderer.setYawOffset(accumulatedTouchOffsetDegrees.x); | |
@@ -238,9 +297,9 @@ public final class MonoscopicView extends GLSurfaceView { | |
} | |
@BinderThread | |
- public void setRoll(float roll) { | |
+ public void setRoll(float rollRadians) { | |
// We compensate for roll by rotating in the opposite direction. | |
- this.roll = -roll; | |
+ this.rollRadians = -rollRadians; | |
} | |
} | |
@@ -251,7 +310,7 @@ public final class MonoscopicView extends GLSurfaceView { | |
static class Renderer implements GLSurfaceView.Renderer { | |
private final SceneRenderer scene = SceneRenderer.createFor2D(); | |
- // Arbitrary vertical field of view. Adjust as desired. | |
+ // Arbitrary max field of view. Adjust as desired. | |
private static final int FIELD_OF_VIEW_DEGREES = 90; | |
private static final float Z_NEAR = .1f; | |
private static final float Z_FAR = 100; | |
@@ -270,6 +329,7 @@ public final class MonoscopicView extends GLSurfaceView { | |
private final float[] touchYawMatrix = new float[16]; | |
private float touchPitch; | |
private float deviceRoll; | |
+ private final float[] displayRotationMatrix = new float[16]; | |
// viewMatrix = touchPitch * deviceOrientation * touchYaw. | |
private final float[] viewMatrix = new float[16]; | |
@@ -280,6 +340,7 @@ public final class MonoscopicView extends GLSurfaceView { | |
public Renderer(VideoUiView uiView, MediaLoader mediaLoader) { | |
Matrix.setIdentityM(deviceOrientationMatrix, 0); | |
+ Matrix.setIdentityM(displayRotationMatrix, 0); | |
Matrix.setIdentityM(touchPitchMatrix, 0); | |
Matrix.setIdentityM(touchYawMatrix, 0); | |
this.uiView = uiView; | |
@@ -298,8 +359,25 @@ public final class MonoscopicView extends GLSurfaceView { | |
@Override | |
public void onSurfaceChanged(GL10 gl, int width, int height) { | |
GLES20.glViewport(0, 0, width, height); | |
- Matrix.perspectiveM( | |
- projectionMatrix, 0, FIELD_OF_VIEW_DEGREES, (float) width / height, Z_NEAR, Z_FAR); | |
+ float aspectRatio = (float) width / height; | |
+ float verticalFovDegrees; | |
+ if (aspectRatio < 1) { | |
+ // For portrait mode, use the max FOV for the vertical FOV. | |
+ verticalFovDegrees = FIELD_OF_VIEW_DEGREES; | |
+ } else { | |
+ // When in landscape mode, we need to compute the vertical FOV to pass into | |
+ // Matrix.perspectiveM. As a quick calculation we could use | |
+ // verticalFovDegrees = FIELD_OF_VIEW_DEGREES / aspectRatio. However, this results in an | |
+ // incorrect FOV for large values of FIELD_OF_VIEW_DEGREES. The correct calculation should | |
+ // compute the ratios of the tan of the vertical & horizontal FOVs. | |
+ double horizontalHalfFovRadians = Math.toRadians(FIELD_OF_VIEW_DEGREES / 2); | |
+ double horizontalHalfFovTanAngle = Math.tan(horizontalHalfFovRadians); | |
+ double verticalHalfFovTanAngle = horizontalHalfFovTanAngle / aspectRatio; | |
+ double verticalHalfFovRadians = Math.atan(verticalHalfFovTanAngle); | |
+ verticalFovDegrees = (float) Math.toDegrees(2 * verticalHalfFovRadians); | |
+ } | |
+ | |
+ Matrix.perspectiveM(projectionMatrix, 0, verticalFovDegrees, aspectRatio, Z_NEAR, Z_FAR); | |
} | |
@Override | |
@@ -310,9 +388,11 @@ public final class MonoscopicView extends GLSurfaceView { | |
synchronized (this) { | |
Matrix.multiplyMM(tempMatrix, 0, deviceOrientationMatrix, 0, touchYawMatrix, 0); | |
Matrix.multiplyMM(viewMatrix, 0, touchPitchMatrix, 0, tempMatrix, 0); | |
+ Matrix.multiplyMM(tempMatrix, 0, displayRotationMatrix, 0, viewMatrix, 0); | |
} | |
- Matrix.multiplyMM(viewProjectionMatrix, 0, projectionMatrix, 0, viewMatrix, 0); | |
+ Matrix.multiplyMM(viewProjectionMatrix, 0, projectionMatrix, 0, tempMatrix, 0); | |
+ | |
scene.glDrawFrame(viewProjectionMatrix, Type.MONOCULAR); | |
} | |
@@ -349,5 +429,14 @@ public final class MonoscopicView extends GLSurfaceView { | |
public synchronized void setYawOffset(float yawDegrees) { | |
Matrix.setRotateM(touchYawMatrix, 0, -yawDegrees, 0, 1, 0); | |
} | |
+ | |
+ /** | |
+ * Adjust the rendered scene to handle portrait, landscape, etc display rotations. | |
+ * | |
+ * @param displayRotationDegrees should be a multiple of 90 degrees. | |
+ */ | |
+ public synchronized void setDisplayRotation(int displayRotationDegrees) { | |
+ Matrix.setRotateM(displayRotationMatrix, 0, displayRotationDegrees, 0, 0, 1); | |
+ } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi @sigmaxipi. I apply your path into my MonoscopicView file
This is my apply: https://gist.github.com/PhanSon95/bbf7e25f700ec8a00b43406debdacb2c
My Vr 360 video worked, but it's not realy worked as smooth, when phone portrait
(auto rotate: ON)
, I've rotate my phone -> LANDSCAPE, application rotate OK , but content of video it's not rotate, may be delay 5s or more time or have to shake my phone , video will rotate normallyI don't know why. If you see this comment, I hope you can reply soon
Thanks so much!!