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