GameApi 28
Library used by GameApi Builder tool
Loading...
Searching...
No Matches
mesh_prediction_scheme_tex_coords_portable_predictor.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_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_TEX_COORDS_PORTABLE_PREDICTOR_H_
16#define DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_TEX_COORDS_PORTABLE_PREDICTOR_H_
17
18#include <math.h>
19
20#include <algorithm>
21#include <limits>
22
25#include "draco/core/vector_d.h"
27
28namespace draco {
29
30// Predictor functionality used for portable UV prediction by both encoder and
31// decoder.
32template <typename DataTypeT, class MeshDataT>
34 public:
35 static constexpr int kNumComponents = 2;
36
38 : pos_attribute_(nullptr),
39 entry_to_point_id_map_(nullptr),
40 mesh_data_(md) {}
41 void SetPositionAttribute(const PointAttribute &position_attribute) {
42 pos_attribute_ = &position_attribute;
43 }
45 entry_to_point_id_map_ = map;
46 }
47 bool IsInitialized() const { return pos_attribute_ != nullptr; }
48
50 const PointIndex point_id = entry_to_point_id_map_[entry_id];
52 pos_attribute_->ConvertValue(pos_attribute_->mapped_index(point_id),
53 &pos[0]);
54 return pos;
55 }
56
58 const DataTypeT *data) const {
59 const int data_offset = entry_id * kNumComponents;
60 return VectorD<int64_t, 2>(data[data_offset], data[data_offset + 1]);
61 }
62
63 // Computes predicted UV coordinates on a given corner. The coordinates are
64 // stored in |predicted_value_| member.
65 template <bool is_encoder_t>
66 bool ComputePredictedValue(CornerIndex corner_id, const DataTypeT *data,
67 int data_id);
68
69 const DataTypeT *predicted_value() const { return predicted_value_; }
70 bool orientation(int i) const { return orientations_[i]; }
71 void set_orientation(int i, bool v) { orientations_[i] = v; }
72 size_t num_orientations() const { return orientations_.size(); }
74 orientations_.resize(num_orientations);
75 }
76
77 private:
78 const PointAttribute *pos_attribute_;
79 const PointIndex *entry_to_point_id_map_;
80 DataTypeT predicted_value_[kNumComponents];
81 // Encoded / decoded array of UV flips.
82 // TODO(ostava): We should remove this and replace this with in-place encoding
83 // and decoding to avoid unnecessary copy.
84 std::vector<bool> orientations_;
85 MeshDataT mesh_data_;
86};
87
88template <typename DataTypeT, class MeshDataT>
89template <bool is_encoder_t>
90bool MeshPredictionSchemeTexCoordsPortablePredictor<
91 DataTypeT, MeshDataT>::ComputePredictedValue(CornerIndex corner_id,
92 const DataTypeT *data,
93 int data_id) {
94 // Compute the predicted UV coordinate from the positions on all corners
95 // of the processed triangle. For the best prediction, the UV coordinates
96 // on the next/previous corners need to be already encoded/decoded.
97 const CornerIndex next_corner_id = mesh_data_.corner_table()->Next(corner_id);
98 const CornerIndex prev_corner_id =
99 mesh_data_.corner_table()->Previous(corner_id);
100 // Get the encoded data ids from the next and previous corners.
101 // The data id is the encoding order of the UV coordinates.
102 int next_data_id, prev_data_id;
103
104 int next_vert_id, prev_vert_id;
105 next_vert_id = mesh_data_.corner_table()->Vertex(next_corner_id).value();
106 prev_vert_id = mesh_data_.corner_table()->Vertex(prev_corner_id).value();
107
108 next_data_id = mesh_data_.vertex_to_data_map()->at(next_vert_id);
109 prev_data_id = mesh_data_.vertex_to_data_map()->at(prev_vert_id);
110
113 typedef VectorD<uint64_t, 2> Vec2u;
114
115 if (prev_data_id < data_id && next_data_id < data_id) {
116 // Both other corners have available UV coordinates for prediction.
117 const Vec2 n_uv = GetTexCoordForEntryId(next_data_id, data);
118 const Vec2 p_uv = GetTexCoordForEntryId(prev_data_id, data);
119 if (p_uv == n_uv) {
120 // We cannot do a reliable prediction on degenerated UV triangles.
121 predicted_value_[0] = p_uv[0];
122 predicted_value_[1] = p_uv[1];
123 return true;
124 }
125
126 // Get positions at all corners.
127 const Vec3 tip_pos = GetPositionForEntryId(data_id);
128 const Vec3 next_pos = GetPositionForEntryId(next_data_id);
129 const Vec3 prev_pos = GetPositionForEntryId(prev_data_id);
130 // We use the positions of the above triangle to predict the texture
131 // coordinate on the tip corner C.
132 // To convert the triangle into the UV coordinate system we first compute
133 // position X on the vector |prev_pos - next_pos| that is the projection of
134 // point C onto vector |prev_pos - next_pos|:
135 //
136 // C
137 // /. \
138 // / . \
139 // / . \
140 // N---X----------P
141 //
142 // Where next_pos is point (N), prev_pos is point (P) and tip_pos is the
143 // position of predicted coordinate (C).
144 //
145 const Vec3 pn = prev_pos - next_pos;
146 const uint64_t pn_norm2_squared = pn.SquaredNorm();
147 if (pn_norm2_squared != 0) {
148 // Compute the projection of C onto PN by computing dot product of CN with
149 // PN and normalizing it by length of PN. This gives us a factor |s| where
150 // |s = PN.Dot(CN) / PN.SquaredNorm2()|. This factor can be used to
151 // compute X in UV space |X_UV| as |X_UV = N_UV + s * PN_UV|.
152 const Vec3 cn = tip_pos - next_pos;
153 const int64_t cn_dot_pn = pn.Dot(cn);
154
155 const Vec2 pn_uv = p_uv - n_uv;
156 // Because we perform all computations with integers, we don't explicitly
157 // compute the normalized factor |s|, but rather we perform all operations
158 // over UV vectors in a non-normalized coordinate system scaled with a
159 // scaling factor |pn_norm2_squared|:
160 //
161 // x_uv = X_UV * PN.Norm2Squared()
162 //
163 const int64_t n_uv_absmax_element =
164 std::max(std::abs(n_uv[0]), std::abs(n_uv[1]));
165 if (n_uv_absmax_element >
166 std::numeric_limits<int64_t>::max() / pn_norm2_squared) {
167 // Return false if the below multiplication would overflow.
168 return false;
169 }
170 const int64_t pn_uv_absmax_element =
171 std::max(std::abs(pn_uv[0]), std::abs(pn_uv[1]));
172 if (cn_dot_pn >
173 std::numeric_limits<int64_t>::max() / pn_uv_absmax_element) {
174 // Return false if squared length calculation would overflow.
175 return false;
176 }
177 const Vec2 x_uv = n_uv * pn_norm2_squared + (cn_dot_pn * pn_uv);
178 const int64_t pn_absmax_element =
179 std::max(std::max(std::abs(pn[0]), std::abs(pn[1])), std::abs(pn[2]));
180 if (cn_dot_pn > std::numeric_limits<int64_t>::max() / pn_absmax_element) {
181 // Return false if squared length calculation would overflow.
182 return false;
183 }
184
185 // Compute squared length of vector CX in position coordinate system:
186 const Vec3 x_pos = next_pos + (cn_dot_pn * pn) / pn_norm2_squared;
187 const uint64_t cx_norm2_squared = (tip_pos - x_pos).SquaredNorm();
188
189 // Compute vector CX_UV in the uv space by rotating vector PN_UV by 90
190 // degrees and scaling it with factor CX.Norm2() / PN.Norm2():
191 //
192 // CX_UV = (CX.Norm2() / PN.Norm2()) * Rot(PN_UV)
193 //
194 // To preserve precision, we perform all operations in scaled space as
195 // explained above, so we want the final vector to be:
196 //
197 // cx_uv = CX_UV * PN.Norm2Squared()
198 //
199 // We can then rewrite the formula as:
200 //
201 // cx_uv = CX.Norm2() * PN.Norm2() * Rot(PN_UV)
202 //
203 Vec2 cx_uv(pn_uv[1], -pn_uv[0]); // Rotated PN_UV.
204 // Compute CX.Norm2() * PN.Norm2()
205 const uint64_t norm_squared =
206 IntSqrt(cx_norm2_squared * pn_norm2_squared);
207 // Final cx_uv in the scaled coordinate space.
208 cx_uv = cx_uv * norm_squared;
209
210 // Predicted uv coordinate is then computed by either adding or
211 // subtracting CX_UV to/from X_UV.
212 Vec2 predicted_uv;
213 if (is_encoder_t) {
214 // When encoding, compute both possible vectors and determine which one
215 // results in a better prediction.
216 // Both vectors need to be transformed back from the scaled space to
217 // the real UV coordinate space.
218 const Vec2 predicted_uv_0((x_uv + cx_uv) / pn_norm2_squared);
219 const Vec2 predicted_uv_1((x_uv - cx_uv) / pn_norm2_squared);
220 const Vec2 c_uv = GetTexCoordForEntryId(data_id, data);
221 if ((c_uv - predicted_uv_0).SquaredNorm() <
222 (c_uv - predicted_uv_1).SquaredNorm()) {
223 predicted_uv = predicted_uv_0;
224 orientations_.push_back(true);
225 } else {
226 predicted_uv = predicted_uv_1;
227 orientations_.push_back(false);
228 }
229 } else {
230 // When decoding the data, we already know which orientation to use.
231 if (orientations_.empty()) {
232 return false;
233 }
234 const bool orientation = orientations_.back();
235 orientations_.pop_back();
236 // Perform operations in unsigned type to avoid signed integer overflow.
237 // Note that the result will be the same (for non-overflowing values).
238 if (orientation) {
239 predicted_uv = Vec2(Vec2u(x_uv) + Vec2u(cx_uv)) / pn_norm2_squared;
240 } else {
241 predicted_uv = Vec2(Vec2u(x_uv) - Vec2u(cx_uv)) / pn_norm2_squared;
242 }
243 }
244 predicted_value_[0] = static_cast<int>(predicted_uv[0]);
245 predicted_value_[1] = static_cast<int>(predicted_uv[1]);
246 return true;
247 }
248 }
249 // Else we don't have available textures on both corners or the position data
250 // is invalid. For such cases we can't use positions for predicting the uv
251 // value and we resort to delta coding.
252 int data_offset = 0;
253 if (prev_data_id < data_id) {
254 // Use the value on the previous corner as the prediction.
255 data_offset = prev_data_id * kNumComponents;
256 }
257 if (next_data_id < data_id) {
258 // Use the value on the next corner as the prediction.
259 data_offset = next_data_id * kNumComponents;
260 } else {
261 // None of the other corners have a valid value. Use the last encoded value
262 // as the prediction if possible.
263 if (data_id > 0) {
264 data_offset = (data_id - 1) * kNumComponents;
265 } else {
266 // We are encoding the first value. Predict 0.
267 for (int i = 0; i < kNumComponents; ++i) {
268 predicted_value_[i] = 0;
269 }
270 return true;
271 }
272 }
273 for (int i = 0; i < kNumComponents; ++i) {
274 predicted_value_[i] = data[data_offset + i];
275 }
276 return true;
277}
278
279} // namespace draco
280
281#endif // DRACO_COMPRESSION_ATTRIBUTES_PREDICTION_SCHEMES_MESH_PREDICTION_SCHEME_TEX_COORDS_PORTABLE_PREDICTOR_H_
Definition GraphI.hh:3545
Definition GraphI.hh:3553
void ResizeOrientations(int num_orientations)
Definition mesh_prediction_scheme_tex_coords_portable_predictor.h:73
const DataTypeT * predicted_value() const
Definition mesh_prediction_scheme_tex_coords_portable_predictor.h:69
void SetEntryToPointIdMap(const PointIndex *map)
Definition mesh_prediction_scheme_tex_coords_portable_predictor.h:44
VectorD< int64_t, 2 > GetTexCoordForEntryId(int entry_id, const DataTypeT *data) const
Definition mesh_prediction_scheme_tex_coords_portable_predictor.h:57
static constexpr int kNumComponents
Definition mesh_prediction_scheme_tex_coords_portable_predictor.h:35
size_t num_orientations() const
Definition mesh_prediction_scheme_tex_coords_portable_predictor.h:72
VectorD< int64_t, 3 > GetPositionForEntryId(int entry_id) const
Definition mesh_prediction_scheme_tex_coords_portable_predictor.h:49
MeshPredictionSchemeTexCoordsPortablePredictor(const MeshDataT &md)
Definition mesh_prediction_scheme_tex_coords_portable_predictor.h:37
bool orientation(int i) const
Definition mesh_prediction_scheme_tex_coords_portable_predictor.h:70
void SetPositionAttribute(const PointAttribute &position_attribute)
Definition mesh_prediction_scheme_tex_coords_portable_predictor.h:41
bool IsInitialized() const
Definition mesh_prediction_scheme_tex_coords_portable_predictor.h:47
bool ComputePredictedValue(CornerIndex corner_id, const DataTypeT *data, int data_id)
Definition mesh_prediction_scheme_tex_coords_portable_predictor.h:91
void set_orientation(int i, bool v)
Definition mesh_prediction_scheme_tex_coords_portable_predictor.h:71
Definition point_attribute.h:33
Definition vector_d.h:30
lazy data
Definition meshpage.php:1583
Definition attribute_octahedron_transform.cc:21
uint64_t IntSqrt(uint64_t number)
Definition math_utils.h:31
CornerIndex CornerIndex
Definition mesh_edgebreaker_encoder_impl.cc:35
Definition GameApi_pl.cc:29382