• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "platform_tools/android/apps/arcore/src/main/cpp/plane_renderer.h"
18 #include "platform_tools/android/apps/arcore/src/main/cpp/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 
InitializeGlContent(AAssetManager * asset_manager)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 
Draw(const glm::mat4 & projection_mat,const glm::mat4 & view_mat,const ArSession * ar_session,const ArPlane * ar_plane,const glm::vec3 & color)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 
UpdateForPlane(const ArSession * ar_session,const ArPlane * ar_plane)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