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