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