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 Esteban Tovagliari, 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 #pragma once
30
31 // appleseed.renderer headers.
32 #include "renderer/global/globaltypes.h"
33
34 // appleseed.foundation headers.
35 #include "foundation/core/concepts/noncopyable.h"
36 #include "foundation/core/exceptions/exception.h"
37 #include "foundation/image/color.h"
38 #include "foundation/math/basis.h"
39 #include "foundation/math/vector.h"
40 #include "foundation/platform/compiler.h"
41
42 // OSL headers.
43 #include "foundation/platform/_beginoslheaders.h"
44 #include "OSL/dual.h"
45 #include "OSL/oslexec.h"
46 #include "foundation/platform/_endoslheaders.h"
47
48 // Standard headers.
49 #include <cassert>
50 #include <cstddef>
51
52 // Forward declarations.
53 namespace foundation { class Arena; }
54 namespace renderer { class BSDF; }
55 namespace renderer { class OSLShadingSystem; }
56
57 namespace renderer
58 {
59
60 //
61 // appleseed's closure IDs.
62 //
63
64 enum ClosureID
65 {
66 // BSDF closures.
67 AshikhminShirleyID,
68 BlinnID,
69 DiffuseID,
70 DisneyID,
71 OrenNayarID,
72 PhongID,
73 ReflectionID,
74 SheenID,
75 TranslucentID,
76
77 // Microfacet closures.
78 GlassID,
79 GlossyID,
80 MetalID,
81 PlasticID,
82
83 // BSSRDF closures.
84 SubsurfaceID,
85 SubsurfaceBetterDipoleID,
86 SubsurfaceStandardDipoleID,
87 SubsurfaceDirectionalDipoleID,
88 SubsurfaceNormalizedDiffusionID,
89 SubsurfaceGaussianID,
90 SubsurfaceRandomwalkID,
91
92 RandomwalkGlassID,
93
94 // Emission closures.
95 EmissionID,
96
97 // Special closures.
98 BackgroundID,
99 DebugID,
100 HoldoutID,
101 TransparentID,
102 MatteID,
103
104 // NPR closures.
105 NPRShadingID,
106 NPRContourID,
107
108 NumClosuresIDs
109 };
110
111
112 //
113 // Exception thrown in case of an OSL runtime error.
114 //
115
116 struct ExceptionOSLRuntimeError
117 : public foundation::Exception
118 {
ExceptionOSLRuntimeErrorExceptionOSLRuntimeError119 explicit ExceptionOSLRuntimeError(const char* what)
120 : foundation::Exception(what)
121 {
122 }
123 };
124
125
126 //
127 // Composite OSL closure base class.
128 //
129
130 class APPLESEED_ALIGN(16) CompositeClosure
131 : public foundation::NonCopyable
132 {
133 public:
134 enum { MaxClosureEntries = 16 };
135
136 size_t get_closure_count() const;
137
138 ClosureID get_closure_type(const size_t index) const;
139 void* get_closure_input_values(const size_t index) const;
140
141 const Spectrum& get_closure_weight(const size_t index) const;
142 float get_closure_scalar_weight(const size_t index) const;
143
144 const foundation::Basis3f& get_closure_shading_basis(const size_t index) const;
145
146 void override_closure_scalar_weight(const float weight);
147
148 void compute_closure_shading_basis(
149 const foundation::Vector3f& normal,
150 const foundation::Basis3f& original_shading_basis);
151
152 void compute_closure_shading_basis(
153 const foundation::Vector3f& normal,
154 const foundation::Vector3f& tangent,
155 const foundation::Basis3f& original_shading_basis);
156
157 template <typename InputValues>
158 InputValues* add_closure(
159 const ClosureID closure_type,
160 const foundation::Basis3f& original_shading_basis,
161 const foundation::Color3f& weight,
162 const foundation::Vector3f& normal,
163 foundation::Arena& arena);
164
165 template <typename InputValues>
166 InputValues* add_closure(
167 const ClosureID closure_type,
168 const foundation::Basis3f& original_shading_basis,
169 const foundation::Color3f& weight,
170 const foundation::Vector3f& normal,
171 const foundation::Vector3f& tangent,
172 foundation::Arena& arena);
173
174 protected:
175 size_t m_closure_count;
176 void* m_input_values[MaxClosureEntries];
177 ClosureID m_closure_types[MaxClosureEntries];
178 Spectrum m_weights[MaxClosureEntries];
179 float m_scalar_weights[MaxClosureEntries];
180 foundation::Basis3f m_bases[MaxClosureEntries];
181
182 CompositeClosure();
183
184 template <typename InputValues>
185 InputValues* do_add_closure(
186 const ClosureID closure_type,
187 const foundation::Basis3f& original_shading_basis,
188 const foundation::Color3f& weight,
189 const foundation::Vector3f& normal,
190 const bool has_tangent,
191 const foundation::Vector3f& tangent,
192 foundation::Arena& arena);
193
194 void compute_pdfs(float pdfs[MaxClosureEntries]);
195 };
196
197
198 //
199 // Composite OSL surface closure.
200 //
201
202 class APPLESEED_ALIGN(16) CompositeSurfaceClosure
203 : public CompositeClosure
204 {
205 public:
206 CompositeSurfaceClosure(
207 const foundation::Basis3f& original_shading_basis,
208 const OSL::ClosureColor* ci,
209 foundation::Arena& arena);
210
211 int compute_pdfs(
212 const int modes,
213 float pdf[MaxClosureEntries]) const;
214
215 size_t choose_closure(
216 const float w,
217 const size_t num_closures,
218 float pdfs[MaxClosureEntries]) const;
219
220 void add_ior(
221 const foundation::Color3f& weight,
222 const float ior);
223
224 float choose_ior(const float w) const;
225
226 private:
227 size_t m_ior_count;
228 float m_iors[MaxClosureEntries];
229 float m_ior_cdf[MaxClosureEntries];
230
231 void process_closure_tree(
232 const OSL::ClosureColor* closure,
233 const foundation::Basis3f& original_shading_basis,
234 const foundation::Color3f& weight,
235 foundation::Arena& arena);
236 };
237
238
239 //
240 // Composite OSL subsurface closure.
241 //
242
243 class APPLESEED_ALIGN(16) CompositeSubsurfaceClosure
244 : public CompositeClosure
245 {
246 public:
247 CompositeSubsurfaceClosure(
248 const foundation::Basis3f& original_shading_basis,
249 const OSL::ClosureColor* ci,
250 foundation::Arena& arena);
251
252 float get_closure_pdf(const size_t index) const;
253
254 size_t choose_closure(const float w) const;
255
256 private:
257 float m_pdfs[MaxClosureEntries];
258
259 void process_closure_tree(
260 const OSL::ClosureColor* closure,
261 const foundation::Basis3f& original_shading_basis,
262 const foundation::Color3f& weight,
263 foundation::Arena& arena);
264 };
265
266
267 //
268 // Composite OSL emission closure.
269 //
270
271 class APPLESEED_ALIGN(16) CompositeEmissionClosure
272 : public CompositeClosure
273 {
274 public:
275 CompositeEmissionClosure(
276 const OSL::ClosureColor* ci,
277 foundation::Arena& arena);
278
279 template <typename InputValues>
280 InputValues* add_closure(
281 const ClosureID closure_type,
282 const foundation::Color3f& weight,
283 const float max_weight_component,
284 foundation::Arena& arena);
285
286 float get_closure_pdf(const size_t index) const;
287
288 size_t choose_closure(const float w) const;
289
290 private:
291 float m_pdfs[MaxClosureEntries];
292
293 void process_closure_tree(
294 const OSL::ClosureColor* closure,
295 const foundation::Color3f& weight,
296 foundation::Arena& arena);
297 };
298
299
300 //
301 // Composite OSL NPR closure.
302 //
303
304 class APPLESEED_ALIGN(16) CompositeNPRClosure
305 : public CompositeClosure
306 {
307 public:
308 CompositeNPRClosure(
309 const OSL::ClosureColor* ci,
310 foundation::Arena& arena);
311
312 template <typename InputValues>
313 InputValues* add_closure(
314 const ClosureID closure_type,
315 const foundation::Color3f& weight,
316 foundation::Arena& arena);
317
318 size_t get_nth_contour_closure_index(const size_t i) const;
319
320 private:
321 void process_closure_tree(
322 const OSL::ClosureColor* closure,
323 const foundation::Color3f& weight,
324 foundation::Arena& arena);
325 };
326
327
328 //
329 // Utility functions.
330 //
331
332 void process_transparency_tree(const OSL::ClosureColor* ci, Alpha& alpha);
333
334 bool process_matte_tree(
335 const OSL::ClosureColor* ci,
336 foundation::Color3f& matte_color,
337 float& matte_alpha);
338
339 foundation::Color3f process_background_tree(const OSL::ClosureColor* ci);
340
341 void register_closures(OSLShadingSystem& shading_system);
342
343
344 //
345 // CompositeClosure class implementation.
346 //
347
get_closure_count()348 inline size_t CompositeClosure::get_closure_count() const
349 {
350 return m_closure_count;
351 }
352
get_closure_type(const size_t index)353 inline ClosureID CompositeClosure::get_closure_type(const size_t index) const
354 {
355 assert(index < get_closure_count());
356 return m_closure_types[index];
357 }
358
get_closure_input_values(const size_t index)359 inline void* CompositeClosure::get_closure_input_values(const size_t index) const
360 {
361 assert(index < get_closure_count());
362 return m_input_values[index];
363 }
364
get_closure_weight(const size_t index)365 inline const Spectrum& CompositeClosure::get_closure_weight(const size_t index) const
366 {
367 assert(index < get_closure_count());
368 return m_weights[index];
369 }
370
get_closure_scalar_weight(const size_t index)371 inline float CompositeClosure::get_closure_scalar_weight(const size_t index) const
372 {
373 assert(index < get_closure_count());
374 return m_scalar_weights[index];
375 }
376
get_closure_shading_basis(const size_t index)377 inline const foundation::Basis3f& CompositeClosure::get_closure_shading_basis(const size_t index) const
378 {
379 assert(index < get_closure_count());
380 return m_bases[index];
381 }
382
override_closure_scalar_weight(const float weight)383 inline void CompositeClosure::override_closure_scalar_weight(const float weight)
384 {
385 assert(m_closure_count > 0);
386 m_scalar_weights[m_closure_count - 1] = weight;
387 }
388
389
390 //
391 // CompositeSubsurfaceClosure class implementation.
392 //
393
get_closure_pdf(const size_t index)394 inline float CompositeSubsurfaceClosure::get_closure_pdf(const size_t index) const
395 {
396 assert(index < get_closure_count());
397 return m_pdfs[index];
398 }
399
400
401 //
402 // CompositeEmissionClosure class implementation.
403 //
404
get_closure_pdf(const size_t index)405 inline float CompositeEmissionClosure::get_closure_pdf(const size_t index) const
406 {
407 assert(index < get_closure_count());
408 return m_pdfs[index];
409 }
410
411 } // namespace renderer
412