Edit

kc3-lang/angle/samples/multiview

Branch :

  • Show log

    Commit

  • Author : Shahbaz Youssefi
    Date : 2022-07-06 11:46:17
    Hash : 5a65a2b1
    Message : Fix samples' arguments to SampleApplication Two new parameters were added in https://chromium-review.googlesource.com/c/angle/angle/+/3664916 with default values, but not all samples were updated to accomodate them. As a result, many samples passed in the major version for client type and thus couldn't run. This change introduces an enum class for the client type + version to make sure such a mistake is impossible. Bug: angleproject:7360 Change-Id: I450edee612d08a7b67530b61615f63268fefb200 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/3748413 Auto-Submit: Shahbaz Youssefi <syoussefi@chromium.org> Reviewed-by: Lingfeng Yang <lfy@google.com> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>

  • Multiview.cpp
  • //
    // Copyright 2017 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    // This sample shows basic usage of the GL_OVR_multiview2 extension.
    
    #include "SampleApplication.h"
    
    #include "util/geometry_utils.h"
    #include "util/shader_utils.h"
    
    #include <iostream>
    
    namespace
    {
    
    void FillTranslationMatrix(float xOffset, float yOffset, float zOffset, float *matrix)
    {
        matrix[0] = 1.0f;
        matrix[1] = 0.0f;
        matrix[2] = 0.0f;
        matrix[3] = xOffset;
    
        matrix[4] = 0.0f;
        matrix[5] = 1.0f;
        matrix[6] = 0.0f;
        matrix[7] = yOffset;
    
        matrix[8]  = 0.0f;
        matrix[9]  = 0.0f;
        matrix[10] = 1.0f;
        matrix[11] = zOffset;
    
        matrix[12] = 0.0f;
        matrix[13] = 0.0f;
        matrix[14] = 0.0f;
        matrix[15] = 1.0f;
    }
    
    }  // namespace
    
    class MultiviewSample : public SampleApplication
    {
      public:
        MultiviewSample(int argc, char **argv)
            : SampleApplication("Multiview", argc, argv, ClientType::ES3_0),
              mMultiviewProgram(0),
              mMultiviewPersperiveUniformLoc(-1),
              mMultiviewLeftEyeCameraUniformLoc(-1),
              mMultiviewRightEyeCameraUniformLoc(-1),
              mMultiviewTranslationUniformLoc(-1),
              mMultiviewFBO(0),
              mColorTexture(0),
              mDepthTexture(0),
              mQuadVAO(0),
              mQuadVBO(0),
              mCubeVAO(0),
              mCubePosVBO(0),
              mCubeNormalVBO(0),
              mCubeIBO(0),
              mCombineProgram(0)
        {}
    
        bool initialize() override
        {
            // Check whether the GL_OVR_multiview(2) extension is supported. If not, abort
            // initialization.
            const char *allExtensions = reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS));
            const std::string paddedExtensions = std::string(" ") + allExtensions + std::string(" ");
            if ((paddedExtensions.find(std::string(" GL_OVR_multiview2 ")) == std::string::npos) &&
                (paddedExtensions.find(std::string(" GL_OVR_multiview ")) == std::string::npos))
            {
                std::cout << "GL_OVR_multiview(2) is not available." << std::endl;
                return false;
            }
    
            // A view covers horizontally half of the screen.
            int viewWidth  = getWindow()->getWidth() / 2;
            int viewHeight = getWindow()->getHeight();
    
            // Create color and depth texture arrays with two layers to which we render each view.
            glGenTextures(1, &mColorTexture);
            glBindTexture(GL_TEXTURE_2D_ARRAY, mColorTexture);
            glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA8, viewWidth, viewHeight, 2, 0, GL_RGBA,
                         GL_UNSIGNED_BYTE, nullptr);
            glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
            glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    
            glGenTextures(1, &mDepthTexture);
            glBindTexture(GL_TEXTURE_2D_ARRAY, mDepthTexture);
            glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_DEPTH_COMPONENT32F, viewWidth, viewHeight, 2, 0,
                         GL_DEPTH_COMPONENT, GL_FLOAT, nullptr);
    
            // Generate multiview framebuffer for layered rendering.
            glGenFramebuffers(1, &mMultiviewFBO);
            glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
            glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, mColorTexture, 0, 0,
                                             2);
            glFramebufferTextureMultiviewOVR(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, mDepthTexture, 0, 0,
                                             2);
            GLenum drawBuffer = GL_COLOR_ATTACHMENT0;
            glDrawBuffers(1, &drawBuffer);
    
            // Check that the framebuffer is complete. Abort initialization otherwise.
            if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
            {
                return false;
            }
    
            // Create multiview program and query the uniform locations.
            // The program has two code paths based on the gl_ViewID_OVR attribute which tells us which
            // view is currently being rendered to. Based on it we decide which eye's camera matrix to
            // use.
            constexpr char kMultiviewVS[] =
                "#version 300 es\n"
                "#extension GL_OVR_multiview2 : require\n"
                "layout(num_views = 2) in;\n"
                "layout(location=0) in vec3 posIn;\n"
                "layout(location=1) in vec3 normalIn;\n"
                "uniform mat4 uPerspective;\n"
                "uniform mat4 uCameraLeftEye;\n"
                "uniform mat4 uCameraRightEye;\n"
                "uniform mat4 uTranslation;\n"
                "out vec3 oNormal;\n"
                "void main()\n"
                "{\n"
                "   vec4 p = uTranslation * vec4(posIn,1.);\n"
                "   if (gl_ViewID_OVR == 0u) {\n"
                "       p = uCameraLeftEye * p;\n"
                "   } else {\n"
                "       p = uCameraRightEye * p;\n"
                "   }\n"
                "   oNormal = normalIn;\n"
                "   gl_Position = uPerspective * p;\n"
                "}\n";
    
            constexpr char kMultiviewFS[] =
                "#version 300 es\n"
                "#extension GL_OVR_multiview2 : require\n"
                "precision mediump float;\n"
                "out vec4 color;\n"
                "in vec3 oNormal;\n"
                "void main()\n"
                "{\n"
                "   vec3 col = 0.5 * oNormal + vec3(0.5);\n"
                "   color = vec4(col, 1.);\n"
                "}\n";
    
            mMultiviewProgram = CompileProgram(kMultiviewVS, kMultiviewFS);
            if (!mMultiviewProgram)
            {
                return false;
            }
            mMultiviewPersperiveUniformLoc = glGetUniformLocation(mMultiviewProgram, "uPerspective");
            mMultiviewLeftEyeCameraUniformLoc =
                glGetUniformLocation(mMultiviewProgram, "uCameraLeftEye");
            mMultiviewRightEyeCameraUniformLoc =
                glGetUniformLocation(mMultiviewProgram, "uCameraRightEye");
            mMultiviewTranslationUniformLoc = glGetUniformLocation(mMultiviewProgram, "uTranslation");
    
            // Create a normal program to combine both layers of the color array texture.
            constexpr char kCombineVS[] =
                "#version 300 es\n"
                "in vec2 vIn;\n"
                "out vec2 uv;\n"
                "void main()\n"
                "{\n"
                "   gl_Position = vec4(vIn, 0., 1.);\n"
                "   uv = vIn * .5 + vec2(.5);\n"
                "}\n";
    
            constexpr char kCombineFS[] =
                "#version 300 es\n"
                "precision mediump float;\n"
                "precision mediump sampler2DArray;\n"
                "uniform sampler2DArray uMultiviewTex;\n"
                "in vec2 uv;\n"
                "out vec4 color;\n"
                "void main()\n"
                "{\n"
                "   float scaledX = 2.0 * uv.x;\n"
                "   float layer = floor(scaledX);\n"
                "   vec2 adjustedUV = vec2(fract(scaledX), uv.y);\n"
                "   vec3 texColor = texture(uMultiviewTex, vec3(adjustedUV, layer)).rgb;\n"
                "   color = vec4(texColor, 1.);\n"
                "}\n";
    
            mCombineProgram = CompileProgram(kCombineVS, kCombineFS);
            if (!mCombineProgram)
            {
                return false;
            }
    
            // Generate a quad which covers the whole screen.
            glGenVertexArrays(1, &mQuadVAO);
            glBindVertexArray(mQuadVAO);
    
            glGenBuffers(1, &mQuadVBO);
            glBindBuffer(GL_ARRAY_BUFFER, mQuadVBO);
            const float kQuadPositionData[] = {1.f, -1.f, 1.f, 1.f, -1.f, -1.f, -1.f, 1.f};
            glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 8, kQuadPositionData, GL_STATIC_DRAW);
            glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
            glEnableVertexAttribArray(0);
            glBindVertexArray(0);
    
            // Generate a cube.
            GenerateCubeGeometry(1.0f, &mCube);
            glGenVertexArrays(1, &mCubeVAO);
            glBindVertexArray(mCubeVAO);
    
            glGenBuffers(1, &mCubePosVBO);
            glBindBuffer(GL_ARRAY_BUFFER, mCubePosVBO);
            glBufferData(GL_ARRAY_BUFFER, sizeof(angle::Vector3) * mCube.positions.size(),
                         mCube.positions.data(), GL_STATIC_DRAW);
            glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
            glEnableVertexAttribArray(0);
    
            glGenBuffers(1, &mCubeNormalVBO);
            glBindBuffer(GL_ARRAY_BUFFER, mCubeNormalVBO);
            glBufferData(GL_ARRAY_BUFFER, sizeof(angle::Vector3) * mCube.normals.size(),
                         mCube.normals.data(), GL_STATIC_DRAW);
            glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
            glEnableVertexAttribArray(1);
    
            glGenBuffers(1, &mCubeIBO);
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mCubeIBO);
            glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLushort) * mCube.indices.size(),
                         mCube.indices.data(), GL_STATIC_DRAW);
    
            glBindVertexArray(0);
    
            glEnable(GL_DEPTH_TEST);
            glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    
            return true;
        }
    
        void destroy() override
        {
            glDeleteProgram(mMultiviewProgram);
            glDeleteFramebuffers(1, &mMultiviewFBO);
            glDeleteTextures(1, &mColorTexture);
            glDeleteTextures(1, &mDepthTexture);
            glDeleteVertexArrays(1, &mQuadVAO);
            glDeleteBuffers(1, &mQuadVBO);
            glDeleteVertexArrays(1, &mCubeVAO);
            glDeleteBuffers(1, &mQuadVBO);
            glDeleteBuffers(1, &mCubePosVBO);
            glDeleteBuffers(1, &mCubeNormalVBO);
            glDeleteBuffers(1, &mCubeIBO);
            glDeleteProgram(mCombineProgram);
        }
    
        void draw() override
        {
            // Draw to multiview fbo.
            {
                // Generate the perspective projection matrix.
                const int viewWidth          = getWindow()->getWidth() / 2;
                const int viewHeight         = getWindow()->getHeight();
                const float kFOV             = 90.f;
                const float kNear            = 1.0f;
                const float kFar             = 100.0f;
                const float kPlaneDifference = kFar - kNear;
                const float kXYScale         = 1.f / (tanf(kFOV / 2.0f));
                const float kAspectRatio     = static_cast<float>(viewWidth) / viewHeight;
                float kPerspectiveProjectionMatrix[16];
                kPerspectiveProjectionMatrix[0] = kXYScale / kAspectRatio;
                kPerspectiveProjectionMatrix[1] = .0f;
                kPerspectiveProjectionMatrix[2] = .0f;
                kPerspectiveProjectionMatrix[3] = .0f;
    
                kPerspectiveProjectionMatrix[4] = .0f;
                kPerspectiveProjectionMatrix[5] = kXYScale;
                kPerspectiveProjectionMatrix[6] = .0f;
                kPerspectiveProjectionMatrix[7] = .0f;
    
                kPerspectiveProjectionMatrix[8]  = .0f;
                kPerspectiveProjectionMatrix[9]  = .0;
                kPerspectiveProjectionMatrix[10] = -kFar / kPlaneDifference;
                kPerspectiveProjectionMatrix[11] = -1.f;
    
                kPerspectiveProjectionMatrix[12] = .0f;
                kPerspectiveProjectionMatrix[13] = .0;
                kPerspectiveProjectionMatrix[14] = -kFar * kNear / kPlaneDifference;
                kPerspectiveProjectionMatrix[15] = .0;
    
                // Generate the camera matrices for the left and right eye.
                const float kXOffset = 1.5f;
                const float kYOffset = 1.5f;
                const float kZOffset = 5.0f;
                float kLeftCameraMatrix[16];
                FillTranslationMatrix(kXOffset, -kYOffset, -kZOffset, kLeftCameraMatrix);
                float kRightCameraMatrix[16];
                FillTranslationMatrix(-kXOffset, -kYOffset, -kZOffset, kRightCameraMatrix);
    
                // Bind and clear the multiview framebuffer.
                glBindFramebuffer(GL_FRAMEBUFFER, mMultiviewFBO);
                glClearColor(0, 0, 0, 1);
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
                // Set the viewport to be the size as one of the views.
                glViewport(0, 0, viewWidth, viewHeight);
    
                // Bind multiview program and set matrices.
                glUseProgram(mMultiviewProgram);
                glUniformMatrix4fv(mMultiviewPersperiveUniformLoc, 1, GL_TRUE,
                                   kPerspectiveProjectionMatrix);
                glUniformMatrix4fv(mMultiviewLeftEyeCameraUniformLoc, 1, GL_TRUE, kLeftCameraMatrix);
                glUniformMatrix4fv(mMultiviewRightEyeCameraUniformLoc, 1, GL_TRUE, kRightCameraMatrix);
    
                glBindVertexArray(mCubeVAO);
    
                // Draw first cube.
                float kTranslationMatrix[16];
                FillTranslationMatrix(0.0f, 0.0f, 0.0f, kTranslationMatrix);
                glUniformMatrix4fv(mMultiviewTranslationUniformLoc, 1, GL_TRUE, kTranslationMatrix);
                glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(mCube.indices.size()),
                               GL_UNSIGNED_SHORT, nullptr);
    
                // Draw second cube.
                FillTranslationMatrix(1.0f, 1.0f, -2.0f, kTranslationMatrix);
                glUniformMatrix4fv(mMultiviewTranslationUniformLoc, 1, GL_TRUE, kTranslationMatrix);
                glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(mCube.indices.size()),
                               GL_UNSIGNED_SHORT, nullptr);
    
                glBindVertexArray(0);
            }
    
            // Combine both views.
            {
                // Bind the default framebuffer object and clear.
                glBindFramebuffer(GL_FRAMEBUFFER, 0);
    
                glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
                // Set the viewport to cover the whole screen.
                glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());
    
                glUseProgram(mCombineProgram);
    
                // Bind the 2D array texture to be used as a sampler.
                glUniform1i(glGetUniformLocation(mCombineProgram, "uMultiviewTex"), 0);
                glBindTexture(GL_TEXTURE_2D_ARRAY, mMultiviewFBO);
                glActiveTexture(GL_TEXTURE0);
    
                // Draw a quad which covers the whole screen. Layer and texture coordinates are
                // calculated in the vertex shader based on the UV coordinates of the quad.
                glBindVertexArray(mQuadVAO);
                glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
                glBindVertexArray(0);
            }
        }
    
      private:
        GLuint mMultiviewProgram;
        GLint mMultiviewPersperiveUniformLoc;
        GLint mMultiviewLeftEyeCameraUniformLoc;
        GLint mMultiviewRightEyeCameraUniformLoc;
        GLint mMultiviewTranslationUniformLoc;
    
        GLuint mMultiviewFBO;
        GLuint mColorTexture;
        GLuint mDepthTexture;
    
        GLuint mQuadVAO;
        GLuint mQuadVBO;
    
        CubeGeometry mCube;
        GLuint mCubeVAO;
        GLuint mCubePosVBO;
        GLuint mCubeNormalVBO;
        GLuint mCubeIBO;
    
        GLuint mCombineProgram;
    };
    
    int main(int argc, char **argv)
    {
        MultiviewSample app(argc, argv);
        return app.run();
    }