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 // Interface header.
30 #include "closures.h"
31 
32 // appleseed.renderer headers.
33 #include "renderer/global/globallogger.h"
34 #include "renderer/kernel/npr/nprclosures.h"
35 #include "renderer/kernel/shading/oslshadingsystem.h"
36 #include "renderer/modeling/bsdf/ashikhminbrdf.h"
37 #include "renderer/modeling/bsdf/blinnbrdf.h"
38 #include "renderer/modeling/bsdf/diffusebtdf.h"
39 #include "renderer/modeling/bsdf/disneybrdf.h"
40 #include "renderer/modeling/bsdf/glassbsdf.h"
41 #include "renderer/modeling/bsdf/glossybrdf.h"
42 #include "renderer/modeling/bsdf/metalbrdf.h"
43 #include "renderer/modeling/bsdf/microfacethelper.h"
44 #include "renderer/modeling/bsdf/orennayarbrdf.h"
45 #include "renderer/modeling/bsdf/plasticbrdf.h"
46 #include "renderer/modeling/bsdf/sheenbrdf.h"
47 #include "renderer/modeling/bssrdf/dipolebssrdf.h"
48 #include "renderer/modeling/bssrdf/directionaldipolebssrdf.h"
49 #include "renderer/modeling/bssrdf/gaussianbssrdf.h"
50 #include "renderer/modeling/bssrdf/normalizeddiffusionbssrdf.h"
51 #include "renderer/modeling/bssrdf/randomwalkbssrdf.h"
52 #include "renderer/modeling/color/colorspace.h"
53 #include "renderer/modeling/edf/diffuseedf.h"
54 
55 // appleseed.foundation headers.
56 #include "foundation/math/cdf.h"
57 #include "foundation/math/fresnel.h"
58 #include "foundation/math/scalar.h"
59 #include "foundation/utility/arena.h"
60 #include "foundation/utility/memory.h"
61 #include "foundation/utility/otherwise.h"
62 
63 // OSL headers.
64 #include "foundation/platform/_beginoslheaders.h"
65 #include "OSL/genclosure.h"
66 #include "OSL/oslclosure.h"
67 #include "OSL/oslversion.h"
68 #include "foundation/platform/_endoslheaders.h"
69 
70 // Standard headers.
71 #include <algorithm>
72 #include <cmath>
73 
74 using namespace foundation;
75 using namespace renderer;
76 using namespace std;
77 
78 using OSL::TypeDesc;
79 
80 namespace renderer
81 {
82 namespace
83 {
84 
85     //
86     // Global ustrings.
87     //
88 
89     const OIIO::ustring g_beckmann_str("beckmann");
90     const OIIO::ustring g_ggx_str("ggx");
91     const OIIO::ustring g_gtr1_str("gtr1");
92     const OIIO::ustring g_std_str("std");
93 
94     const OIIO::ustring g_standard_dipole_profile_str("standard_dipole");
95     const OIIO::ustring g_better_dipole_profile_str("better_dipole");
96     const OIIO::ustring g_directional_dipole_profile_str("directional_dipole");
97     const OIIO::ustring g_normalized_diffusion_profile_str("normalized_diffusion");
98     const OIIO::ustring g_gaussian_profile_str("gaussian");
99     const OIIO::ustring g_randomwalk_profile_str("randomwalk");
100 
101     //
102     // Closure functions.
103     //
104 
105     typedef void (*convert_closure_fun)(
106         CompositeSurfaceClosure&    composite_closure,
107         const Basis3f&              shading_basis,
108         const void*                 osl_params,
109         const Color3f&              weight,
110         Arena&                      arena);
111 
112     convert_closure_fun g_closure_convert_funs[NumClosuresIDs];
113 
convert_closure_nop(CompositeSurfaceClosure & composite_closure,const Basis3f & shading_basis,const void * osl_params,const Color3f & weight,Arena & arena)114     void convert_closure_nop(
115         CompositeSurfaceClosure&    composite_closure,
116         const Basis3f&              shading_basis,
117         const void*                 osl_params,
118         const Color3f&              weight,
119         Arena&                      arena)
120     {
121     }
122 
123     typedef int (*closure_get_modes)();
124 
125     closure_get_modes g_closure_get_modes_funs[NumClosuresIDs];
126 
closure_no_modes()127     int closure_no_modes()
128     {
129         return 0;
130     }
131 
132     //
133     // Closures.
134     //
135 
136     struct AshikhminShirleyClosure
137     {
138         struct Params
139         {
140             OSL::Vec3   N;
141             OSL::Vec3   T;
142             OSL::Color3 diffuse_reflectance;
143             OSL::Color3 glossy_reflectance;
144             float       exponent_u;
145             float       exponent_v;
146             float       fresnel_multiplier;
147         };
148 
namerenderer::__anon50bdf1300111::AshikhminShirleyClosure149         static const char* name()
150         {
151             return "as_ashikhmin_shirley";
152         }
153 
idrenderer::__anon50bdf1300111::AshikhminShirleyClosure154         static ClosureID id()
155         {
156             return AshikhminShirleyID;
157         }
158 
modesrenderer::__anon50bdf1300111::AshikhminShirleyClosure159         static int modes()
160         {
161             return ScatteringMode::Diffuse | ScatteringMode::Glossy;
162         }
163 
register_closurerenderer::__anon50bdf1300111::AshikhminShirleyClosure164         static void register_closure(OSLShadingSystem& shading_system)
165         {
166             const OSL::ClosureParam params[] =
167             {
168                 CLOSURE_VECTOR_PARAM(Params, N),
169                 CLOSURE_VECTOR_PARAM(Params, T),
170                 CLOSURE_COLOR_PARAM(Params, diffuse_reflectance),
171                 CLOSURE_COLOR_PARAM(Params, glossy_reflectance),
172                 CLOSURE_FLOAT_PARAM(Params, exponent_u),
173                 CLOSURE_FLOAT_PARAM(Params, exponent_v),
174                 CLOSURE_FLOAT_PARAM(Params, fresnel_multiplier),
175                 CLOSURE_FINISH_PARAM(Params)
176             };
177 
178             shading_system.register_closure(name(), id(), params, nullptr, nullptr);
179 
180             g_closure_convert_funs[id()] = &convert_closure;
181             g_closure_get_modes_funs[id()] = &modes;
182         }
183 
convert_closurerenderer::__anon50bdf1300111::AshikhminShirleyClosure184         static void convert_closure(
185             CompositeSurfaceClosure&    composite_closure,
186             const Basis3f&              shading_basis,
187             const void*                 osl_params,
188             const Color3f&              weight,
189             Arena&                      arena)
190         {
191             const Params* p = static_cast<const Params*>(osl_params);
192 
193             AshikhminBRDFInputValues* values =
194                 composite_closure.add_closure<AshikhminBRDFInputValues>(
195                     id(),
196                     shading_basis,
197                     weight,
198                     p->N,
199                     p->T,
200                     arena);
201 
202             values->m_rd.set(Color3f(p->diffuse_reflectance), g_std_lighting_conditions, Spectrum::Reflectance);
203             values->m_rd_multiplier = 1.0f;
204             values->m_rg.set(Color3f(p->glossy_reflectance), g_std_lighting_conditions, Spectrum::Reflectance);
205             values->m_rg_multiplier = 1.0f;
206             values->m_nu = max(p->exponent_u, 0.01f);
207             values->m_nv = max(p->exponent_v, 0.01f);
208             values->m_fr_multiplier = p->fresnel_multiplier;
209         }
210     };
211 
212     struct BackgroundClosure
213     {
214         struct Params
215         {
216         };
217 
namerenderer::__anon50bdf1300111::BackgroundClosure218         static const char* name()
219         {
220             return "background";
221         }
222 
idrenderer::__anon50bdf1300111::BackgroundClosure223         static ClosureID id()
224         {
225             return BackgroundID;
226         }
227 
register_closurerenderer::__anon50bdf1300111::BackgroundClosure228         static void register_closure(OSLShadingSystem& shading_system)
229         {
230             const OSL::ClosureParam params[] =
231             {
232                 CLOSURE_FINISH_PARAM(Params)
233             };
234 
235             shading_system.register_closure(name(), id(), params, nullptr, nullptr);
236         }
237     };
238 
239     struct BlinnClosure
240     {
241         struct Params
242         {
243             OSL::Vec3       N;
244             float           exponent;
245             float           ior;
246         };
247 
namerenderer::__anon50bdf1300111::BlinnClosure248         static const char* name()
249         {
250             return "as_blinn";
251         }
252 
idrenderer::__anon50bdf1300111::BlinnClosure253         static ClosureID id()
254         {
255             return BlinnID;
256         }
257 
modesrenderer::__anon50bdf1300111::BlinnClosure258         static int modes()
259         {
260             return ScatteringMode::Glossy;
261         }
262 
register_closurerenderer::__anon50bdf1300111::BlinnClosure263         static void register_closure(OSLShadingSystem& shading_system)
264         {
265             const OSL::ClosureParam params[] =
266             {
267                 CLOSURE_VECTOR_PARAM(Params, N),
268                 CLOSURE_FLOAT_PARAM(Params, exponent),
269                 CLOSURE_FLOAT_PARAM(Params, ior),
270                 CLOSURE_FINISH_PARAM(Params)
271             };
272 
273             shading_system.register_closure(name(), id(), params, nullptr, nullptr);
274 
275             g_closure_convert_funs[id()] = &convert_closure;
276             g_closure_get_modes_funs[id()] = &modes;
277         }
278 
convert_closurerenderer::__anon50bdf1300111::BlinnClosure279         static void convert_closure(
280             CompositeSurfaceClosure&    composite_closure,
281             const Basis3f&              shading_basis,
282             const void*                 osl_params,
283             const Color3f&              weight,
284             Arena&                      arena)
285         {
286             const Params* p = static_cast<const Params*>(osl_params);
287 
288             BlinnBRDFInputValues* values =
289                 composite_closure.add_closure<BlinnBRDFInputValues>(
290                     BlinnID,
291                     shading_basis,
292                     weight,
293                     p->N,
294                     arena);
295 
296             values->m_exponent = max(p->exponent, 0.001f);
297             values->m_ior = max(p->ior, 0.001f);
298         }
299     };
300 
301     struct DebugClosure
302     {
303         struct Params
304         {
305             OSL::ustring tag;
306         };
307 
namerenderer::__anon50bdf1300111::DebugClosure308         static const char* name()
309         {
310             return "debug";
311         }
312 
idrenderer::__anon50bdf1300111::DebugClosure313         static ClosureID id()
314         {
315             return DebugID;
316         }
317 
register_closurerenderer::__anon50bdf1300111::DebugClosure318         static void register_closure(OSLShadingSystem& shading_system)
319         {
320             const OSL::ClosureParam params[] =
321             {
322                 CLOSURE_STRING_PARAM(Params, tag),
323                 CLOSURE_FINISH_PARAM(Params)
324             };
325 
326             shading_system.register_closure(name(), id(), params, nullptr, nullptr);
327         }
328     };
329 
330     struct DiffuseClosure
331     {
332         struct Params
333         {
334             OSL::Vec3   N;
335         };
336 
namerenderer::__anon50bdf1300111::DiffuseClosure337         static const char* name()
338         {
339             return "diffuse";
340         }
341 
idrenderer::__anon50bdf1300111::DiffuseClosure342         static ClosureID id()
343         {
344             return DiffuseID;
345         }
346 
modesrenderer::__anon50bdf1300111::DiffuseClosure347         static int modes()
348         {
349             return ScatteringMode::Diffuse;
350         }
351 
register_closurerenderer::__anon50bdf1300111::DiffuseClosure352         static void register_closure(OSLShadingSystem& shading_system)
353         {
354             const OSL::ClosureParam params[] =
355             {
356                 CLOSURE_VECTOR_PARAM(Params, N),
357                 CLOSURE_FINISH_PARAM(Params)
358             };
359 
360             shading_system.register_closure(name(), id(), params, nullptr, nullptr);
361 
362             g_closure_convert_funs[id()] = &convert_closure;
363             g_closure_get_modes_funs[id()] = &modes;
364         }
365 
convert_closurerenderer::__anon50bdf1300111::DiffuseClosure366         static void convert_closure(
367             CompositeSurfaceClosure&    composite_closure,
368             const Basis3f&              shading_basis,
369             const void*                 osl_params,
370             const Color3f&              weight,
371             Arena&                      arena)
372         {
373             const Params* p = static_cast<const Params*>(osl_params);
374 
375             OrenNayarBRDFInputValues* values =
376                 composite_closure.add_closure<OrenNayarBRDFInputValues>(
377                     OrenNayarID,
378                     shading_basis,
379                     weight,
380                     p->N,
381                     arena);
382 
383             values->m_reflectance.set(1.0f);
384             values->m_reflectance_multiplier = 1.0f;
385             values->m_roughness = 0.0f;
386         }
387     };
388 
389     struct DisneyClosure
390     {
391         struct Params
392         {
393             OSL::Vec3   N;
394             OSL::Vec3   T;
395             OSL::Color3 base_color;
396             float       subsurface;
397             float       metallic;
398             float       specular;
399             float       specular_tint;
400             float       anisotropic;
401             float       roughness;
402             float       sheen;
403             float       sheen_tint;
404             float       clearcoat;
405             float       clearcoat_gloss;
406         };
407 
namerenderer::__anon50bdf1300111::DisneyClosure408         static const char* name()
409         {
410             return "as_disney";
411         }
412 
idrenderer::__anon50bdf1300111::DisneyClosure413         static ClosureID id()
414         {
415             return DisneyID;
416         }
417 
modesrenderer::__anon50bdf1300111::DisneyClosure418         static int modes()
419         {
420             return ScatteringMode::Diffuse | ScatteringMode::Glossy;
421         }
422 
register_closurerenderer::__anon50bdf1300111::DisneyClosure423         static void register_closure(OSLShadingSystem& shading_system)
424         {
425             const OSL::ClosureParam params[] =
426             {
427                 CLOSURE_VECTOR_PARAM(Params, N),
428                 CLOSURE_VECTOR_PARAM(Params, T),
429                 CLOSURE_COLOR_PARAM(Params, base_color),
430                 CLOSURE_FLOAT_PARAM(Params, subsurface),
431                 CLOSURE_FLOAT_PARAM(Params, metallic),
432                 CLOSURE_FLOAT_PARAM(Params, specular),
433                 CLOSURE_FLOAT_PARAM(Params, specular_tint),
434                 CLOSURE_FLOAT_PARAM(Params, anisotropic),
435                 CLOSURE_FLOAT_PARAM(Params, roughness),
436                 CLOSURE_FLOAT_PARAM(Params, sheen),
437                 CLOSURE_FLOAT_PARAM(Params, sheen_tint),
438                 CLOSURE_FLOAT_PARAM(Params, clearcoat),
439                 CLOSURE_FLOAT_PARAM(Params, clearcoat_gloss),
440                 CLOSURE_FINISH_PARAM(Params)
441             };
442 
443             shading_system.register_closure(name(), id(), params, nullptr, nullptr);
444 
445             g_closure_convert_funs[id()] = &convert_closure;
446             g_closure_get_modes_funs[id()] = &modes;
447         }
448 
convert_closurerenderer::__anon50bdf1300111::DisneyClosure449         static void convert_closure(
450             CompositeSurfaceClosure&    composite_closure,
451             const Basis3f&              shading_basis,
452             const void*                 osl_params,
453             const Color3f&              weight,
454             Arena&                      arena)
455         {
456             const Params* p = static_cast<const Params*>(osl_params);
457 
458             DisneyBRDFInputValues* values =
459                 composite_closure.add_closure<DisneyBRDFInputValues>(
460                     id(),
461                     shading_basis,
462                     weight,
463                     p->N,
464                     p->T,
465                     arena);
466 
467             values->m_base_color.set(Color3f(p->base_color), g_std_lighting_conditions, Spectrum::Reflectance);
468             values->m_subsurface = saturate(p->subsurface);
469             values->m_metallic = saturate(p->metallic);
470             values->m_specular = max(p->specular, 0.0f);
471             values->m_specular_tint = saturate(p->specular_tint);
472             values->m_anisotropic = clamp(p->anisotropic, -1.0f, 1.0f);
473             values->m_roughness = clamp(p->roughness, 0.0001f, 1.0f);
474             values->m_sheen = saturate(p->sheen);
475             values->m_sheen_tint = saturate(p->sheen_tint);
476             values->m_clearcoat = max(p->clearcoat, 0.0f);
477             values->m_clearcoat_gloss = clamp(p->clearcoat_gloss, 0.0001f, 1.0f);
478         }
479     };
480 
481     struct EmissionClosure
482     {
483         struct Params
484         {
485         };
486 
namerenderer::__anon50bdf1300111::EmissionClosure487         static const char* name()
488         {
489             return "emission";
490         }
491 
idrenderer::__anon50bdf1300111::EmissionClosure492         static ClosureID id()
493         {
494             return EmissionID;
495         }
496 
register_closurerenderer::__anon50bdf1300111::EmissionClosure497         static void register_closure(OSLShadingSystem& shading_system)
498         {
499             const OSL::ClosureParam params[] =
500             {
501                 CLOSURE_FINISH_PARAM(Params)
502             };
503 
504             shading_system.register_closure(name(), id(), params, nullptr, nullptr);
505         }
506 
convert_closurerenderer::__anon50bdf1300111::EmissionClosure507         static void convert_closure(
508             CompositeEmissionClosure&   composite_closure,
509             const void*                 osl_params,
510             const Color3f&              weight,
511             const float                 max_weight_component,
512             Arena&                      arena)
513         {
514             DiffuseEDFInputValues* values =
515                 composite_closure.add_closure<DiffuseEDFInputValues>(
516                     id(),
517                     weight,
518                     max_weight_component,
519                     arena);
520 
521             values->m_radiance.set(Color3f(weight / max_weight_component), g_std_lighting_conditions, Spectrum::Illuminance);
522             values->m_radiance_multiplier = max_weight_component;
523             values->m_exposure = 0.0f;
524         }
525     };
526 
527     struct GlassClosure
528     {
529         struct Params
530         {
531             OSL::Vec3       N;
532             OSL::Vec3       T;
533             OSL::Color3     surface_transmittance;
534             OSL::Color3     reflection_tint;
535             OSL::Color3     refraction_tint;
536             float           roughness;
537             float           anisotropy;
538             float           ior;
539             OSL::Color3     volume_transmittance;
540             float           volume_transmittance_distance;
541             float           energy_compensation;
542         };
543 
namerenderer::__anon50bdf1300111::GlassClosure544         static const char* name()
545         {
546             return "as_glass";
547         }
548 
idrenderer::__anon50bdf1300111::GlassClosure549         static ClosureID id()
550         {
551             return GlassID;
552         }
553 
modesrenderer::__anon50bdf1300111::GlassClosure554         static int modes()
555         {
556             return ScatteringMode::Glossy | ScatteringMode::Specular;
557         }
558 
prepare_closurerenderer::__anon50bdf1300111::GlassClosure559         static void prepare_closure(
560             OSL::RendererServices*      render_services,
561             int                         id,
562             void*                       data)
563         {
564             // Initialize keyword parameter defaults.
565             Params* params = new (data) Params();
566             params->energy_compensation = 0.0f;
567         }
568 
register_closurerenderer::__anon50bdf1300111::GlassClosure569         static void register_closure(OSLShadingSystem& shading_system)
570         {
571             const OSL::ClosureParam params[] =
572             {
573                 CLOSURE_VECTOR_PARAM(Params, N),
574                 CLOSURE_VECTOR_PARAM(Params, T),
575                 CLOSURE_COLOR_PARAM(Params, surface_transmittance),
576                 CLOSURE_COLOR_PARAM(Params, reflection_tint),
577                 CLOSURE_COLOR_PARAM(Params, refraction_tint),
578                 CLOSURE_FLOAT_PARAM(Params, roughness),
579                 CLOSURE_FLOAT_PARAM(Params, anisotropy),
580                 CLOSURE_FLOAT_PARAM(Params, ior),
581                 CLOSURE_COLOR_PARAM(Params, volume_transmittance),
582                 CLOSURE_FLOAT_PARAM(Params, volume_transmittance_distance),
583                 CLOSURE_FLOAT_KEYPARAM(Params, energy_compensation, "energy_compensation"),
584                 CLOSURE_FINISH_PARAM(Params)
585             };
586 
587             shading_system.register_closure(name(), id(), params, &prepare_closure, nullptr);
588             g_closure_convert_funs[id()] = &convert_closure;
589             g_closure_get_modes_funs[id()] = &modes;
590         }
591 
convert_closurerenderer::__anon50bdf1300111::GlassClosure592         static void convert_closure(
593             CompositeSurfaceClosure&    composite_closure,
594             const Basis3f&              shading_basis,
595             const void*                 osl_params,
596             const Color3f&              weight,
597             Arena&                      arena)
598         {
599             const Params* p = static_cast<const Params*>(osl_params);
600 
601             GlassBSDFInputValues* values =
602                 composite_closure.add_closure<GlassBSDFInputValues>(
603                     id(),
604                     shading_basis,
605                     weight,
606                     p->N,
607                     p->T,
608                     arena);
609 
610             values->m_surface_transmittance.set(Color3f(p->surface_transmittance), g_std_lighting_conditions, Spectrum::Reflectance);
611             values->m_surface_transmittance_multiplier = 1.0f;
612             values->m_reflection_tint.set(Color3f(p->reflection_tint), g_std_lighting_conditions, Spectrum::Reflectance);
613             values->m_refraction_tint.set(Color3f(p->refraction_tint), g_std_lighting_conditions, Spectrum::Reflectance);
614             values->m_roughness = max(p->roughness, 0.0001f);
615             values->m_anisotropy = clamp(p->anisotropy, -1.0f, 1.0f);
616             values->m_ior = max(p->ior, 0.001f);
617             values->m_volume_transmittance.set(Color3f(p->volume_transmittance), g_std_lighting_conditions, Spectrum::Reflectance);
618             values->m_volume_transmittance_distance = p->volume_transmittance_distance;
619             values->m_energy_compensation = saturate(p->energy_compensation);
620             composite_closure.add_ior(weight, values->m_ior);
621         }
622     };
623 
624     struct GlossyClosure
625     {
626         struct Params
627         {
628             OSL::Vec3       N;
629             OSL::Vec3       T;
630             float           roughness;
631             float           anisotropy;
632             float           ior;
633             float           energy_compensation;
634             float           fresnel_weight;
635         };
636 
namerenderer::__anon50bdf1300111::GlossyClosure637         static const char* name()
638         {
639             return "as_glossy";
640         }
641 
idrenderer::__anon50bdf1300111::GlossyClosure642         static ClosureID id()
643         {
644             return GlossyID;
645         }
646 
modesrenderer::__anon50bdf1300111::GlossyClosure647         static int modes()
648         {
649             return ScatteringMode::Glossy | ScatteringMode::Specular;
650         }
651 
prepare_closurerenderer::__anon50bdf1300111::GlossyClosure652         static void prepare_closure(
653             OSL::RendererServices*      render_services,
654             int                         id,
655             void*                       data)
656         {
657             // Initialize keyword parameter defaults.
658             Params* params = new (data) Params();
659             params->energy_compensation = 0.0f;
660             params->fresnel_weight = 1.0f;
661         }
662 
register_closurerenderer::__anon50bdf1300111::GlossyClosure663         static void register_closure(OSLShadingSystem& shading_system)
664         {
665             const OSL::ClosureParam params[] =
666             {
667                 CLOSURE_VECTOR_PARAM(Params, N),
668                 CLOSURE_VECTOR_PARAM(Params, T),
669                 CLOSURE_FLOAT_PARAM(Params, roughness),
670                 CLOSURE_FLOAT_PARAM(Params, anisotropy),
671                 CLOSURE_FLOAT_PARAM(Params, ior),
672                 CLOSURE_FLOAT_KEYPARAM(Params, energy_compensation, "energy_compensation"),
673                 CLOSURE_FLOAT_KEYPARAM(Params, fresnel_weight, "fresnel_weight"),
674                 CLOSURE_FINISH_PARAM(Params)
675             };
676 
677             shading_system.register_closure(name(), id(), params, &prepare_closure, nullptr);
678             g_closure_convert_funs[id()] = &convert_closure;
679             g_closure_get_modes_funs[id()] = &modes;
680         }
681 
convert_closurerenderer::__anon50bdf1300111::GlossyClosure682         static void convert_closure(
683             CompositeSurfaceClosure&    composite_closure,
684             const Basis3f&              shading_basis,
685             const void*                 osl_params,
686             const Color3f&              weight,
687             Arena&                      arena)
688         {
689             const Params* p = static_cast<const Params*>(osl_params);
690 
691             const float roughness = saturate(p->roughness);
692             const float fresnel_weight = saturate(p->fresnel_weight);
693 
694             const float ior = max(p->ior, 0.001f);
695 
696             GlossyBRDFInputValues* values =
697                 composite_closure.add_closure<GlossyBRDFInputValues>(
698                     id(),
699                     shading_basis,
700                     weight,
701                     p->N,
702                     p->T,
703                     arena);
704 
705             composite_closure.override_closure_scalar_weight(
706                 luminance(weight) * sample_weight(roughness, ior, fresnel_weight));
707 
708             values->m_reflectance.set(1.0f);
709             values->m_reflectance_multiplier = 1.0f;
710             values->m_roughness = roughness;
711             values->m_anisotropy = clamp(p->anisotropy, -1.0f, 1.0f);
712             values->m_ior = ior;
713             values->m_fresnel_weight = fresnel_weight;
714             values->m_energy_compensation = saturate(p->energy_compensation);
715         }
716 
sample_weightrenderer::__anon50bdf1300111::GlossyClosure717         static float sample_weight(
718             const float                 roughness,
719             const float                 ior,
720             const float                 fresnel_weight)
721         {
722             const float eavg = get_average_albedo(roughness);
723             const float favg = lerp(
724                 1.0f,
725                 average_fresnel_reflectance_dielectric(ior),
726                 fresnel_weight);
727             return eavg * favg;
728         }
729     };
730 
731     struct HoldoutClosure
732     {
733         struct Params
734         {
735         };
736 
namerenderer::__anon50bdf1300111::HoldoutClosure737         static const char* name()
738         {
739             return "holdout";
740         }
741 
idrenderer::__anon50bdf1300111::HoldoutClosure742         static ClosureID id()
743         {
744             return HoldoutID;
745         }
746 
register_closurerenderer::__anon50bdf1300111::HoldoutClosure747         static void register_closure(OSLShadingSystem& shading_system)
748         {
749             const OSL::ClosureParam params[] =
750             {
751                 CLOSURE_FINISH_PARAM(Params)
752             };
753 
754             shading_system.register_closure(name(), id(), params, nullptr, nullptr);
755         }
756     };
757 
758     struct MatteClosure
759     {
760         struct Params
761         {
762             OSL::Color3 matte_color;
763             float       matte_alpha;
764         };
765 
namerenderer::__anon50bdf1300111::MatteClosure766         static const char* name()
767         {
768             return "as_matte";
769         }
770 
idrenderer::__anon50bdf1300111::MatteClosure771         static ClosureID id()
772         {
773             return MatteID;
774         }
775 
prepare_closurerenderer::__anon50bdf1300111::MatteClosure776         static void prepare_closure(
777             OSL::RendererServices*      render_services,
778             int                         id,
779             void*                       data)
780         {
781             // Initialize keyword parameter defaults.
782             Params* params = new (data) Params();
783             params->matte_color = OSL::Color3(0.0f);
784             params->matte_alpha = 0.0f;
785         }
786 
register_closurerenderer::__anon50bdf1300111::MatteClosure787         static void register_closure(OSLShadingSystem& shading_system)
788         {
789             const OSL::ClosureParam params[] =
790             {
791                 CLOSURE_COLOR_PARAM(Params, matte_color),
792                 CLOSURE_FLOAT_PARAM(Params, matte_alpha),
793                 CLOSURE_FINISH_PARAM(Params)
794             };
795 
796             shading_system.register_closure(name(), id(), params, nullptr, nullptr);
797         }
798     };
799 
800     struct MetalClosure
801     {
802         struct Params
803         {
804             OSL::Vec3       N;
805             OSL::Vec3       T;
806             OSL::Color3     normal_reflectance;
807             OSL::Color3     edge_tint;
808             float           roughness;
809             float           anisotropy;
810             float           energy_compensation;
811         };
812 
namerenderer::__anon50bdf1300111::MetalClosure813         static const char* name()
814         {
815             return "as_metal";
816         }
817 
idrenderer::__anon50bdf1300111::MetalClosure818         static ClosureID id()
819         {
820             return MetalID;
821         }
822 
modesrenderer::__anon50bdf1300111::MetalClosure823         static int modes()
824         {
825             return ScatteringMode::Glossy | ScatteringMode::Specular;
826         }
827 
prepare_closurerenderer::__anon50bdf1300111::MetalClosure828         static void prepare_closure(
829             OSL::RendererServices*      render_services,
830             int                         id,
831             void*                       data)
832         {
833             // Initialize keyword parameter defaults.
834             Params* params = new (data) Params();
835             params->energy_compensation = 0.0f;
836         }
837 
register_closurerenderer::__anon50bdf1300111::MetalClosure838         static void register_closure(OSLShadingSystem& shading_system)
839         {
840             const OSL::ClosureParam params[] =
841             {
842                 CLOSURE_VECTOR_PARAM(Params, N),
843                 CLOSURE_VECTOR_PARAM(Params, T),
844                 CLOSURE_COLOR_PARAM(Params, normal_reflectance),
845                 CLOSURE_COLOR_PARAM(Params, edge_tint),
846                 CLOSURE_FLOAT_PARAM(Params, roughness),
847                 CLOSURE_FLOAT_PARAM(Params, anisotropy),
848                 CLOSURE_FLOAT_KEYPARAM(Params, energy_compensation, "energy_compensation"),
849                 CLOSURE_FINISH_PARAM(Params)
850             };
851 
852             shading_system.register_closure(name(), id(), params, &prepare_closure, nullptr);
853             g_closure_convert_funs[id()] = &convert_closure;
854             g_closure_get_modes_funs[id()] = &modes;
855         }
856 
convert_closurerenderer::__anon50bdf1300111::MetalClosure857         static void convert_closure(
858             CompositeSurfaceClosure&    composite_closure,
859             const Basis3f&              shading_basis,
860             const void*                 osl_params,
861             const Color3f&              weight,
862             Arena&                      arena)
863         {
864             const Params* p = static_cast<const Params*>(osl_params);
865 
866             MetalBRDFInputValues* values =
867                 composite_closure.add_closure<MetalBRDFInputValues>(
868                     id(),
869                     shading_basis,
870                     weight,
871                     p->N,
872                     p->T,
873                     arena);
874 
875             values->m_normal_reflectance.set(Color3f(p->normal_reflectance), g_std_lighting_conditions, Spectrum::Reflectance);
876             values->m_edge_tint.set(Color3f(p->edge_tint), g_std_lighting_conditions, Spectrum::Reflectance);
877             values->m_reflectance_multiplier = 1.0f;
878             values->m_roughness = max(p->roughness, 0.0f);
879             values->m_anisotropy = clamp(p->anisotropy, -1.0f, 1.0f);
880             values->m_energy_compensation = saturate(p->energy_compensation);
881         }
882     };
883 
884     struct OrenNayarClosure
885     {
886         struct Params
887         {
888             OSL::Color3 reflectance;
889             OSL::Vec3   N;
890             float       roughness;
891         };
892 
namerenderer::__anon50bdf1300111::OrenNayarClosure893         static const char* name()
894         {
895             return "as_oren_nayar";
896         }
897 
idrenderer::__anon50bdf1300111::OrenNayarClosure898         static ClosureID id()
899         {
900             return OrenNayarID;
901         }
902 
modesrenderer::__anon50bdf1300111::OrenNayarClosure903         static int modes()
904         {
905             return ScatteringMode::Diffuse;
906         }
907 
register_closurerenderer::__anon50bdf1300111::OrenNayarClosure908         static void register_closure(OSLShadingSystem& shading_system)
909         {
910             const OSL::ClosureParam params[] =
911             {
912                 CLOSURE_COLOR_PARAM(Params, reflectance),
913                 CLOSURE_VECTOR_PARAM(Params, N),
914                 CLOSURE_FLOAT_PARAM(Params, roughness),
915                 CLOSURE_FINISH_PARAM(Params)
916             };
917 
918             shading_system.register_closure(name(), id(), params, nullptr, nullptr);
919 
920             g_closure_convert_funs[id()] = &convert_closure;
921             g_closure_get_modes_funs[id()] = &modes;
922         }
923 
convert_closurerenderer::__anon50bdf1300111::OrenNayarClosure924         static void convert_closure(
925             CompositeSurfaceClosure&    composite_closure,
926             const Basis3f&              shading_basis,
927             const void*                 osl_params,
928             const Color3f&              weight,
929             Arena&                      arena)
930         {
931             const Params* p = static_cast<const Params*>(osl_params);
932 
933             OrenNayarBRDFInputValues* values =
934                 composite_closure.add_closure<OrenNayarBRDFInputValues>(
935                     id(),
936                     shading_basis,
937                     weight,
938                     p->N,
939                     arena);
940 
941             const Color3f reflectance = Color3f(p->reflectance);
942             values->m_reflectance.set(reflectance, g_std_lighting_conditions, Spectrum::Reflectance);
943             values->m_reflectance_multiplier = 1.0f;
944             values->m_roughness = max(p->roughness, 0.0f);
945 
946             const float w = luminance(weight) * luminance(reflectance);
947             composite_closure.override_closure_scalar_weight(w);
948         }
949     };
950 
951     struct PhongClosure
952     {
953         struct Params
954         {
955             OSL::Vec3   N;
956             float       exponent;
957         };
958 
namerenderer::__anon50bdf1300111::PhongClosure959         static const char* name()
960         {
961             return "phong";
962         }
963 
idrenderer::__anon50bdf1300111::PhongClosure964         static ClosureID id()
965         {
966             return PhongID;
967         }
968 
modesrenderer::__anon50bdf1300111::PhongClosure969         static int modes()
970         {
971             return ScatteringMode::Glossy;
972         }
973 
register_closurerenderer::__anon50bdf1300111::PhongClosure974         static void register_closure(OSLShadingSystem& shading_system)
975         {
976             const OSL::ClosureParam params[] =
977             {
978                 CLOSURE_VECTOR_PARAM(Params, N),
979                 CLOSURE_FLOAT_PARAM(Params, exponent),
980                 CLOSURE_FINISH_PARAM(Params)
981             };
982 
983             shading_system.register_closure(name(), id(), params, nullptr, nullptr);
984 
985             g_closure_convert_funs[id()] = &convert_closure;
986             g_closure_get_modes_funs[id()] = &modes;
987         }
988 
convert_closurerenderer::__anon50bdf1300111::PhongClosure989         static void convert_closure(
990             CompositeSurfaceClosure&    composite_closure,
991             const Basis3f&              shading_basis,
992             const void*                 osl_params,
993             const Color3f&              weight,
994             Arena&                      arena)
995         {
996             const Params* p = static_cast<const Params*>(osl_params);
997 
998             AshikhminBRDFInputValues* values =
999                 composite_closure.add_closure<AshikhminBRDFInputValues>(
1000                     AshikhminShirleyID,
1001                     shading_basis,
1002                     weight,
1003                     p->N,
1004                     arena);
1005 
1006             values->m_rd.set(1.0f);
1007             values->m_rd_multiplier = 1.0f;
1008             values->m_rg.set(1.0f);
1009             values->m_rg_multiplier = 1.0f;
1010             values->m_nu = max(p->exponent, 0.01f);
1011             values->m_nv = max(p->exponent, 0.01f);
1012             values->m_fr_multiplier = 1.0f;
1013         }
1014     };
1015 
1016     struct PlasticClosure
1017     {
1018         struct Params
1019         {
1020             OSL::Vec3       N;
1021             OSL::Color3     specular_reflectance;
1022             float           specular_reflectance_multiplier;
1023             float           roughness;
1024             float           ior;
1025             OSL::Color3     diffuse_reflectance;
1026             float           diffuse_reflectance_multiplier;
1027             float           internal_scattering;
1028         };
1029 
namerenderer::__anon50bdf1300111::PlasticClosure1030         static const char* name()
1031         {
1032             return "as_plastic";
1033         }
1034 
idrenderer::__anon50bdf1300111::PlasticClosure1035         static ClosureID id()
1036         {
1037             return PlasticID;
1038         }
1039 
modesrenderer::__anon50bdf1300111::PlasticClosure1040         static int modes()
1041         {
1042             return ScatteringMode::Diffuse | ScatteringMode::Glossy | ScatteringMode::Specular;
1043         }
1044 
register_closurerenderer::__anon50bdf1300111::PlasticClosure1045         static void register_closure(OSLShadingSystem& shading_system)
1046         {
1047             const OSL::ClosureParam params[] =
1048             {
1049                 CLOSURE_VECTOR_PARAM(Params, N),
1050                 CLOSURE_COLOR_PARAM(Params, specular_reflectance),
1051                 CLOSURE_FLOAT_PARAM(Params, specular_reflectance_multiplier),
1052                 CLOSURE_FLOAT_PARAM(Params, roughness),
1053                 CLOSURE_FLOAT_PARAM(Params, ior),
1054                 CLOSURE_COLOR_PARAM(Params, diffuse_reflectance),
1055                 CLOSURE_FLOAT_PARAM(Params, diffuse_reflectance_multiplier),
1056                 CLOSURE_FLOAT_PARAM(Params, internal_scattering),
1057                 CLOSURE_FINISH_PARAM(Params)
1058             };
1059 
1060             shading_system.register_closure(name(), id(), params, nullptr, nullptr);
1061             g_closure_convert_funs[id()] = &convert_closure;
1062             g_closure_get_modes_funs[id()] = &modes;
1063         }
1064 
convert_closurerenderer::__anon50bdf1300111::PlasticClosure1065         static void convert_closure(
1066             CompositeSurfaceClosure&    composite_closure,
1067             const Basis3f&              shading_basis,
1068             const void*                 osl_params,
1069             const Color3f&              weight,
1070             Arena&                      arena)
1071         {
1072             const Params* p = static_cast<const Params*>(osl_params);
1073 
1074             PlasticBRDFInputValues* values =
1075                 composite_closure.add_closure<PlasticBRDFInputValues>(
1076                     id(),
1077                     shading_basis,
1078                     weight,
1079                     p->N,
1080                     arena);
1081 
1082             values->m_specular_reflectance.set(Color3f(p->specular_reflectance), g_std_lighting_conditions,
1083             Spectrum::Reflectance);
1084             values->m_specular_reflectance_multiplier = max(p->specular_reflectance_multiplier, 0.0f);
1085             values->m_roughness = clamp(p->roughness, 0.0001f, 1.0f);
1086             values->m_ior = max(p->ior, 0.001f);
1087             values->m_diffuse_reflectance.set(Color3f(p->diffuse_reflectance), g_std_lighting_conditions,
1088             Spectrum::Reflectance);
1089             values->m_diffuse_reflectance_multiplier = max(p->diffuse_reflectance_multiplier, 0.0f);
1090             values->m_internal_scattering = max(p->internal_scattering, 0.0f);
1091         }
1092     };
1093 
1094     struct ReflectionClosure
1095     {
1096         struct Params
1097         {
1098             OSL::Vec3       N;
1099             float           ior;
1100         };
1101 
namerenderer::__anon50bdf1300111::ReflectionClosure1102         static const char* name()
1103         {
1104             return "reflection";
1105         }
1106 
idrenderer::__anon50bdf1300111::ReflectionClosure1107         static ClosureID id()
1108         {
1109             return ReflectionID;
1110         }
1111 
modesrenderer::__anon50bdf1300111::ReflectionClosure1112         static int modes()
1113         {
1114             return ScatteringMode::Specular;
1115         }
1116 
register_closurerenderer::__anon50bdf1300111::ReflectionClosure1117         static void register_closure(OSLShadingSystem& shading_system)
1118         {
1119             const OSL::ClosureParam params[] =
1120             {
1121                 CLOSURE_VECTOR_PARAM(Params, N),
1122                 CLOSURE_FLOAT_PARAM(Params, ior),
1123                 CLOSURE_FINISH_PARAM(Params)
1124             };
1125 
1126             shading_system.register_closure(name(), id(), params, nullptr, nullptr);
1127 
1128             g_closure_convert_funs[id()] = &convert_closure;
1129             g_closure_get_modes_funs[id()] = &modes;
1130         }
1131 
convert_closurerenderer::__anon50bdf1300111::ReflectionClosure1132         static void convert_closure(
1133             CompositeSurfaceClosure&    composite_closure,
1134             const Basis3f&              shading_basis,
1135             const void*                 osl_params,
1136             const Color3f&              weight,
1137             Arena&                      arena)
1138         {
1139             const Params* p = static_cast<const Params*>(osl_params);
1140 
1141             GlossyBRDFInputValues* values =
1142                 composite_closure.add_closure<GlossyBRDFInputValues>(
1143                     GlossyID,
1144                     shading_basis,
1145                     weight,
1146                     p->N,
1147                     arena);
1148 
1149             values->m_reflectance.set(1.0f);
1150             values->m_reflectance_multiplier = 1.0f;
1151             values->m_roughness = 0.0f;
1152             values->m_anisotropy = 0.0f;
1153             values->m_ior = max(p->ior, 0.001f);
1154             values->m_energy_compensation = 0.0f;
1155         }
1156     };
1157 
1158     struct SheenClosure
1159     {
1160         struct Params
1161         {
1162             OSL::Vec3 N;
1163         };
1164 
namerenderer::__anon50bdf1300111::SheenClosure1165         static const char* name()
1166         {
1167             return "as_sheen";
1168         }
1169 
idrenderer::__anon50bdf1300111::SheenClosure1170         static ClosureID id()
1171         {
1172             return SheenID;
1173         }
1174 
modesrenderer::__anon50bdf1300111::SheenClosure1175         static int modes()
1176         {
1177             return ScatteringMode::Diffuse;
1178         }
1179 
register_closurerenderer::__anon50bdf1300111::SheenClosure1180         static void register_closure(OSLShadingSystem& shading_system)
1181         {
1182             const OSL::ClosureParam params[] =
1183             {
1184                 CLOSURE_VECTOR_PARAM(Params, N),
1185                 CLOSURE_FINISH_PARAM(Params)
1186             };
1187 
1188             shading_system.register_closure(name(), id(), params, nullptr, nullptr);
1189 
1190             g_closure_convert_funs[id()] = &convert_closure;
1191             g_closure_get_modes_funs[id()] = &modes;
1192         }
1193 
convert_closurerenderer::__anon50bdf1300111::SheenClosure1194         static void convert_closure(
1195             CompositeSurfaceClosure&    composite_closure,
1196             const Basis3f&              shading_basis,
1197             const void*                 osl_params,
1198             const Color3f&              weight,
1199             Arena&                      arena)
1200         {
1201             const Params* p = static_cast<const Params*>(osl_params);
1202 
1203             SheenBRDFInputValues* values =
1204                 composite_closure.add_closure<SheenBRDFInputValues>(
1205                     id(),
1206                     shading_basis,
1207                     weight,
1208                     p->N,
1209                     arena);
1210 
1211             values->m_reflectance.set(1.0f);
1212             values->m_reflectance_multiplier = 1.0f;
1213         }
1214     };
1215 
1216     struct SubsurfaceClosure
1217     {
1218         struct Params
1219         {
1220             OSL::ustring    profile;
1221             OSL::Vec3       N;
1222             OSL::Color3     reflectance;
1223             OSL::Color3     mean_free_path;
1224             float           ior;
1225             float           fresnel_weight;
1226             float           volume_anisotropy;
1227         };
1228 
namerenderer::__anon50bdf1300111::SubsurfaceClosure1229         static const char* name()
1230         {
1231             return "as_subsurface";
1232         }
1233 
idrenderer::__anon50bdf1300111::SubsurfaceClosure1234         static ClosureID id()
1235         {
1236             return SubsurfaceID;
1237         }
1238 
prepare_closurerenderer::__anon50bdf1300111::SubsurfaceClosure1239         static void prepare_closure(
1240             OSL::RendererServices*      render_services,
1241             int                         id,
1242             void*                       data)
1243         {
1244             // Initialize keyword parameter defaults.
1245             Params* params = new (data) Params();
1246             params->fresnel_weight = 1.0f;
1247             params->volume_anisotropy = 0.0f;
1248         }
1249 
register_closurerenderer::__anon50bdf1300111::SubsurfaceClosure1250         static void register_closure(OSLShadingSystem& shading_system)
1251         {
1252             const OSL::ClosureParam params[] =
1253             {
1254                 CLOSURE_STRING_PARAM(Params, profile),
1255                 CLOSURE_VECTOR_PARAM(Params, N),
1256                 CLOSURE_COLOR_PARAM(Params, reflectance),
1257                 CLOSURE_COLOR_PARAM(Params, mean_free_path),
1258                 CLOSURE_FLOAT_PARAM(Params, ior),
1259                 CLOSURE_FLOAT_KEYPARAM(Params, fresnel_weight, "fresnel_weight"),
1260                 CLOSURE_FLOAT_KEYPARAM(Params, volume_anisotropy, "volume_anisotropy"),
1261                 CLOSURE_FINISH_PARAM(Params)
1262             };
1263 
1264             shading_system.register_closure(name(), id(), params, &prepare_closure, nullptr);
1265         }
1266 
convert_closurerenderer::__anon50bdf1300111::SubsurfaceClosure1267         static void convert_closure(
1268             CompositeSubsurfaceClosure& composite_closure,
1269             const Basis3f&              shading_basis,
1270             const void*                 osl_params,
1271             const Color3f&              weight,
1272             Arena&                      arena)
1273         {
1274             const Params* p = static_cast<const Params*>(osl_params);
1275 
1276             if (p->profile == g_standard_dipole_profile_str)
1277             {
1278                 DipoleBSSRDFInputValues* values =
1279                     composite_closure.add_closure<DipoleBSSRDFInputValues>(
1280                         SubsurfaceStandardDipoleID,
1281                         shading_basis,
1282                         weight,
1283                         p->N,
1284                         arena);
1285 
1286                 copy_parameters(p, values);
1287             }
1288             else if (p->profile == g_better_dipole_profile_str)
1289             {
1290                 DipoleBSSRDFInputValues* values =
1291                     composite_closure.add_closure<DipoleBSSRDFInputValues>(
1292                         SubsurfaceBetterDipoleID,
1293                         shading_basis,
1294                         weight,
1295                         p->N,
1296                         arena);
1297 
1298                 copy_parameters(p, values);
1299             }
1300             else if (p->profile == g_directional_dipole_profile_str)
1301             {
1302                 DipoleBSSRDFInputValues* values =
1303                     composite_closure.add_closure<DipoleBSSRDFInputValues>(
1304                         SubsurfaceDirectionalDipoleID,
1305                         shading_basis,
1306                         weight,
1307                         p->N,
1308                         arena);
1309 
1310                 copy_parameters(p, values);
1311             }
1312             else if (p->profile == g_normalized_diffusion_profile_str)
1313             {
1314                 NormalizedDiffusionBSSRDFInputValues* values =
1315                     composite_closure.add_closure<NormalizedDiffusionBSSRDFInputValues>(
1316                         SubsurfaceNormalizedDiffusionID,
1317                         shading_basis,
1318                         weight,
1319                         p->N,
1320                         arena);
1321 
1322                 copy_parameters(p, values);
1323             }
1324             else if (p->profile == g_gaussian_profile_str)
1325             {
1326                 GaussianBSSRDFInputValues* values =
1327                     composite_closure.add_closure<GaussianBSSRDFInputValues>(
1328                         SubsurfaceGaussianID,
1329                         shading_basis,
1330                         weight,
1331                         p->N,
1332                         arena);
1333 
1334                 copy_parameters(p, values);
1335             }
1336             else if (p->profile == g_randomwalk_profile_str)
1337             {
1338                 RandomwalkBSSRDFInputValues* values =
1339                     composite_closure.add_closure<RandomwalkBSSRDFInputValues>(
1340                         SubsurfaceRandomwalkID,
1341                         shading_basis,
1342                         weight,
1343                         p->N,
1344                         arena);
1345 
1346                 copy_parameters(p, values);
1347                 values->m_volume_anisotropy = clamp(p->volume_anisotropy, -0.999f, 0.999f);
1348             }
1349             else
1350             {
1351                 string msg = "unknown subsurface profile: ";
1352                 msg += p->profile.c_str();
1353                 throw ExceptionOSLRuntimeError(msg.c_str());
1354             }
1355         }
1356 
1357         template <typename InputValues>
copy_parametersrenderer::__anon50bdf1300111::SubsurfaceClosure1358         static void copy_parameters(
1359             const Params*               p,
1360             InputValues*                values)
1361         {
1362             values->m_weight = 1.0f;
1363             values->m_reflectance.set(Color3f(p->reflectance), g_std_lighting_conditions, Spectrum::Reflectance);
1364             values->m_reflectance_multiplier = 1.0f;
1365             values->m_mfp.set(Color3f(p->mean_free_path), g_std_lighting_conditions, Spectrum::Reflectance);
1366             values->m_mfp_multiplier = 1.0f;
1367             values->m_ior = p->ior;
1368             values->m_fresnel_weight = saturate(p->fresnel_weight);
1369         }
1370     };
1371 
1372     struct RandomwalkGlassClosure
1373     {
1374         struct Params
1375         {
1376             OSL::Vec3       N;
1377             OSL::Color3     reflectance;
1378             OSL::Color3     mean_free_path;
1379             float           ior;
1380             float           surface_roughness;
1381             float           volume_anisotropy;
1382         };
1383 
namerenderer::__anon50bdf1300111::RandomwalkGlassClosure1384         static const char* name()
1385         {
1386             return "as_randomwalk_glass";
1387         }
1388 
idrenderer::__anon50bdf1300111::RandomwalkGlassClosure1389         static ClosureID id()
1390         {
1391             return RandomwalkGlassID;
1392         }
1393 
prepare_closurerenderer::__anon50bdf1300111::RandomwalkGlassClosure1394         static void prepare_closure(
1395             OSL::RendererServices*      render_services,
1396             int                         id,
1397             void*                       data)
1398         {
1399             // Initialize keyword parameter defaults.
1400             Params* params = new (data) Params();
1401             params->volume_anisotropy = 0.0f;
1402         }
1403 
register_closurerenderer::__anon50bdf1300111::RandomwalkGlassClosure1404         static void register_closure(OSLShadingSystem& shading_system)
1405         {
1406             const OSL::ClosureParam params[] =
1407             {
1408                 CLOSURE_VECTOR_PARAM(Params, N),
1409                 CLOSURE_COLOR_PARAM(Params, reflectance),
1410                 CLOSURE_COLOR_PARAM(Params, mean_free_path),
1411                 CLOSURE_FLOAT_PARAM(Params, ior),
1412                 CLOSURE_FLOAT_PARAM(Params, surface_roughness),
1413                 CLOSURE_FLOAT_KEYPARAM(Params, volume_anisotropy, "volume_anisotropy"),
1414                 CLOSURE_FINISH_PARAM(Params)
1415             };
1416 
1417             shading_system.register_closure(name(), id(), params, &prepare_closure, nullptr);
1418         }
1419 
convert_closurerenderer::__anon50bdf1300111::RandomwalkGlassClosure1420         static void convert_closure(
1421             CompositeSubsurfaceClosure& composite_closure,
1422             const Basis3f&              shading_basis,
1423             const void*                 osl_params,
1424             const Color3f&              weight,
1425             Arena&                      arena)
1426         {
1427             const Params* p = static_cast<const Params*>(osl_params);
1428 
1429             RandomwalkBSSRDFInputValues* values =
1430                 composite_closure.add_closure<RandomwalkBSSRDFInputValues>(
1431                     RandomwalkGlassID,
1432                     shading_basis,
1433                     weight,
1434                     p->N,
1435                     arena);
1436 
1437             copy_parameters(p, values);
1438         }
1439 
copy_parametersrenderer::__anon50bdf1300111::RandomwalkGlassClosure1440         static void copy_parameters(
1441             const Params*                   p,
1442             RandomwalkBSSRDFInputValues*    values)
1443         {
1444             values->m_weight = 1.0f;
1445             values->m_reflectance.set(Color3f(p->reflectance), g_std_lighting_conditions, Spectrum::Reflectance);
1446             values->m_reflectance_multiplier = 1.0f;
1447             values->m_mfp.set(Color3f(p->mean_free_path), g_std_lighting_conditions, Spectrum::Reflectance);
1448             values->m_mfp_multiplier = 1.0f;
1449             values->m_ior = p->ior;
1450             values->m_surface_roughness = clamp(p->surface_roughness, 0.0001f, 1.0f);
1451             values->m_fresnel_weight = 1.0f;
1452             values->m_volume_anisotropy = clamp(p->volume_anisotropy, -0.999f, 0.999f);
1453         }
1454     };
1455 
1456     struct TranslucentClosure
1457     {
1458         struct Params
1459         {
1460             OSL::Vec3 N;
1461         };
1462 
namerenderer::__anon50bdf1300111::TranslucentClosure1463         static const char* name()
1464         {
1465             return "translucent";
1466         }
1467 
idrenderer::__anon50bdf1300111::TranslucentClosure1468         static ClosureID id()
1469         {
1470             return TranslucentID;
1471         }
1472 
modesrenderer::__anon50bdf1300111::TranslucentClosure1473         static int modes()
1474         {
1475             return ScatteringMode::Diffuse;
1476         }
1477 
register_closurerenderer::__anon50bdf1300111::TranslucentClosure1478         static void register_closure(OSLShadingSystem& shading_system)
1479         {
1480             const OSL::ClosureParam params[] =
1481             {
1482                 CLOSURE_VECTOR_PARAM(Params, N),
1483                 CLOSURE_FINISH_PARAM(Params)
1484             };
1485 
1486             shading_system.register_closure(name(), id(), params, nullptr, nullptr);
1487 
1488             g_closure_convert_funs[id()] = &convert_closure;
1489             g_closure_get_modes_funs[id()] = &modes;
1490         }
1491 
convert_closurerenderer::__anon50bdf1300111::TranslucentClosure1492         static void convert_closure(
1493             CompositeSurfaceClosure&    composite_closure,
1494             const Basis3f&              shading_basis,
1495             const void*                 osl_params,
1496             const Color3f&              weight,
1497             Arena&                      arena)
1498         {
1499             const Params* p = static_cast<const Params*>(osl_params);
1500 
1501             DiffuseBTDFInputValues* values =
1502                 composite_closure.add_closure<DiffuseBTDFInputValues>(
1503                     id(),
1504                     shading_basis,
1505                     weight,
1506                     p->N,
1507                     arena);
1508 
1509             values->m_transmittance.set(1.0f);
1510             values->m_transmittance_multiplier = 1.0f;
1511         }
1512     };
1513 
1514     struct TransparentClosure
1515     {
1516         struct Params
1517         {
1518         };
1519 
namerenderer::__anon50bdf1300111::TransparentClosure1520         static const char* name()
1521         {
1522             return "transparent";
1523         }
1524 
idrenderer::__anon50bdf1300111::TransparentClosure1525         static ClosureID id()
1526         {
1527             return TransparentID;
1528         }
1529 
register_closurerenderer::__anon50bdf1300111::TransparentClosure1530         static void register_closure(OSLShadingSystem& shading_system)
1531         {
1532             const OSL::ClosureParam params[] =
1533             {
1534                 CLOSURE_FINISH_PARAM(Params)
1535             };
1536 
1537             shading_system.register_closure(name(), id(), params, nullptr, nullptr);
1538         }
1539     };
1540 
1541     //
1542     // NPR closures.
1543     //
1544 
1545     struct NPRShadingClosure
1546     {
1547         struct Params
1548         {
1549         };
1550 
namerenderer::__anon50bdf1300111::NPRShadingClosure1551         static const char* name()
1552         {
1553             return "as_npr_shading";
1554         }
1555 
idrenderer::__anon50bdf1300111::NPRShadingClosure1556         static ClosureID id()
1557         {
1558             return NPRShadingID;
1559         }
1560 
register_closurerenderer::__anon50bdf1300111::NPRShadingClosure1561         static void register_closure(OSLShadingSystem& shading_system)
1562         {
1563             const OSL::ClosureParam params[] =
1564             {
1565                 CLOSURE_FINISH_PARAM(Params)
1566             };
1567 
1568             shading_system.register_closure(name(), id(), params, nullptr, nullptr);
1569         }
1570 
convert_closurerenderer::__anon50bdf1300111::NPRShadingClosure1571         static void convert_closure(
1572             CompositeNPRClosure&    composite_closure,
1573             const void*             osl_params,
1574             const Color3f&          weight,
1575             Arena&                  arena)
1576         {
1577             composite_closure.add_closure<NPRShadingInputValues>(id(), weight, arena);
1578         }
1579     };
1580 
1581     struct NPRContourClosure
1582     {
1583         struct Params
1584         {
1585             OSL::Color3 contour_color;
1586             float       contour_opacity;
1587             float       contour_width;
1588             int         object_id;
1589             int         material_id;
1590             int         occlusion;
1591             float       occlusion_threshold;
1592             int         creases;
1593             float       creases_threshold;
1594             int         quality;
1595         };
1596 
namerenderer::__anon50bdf1300111::NPRContourClosure1597         static const char* name()
1598         {
1599             return "as_npr_contour";
1600         }
1601 
idrenderer::__anon50bdf1300111::NPRContourClosure1602         static ClosureID id()
1603         {
1604             return NPRContourID;
1605         }
1606 
prepare_closurerenderer::__anon50bdf1300111::NPRContourClosure1607         static void prepare_closure(
1608             OSL::RendererServices*      render_services,
1609             int                         id,
1610             void*                       data)
1611         {
1612             // Initialize keyword parameter defaults.
1613             Params* params = new (data) Params();
1614             params->quality = 1;
1615         }
1616 
register_closurerenderer::__anon50bdf1300111::NPRContourClosure1617         static void register_closure(OSLShadingSystem& shading_system)
1618         {
1619             const OSL::ClosureParam params[] =
1620             {
1621                 CLOSURE_COLOR_PARAM(Params, contour_color),
1622                 CLOSURE_FLOAT_PARAM(Params, contour_opacity),
1623                 CLOSURE_FLOAT_PARAM(Params, contour_width),
1624                 CLOSURE_INT_PARAM(Params, object_id),
1625                 CLOSURE_INT_PARAM(Params, material_id),
1626 
1627                 CLOSURE_INT_PARAM(Params, occlusion),
1628                 CLOSURE_FLOAT_PARAM(Params, occlusion_threshold),
1629                 CLOSURE_INT_PARAM(Params, creases),
1630                 CLOSURE_FLOAT_PARAM(Params, creases_threshold),
1631 
1632                 CLOSURE_INT_KEYPARAM(Params, quality, "quality"),
1633                 CLOSURE_FINISH_PARAM(Params)
1634             };
1635 
1636             shading_system.register_closure(name(), id(), params, &prepare_closure, nullptr);
1637         }
1638 
convert_closurerenderer::__anon50bdf1300111::NPRContourClosure1639         static void convert_closure(
1640             CompositeNPRClosure&    composite_closure,
1641             const void*             osl_params,
1642             const Color3f&          weight,
1643             Arena&                  arena)
1644         {
1645             const Params* p = static_cast<const Params*>(osl_params);
1646 
1647             unsigned int features = 0;
1648             if (p->object_id != 0) features |= static_cast<unsigned int>(NPRContourFeatures::ObjectInstanceID);
1649             if (p->material_id != 0) features |= static_cast<unsigned int>(NPRContourFeatures::MaterialID);
1650             if (p->occlusion != 0) features |= static_cast<unsigned int>(NPRContourFeatures::OcclusionEdges);
1651             if (p->creases != 0) features |= static_cast<unsigned int>(NPRContourFeatures::CreaseEdges);
1652 
1653             if (features == 0 || p->contour_opacity == 0.0f || p->contour_width == 0.0f)
1654                 return;
1655 
1656             NPRContourInputValues* values =
1657                 composite_closure.add_closure<NPRContourInputValues>(id(), weight, arena);
1658 
1659             values->m_color = Color3f(p->contour_color);
1660             values->m_opacity = saturate(p->contour_opacity);
1661             values->m_width = max(p->contour_width, 0.0f);
1662 
1663             values->m_occlusion_threshold = max(p->occlusion_threshold, 0.0f);
1664             values->m_cos_crease_threshold = cos(deg_to_rad(p->creases_threshold));
1665 
1666             values->m_features = features;
1667             values->m_quality = static_cast<size_t>(clamp(p->quality, 1, 4));
1668         }
1669     };
1670 }
1671 
1672 
1673 //
1674 // CompositeClosure class implementation.
1675 //
1676 
CompositeClosure()1677 CompositeClosure::CompositeClosure()
1678   : m_closure_count(0)
1679 {
1680 }
1681 
compute_closure_shading_basis(const Vector3f & normal,const Basis3f & original_shading_basis)1682 void CompositeClosure::compute_closure_shading_basis(
1683     const Vector3f& normal,
1684     const Basis3f&  original_shading_basis)
1685 {
1686     const float normal_square_norm = square_norm(normal);
1687     if APPLESEED_LIKELY(normal_square_norm != 0.0f)
1688     {
1689         const float rcp_normal_norm = 1.0f / sqrt(normal_square_norm);
1690         m_bases[m_closure_count] =
1691             Basis3f(
1692                 normal * rcp_normal_norm,
1693                 original_shading_basis.get_tangent_u());
1694     }
1695     else
1696     {
1697         // Fallback to the original shading basis if the normal is zero.
1698         m_bases[m_closure_count] = original_shading_basis;
1699     }
1700 }
1701 
compute_closure_shading_basis(const Vector3f & normal,const Vector3f & tangent,const Basis3f & original_shading_basis)1702 void CompositeClosure::compute_closure_shading_basis(
1703     const Vector3f& normal,
1704     const Vector3f& tangent,
1705     const Basis3f&  original_shading_basis)
1706 {
1707     const float tangent_square_norm = square_norm(tangent);
1708     if APPLESEED_LIKELY(tangent_square_norm != 0.0f)
1709     {
1710         const float normal_square_norm = square_norm(normal);
1711         if APPLESEED_LIKELY(normal_square_norm != 0.0f)
1712         {
1713             const float rcp_normal_norm = 1.0f / sqrt(normal_square_norm);
1714             const float rcp_tangent_norm = 1.0f / sqrt(tangent_square_norm);
1715             m_bases[m_closure_count] =
1716                 Basis3f(
1717                     normal * rcp_normal_norm,
1718                     tangent * rcp_tangent_norm);
1719         }
1720         else
1721         {
1722             // Fallback to the original shading basis if the normal is zero.
1723             m_bases[m_closure_count] = original_shading_basis;
1724         }
1725     }
1726     else
1727     {
1728         // If the tangent is zero, ignore it.
1729         // This can happen when using the isotropic microfacet closure overloads, for example.
1730         compute_closure_shading_basis(normal, original_shading_basis);
1731     }
1732 }
1733 
1734 template <typename InputValues>
add_closure(const ClosureID closure_type,const Basis3f & original_shading_basis,const Color3f & weight,const Vector3f & normal,Arena & arena)1735 InputValues* CompositeClosure::add_closure(
1736     const ClosureID             closure_type,
1737     const Basis3f&              original_shading_basis,
1738     const Color3f&              weight,
1739     const Vector3f&             normal,
1740     Arena&                      arena)
1741 {
1742     return do_add_closure<InputValues>(
1743         closure_type,
1744         original_shading_basis,
1745         weight,
1746         normal,
1747         false,
1748         Vector3f(0.0f),
1749         arena);
1750 }
1751 
1752 template <typename InputValues>
add_closure(const ClosureID closure_type,const Basis3f & original_shading_basis,const Color3f & weight,const Vector3f & normal,const Vector3f & tangent,Arena & arena)1753 InputValues* CompositeClosure::add_closure(
1754     const ClosureID             closure_type,
1755     const Basis3f&              original_shading_basis,
1756     const Color3f&              weight,
1757     const Vector3f&             normal,
1758     const Vector3f&             tangent,
1759     Arena&                      arena)
1760 {
1761     return do_add_closure<InputValues>(
1762         closure_type,
1763         original_shading_basis,
1764         weight,
1765         normal,
1766         true,
1767         tangent,
1768         arena);
1769 }
1770 
1771 template <typename InputValues>
do_add_closure(const ClosureID closure_type,const Basis3f & original_shading_basis,const Color3f & weight,const Vector3f & normal,const bool has_tangent,const Vector3f & tangent,Arena & arena)1772 InputValues* CompositeClosure::do_add_closure(
1773     const ClosureID             closure_type,
1774     const Basis3f&              original_shading_basis,
1775     const Color3f&              weight,
1776     const Vector3f&             normal,
1777     const bool                  has_tangent,
1778     const Vector3f&             tangent,
1779     Arena&                      arena)
1780 {
1781     // Make sure we have enough space.
1782     if APPLESEED_UNLIKELY(get_closure_count() >= MaxClosureEntries)
1783     {
1784         throw ExceptionOSLRuntimeError(
1785             "maximum number of closures in osl shader group exceeded");
1786     }
1787 
1788     // We use the luminance of the weight as the BSDF weight.
1789     const float w = luminance(weight);
1790     assert(w > 0.0f);
1791 
1792     m_weights[m_closure_count].set(weight, g_std_lighting_conditions, Spectrum::Reflectance);
1793     m_scalar_weights[m_closure_count] = w;
1794 
1795     if (!has_tangent)
1796         compute_closure_shading_basis(normal, original_shading_basis);
1797     else compute_closure_shading_basis(normal, tangent, original_shading_basis);
1798 
1799     m_closure_types[m_closure_count] = closure_type;
1800 
1801     InputValues* values = arena.allocate<InputValues>();
1802     m_input_values[m_closure_count] = values;
1803 
1804     ++m_closure_count;
1805 
1806     return values;
1807 }
1808 
compute_pdfs(float pdfs[MaxClosureEntries])1809 void CompositeClosure::compute_pdfs(float pdfs[MaxClosureEntries])
1810 {
1811     const size_t closure_count = get_closure_count();
1812 
1813     float total_weight = 0.0f;
1814     for (size_t i = 0; i < closure_count; ++i)
1815     {
1816         pdfs[i] = m_scalar_weights[i];
1817         total_weight += pdfs[i];
1818     }
1819 
1820     if (total_weight != 0.0f)
1821     {
1822         const float rcp_total_weight = 1.0f / total_weight;
1823 
1824         for (size_t i = 0; i < closure_count; ++i)
1825             pdfs[i] *= rcp_total_weight;
1826     }
1827 }
1828 
1829 
1830 //
1831 // CompositeSurfaceClosure class implementation.
1832 //
1833 
CompositeSurfaceClosure(const Basis3f & original_shading_basis,const OSL::ClosureColor * ci,Arena & arena)1834 CompositeSurfaceClosure::CompositeSurfaceClosure(
1835     const Basis3f&              original_shading_basis,
1836     const OSL::ClosureColor*    ci,
1837     Arena&                      arena)
1838   : m_ior_count(0)
1839 {
1840     process_closure_tree(ci, original_shading_basis, Color3f(1.0f), arena);
1841 
1842     if (m_ior_count == 0)
1843     {
1844         m_ior_count = 1;
1845         m_iors[0] = 1.0f;
1846         return;
1847     }
1848 
1849     // Build the IOR CDF in place if needed.
1850     if (m_ior_count > 1)
1851     {
1852         float total_weight = m_ior_cdf[0];
1853         for (size_t i = 1; i < m_ior_count; ++i)
1854         {
1855             total_weight += m_ior_cdf[i];
1856             m_ior_cdf[i] = total_weight;
1857         }
1858 
1859         const float rcp_total_weight = 1.0f / total_weight;
1860 
1861         for (size_t i = 0; i < m_ior_count - 1; ++i)
1862             m_ior_cdf[i] *= rcp_total_weight;
1863 
1864         m_ior_cdf[m_ior_count - 1] = 1.0f;
1865     }
1866 }
1867 
compute_pdfs(const int modes,float pdfs[MaxClosureEntries]) const1868 int CompositeSurfaceClosure::compute_pdfs(
1869     const int                   modes,
1870     float                       pdfs[MaxClosureEntries]) const
1871 {
1872     memset(pdfs, 0, sizeof(float) * MaxClosureEntries);
1873 
1874     int num_closures = 0;
1875     float sum_weights = 0.0f;
1876 
1877     for (size_t i = 0, e = get_closure_count(); i < e; ++i)
1878     {
1879         const ClosureID cid = m_closure_types[i];
1880         const int closure_modes = g_closure_get_modes_funs[cid]();
1881 
1882         if (closure_modes & modes)
1883         {
1884             pdfs[i] = m_scalar_weights[i];
1885             sum_weights += m_scalar_weights[i];
1886             ++num_closures;
1887         }
1888         else
1889             pdfs[i] = 0.0f;
1890     }
1891 
1892     if (sum_weights != 0.0f)
1893     {
1894         const float rcp_sum_weights = 1.0f / sum_weights;
1895         for (size_t i = 0, e = get_closure_count(); i < e; ++i)
1896             pdfs[i] *= rcp_sum_weights;
1897     }
1898 
1899     return num_closures;
1900 }
1901 
choose_closure(const float w,const size_t num_closures,float pdfs[MaxClosureEntries]) const1902 size_t CompositeSurfaceClosure::choose_closure(
1903     const float                 w,
1904     const size_t                num_closures,
1905     float                       pdfs[MaxClosureEntries]) const
1906 {
1907     assert(num_closures > 0);
1908     assert(num_closures < MaxClosureEntries);
1909 
1910     return sample_pdf_linear_search(pdfs, num_closures, w);
1911 }
1912 
add_ior(const Color3f & weight,const float ior)1913 void CompositeSurfaceClosure::add_ior(
1914     const Color3f&              weight,
1915     const float                 ior)
1916 {
1917     // We use the luminance of the weight as the IOR weight.
1918     const float w = luminance(weight);
1919     assert(w > 0.0f);
1920 
1921     m_iors[m_ior_count] = ior;
1922     m_ior_cdf[m_ior_count] = w;
1923     ++m_ior_count;
1924 }
1925 
choose_ior(const float w) const1926 float CompositeSurfaceClosure::choose_ior(const float w) const
1927 {
1928     assert(m_ior_count > 0);
1929 
1930     if APPLESEED_LIKELY(m_ior_count == 1)
1931         return m_iors[0];
1932 
1933     const size_t index = sample_cdf_linear_search(m_ior_cdf, w);
1934     return m_iors[index];
1935 }
1936 
process_closure_tree(const OSL::ClosureColor * closure,const Basis3f & original_shading_basis,const Color3f & weight,Arena & arena)1937 void CompositeSurfaceClosure::process_closure_tree(
1938     const OSL::ClosureColor*    closure,
1939     const Basis3f&              original_shading_basis,
1940     const Color3f&              weight,
1941     Arena&                      arena)
1942 {
1943     if (closure == nullptr)
1944         return;
1945 
1946     switch (closure->id)
1947     {
1948       case OSL::ClosureColor::MUL:
1949         {
1950             const OSL::ClosureMul* c = reinterpret_cast<const OSL::ClosureMul*>(closure);
1951             const Color3f w = weight * Color3f(c->weight);
1952             process_closure_tree(c->closure, original_shading_basis, w, arena);
1953         }
1954         break;
1955 
1956       case OSL::ClosureColor::ADD:
1957         {
1958             const OSL::ClosureAdd* c = reinterpret_cast<const OSL::ClosureAdd*>(closure);
1959             process_closure_tree(c->closureA, original_shading_basis, weight, arena);
1960             process_closure_tree(c->closureB, original_shading_basis, weight, arena);
1961         }
1962         break;
1963 
1964       default:
1965         {
1966             const OSL::ClosureComponent* c = reinterpret_cast<const OSL::ClosureComponent*>(closure);
1967             const Color3f w = weight * Color3f(c->w);
1968 
1969             if (luminance(w) > 0.0f)
1970                 g_closure_convert_funs[c->id](*this, original_shading_basis, c->data(), w, arena);
1971         }
1972         break;
1973     }
1974 }
1975 
1976 
1977 //
1978 // CompositeSubsurfaceClosure class implementation.
1979 //
1980 
CompositeSubsurfaceClosure(const Basis3f & original_shading_basis,const OSL::ClosureColor * ci,Arena & arena)1981 CompositeSubsurfaceClosure::CompositeSubsurfaceClosure(
1982     const Basis3f&              original_shading_basis,
1983     const OSL::ClosureColor*    ci,
1984     Arena&                      arena)
1985 {
1986     process_closure_tree(ci, original_shading_basis, Color3f(1.0f), arena);
1987     compute_pdfs(m_pdfs);
1988 }
1989 
choose_closure(const float w) const1990 size_t CompositeSubsurfaceClosure::choose_closure(const float w) const
1991 {
1992     assert(get_closure_count() > 0);
1993     return sample_pdf_linear_search(m_pdfs, get_closure_count(), w);
1994 }
1995 
process_closure_tree(const OSL::ClosureColor * closure,const Basis3f & original_shading_basis,const Color3f & weight,Arena & arena)1996 void CompositeSubsurfaceClosure::process_closure_tree(
1997     const OSL::ClosureColor*    closure,
1998     const Basis3f&              original_shading_basis,
1999     const Color3f&              weight,
2000     Arena&                      arena)
2001 {
2002     if (closure == nullptr)
2003         return;
2004 
2005     switch (closure->id)
2006     {
2007       case OSL::ClosureColor::MUL:
2008         {
2009             const OSL::ClosureMul* c = reinterpret_cast<const OSL::ClosureMul*>(closure);
2010             process_closure_tree(c->closure, original_shading_basis, weight * Color3f(c->weight), arena);
2011         }
2012         break;
2013 
2014       case OSL::ClosureColor::ADD:
2015         {
2016             const OSL::ClosureAdd* c = reinterpret_cast<const OSL::ClosureAdd*>(closure);
2017             process_closure_tree(c->closureA, original_shading_basis, weight, arena);
2018             process_closure_tree(c->closureB, original_shading_basis, weight, arena);
2019         }
2020         break;
2021 
2022       default:
2023         {
2024             const OSL::ClosureComponent* c = reinterpret_cast<const OSL::ClosureComponent*>(closure);
2025 
2026             if (c->id == SubsurfaceID)
2027             {
2028                 const Color3f w = weight * Color3f(c->w);
2029                 if (luminance(w) > 0.0f)
2030                 {
2031                     SubsurfaceClosure::convert_closure(
2032                         *this,
2033                         original_shading_basis,
2034                         c->data(),
2035                         w,
2036                         arena);
2037                 }
2038             }
2039             else if (c->id == RandomwalkGlassID)
2040             {
2041                 const Color3f w = weight * Color3f(c->w);
2042                 if (luminance(w) > 0.0f)
2043                 {
2044                     RandomwalkGlassClosure::convert_closure(
2045                         *this,
2046                         original_shading_basis,
2047                         c->data(),
2048                         w,
2049                         arena);
2050                 }
2051             }
2052         }
2053         break;
2054     }
2055 }
2056 
2057 
2058 //
2059 // CompositeEmissionClosure class implementation.
2060 //
2061 
CompositeEmissionClosure(const OSL::ClosureColor * ci,Arena & arena)2062 CompositeEmissionClosure::CompositeEmissionClosure(
2063     const OSL::ClosureColor*    ci,
2064     Arena&                      arena)
2065 {
2066     process_closure_tree(ci, Color3f(1.0f), arena);
2067     compute_pdfs(m_pdfs);
2068 }
2069 
choose_closure(const float w) const2070 size_t CompositeEmissionClosure::choose_closure(const float w) const
2071 {
2072     assert(get_closure_count() > 0);
2073     return sample_pdf_linear_search(m_pdfs, get_closure_count(), w);
2074 }
2075 
2076 template <typename InputValues>
add_closure(const ClosureID closure_type,const Color3f & weight,const float max_weight_component,Arena & arena)2077 InputValues* CompositeEmissionClosure::add_closure(
2078     const ClosureID             closure_type,
2079     const Color3f&              weight,
2080     const float                 max_weight_component,
2081     Arena&                      arena)
2082 {
2083     // Make sure we have enough space.
2084     if APPLESEED_UNLIKELY(get_closure_count() >= MaxClosureEntries)
2085     {
2086         throw ExceptionOSLRuntimeError(
2087             "maximum number of closures in osl shader group exceeded");
2088     }
2089 
2090     m_closure_types[m_closure_count] = closure_type;
2091     m_weights[m_closure_count].set(weight, g_std_lighting_conditions, Spectrum::Reflectance);
2092     m_pdfs[m_closure_count] = max_weight_component;
2093 
2094     InputValues* values = arena.allocate<InputValues>();
2095     m_input_values[m_closure_count] = values;
2096 
2097     ++m_closure_count;
2098 
2099     return values;
2100 }
2101 
process_closure_tree(const OSL::ClosureColor * closure,const Color3f & weight,Arena & arena)2102 void CompositeEmissionClosure::process_closure_tree(
2103     const OSL::ClosureColor*    closure,
2104     const Color3f&              weight,
2105     Arena&                      arena)
2106 {
2107     if (closure == nullptr)
2108         return;
2109 
2110     switch (closure->id)
2111     {
2112       case OSL::ClosureColor::MUL:
2113         {
2114             const OSL::ClosureMul* c = reinterpret_cast<const OSL::ClosureMul*>(closure);
2115             process_closure_tree(c->closure, weight * Color3f(c->weight), arena);
2116         }
2117         break;
2118 
2119       case OSL::ClosureColor::ADD:
2120         {
2121             const OSL::ClosureAdd* c = reinterpret_cast<const OSL::ClosureAdd*>(closure);
2122             process_closure_tree(c->closureA, weight, arena);
2123             process_closure_tree(c->closureB, weight, arena);
2124         }
2125         break;
2126 
2127       default:
2128         {
2129             const OSL::ClosureComponent* c = reinterpret_cast<const OSL::ClosureComponent*>(closure);
2130 
2131             const Color3f w = weight * Color3f(c->w);
2132             const float max_weight_component = max_value(w);
2133 
2134             if (max_weight_component > 0.0f)
2135             {
2136                 if (c->id == EmissionID)
2137                 {
2138                     EmissionClosure::convert_closure(
2139                         *this,
2140                         c->data(),
2141                         w,
2142                         max_weight_component,
2143                         arena);
2144                 }
2145             }
2146         }
2147         break;
2148     }
2149 }
2150 
2151 
2152 //
2153 // CompositeNPRClosure class implementation.
2154 //
2155 
CompositeNPRClosure(const OSL::ClosureColor * ci,Arena & arena)2156 CompositeNPRClosure::CompositeNPRClosure(
2157     const OSL::ClosureColor*    ci,
2158     Arena&                      arena)
2159 {
2160     process_closure_tree(ci, Color3f(1.0f), arena);
2161 }
2162 
2163 template <typename InputValues>
add_closure(const ClosureID closure_type,const Color3f & weight,Arena & arena)2164 InputValues* CompositeNPRClosure::add_closure(
2165     const ClosureID             closure_type,
2166     const Color3f&              weight,
2167     Arena&                      arena)
2168 {
2169     // Make sure we have enough space.
2170     if APPLESEED_UNLIKELY(get_closure_count() >= MaxClosureEntries)
2171     {
2172         throw ExceptionOSLRuntimeError(
2173             "maximum number of closures in osl shader group exceeded");
2174     }
2175 
2176     m_closure_types[m_closure_count] = closure_type;
2177     m_weights[m_closure_count].set(weight, g_std_lighting_conditions, Spectrum::Reflectance);
2178 
2179     InputValues* values = arena.allocate<InputValues>();
2180     m_input_values[m_closure_count] = values;
2181 
2182     ++m_closure_count;
2183 
2184     return values;
2185 }
2186 
get_nth_contour_closure_index(const size_t i) const2187 size_t CompositeNPRClosure::get_nth_contour_closure_index(const size_t i) const
2188 {
2189     size_t n = 0;
2190 
2191     for (size_t j = 0 , e = get_closure_count(); j < e; ++j)
2192     {
2193         if (get_closure_type(j) == NPRContourID)
2194         {
2195             if (n == i)
2196                 return j;
2197 
2198             ++n;
2199         }
2200     }
2201 
2202     return ~0;
2203 }
2204 
process_closure_tree(const OSL::ClosureColor * closure,const Color3f & weight,Arena & arena)2205 void CompositeNPRClosure::process_closure_tree(
2206     const OSL::ClosureColor*    closure,
2207     const Color3f&              weight,
2208     Arena&                      arena)
2209 {
2210     if (closure == nullptr)
2211         return;
2212 
2213     switch (closure->id)
2214     {
2215       case OSL::ClosureColor::MUL:
2216         {
2217             const OSL::ClosureMul* c = reinterpret_cast<const OSL::ClosureMul*>(closure);
2218             process_closure_tree(c->closure, weight * Color3f(c->weight), arena);
2219         }
2220         break;
2221 
2222       case OSL::ClosureColor::ADD:
2223         {
2224             const OSL::ClosureAdd* c = reinterpret_cast<const OSL::ClosureAdd*>(closure);
2225             process_closure_tree(c->closureA, weight, arena);
2226             process_closure_tree(c->closureB, weight, arena);
2227         }
2228         break;
2229 
2230       default:
2231         {
2232             const OSL::ClosureComponent* c = reinterpret_cast<const OSL::ClosureComponent*>(closure);
2233             if (c->id == NPRShadingID)
2234             {
2235                 const Color3f w = weight * Color3f(c->w);
2236                 NPRShadingClosure::convert_closure(
2237                     *this,
2238                     c->data(),
2239                     w,
2240                     arena);
2241             }
2242             else if (c->id == NPRContourID)
2243             {
2244                 const Color3f w = weight * Color3f(c->w);
2245                 NPRContourClosure::convert_closure(
2246                     *this,
2247                     c->data(),
2248                     w,
2249                     arena);
2250             }
2251         }
2252         break;
2253     }
2254 }
2255 
2256 
2257 //
2258 // Utility functions implementation.
2259 //
2260 
2261 namespace
2262 {
do_process_closure_id_tree(const OSL::ClosureColor * closure,const int closure_id)2263     Color3f do_process_closure_id_tree(
2264         const OSL::ClosureColor*    closure,
2265         const int                   closure_id)
2266     {
2267         if (closure)
2268         {
2269             switch (closure->id)
2270             {
2271               case OSL::ClosureColor::MUL:
2272                 {
2273                     const OSL::ClosureMul* c = reinterpret_cast<const OSL::ClosureMul*>(closure);
2274                     return Color3f(c->weight) * do_process_closure_id_tree(c->closure, closure_id);
2275                 }
2276                 break;
2277 
2278               case OSL::ClosureColor::ADD:
2279                 {
2280                     const OSL::ClosureAdd* c = reinterpret_cast<const OSL::ClosureAdd*>(closure);
2281                     return do_process_closure_id_tree(c->closureA, closure_id) +
2282                            do_process_closure_id_tree(c->closureB, closure_id);
2283                 }
2284                 break;
2285 
2286               default:
2287                 {
2288                     const OSL::ClosureComponent* c = reinterpret_cast<const OSL::ClosureComponent*>(closure);
2289                     if (c->id == closure_id)
2290                         return Color3f(c->w);
2291                     else return Color3f(0.0f);
2292                 }
2293                 break;
2294             }
2295         }
2296 
2297         return Color3f(0.0f);
2298     }
2299 }
2300 
process_transparency_tree(const OSL::ClosureColor * ci,Alpha & alpha)2301 void process_transparency_tree(const OSL::ClosureColor* ci, Alpha& alpha)
2302 {
2303     // Convert from transparency to opacity.
2304     const float transparency = saturate(luminance(do_process_closure_id_tree(ci, TransparentID)));
2305     alpha.set(1.0f - transparency);
2306 }
2307 
process_matte_tree(const OSL::ClosureColor * closure,Color3f & matte_color,float & matte_alpha)2308 bool process_matte_tree(
2309     const OSL::ClosureColor*    closure,
2310     Color3f&                    matte_color,
2311     float&                      matte_alpha)
2312 {
2313     if (closure)
2314     {
2315         switch (closure->id)
2316         {
2317           case OSL::ClosureColor::MUL:
2318             {
2319                 const OSL::ClosureMul* c = reinterpret_cast<const OSL::ClosureMul*>(closure);
2320                 const bool is_matte = process_matte_tree(c->closure, matte_color, matte_alpha);
2321                 matte_color = Color3f(c->weight) * matte_color;
2322                 matte_alpha = saturate(luminance(Color3f((c->weight) * matte_alpha)));
2323                 return is_matte;
2324             }
2325 
2326           case OSL::ClosureColor::ADD:
2327             {
2328                 const OSL::ClosureAdd* c = reinterpret_cast<const OSL::ClosureAdd*>(closure);
2329                 Color3f color_a(0.0f), color_b(0.0f);
2330                 float alpha_a(0.0f), alpha_b(0.0f);
2331                 const bool is_matte_a = process_matte_tree(c->closureA, color_a, alpha_a);
2332                 const bool is_matte_b = process_matte_tree(c->closureB, color_b, alpha_b);
2333                 matte_color = color_a + color_b;
2334                 matte_alpha = alpha_a + alpha_b;
2335                 return is_matte_a || is_matte_b;
2336             }
2337 
2338           default:
2339             {
2340                 const OSL::ClosureComponent* c = reinterpret_cast<const OSL::ClosureComponent*>(closure);
2341 
2342                 if (c->id == MatteID)
2343                 {
2344                     const MatteClosure::Params* p = static_cast<const MatteClosure::Params*>(c->data());
2345                     matte_color = p->matte_color;
2346                     matte_alpha = p->matte_alpha;
2347                     return true;
2348                 }
2349                 else if (c->id == HoldoutID)
2350                 {
2351                     matte_color.set(0.0f);
2352                     matte_alpha = 0.0f;
2353                     return true;
2354                 }
2355             }
2356             break;
2357         }
2358     }
2359 
2360     return false;
2361 }
2362 
process_background_tree(const OSL::ClosureColor * ci)2363 Color3f process_background_tree(const OSL::ClosureColor* ci)
2364 {
2365     return do_process_closure_id_tree(ci, BackgroundID);
2366 }
2367 
2368 namespace
2369 {
2370     template <typename ClosureType>
register_closure(OSLShadingSystem & shading_system)2371     void register_closure(OSLShadingSystem& shading_system)
2372     {
2373         ClosureType::register_closure(shading_system);
2374         RENDERER_LOG_DEBUG("registered osl closure %s.", ClosureType::name());
2375     }
2376 }
2377 
register_closures(OSLShadingSystem & shading_system)2378 void register_closures(OSLShadingSystem& shading_system)
2379 {
2380     for (size_t i = 0; i < NumClosuresIDs; ++i)
2381     {
2382         g_closure_convert_funs[i] = &convert_closure_nop;
2383         g_closure_get_modes_funs[i] = &closure_no_modes;
2384     }
2385 
2386     register_closure<AshikhminShirleyClosure>(shading_system);
2387     register_closure<BackgroundClosure>(shading_system);
2388     register_closure<BlinnClosure>(shading_system);
2389     register_closure<DebugClosure>(shading_system);
2390     register_closure<DiffuseClosure>(shading_system);
2391     register_closure<DisneyClosure>(shading_system);
2392     register_closure<EmissionClosure>(shading_system);
2393     register_closure<GlassClosure>(shading_system);
2394     register_closure<GlossyClosure>(shading_system);
2395     register_closure<HoldoutClosure>(shading_system);
2396     register_closure<MatteClosure>(shading_system);
2397     register_closure<MetalClosure>(shading_system);
2398     register_closure<NPRContourClosure>(shading_system);
2399     register_closure<NPRShadingClosure>(shading_system);
2400     register_closure<OrenNayarClosure>(shading_system);
2401     register_closure<PhongClosure>(shading_system);
2402     register_closure<PlasticClosure>(shading_system);
2403     register_closure<RandomwalkGlassClosure>(shading_system);
2404     register_closure<ReflectionClosure>(shading_system);
2405     register_closure<SheenClosure>(shading_system);
2406     register_closure<SubsurfaceClosure>(shading_system);
2407     register_closure<TranslucentClosure>(shading_system);
2408     register_closure<TransparentClosure>(shading_system);
2409 }
2410 
2411 }   // namespace renderer
2412