Path: blob/main_old/samples/multiview/Multiview.cpp
1693 views
//1// Copyright 2017 The ANGLE Project Authors. All rights reserved.2// Use of this source code is governed by a BSD-style license that can be3// found in the LICENSE file.4//5// This sample shows basic usage of the GL_OVR_multiview2 extension.67#include "SampleApplication.h"89#include "util/geometry_utils.h"10#include "util/shader_utils.h"1112#include <iostream>1314namespace15{1617void FillTranslationMatrix(float xOffset, float yOffset, float zOffset, float *matrix)18{19matrix[0] = 1.0f;20matrix[1] = 0.0f;21matrix[2] = 0.0f;22matrix[3] = xOffset;2324matrix[4] = 0.0f;25matrix[5] = 1.0f;26matrix[6] = 0.0f;27matrix[7] = yOffset;2829matrix[8] = 0.0f;30matrix[9] = 0.0f;31matrix[10] = 1.0f;32matrix[11] = zOffset;3334matrix[12] = 0.0f;35matrix[13] = 0.0f;36matrix[14] = 0.0f;37matrix[15] = 1.0f;38}3940} // namespace4142class MultiviewSample : public SampleApplication43{44public:45MultiviewSample(int argc, char **argv)46: SampleApplication("Multiview", argc, argv, 3, 0),47mMultiviewProgram(0),48mMultiviewPersperiveUniformLoc(-1),49mMultiviewLeftEyeCameraUniformLoc(-1),50mMultiviewRightEyeCameraUniformLoc(-1),51mMultiviewTranslationUniformLoc(-1),52mMultiviewFBO(0),53mColorTexture(0),54mDepthTexture(0),55mQuadVAO(0),56mQuadVBO(0),57mCubeVAO(0),58mCubePosVBO(0),59mCubeNormalVBO(0),60mCubeIBO(0),61mCombineProgram(0)62{}6364bool initialize() override65{66// Check whether the GL_OVR_multiview(2) extension is supported. If not, abort67// initialization.68const char *allExtensions = reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS));69const std::string paddedExtensions = std::string(" ") + allExtensions + std::string(" ");70if ((paddedExtensions.find(std::string(" GL_OVR_multiview2 ")) == std::string::npos) &&71(paddedExtensions.find(std::string(" GL_OVR_multiview ")) == std::string::npos))72{73std::cout << "GL_OVR_multiview(2) is not available." << std::endl;74return false;75}7677// A view covers horizontally half of the screen.78int viewWidth = getWindow()->getWidth() / 2;79int viewHeight = getWindow()->getHeight();8081// Create color and depth texture arrays with two layers to which we render each view.82glGenTextures(1, &mColorTexture);83glBindTexture(GL_TEXTURE_2D_ARRAY, mColorTexture);84glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, viewWidth, viewHeight, 2, 0, GL_RGBA,85GL_UNSIGNED_BYTE, nullptr);86glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);87glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);8889glGenTextures(1, &mDepthTexture);90glBindTexture(GL_TEXTURE_2D_ARRAY, mDepthTexture);91glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT32F, viewWidth, viewHeight, 2, 0,92GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);9394// Generate multiview framebuffer for layered rendering.95glGenFramebuffers(1, &mMultiviewFBO);96glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);97glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mColorTexture, 0, 0,982);99glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, mDepthTexture, 0, 0,1002);101GLenum drawBuffer = GL_COLOR_ATTACHMENT0;102glDrawBuffers(1, &drawBuffer);103104// Check that the framebuffer is complete. Abort initialization otherwise.105if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)106{107return false;108}109110// Create multiview program and query the uniform locations.111// The program has two code paths based on the gl_ViewID_OVR attribute which tells us which112// view is currently being rendered to. Based on it we decide which eye's camera matrix to113// use.114constexpr char kMultiviewVS[] =115"#version 300 es\n"116"#extension GL_OVR_multiview2 : require\n"117"layout(num_views = 2) in;\n"118"layout(location=0) in vec3 posIn;\n"119"layout(location=1) in vec3 normalIn;\n"120"uniform mat4 uPerspective;\n"121"uniform mat4 uCameraLeftEye;\n"122"uniform mat4 uCameraRightEye;\n"123"uniform mat4 uTranslation;\n"124"out vec3 oNormal;\n"125"void main()\n"126"{\n"127" vec4 p = uTranslation * vec4(posIn,1.);\n"128" if (gl_ViewID_OVR == 0u) {\n"129" p = uCameraLeftEye * p;\n"130" } else {\n"131" p = uCameraRightEye * p;\n"132" }\n"133" oNormal = normalIn;\n"134" gl_Position = uPerspective * p;\n"135"}\n";136137constexpr char kMultiviewFS[] =138"#version 300 es\n"139"#extension GL_OVR_multiview2 : require\n"140"precision mediump float;\n"141"out vec4 color;\n"142"in vec3 oNormal;\n"143"void main()\n"144"{\n"145" vec3 col = 0.5 * oNormal + vec3(0.5);\n"146" color = vec4(col, 1.);\n"147"}\n";148149mMultiviewProgram = CompileProgram(kMultiviewVS, kMultiviewFS);150if (!mMultiviewProgram)151{152return false;153}154mMultiviewPersperiveUniformLoc = glGetUniformLocation(mMultiviewProgram, "uPerspective");155mMultiviewLeftEyeCameraUniformLoc =156glGetUniformLocation(mMultiviewProgram, "uCameraLeftEye");157mMultiviewRightEyeCameraUniformLoc =158glGetUniformLocation(mMultiviewProgram, "uCameraRightEye");159mMultiviewTranslationUniformLoc = glGetUniformLocation(mMultiviewProgram, "uTranslation");160161// Create a normal program to combine both layers of the color array texture.162constexpr char kCombineVS[] =163"#version 300 es\n"164"in vec2 vIn;\n"165"out vec2 uv;\n"166"void main()\n"167"{\n"168" gl_Position = vec4(vIn, 0., 1.);\n"169" uv = vIn * .5 + vec2(.5);\n"170"}\n";171172constexpr char kCombineFS[] =173"#version 300 es\n"174"precision mediump float;\n"175"precision mediump sampler2DArray;\n"176"uniform sampler2DArray uMultiviewTex;\n"177"in vec2 uv;\n"178"out vec4 color;\n"179"void main()\n"180"{\n"181" float scaledX = 2.0 * uv.x;\n"182" float layer = floor(scaledX);\n"183" vec2 adjustedUV = vec2(fract(scaledX), uv.y);\n"184" vec3 texColor = texture(uMultiviewTex, vec3(adjustedUV, layer)).rgb;\n"185" color = vec4(texColor, 1.);\n"186"}\n";187188mCombineProgram = CompileProgram(kCombineVS, kCombineFS);189if (!mCombineProgram)190{191return false;192}193194// Generate a quad which covers the whole screen.195glGenVertexArrays(1, &mQuadVAO);196glBindVertexArray(mQuadVAO);197198glGenBuffers(1, &mQuadVBO);199glBindBuffer(GL_ARRAY_BUFFER, mQuadVBO);200const float kQuadPositionData[] = {1.f, -1.f, 1.f, 1.f, -1.f, -1.f, -1.f, 1.f};201glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 8, kQuadPositionData, GL_STATIC_DRAW);202glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);203glEnableVertexAttribArray(0);204glBindVertexArray(0);205206// Generate a cube.207GenerateCubeGeometry(1.0f, &mCube);208glGenVertexArrays(1, &mCubeVAO);209glBindVertexArray(mCubeVAO);210211glGenBuffers(1, &mCubePosVBO);212glBindBuffer(GL_ARRAY_BUFFER, mCubePosVBO);213glBufferData(GL_ARRAY_BUFFER, sizeof(angle::Vector3) * mCube.positions.size(),214mCube.positions.data(), GL_STATIC_DRAW);215glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);216glEnableVertexAttribArray(0);217218glGenBuffers(1, &mCubeNormalVBO);219glBindBuffer(GL_ARRAY_BUFFER, mCubeNormalVBO);220glBufferData(GL_ARRAY_BUFFER, sizeof(angle::Vector3) * mCube.normals.size(),221mCube.normals.data(), GL_STATIC_DRAW);222glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, nullptr);223glEnableVertexAttribArray(1);224225glGenBuffers(1, &mCubeIBO);226glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mCubeIBO);227glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * mCube.indices.size(),228mCube.indices.data(), GL_STATIC_DRAW);229230glBindVertexArray(0);231232glEnable(GL_DEPTH_TEST);233glClearColor(0.0f, 0.0f, 0.0f, 0.0f);234235return true;236}237238void destroy() override239{240glDeleteProgram(mMultiviewProgram);241glDeleteFramebuffers(1, &mMultiviewFBO);242glDeleteTextures(1, &mColorTexture);243glDeleteTextures(1, &mDepthTexture);244glDeleteVertexArrays(1, &mQuadVAO);245glDeleteBuffers(1, &mQuadVBO);246glDeleteVertexArrays(1, &mCubeVAO);247glDeleteBuffers(1, &mQuadVBO);248glDeleteBuffers(1, &mCubePosVBO);249glDeleteBuffers(1, &mCubeNormalVBO);250glDeleteBuffers(1, &mCubeIBO);251glDeleteProgram(mCombineProgram);252}253254void draw() override255{256// Draw to multiview fbo.257{258// Generate the perspective projection matrix.259const int viewWidth = getWindow()->getWidth() / 2;260const int viewHeight = getWindow()->getHeight();261const float kFOV = 90.f;262const float kNear = 1.0f;263const float kFar = 100.0f;264const float kPlaneDifference = kFar - kNear;265const float kXYScale = 1.f / (tanf(kFOV / 2.0f));266const float kAspectRatio = static_cast<float>(viewWidth) / viewHeight;267float kPerspectiveProjectionMatrix[16];268kPerspectiveProjectionMatrix[0] = kXYScale / kAspectRatio;269kPerspectiveProjectionMatrix[1] = .0f;270kPerspectiveProjectionMatrix[2] = .0f;271kPerspectiveProjectionMatrix[3] = .0f;272273kPerspectiveProjectionMatrix[4] = .0f;274kPerspectiveProjectionMatrix[5] = kXYScale;275kPerspectiveProjectionMatrix[6] = .0f;276kPerspectiveProjectionMatrix[7] = .0f;277278kPerspectiveProjectionMatrix[8] = .0f;279kPerspectiveProjectionMatrix[9] = .0;280kPerspectiveProjectionMatrix[10] = -kFar / kPlaneDifference;281kPerspectiveProjectionMatrix[11] = -1.f;282283kPerspectiveProjectionMatrix[12] = .0f;284kPerspectiveProjectionMatrix[13] = .0;285kPerspectiveProjectionMatrix[14] = -kFar * kNear / kPlaneDifference;286kPerspectiveProjectionMatrix[15] = .0;287288// Generate the camera matrices for the left and right eye.289const float kXOffset = 1.5f;290const float kYOffset = 1.5f;291const float kZOffset = 5.0f;292float kLeftCameraMatrix[16];293FillTranslationMatrix(kXOffset, -kYOffset, -kZOffset, kLeftCameraMatrix);294float kRightCameraMatrix[16];295FillTranslationMatrix(-kXOffset, -kYOffset, -kZOffset, kRightCameraMatrix);296297// Bind and clear the multiview framebuffer.298glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);299glClearColor(0, 0, 0, 1);300glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);301302// Set the viewport to be the size as one of the views.303glViewport(0, 0, viewWidth, viewHeight);304305// Bind multiview program and set matrices.306glUseProgram(mMultiviewProgram);307glUniformMatrix4fv(mMultiviewPersperiveUniformLoc, 1, GL_TRUE,308kPerspectiveProjectionMatrix);309glUniformMatrix4fv(mMultiviewLeftEyeCameraUniformLoc, 1, GL_TRUE, kLeftCameraMatrix);310glUniformMatrix4fv(mMultiviewRightEyeCameraUniformLoc, 1, GL_TRUE, kRightCameraMatrix);311312glBindVertexArray(mCubeVAO);313314// Draw first cube.315float kTranslationMatrix[16];316FillTranslationMatrix(0.0f, 0.0f, 0.0f, kTranslationMatrix);317glUniformMatrix4fv(mMultiviewTranslationUniformLoc, 1, GL_TRUE, kTranslationMatrix);318glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(mCube.indices.size()),319GL_UNSIGNED_SHORT, nullptr);320321// Draw second cube.322FillTranslationMatrix(1.0f, 1.0f, -2.0f, kTranslationMatrix);323glUniformMatrix4fv(mMultiviewTranslationUniformLoc, 1, GL_TRUE, kTranslationMatrix);324glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(mCube.indices.size()),325GL_UNSIGNED_SHORT, nullptr);326327glBindVertexArray(0);328}329330// Combine both views.331{332// Bind the default framebuffer object and clear.333glBindFramebuffer(GL_FRAMEBUFFER, 0);334335glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);336337// Set the viewport to cover the whole screen.338glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());339340glUseProgram(mCombineProgram);341342// Bind the 2D array texture to be used as a sampler.343glUniform1i(glGetUniformLocation(mCombineProgram, "uMultiviewTex"), 0);344glBindTexture(GL_TEXTURE_2D_ARRAY, mMultiviewFBO);345glActiveTexture(GL_TEXTURE0);346347// Draw a quad which covers the whole screen. Layer and texture coordinates are348// calculated in the vertex shader based on the UV coordinates of the quad.349glBindVertexArray(mQuadVAO);350glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);351glBindVertexArray(0);352}353}354355private:356GLuint mMultiviewProgram;357GLint mMultiviewPersperiveUniformLoc;358GLint mMultiviewLeftEyeCameraUniformLoc;359GLint mMultiviewRightEyeCameraUniformLoc;360GLint mMultiviewTranslationUniformLoc;361362GLuint mMultiviewFBO;363GLuint mColorTexture;364GLuint mDepthTexture;365366GLuint mQuadVAO;367GLuint mQuadVBO;368369CubeGeometry mCube;370GLuint mCubeVAO;371GLuint mCubePosVBO;372GLuint mCubeNormalVBO;373GLuint mCubeIBO;374375GLuint mCombineProgram;376};377378int main(int argc, char **argv)379{380MultiviewSample app(argc, argv);381return app.run();382}383384385