GameApi 28
Library used by GameApi Builder tool
Loading...
Searching...
No Matches
mesh_stripifier.h
Go to the documentation of this file.
1// Copyright 2017 The Draco Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15#ifndef DRACO_MESH_MESH_STRIPIFIER_H_
16#define DRACO_MESH_MESH_STRIPIFIER_H_
17
19
20namespace draco {
21
22// Class that generates triangle strips from a provided draco::Mesh data
23// structure. The strips represent a more memory efficient storage of triangle
24// connectivity that can be used directly on the GPU (see
25// https://en.wikipedia.org/wiki/Triangle_strip ). In general, a mesh needs to
26// be represented by several triangle strips and it has been proven that finding
27// the optimal set of triangle strips is an NP-complete problem. The algorithm
28// implemented by this class finds this set of triangle strips based on a greedy
29// heuristic that always selects the longest available strip that covers the
30// next unprocessed face. The longest strip is found by analyzing all strips
31// that can cover the given face (three strips corresponding to three
32// directions).
34 public:
36 : mesh_(nullptr),
37 num_strips_(0),
38 num_encoded_faces_(0),
39 last_encoded_point_(kInvalidPointIndex) {}
40
41 // Generate triangle strips for a given mesh and output them to the output
42 // iterator |out_it|. In most cases |out_it| stores the values in a buffer
43 // that can be used directly on the GPU. Note that the algorithm can generate
44 // multiple strips to represent the whole mesh. In such cases multiple strips
45 // are separated using a so called primitive restart index that is specified
46 // by the |primitive_restart_index| (usually defined as the maximum allowed
47 // value for the given type).
48 // https://www.khronos.org/opengl/wiki/Vertex_Rendering#Primitive_Restart
49 template <typename OutputIteratorT, typename IndexTypeT>
51 const Mesh &mesh, IndexTypeT primitive_restart_index,
52 OutputIteratorT out_it);
53
54 // The same as above but disjoint triangle strips are separated by degenerate
55 // triangles instead of the primitive restart index. Degenerate triangles are
56 // zero area triangles that are automatically discarded by the GPU. Using
57 // degenerate triangles usually results in a slightly longer output indices
58 // array compared to the similar triangle strips that use primitive restart
59 // index. The advantage of this method is that it is supported by all hardware
60 // and all relevant APIs (including WebGL 1.0).
61 template <typename OutputIteratorT>
63 OutputIteratorT out_it);
64
65 // Returns the number of strips generated by the last call of the
66 // GenerateTriangleStrips() method.
67 int num_strips() const { return num_strips_; }
68
69 private:
70 bool Prepare(const Mesh &mesh) {
71 mesh_ = &mesh;
72 num_strips_ = 0;
73 num_encoded_faces_ = 0;
74 corner_table_ = CreateCornerTableFromPositionAttribute(mesh_);
75 if (corner_table_ == nullptr) {
76 return false;
77 }
78
79 // Mark all faces as unvisited.
80 is_face_visited_.assign(mesh.num_faces(), false);
81 return true;
82 }
83
84 // Returns local id of the longest strip that can be created from the given
85 // face |fi|.
86 int FindLongestStripFromFace(FaceIndex fi) {
87 // There are three possible strip directions that can contain the provided
88 // input face. We try all of them and select the direction that result in
89 // the longest strip.
90 const CornerIndex first_ci = corner_table_->FirstCorner(fi);
91 int longest_strip_id = -1;
92 int longest_strip_length = 0;
93 for (int i = 0; i < 3; ++i) {
94 GenerateStripsFromCorner(i, first_ci + i);
95 if (strip_faces_[i].size() > longest_strip_length) {
96 longest_strip_length = static_cast<int>(strip_faces_[i].size());
97 longest_strip_id = i;
98 }
99 }
100 return longest_strip_id;
101 }
102
103 // Generates strip from the data stored in |strip_faces_| and
104 // |strip_start_start_corners_| and stores it to |out_it|.
105 template <typename OutputIteratorT>
106 void StoreStrip(int local_strip_id, OutputIteratorT out_it) {
107 ++num_strips_;
108
109 const int num_strip_faces = strip_faces_[local_strip_id].size();
110 CornerIndex ci = strip_start_corners_[local_strip_id];
111 for (int i = 0; i < num_strip_faces; ++i) {
112 const FaceIndex fi = corner_table_->Face(ci);
113 is_face_visited_[fi] = true;
114 ++num_encoded_faces_;
115
116 if (i == 0) {
117 // Add the start face (three indices).
118 *out_it++ = CornerToPointIndex(ci).value();
119 *out_it++ = CornerToPointIndex(corner_table_->Next(ci)).value();
120 last_encoded_point_ = CornerToPointIndex(corner_table_->Previous(ci));
121 *out_it++ = last_encoded_point_.value();
122 } else {
123 // Store the point on the newly reached corner.
124 last_encoded_point_ = CornerToPointIndex(ci);
125 *out_it++ = last_encoded_point_.value();
126
127 // Go to the correct source corner to proceed to the next face.
128 if (i & 1) {
129 ci = corner_table_->Previous(ci);
130 } else {
131 ci = corner_table_->Next(ci);
132 }
133 }
134 ci = corner_table_->Opposite(ci);
135 }
136 }
137
138 PointIndex CornerToPointIndex(CornerIndex ci) const {
139 return mesh_->CornerToPointId(ci);
140 }
141
142 // Returns the opposite corner in case the opposite triangle does not lie
143 // across an attribute seam. Otherwise return kInvalidCornerIndex.
144 CornerIndex GetOppositeCorner(CornerIndex ci) const {
145 const CornerIndex oci = corner_table_->Opposite(ci);
146 if (oci < 0) {
147 return kInvalidCornerIndex;
148 }
149 // Ensure the point ids are same on both sides of the shared edge between
150 // the triangles.
151 if (CornerToPointIndex(corner_table_->Next(ci)) !=
152 CornerToPointIndex(corner_table_->Previous(oci))) {
153 return kInvalidCornerIndex;
154 }
155 if (CornerToPointIndex(corner_table_->Previous(ci)) !=
156 CornerToPointIndex(corner_table_->Next(oci))) {
157 return kInvalidCornerIndex;
158 }
159 return oci;
160 }
161
162 void GenerateStripsFromCorner(int local_strip_id, CornerIndex ci);
163
164 const Mesh *mesh_;
165 std::unique_ptr<CornerTable> corner_table_;
166
167 // Store strip faces for each of three possible directions from a given face.
168 std::vector<FaceIndex> strip_faces_[3];
169 // Start corner for each direction of the strip containing the processed face.
170 CornerIndex strip_start_corners_[3];
171 IndexTypeVector<FaceIndex, bool> is_face_visited_;
172 // The number of strips generated by this method.
173 int num_strips_;
174 // The number of encoded triangles.
175 int num_encoded_faces_;
176 // Last encoded point.
177 PointIndex last_encoded_point_;
178};
179
180template <typename OutputIteratorT, typename IndexTypeT>
182 const Mesh &mesh, IndexTypeT primitive_restart_index,
183 OutputIteratorT out_it) {
184 if (!Prepare(mesh)) {
185 return false;
186 }
187
188 // Go over all faces and generate strips from the first unvisited one.
189 for (FaceIndex fi(0); fi < mesh.num_faces(); ++fi) {
190 if (is_face_visited_[fi]) {
191 continue;
192 }
193
194 const int longest_strip_id = FindLongestStripFromFace(fi);
195
196 // Separate triangle strips with the primitive restart index.
197 if (num_strips_ > 0) {
198 *out_it++ = primitive_restart_index;
199 }
200
201 StoreStrip(longest_strip_id, out_it);
202 }
203
204 return true;
205}
206
207template <typename OutputIteratorT>
209 const Mesh &mesh, OutputIteratorT out_it) {
210 if (!Prepare(mesh)) {
211 return false;
212 }
213
214 // Go over all faces and generate strips from the first unvisited one.
215 for (FaceIndex fi(0); fi < mesh.num_faces(); ++fi) {
216 if (is_face_visited_[fi]) {
217 continue;
218 }
219
220 const int longest_strip_id = FindLongestStripFromFace(fi);
221
222 // Separate triangle strips by degenerate triangles. There will be either
223 // three or four degenerate triangles inserted based on the number of
224 // triangles that are already encoded in the output strip (three degenerate
225 // triangles for even number of existing triangles, four degenerate
226 // triangles for odd number of triangles).
227 if (num_strips_ > 0) {
228 // Duplicate last encoded index (first degenerate face).
229 *out_it++ = last_encoded_point_.value();
230
231 // Connect it to the start point of the new triangle strip (second
232 // degenerate face).
233 const CornerIndex new_start_corner =
234 strip_start_corners_[longest_strip_id];
235 const PointIndex new_start_point = CornerToPointIndex(new_start_corner);
236 *out_it++ = new_start_point.value();
237 num_encoded_faces_ += 2;
238 // If we have previously encoded number of faces we need to duplicate the
239 // point one more time to preserve the correct orientation of the next
240 // strip.
241 if (num_encoded_faces_ & 1) {
242 *out_it++ = new_start_point.value();
243 num_encoded_faces_ += 1;
244 }
245 // The last degenerate face will be added implicitly in the StoreStrip()
246 // function below as the first point index is going to be encoded there
247 // again.
248 }
249
250 StoreStrip(longest_strip_id, out_it);
251 }
252
253 return true;
254}
255
256} // namespace draco
257
258#endif // DRACO_MESH_MESH_STRIPIFIER_H_
void assign(size_t size, const ValueTypeT &val)
Definition draco_index_type_vector.h:52
int num_strips() const
Definition mesh_stripifier.h:67
bool GenerateTriangleStripsWithDegenerateTriangles(const Mesh &mesh, OutputIteratorT out_it)
Definition mesh_stripifier.h:208
MeshStripifier()
Definition mesh_stripifier.h:35
bool GenerateTriangleStripsWithPrimitiveRestart(const Mesh &mesh, IndexTypeT primitive_restart_index, OutputIteratorT out_it)
Definition mesh_stripifier.h:181
Definition mesh.h:52
FaceIndex::ValueType num_faces() const
Definition mesh.h:76
n< br > font size
Definition meshpage.php:3536
Definition attribute_octahedron_transform.cc:21
CornerIndex CornerIndex
Definition mesh_edgebreaker_encoder_impl.cc:35
FaceIndex FaceIndex
Definition mesh_edgebreaker_encoder_impl.cc:36
std::unique_ptr< CornerTable > CreateCornerTableFromPositionAttribute(const Mesh *mesh)
Definition mesh_misc_functions.cc:19
Definition GameApi_pl.cc:29382