Home | History | Annotate | Download | only in cpp
      1 /*
      2  * Copyright 2017 Google Inc. All Rights Reserved.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "plane_renderer.h"
     18 #include "util.h"
     19 
     20 namespace hello_ar {
     21     namespace {
     22         constexpr char kVertexShader[] = R"(
     23     precision highp float;
     24     precision highp int;
     25     attribute vec3 vertex;
     26     varying vec2 v_textureCoords;
     27     varying float v_alpha;
     28 
     29     uniform mat4 mvp;
     30     uniform mat4 model_mat;
     31     uniform vec3 normal;
     32 
     33     void main() {
     34       // Vertex Z value is used as the alpha in this shader.
     35       v_alpha = vertex.z;
     36 
     37       vec4 local_pos = vec4(vertex.x, 0.0, vertex.y, 1.0);
     38       gl_Position = mvp * local_pos;
     39       vec4 world_pos = model_mat * local_pos;
     40 
     41       // Construct two vectors that are orthogonal to the normal.
     42       // This arbitrary choice is not co-linear with either horizontal
     43       // or vertical plane normals.
     44       const vec3 arbitrary = vec3(1.0, 1.0, 0.0);
     45       vec3 vec_u = normalize(cross(normal, arbitrary));
     46       vec3 vec_v = normalize(cross(normal, vec_u));
     47 
     48       // Project vertices in world frame onto vec_u and vec_v.
     49       v_textureCoords = vec2(
     50          dot(world_pos.xyz, vec_u), dot(world_pos.xyz, vec_v));
     51     })";
     52 
     53         constexpr char kFragmentShader[] = R"(
     54     precision highp float;
     55     precision highp int;
     56     uniform sampler2D texture;
     57     uniform vec3 color;
     58     varying vec2 v_textureCoords;
     59     varying float v_alpha;
     60     void main() {
     61       float r = texture2D(texture, v_textureCoords).r;
     62       gl_FragColor = vec4(color.xyz, r * v_alpha);
     63     })";
     64     }  // namespace
     65 
     66     void PlaneRenderer::InitializeGlContent(AAssetManager *asset_manager) {
     67         shader_program_ = util::CreateProgram(kVertexShader, kFragmentShader);
     68 
     69         if (!shader_program_) {
     70             LOGE("Could not create program.");
     71         }
     72 
     73         uniform_mvp_mat_ = glGetUniformLocation(shader_program_, "mvp");
     74         uniform_texture_ = glGetUniformLocation(shader_program_, "texture");
     75         uniform_model_mat_ = glGetUniformLocation(shader_program_, "model_mat");
     76         uniform_normal_vec_ = glGetUniformLocation(shader_program_, "normal");
     77         uniform_color_ = glGetUniformLocation(shader_program_, "color");
     78         attri_vertices_ = glGetAttribLocation(shader_program_, "vertex");
     79 
     80         glGenTextures(1, &texture_id_);
     81         glBindTexture(GL_TEXTURE_2D, texture_id_);
     82         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
     83         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
     84         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
     85                         GL_LINEAR_MIPMAP_LINEAR);
     86         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
     87 
     88         if (!util::LoadPngFromAssetManager(GL_TEXTURE_2D, "models/trigrid.png")) {
     89             LOGE("Could not load png texture for planes.");
     90         }
     91 
     92         glGenerateMipmap(GL_TEXTURE_2D);
     93 
     94         glBindTexture(GL_TEXTURE_2D, 0);
     95 
     96         util::CheckGlError("plane_renderer::InitializeGlContent()");
     97     }
     98 
     99     void PlaneRenderer::Draw(const glm::mat4 &projection_mat,
    100                              const glm::mat4 &view_mat, const ArSession *ar_session,
    101                              const ArPlane *ar_plane, const glm::vec3 &color) {
    102         if (!shader_program_) {
    103             LOGE("shader_program is null.");
    104             return;
    105         }
    106 
    107         UpdateForPlane(ar_session, ar_plane);
    108 
    109         glUseProgram(shader_program_);
    110         glDepthMask(GL_FALSE);
    111 
    112         glActiveTexture(GL_TEXTURE0);
    113         glUniform1i(uniform_texture_, 0);
    114         glBindTexture(GL_TEXTURE_2D, texture_id_);
    115 
    116         // Compose final mvp matrix for this plane renderer.
    117         glUniformMatrix4fv(uniform_mvp_mat_, 1, GL_FALSE,
    118                            glm::value_ptr(projection_mat * view_mat * model_mat_));
    119 
    120         glUniformMatrix4fv(uniform_model_mat_, 1, GL_FALSE,
    121                            glm::value_ptr(model_mat_));
    122         glUniform3f(uniform_normal_vec_, normal_vec_.x, normal_vec_.y, normal_vec_.z);
    123         glUniform3f(uniform_color_, color.x, color.y, color.z);
    124 
    125         glEnableVertexAttribArray(attri_vertices_);
    126         glVertexAttribPointer(attri_vertices_, 3, GL_FLOAT, GL_FALSE, 0,
    127                               vertices_.data());
    128 
    129         glDrawElements(GL_TRIANGLES, triangles_.size(), GL_UNSIGNED_SHORT,
    130                        triangles_.data());
    131 
    132         glUseProgram(0);
    133         glDepthMask(GL_TRUE);
    134         util::CheckGlError("plane_renderer::Draw()");
    135     }
    136 
    137     void PlaneRenderer::UpdateForPlane(const ArSession *ar_session,
    138                                        const ArPlane *ar_plane) {
    139         // The following code generates a triangle mesh filling a convex polygon,
    140         // including a feathered edge for blending.
    141         //
    142         // The indices shown in the diagram are used in comments below.
    143         // _______________     0_______________1
    144         // |             |      |4___________5|
    145         // |             |      | |         | |
    146         // |             | =>   | |         | |
    147         // |             |      | |         | |
    148         // |             |      |7-----------6|
    149         // ---------------     3---------------2
    150 
    151         vertices_.clear();
    152         triangles_.clear();
    153 
    154         int32_t polygon_length;
    155         ArPlane_getPolygonSize(ar_session, ar_plane, &polygon_length);
    156 
    157         if (polygon_length == 0) {
    158             LOGE("PlaneRenderer::UpdatePlane, no valid plane polygon is found");
    159             return;
    160         }
    161 
    162         const int32_t vertices_size = polygon_length / 2;
    163         std::vector<glm::vec2> raw_vertices(vertices_size);
    164         ArPlane_getPolygon(ar_session, ar_plane,
    165                            glm::value_ptr(raw_vertices.front()));
    166 
    167         // Fill vertex 0 to 3. Note that the vertex.xy are used for x and z
    168         // position. vertex.z is used for alpha. The outter polygon's alpha
    169         // is 0.
    170         for (int32_t i = 0; i < vertices_size; ++i) {
    171             vertices_.push_back(glm::vec3(raw_vertices[i].x, raw_vertices[i].y, 0.0f));
    172         }
    173 
    174         util::ScopedArPose scopedArPose(ar_session);
    175         ArPlane_getCenterPose(ar_session, ar_plane, scopedArPose.GetArPose());
    176         ArPose_getMatrix(ar_session, scopedArPose.GetArPose(),
    177                          glm::value_ptr(model_mat_));
    178         normal_vec_ = util::GetPlaneNormal(ar_session, *scopedArPose.GetArPose());
    179 
    180         // Feather distance 0.2 meters.
    181         const float kFeatherLength = 0.2f;
    182         // Feather scale over the distance between plane center and vertices.
    183         const float kFeatherScale = 0.2f;
    184 
    185         // Fill vertex 4 to 7, with alpha set to 1.
    186         for (int32_t i = 0; i < vertices_size; ++i) {
    187             // Vector from plane center to current point.
    188             glm::vec2 v = raw_vertices[i];
    189             const float scale =
    190                     1.0f - std::min((kFeatherLength / glm::length(v)), kFeatherScale);
    191             const glm::vec2 result_v = scale * v;
    192 
    193             vertices_.push_back(glm::vec3(result_v.x, result_v.y, 1.0f));
    194         }
    195 
    196         const int32_t vertices_length = vertices_.size();
    197         const int32_t half_vertices_length = vertices_length / 2;
    198 
    199         // Generate triangle (4, 5, 6) and (4, 6, 7).
    200         for (int i = half_vertices_length + 1; i < vertices_length - 1; ++i) {
    201             triangles_.push_back(half_vertices_length);
    202             triangles_.push_back(i);
    203             triangles_.push_back(i + 1);
    204         }
    205 
    206         // Generate triangle (0, 1, 4), (4, 1, 5), (5, 1, 2), (5, 2, 6),
    207         // (6, 2, 3), (6, 3, 7), (7, 3, 0), (7, 0, 4)
    208         for (int i = 0; i < half_vertices_length; ++i) {
    209             triangles_.push_back(i);
    210             triangles_.push_back((i + 1) % half_vertices_length);
    211             triangles_.push_back(i + half_vertices_length);
    212 
    213             triangles_.push_back(i + half_vertices_length);
    214             triangles_.push_back((i + 1) % half_vertices_length);
    215             triangles_.push_back((i + half_vertices_length + 1) % half_vertices_length +
    216                                  half_vertices_length);
    217         }
    218     }
    219 
    220 }  // namespace hello_ar
    221