Implementing Stereoscopy
  • 29 May 2024
  • 4 Minutes to read
  • Contributors
  • Dark
    Light

Implementing Stereoscopy

  • Dark
    Light

Article summary

Stereoscopy on the Vuzix Shield uses Android's default elevation parameter. All Views have an elevation which the system normally uses for determining drawing order and shadow placement. Vuzix uses this parameter to determine how far a View should shift when it's drawn in stereoscopic 3D. Most Views have an elevation of 0 by default, but some Views, such as Buttons, have a default elevation that is intended to give them a shadow. This means that editing a View's elevation for the purpose of stereo should have little effect on the rest of an app's layout process.
To add elevation to a View which doesn't normally set one, simply add the android:elevation attribute to the View's layout. Developers can also use the function setElevation(float) to programmatically set an elevation for a View.
For example, here is a TextView being assigned an elevation of 4dp in its layout file:

<TextView
    android:id="@+id/textView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:elevation="4dp"
    android:text="Elevation=4" />


Controls

Developers can use <meta-data> subelements to control stereo behavior within their app. These subelements are added to the <application> element in an app's AndroidManifest.xml file. They apply to the entire application and cannot be changed by an activity, though they will be invalidated if an activity sets the option to make itself widescreen (described below).

  • Enable stereoscopy (default: false):

<meta-data android:name="com.vuzix.stereoscopy.enable" android:value="true" />
  • Restrict the maximum view elevation specifically for stereo shifting (default: "4.0px"):

<meta-data android:name="com.vuzix.stereoscopy.max_elevation" android:value="10.0" />
  • Set whether views will add their parents' elevations when calculating their shift value or be shifted individually (default: true):

<meta-data android:name="com.vuzix.stereoscopy.add_parent_elevation" android:value="false" />
  • Example application element:

<application
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:hardwareAccelerated="true"
    tools:targetApi="31">

    <meta-data android:name="com.vuzix.stereoscopy.enable" android:value="true" />                <!-- Enable stereoscopy -->
    <meta-data android:name="com.vuzix.stereoscopy.max_elevation" android:value="10.0" />         <!-- Set maximum elevation to 10.0 -->
    <meta-data android:name="com.vuzix.stereoscopy.add_parent_elevation" android:value="false" /> <!-- Disable stacking parent elevation -->

    <activity
        android:name=".MainActivity"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
</application>
  • Apps can also request to use the entire width of both displays. This will disable automatic stereo shifting for the app and the app will be required to duplicate its own UI. System UI elements (status bar, dialogs, toasts, etc.) will still be duplicated automatically. This mode is intended for fullscreen applications that contain prerendered content, such as a stereoscopic video player or game. The display size in this case will be 1280x480 rather than the normal 640x480. This sub-element can be applied to individual activities or the whole application. If applied to the entire application, every Activity in the application will be rendered using the full width of both displays. Using this option will cause any stereo options to be ignored while this Activity is focused. If applied to the Application, all other stereo options will be ignored.

<meta-data android:name="com.vuzix.stereoscopy.options" android:value="1" />


Elevation

  • When adjusting the stereo strength setting from the Settings app, "Full" is twice as strong as "Medium". Any elevation set by an app is the value for the Medium setting and is doubled for the Full setting.

  • Stereo elevation is controlled by a View's Z position, which is a combination of its <elevation> and <translationZ> properties.

    • It is recommended that apps use the elevation property for a permanent elevation, and translationZ for a temporary setting or an offset from the permanent setting.

  • Elevation is a float value internally, so it doesn't have to be an integer in your app. However, the final position of a View will be rounded to the nearest integer when mapping to the display.

  • Elevation in a theme takes precedence over a specific value in the layout, so if your changes aren't affecting a View check your theme to see if another elevation is already being applied.

  • Elevation may be positive or negative. Positive elevation moves a View toward the user, while negative pushes it away. All default system elevations are zero or positive, so if a developer adds a View with negative elevation it may appear below the system UI.


Layout

  • Try to keep elevated Views away from the left and right sides of the screen to keep them from clipping or being forced back into the frame.

  • Shifted views may overlap other views, but which view will appear on top is determined by their final Z positions. If their Z positions are identical, Views drawn later will appear on top.


RecyclerViews

  • Due to some odd rendering behavior of RecyclerViews, any View hierarchy which contains them will be restricted to 2D. The left frame will be repeated on the right side for this set of Views. Note that this does not set the elevation to 0, and the Views on the right display will shift as they would on the left display if an elevation value is set.


SurfaceViews

  • SurfaceViews will not be elevated because their content is duplicated from the left side. This is due to the way SurfaceView content is composited and rendered. If you need similar functionality to a SurfaceView in an elevated position, use a TextureView instead.


Was this article helpful?