DEV Community

Graham Long
Graham Long

Posted on • Updated on

The start of 3D

The Aim

In order to display the same scene from two different viewpoints i.e. left eye and right eye, we need to render the scene to two different framebuffers and then apply each of these as a texture to a left and right quad.

The Setup

Prior to the development as part of this blog post, I started with a new Empty activity project targeting Android 8.1 and followed the Android developers Displaying graphics with openGL series to the point where I was drawing a triangle to the screen.
Screenshot with green triangle in centre
The following changes were made to the basic tutorial code:

  • I created an AbstractGameObject class which implemented the common rendering code for the objects and the triangle class inherited from this class.
  • I changed the parent theme from Theme.AppCompat.Light.DarkActionBar to Theme.AppCompat.Light.NoActionBar
  • I added the following snippet

    window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_IMMERSIVE)

    to the Activity's onCreate method to force full screen mode as per the [Android Developers guide to enabling full screen mode](https://developer.android.com/training/system-ui/immersive)

The source code can be found on my github repo as Tagged release B1.0

The Development

I started detailing every step of the development, but quickly decided that I would just focus on the key points, the final source code at the end of this development can be found on my github repo as Tagged release B1.1.
I did not use ThinMatrix's framebuffer objects tutorial as part of this development but when I was originally learning about rendering to framebuffers, this tutorial and others of his were great, so for anyone new to openGL the ThinMatrix youtube channel is where I would recommend starting.
As part of this development I merged the code from the following two tutorials, opengl-tutorial.org Render to texture tutorial and
pixel perfect Render to texture tutorial for the framebuffer rendering.

The AbstractTexturedGameObject class

Similar to the Abstract Game Object class which I created in the B1.0 release, I generated an abstract class which will be inherited by any game objects which will be textured.

The Quads

Each Quad is defined in normalised device coordinates as defined in this ray casting tutorial, this means that each quad will be rendered to half the screen without applying any model, view or projection matrices Note the TexturedQuad class inherits from the AbstractTexturedGameObject class so an identity matrix is passed to the draw function which has no effect on the vertices.

The Camera(s)

I created a GameCamera class to define a camera position, look direction and up direction.
The main renderer instantiates two of these GameCamera objects, one for the left eye and one for the right eye.
Having the GameCamera class allowed me to reduce duplicated code by having a single drawScene function which renders the current scene using the passed GameCamera object Note the drawScene function does not currently draw anything.

The Rendering

The VrRenderer class's onDrawFrame function has been changed to call a new drawSceneToFrameBuffer function for each side of the screen

// Draw the left side
drawSceneToFrameBuffer(mLeftCamera,
mFrameBuffer[LEFT_FRAMEBUFFER_INDEX],
mRenderTexture[LEFT_FRAMEBUFFER_INDEX],
mDepthRenderBuffer[LEFT_FRAMEBUFFER_INDEX])

// and the right side
drawSceneToFrameBuffer(mRightCamera,
mFrameBuffer[RIGHT_FRAMEBUFFER_INDEX],
mRenderTexture[RIGHT_FRAMEBUFFER_INDEX],
mDepthRenderBuffer[RIGHT_FRAMEBUFFER_INDEX])

Each call to the drawSceneToFrameBuffer function binds the passed framebuffer, sets the viewport to the framebuffer size, temporarily sets to clear colour for each framebuffer to a different colour, renders the scene using the drawScene function before unbinding the framebuffer.
Finally, the viewport is reset back to the screen size before the left quad is drawn using the left texture and the right quad is rendered using the right texture.

// draw the quad with the generated textures.
mLeftQuad.draw(identityMatrix, mRenderTexture[LEFT_FRAMEBUFFER_INDEX])
mRightQuad.draw(identityMatrix, mRenderTexture[RIGHT_FRAMEBUFFER_INDEX])

The Outcome

At the end of all of this, I am rendering a green quad to the left side of the screen and a red quad to the right side of the screen, this may not look like much but it is the starting point for all the good stuff.
Screenshot with green half and red half horizontally
The next blog will detail drawing an actual 3D scene to each of the Quads.

Discussion (0)