1
2 //
3 // This source file is part of appleseed.
4 // Visit https://appleseedhq.net/ for additional information and resources.
5 //
6 // This software is released under the MIT license.
7 //
8 // Copyright (c) 2014-2018 Francois Beaune, The appleseedhq Organization
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining a copy
11 // of this software and associated documentation files (the "Software"), to deal
12 // in the Software without restriction, including without limitation the rights
13 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 // copies of the Software, and to permit persons to whom the Software is
15 // furnished to do so, subject to the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be included in
18 // all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 // THE SOFTWARE.
27 //
28
29 // Interface header.
30 #include "meshobjectoperations.h"
31
32 // appleseed.renderer headers.
33 #include "renderer/global/globaltypes.h"
34 #include "renderer/modeling/object/meshobject.h"
35 #include "renderer/modeling/object/triangle.h"
36 #include "renderer/utility/triangle.h"
37
38 // appleseed.foundation headers.
39 #include "foundation/math/vector.h"
40 #include "foundation/utility/murmurhash.h"
41
42 // Standard headers.
43 #include <cassert>
44 #include <cstddef>
45 #include <vector>
46
47 using namespace foundation;
48 using namespace std;
49
50 namespace renderer
51 {
52
compute_smooth_vertex_normals_base_pose(MeshObject & object)53 void compute_smooth_vertex_normals_base_pose(MeshObject& object)
54 {
55 assert(object.get_vertex_normal_count() == 0);
56
57 const size_t vertex_count = object.get_vertex_count();
58 const size_t triangle_count = object.get_triangle_count();
59
60 vector<GVector3> normals(vertex_count, GVector3(0.0));
61
62 for (size_t i = 0; i < triangle_count; ++i)
63 {
64 Triangle& triangle = object.get_triangle(i);
65 triangle.m_n0 = triangle.m_v0;
66 triangle.m_n1 = triangle.m_v1;
67 triangle.m_n2 = triangle.m_v2;
68
69 const GVector3& v0 = object.get_vertex(triangle.m_v0);
70 const GVector3& v1 = object.get_vertex(triangle.m_v1);
71 const GVector3& v2 = object.get_vertex(triangle.m_v2);
72 const GVector3 normal = normalize(compute_triangle_normal(v0, v1, v2));
73
74 normals[triangle.m_v0] += normal;
75 normals[triangle.m_v1] += normal;
76 normals[triangle.m_v2] += normal;
77 }
78
79 object.reserve_vertex_normals(vertex_count);
80
81 for (size_t i = 0; i < vertex_count; ++i)
82 object.push_vertex_normal(safe_normalize(normals[i]));
83 }
84
compute_smooth_vertex_normals_pose(MeshObject & object,const size_t motion_segment_index)85 void compute_smooth_vertex_normals_pose(MeshObject& object, const size_t motion_segment_index)
86 {
87 const size_t vertex_count = object.get_vertex_count();
88 const size_t triangle_count = object.get_triangle_count();
89
90 vector<GVector3> normals(vertex_count, GVector3(0.0));
91
92 for (size_t i = 0; i < triangle_count; ++i)
93 {
94 const Triangle& triangle = object.get_triangle(i);
95
96 const GVector3& v0 = object.get_vertex_pose(triangle.m_v0, motion_segment_index);
97 const GVector3& v1 = object.get_vertex_pose(triangle.m_v1, motion_segment_index);
98 const GVector3& v2 = object.get_vertex_pose(triangle.m_v2, motion_segment_index);
99 const GVector3 normal = normalize(compute_triangle_normal(v0, v1, v2));
100
101 normals[triangle.m_v0] += normal;
102 normals[triangle.m_v1] += normal;
103 normals[triangle.m_v2] += normal;
104 }
105
106 for (size_t i = 0; i < vertex_count; ++i)
107 object.set_vertex_normal_pose(i, motion_segment_index, safe_normalize(normals[i]));
108 }
109
compute_smooth_vertex_normals(MeshObject & object)110 void compute_smooth_vertex_normals(MeshObject& object)
111 {
112 compute_smooth_vertex_normals_base_pose(object);
113
114 for (size_t i = 0; i < object.get_motion_segment_count(); ++i)
115 compute_smooth_vertex_normals_pose(object, i);
116 }
117
compute_smooth_vertex_tangents_base_pose(MeshObject & object)118 void compute_smooth_vertex_tangents_base_pose(MeshObject& object)
119 {
120 assert(object.get_vertex_tangent_count() == 0);
121 assert(object.get_tex_coords_count() > 0);
122
123 const size_t vertex_count = object.get_vertex_count();
124 const size_t triangle_count = object.get_triangle_count();
125
126 vector<GVector3> tangents(vertex_count, GVector3(0.0));
127
128 for (size_t i = 0; i < triangle_count; ++i)
129 {
130 const Triangle& triangle = object.get_triangle(i);
131
132 if (!triangle.has_vertex_attributes())
133 continue;
134
135 const GVector2 v0_uv = object.get_tex_coords(triangle.m_a0);
136 const GVector2 v1_uv = object.get_tex_coords(triangle.m_a1);
137 const GVector2 v2_uv = object.get_tex_coords(triangle.m_a2);
138
139 //
140 // Reference:
141 //
142 // Physically Based Rendering, first edition, pp. 128-129
143 //
144
145 const GScalar du0 = v0_uv[0] - v2_uv[0];
146 const GScalar dv0 = v0_uv[1] - v2_uv[1];
147 const GScalar du1 = v1_uv[0] - v2_uv[0];
148 const GScalar dv1 = v1_uv[1] - v2_uv[1];
149 const GScalar det = du0 * dv1 - dv0 * du1;
150
151 if (det == GScalar(0.0))
152 continue;
153
154 const GVector3& v2 = object.get_vertex(triangle.m_v2);
155 const GVector3 dp0 = object.get_vertex(triangle.m_v0) - v2;
156 const GVector3 dp1 = object.get_vertex(triangle.m_v1) - v2;
157 const GVector3 tangent = normalize(dv1 * dp0 - dv0 * dp1);
158
159 tangents[triangle.m_v0] += tangent;
160 tangents[triangle.m_v1] += tangent;
161 tangents[triangle.m_v2] += tangent;
162 }
163
164 object.reserve_vertex_tangents(vertex_count);
165
166 for (size_t i = 0; i < vertex_count; ++i)
167 object.push_vertex_tangent(safe_normalize(tangents[i]));
168 }
169
compute_smooth_vertex_tangents_pose(MeshObject & object,const size_t motion_segment_index)170 void compute_smooth_vertex_tangents_pose(MeshObject& object, const size_t motion_segment_index)
171 {
172 assert(object.get_tex_coords_count() > 0);
173
174 const size_t vertex_count = object.get_vertex_count();
175 const size_t triangle_count = object.get_triangle_count();
176
177 vector<GVector3> tangents(vertex_count, GVector3(0.0));
178
179 for (size_t i = 0; i < triangle_count; ++i)
180 {
181 const Triangle& triangle = object.get_triangle(i);
182
183 if (!triangle.has_vertex_attributes())
184 continue;
185
186 const GVector2 v0_uv = object.get_tex_coords(triangle.m_a0);
187 const GVector2 v1_uv = object.get_tex_coords(triangle.m_a1);
188 const GVector2 v2_uv = object.get_tex_coords(triangle.m_a2);
189
190 //
191 // Reference:
192 //
193 // Physically Based Rendering, first edition, pp. 128-129
194 //
195
196 const GScalar du0 = v0_uv[0] - v2_uv[0];
197 const GScalar dv0 = v0_uv[1] - v2_uv[1];
198 const GScalar du1 = v1_uv[0] - v2_uv[0];
199 const GScalar dv1 = v1_uv[1] - v2_uv[1];
200 const GScalar det = du0 * dv1 - dv0 * du1;
201
202 if (det == GScalar(0.0))
203 continue;
204
205 const GVector3& v2 = object.get_vertex_pose(triangle.m_v2, motion_segment_index);
206 const GVector3 dp0 = object.get_vertex_pose(triangle.m_v0, motion_segment_index) - v2;
207 const GVector3 dp1 = object.get_vertex_pose(triangle.m_v1, motion_segment_index) - v2;
208 const GVector3 tangent = normalize(dv1 * dp0 - dv0 * dp1);
209
210 tangents[triangle.m_v0] += tangent;
211 tangents[triangle.m_v1] += tangent;
212 tangents[triangle.m_v2] += tangent;
213 }
214
215 for (size_t i = 0; i < vertex_count; ++i)
216 object.set_vertex_tangent_pose(i, motion_segment_index, safe_normalize(tangents[i]));
217 }
218
compute_smooth_vertex_tangents(MeshObject & object)219 void compute_smooth_vertex_tangents(MeshObject& object)
220 {
221 compute_smooth_vertex_tangents_base_pose(object);
222
223 for (size_t i = 0; i < object.get_motion_segment_count(); ++i)
224 compute_smooth_vertex_tangents_pose(object, i);
225 }
226
compute_signature(MurmurHash & hash,const MeshObject & object)227 void compute_signature(MurmurHash& hash, const MeshObject& object)
228 {
229 // Static attributes.
230
231 hash.append(object.get_triangle_count());
232 for (size_t i = 0, e = object.get_triangle_count(); i < e; ++i)
233 hash.append(object.get_triangle(i));
234
235 hash.append(object.get_material_slot_count());
236 for (size_t i = 0, e = object.get_material_slot_count(); i < e; ++i)
237 hash.append(object.get_material_slot(i));
238
239 hash.append(object.get_vertex_count());
240 for (size_t i = 0, e = object.get_vertex_count(); i < e; ++i)
241 hash.append(object.get_vertex(i));
242
243 hash.append(object.get_tex_coords_count());
244 for (size_t i = 0, e = object.get_tex_coords_count(); i < e; ++i)
245 hash.append(object.get_tex_coords(i));
246
247 hash.append(object.get_vertex_normal_count());
248 for (size_t i = 0, e = object.get_vertex_normal_count(); i < e; ++i)
249 hash.append(object.get_vertex_normal(i));
250
251 hash.append(object.get_vertex_tangent_count());
252 for (size_t i = 0, e = object.get_vertex_tangent_count(); i < e; ++i)
253 hash.append(object.get_vertex_tangent(i));
254
255 // Poses.
256
257 hash.append(object.get_motion_segment_count());
258 for (size_t j = 0, je = object.get_motion_segment_count(); j < je; ++j)
259 {
260 for (size_t i = 0, e = object.get_vertex_count(); i < e; ++i)
261 hash.append(object.get_vertex_pose(i, j));
262
263 for (size_t i = 0, e = object.get_vertex_normal_count(); i < e; ++i)
264 hash.append(object.get_vertex_normal_pose(i, j));
265
266 for (size_t i = 0, e = object.get_vertex_tangent_count(); i < e; ++i)
267 hash.append(object.get_vertex_tangent_pose(i, j));
268 }
269 }
270
271 } // namespace renderer
272