RenderMan  26.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
RixShadingUtils.h
Go to the documentation of this file.
1 /*
2 # ------------------------------------------------------------------------------
3 #
4 # Copyright (c) 2020 Pixar. All rights reserved.
5 #
6 # The information in this file (the "Software") is provided for the exclusive
7 # use of the software licensees of Pixar ("Licensees"). Licensees have the
8 # right to incorporate the Software into other products for use by other
9 # authorized software licensees of Pixar, without fee. Except as expressly
10 # permitted herein, the Software may not be disclosed to third parties, copied
11 # or duplicated in any form, in whole or in part, without the prior written
12 # permission of Pixar.
13 #
14 # The copyright notices in the Software and this entire statement, including the
15 # above license grant, this restriction and the following disclaimer, must be
16 # included in all copies of the Software, in whole or in part, and all permitted
17 # derivative works of the Software, unless such copies or derivative works are
18 # solely in the form of machine-executable object code generated by a source
19 # language processor.
20 #
21 # PIXAR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
22 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL PIXAR BE
23 # LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
24 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
25 # OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
26 # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. IN NO CASE WILL
27 # PIXAR'S TOTAL LIABILITY FOR ALL DAMAGES ARISING OUT OF OR IN CONNECTION WITH
28 # THE USE OR PERFORMANCE OF THIS SOFTWARE EXCEED $50.
29 #
30 # Pixar
31 # 1200 Park Ave
32 # Emeryville CA 94608
33 #
34 # ------------------------------------------------------------------------------
35 */
36 
37 #ifndef RixShadingUtils_h
38 #define RixShadingUtils_h
39 
40 // RixShadingUtils:
41 //
42 // Utility/portability functions for RixShading plugins.
43 //
44 
45 #include <algorithm> // for max
46 #include <cassert> // for assert
47 #include <cmath> // for sqrt, cosf, sinf, floorf, etc
48 #include <cstddef> // for NULL
49 #include "RixInterfaces.h" // for RixRenderState, etc
50 #include "RixShading.h" // for RixShadingContext, etc
51 #include "prmanapi.h" // for PRMAN_INLINE
52 #include "RiTypesHelper.h" // for RtVector3, RtColorRGB, etc
53 #include "RixPredefinedStrings.hpp" // for k_N primvar
54 
55 #if defined(WIN32)
56 #include <malloc.h>
57 #include <intrin.h>
58 #else
59 #include <alloca.h>
60 #endif
61 
62 
63 // single-precision floating point constants
64 // clang-format off
65 #define F_PI (3.14159265f)
66 #define F_TWOPI (6.283185307f)
67 #define F_FOURPI (12.56637061f)
68 #define F_INVPI (0.318309886f)
69 #define F_INVPISQ (0.1013211836f)
70 #define F_INVTWOPI (0.15915494309f)
71 #define F_INVFOURPI (0.0795774715f)
72 #define F_PIDIV2 (1.57079632679f)
73 #define F_PIDIV4 (0.785398163397f)
74 #define F_DEGTORAD (0.017453292520f)
75 #define F_RADTODEG (57.2957795131f)
76 #define F_INVLN2 (1.44269504089f)
77 #define F_INVLN4 (0.72134752f)
78 #define F_LOG2E (1.44269504088896f)
79 #define F_SQRT2 (1.41421356237f)
80 #define F_MAXDIST (1.0e10f)
81 #define F_SQRTMIN (1.0842021721e-19f)
82 #define F_MINDIVISOR (1.0e-6f)
83 // clang-format on
84 
85 namespace RixConstants
86 {
87 
88 // some additional constants
89 
90 static const RtColorRGB k_ZeroRGB(0.0f);
91 static const RtColorRGB k_OneRGB(1.0f);
92 static const RtFloat3 k_ZeroF3(0.0f);
93 static const RtFloat3 k_OneF3(1.0f);
94 static const RtFloat2 k_ZeroF2(0.0f);
95 static const RtFloat2 k_OneF2(1.0f);
96 static const float k_ZeroF(0.0f);
97 static const float k_OneF(1.0f);
98 static const float k_Infinity(1e+38f);
99 static const RtMatrix4x4 k_IdentityMatrix(1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1);
100 
101 } // namespace RixConstants
102 
103 
104 //
105 // Returns the zero-based index of the first (least significant) bit set in
106 // a 64-bit integer. Compiles to a single quick instruction via intrinsics.
107 //
108 // NOTE: The result is undefined if the input is zero!
109 //
110 PRMAN_INLINE unsigned int RixFindFirstSetBit(unsigned long long v)
111 {
112 #if defined(WIN32)
113  unsigned long r = 0;
114  _BitScanForward64( &r, v );
115  return r;
116 #else // Linux, OS X, gcc or clang
117  return __builtin_ctzll( v );
118 #endif
119 }
120 
121 
122 // Converts degrees to radians
123 PRMAN_INLINE float
124 RixDegreesToRadians(float degrees)
125 {
126  return degrees * F_DEGTORAD;
127 }
128 
129 
130 // Converts radians to degrees
131 PRMAN_INLINE float
133 {
134  return rads * F_RADTODEG;
135 }
136 
137 
138 template <typename T>
139 PRMAN_INLINE T
141 {
142  if (x > T(0))
143  return T(1);
144  if (x < T(0))
145  return T(-1);
146  return T(0);
147 }
148 
149 
150 //
151 // RixIsFinite is helpful in diagnosing bugs that produce NaNs
152 // and other exotic breads.
153 //
154 PRMAN_INLINE int
155 RixIsFinite(float x)
156 {
157  return std::isfinite(x);
158 }
159 
160 
161 //
162 // Returns true of all three components of a point/vector/normal are
163 // finite
164 //
165 PRMAN_INLINE int
166 RixIsFinite(RtFloat3 const& v)
167 {
168  return RixIsFinite(v.x) && RixIsFinite(v.y) && RixIsFinite(v.z);
169 }
170 
171 
172 //
173 // Returns the minimum of two floats
174 //
175 PRMAN_INLINE float
176 RixMin(float x, float y)
177 {
178  return x < y ? x : y;
179 }
180 
181 
182 //
183 // Returns the minimum of two integers
184 //
185 PRMAN_INLINE int
186 RixMin(int x, int y)
187 {
188  return x < y ? x : y;
189 }
190 
191 
192 //
193 // Returns the maximum of two floats
194 //
195 PRMAN_INLINE float
196 RixMax(float x, float y)
197 {
198  return x > y ? x : y;
199 }
200 
201 
202 //
203 // Returns the maximum of two integers
204 //
205 PRMAN_INLINE int
206 RixMax(int x, int y)
207 {
208  return x > y ? x : y;
209 }
210 
211 
212 //
213 // Clamps float x in the interval [min,max]
214 //
215 PRMAN_INLINE float
216 RixClamp(float x, float min, float max)
217 {
218  return x < min ? min : (x > max) ? max : x;
219 }
220 
221 
222 //
223 // Clamps integer x in the interval [min,max]
224 //
225 PRMAN_INLINE int
226 RixClamp(int x, int min, int max)
227 {
228  return x < min ? min : (x > max) ? max : x;
229 }
230 
231 
232 //
233 // Returns the fractional part of float x
234 //
235 PRMAN_INLINE float
237 {
238  return (x - floorf(x));
239 }
240 
241 
242 //
243 // RixMod is a straight port of RSL's mod() shadeop.
244 // It is NOT equivalent to fmodf() from math.h.
245 //
246 PRMAN_INLINE float
247 RixMod(float x, float y)
248 {
249  float n = float(int(x/y));
250  float result = x - n*y;
251  if (result < 0.0f) result += y;
252  return result;
253 }
254 
255 
256 //
257 // RixFresnelDielectric
258 //
259 // Calculate the reflection coefficient based on the following formula:
260 // Kr = (rpar * rpar + rper * rper) / 2.0
261 //
262 // where:
263 // rcos_i = abs(N.V) -- with V == -I
264 // rcos_t = sqrt( 1.0 - eta * eta * ( 1.0 - rcos_i * rcos_i ) )
265 // rpar = ( eta * rcos_t - rcos_i ) / ( eta * rcos_t + rcos_i )
266 // rper = ( eta * rcos_i - rcos_t ) / ( eta * rcos_i + rcos_t )
267 //
268 // and eta is the relative index of refraction, the ratio of
269 // refraction indices ior_i / ior_t
270 //
271 // Subscript 'i' denotes the side the ray came from (incident direction,
272 // ie. the direction V points into); subscript 't' denotes the other
273 // (refraction/transmission) side.
274 //
275 // (The refraction (transmission) coefficient could be computed as:
276 // Kt = (1.0 - Kr) * rcos_i / rcos_t
277 // but usually we just set Kt = 1 - Kr.)
278 //
279 // The reflected and transmitted (unit) vectors are optionally calculated
280 // using the following formula:
281 // R = I - 2.0 * (N.I) * N
282 // = -V + 2.0 * (N.V) * N
283 // = 2.0 * (N.V) * N - V;
284 // T = eta * I + (eta * rcos_i - rcos_t) * N
285 // = (eta * rcos_i - rcos_t) * N - eta * V;
286 //
287 // All vectors have unit length. Input Vn and results Rn and Tn all point
288 // away from the surface. Kr is between 0 and 1.
289 //
290 PRMAN_INLINE void
291 RixFresnelDielectric(float VdN, float eta, float* Kr)
292 {
293  float rcos_i;
294  if (VdN < 0.0f)
295  rcos_i = -VdN;
296  else
297  rcos_i = VdN;
298 
299  float etaSq = eta * eta;
300  float rcos_tSq = 1.0f - etaSq * (1.0f - rcos_i * rcos_i);
301  if (rcos_tSq <= 0.0f)
302  *Kr = 1.0f; // total internal reflection
303  else
304  {
305  float rcos_t = std::sqrt(rcos_tSq);
306  float rpar = (eta * rcos_t - rcos_i) / (eta * rcos_t + rcos_i);
307  float rper = (eta * rcos_i - rcos_t) / (eta * rcos_i + rcos_t);
308  *Kr = 0.5f * (rpar * rpar + rper * rper);
309  }
310 }
311 
312 
313 //
314 // Computes reflection and refraction directions Rn and Tn. Both are unit vectors.
315 //
316 PRMAN_INLINE void
318  const RtVector3& Vn,
319  const RtNormal3& Nn,
320  float eta,
321  float* Kr,
322  RtVector3* Rn = NULL,
323  RtVector3* Tn = NULL)
324 {
325  float VdN = Dot(Nn, Vn);
326  float rcos_i, sign;
327 
328  if (VdN < 0.0f)
329  {
330  rcos_i = -VdN;
331  sign = -1.0f;
332  }
333  else
334  {
335  rcos_i = VdN;
336  sign = 1.0f;
337  }
338 
339  // reflection direction, formula works if Nn and Vn are on
340  // opposite or same sides
341  if (Rn)
342  *Rn = 2.0f * VdN * Nn - Vn;
343 
344  float etaSq = eta * eta;
345  float rcos_tSq = 1.0f - etaSq * (1.0f - rcos_i * rcos_i);
346  if (rcos_tSq <= 0.0f)
347  {
348  *Kr = 1.0f; // total internal reflection
349  if (Tn)
350  *Tn = RtVector3(0.0f); // no refraction (transmission) dir
351  }
352  else
353  {
354  float rcos_t = std::sqrt(rcos_tSq);
355  float rpar = (eta * rcos_t - rcos_i) / (eta * rcos_t + rcos_i);
356  float rper = (eta * rcos_i - rcos_t) / (eta * rcos_i + rcos_t);
357  *Kr = 0.5f * (rpar * rpar + rper * rper);
358  if (Tn)
359  *Tn = sign * (eta * rcos_i - rcos_t) * Nn - eta * Vn;
360  }
361 }
362 
363 
364 //
365 // RixFresnelDielectric:
366 // a varying version of RixFresnelDielectric.
367 //
368 PRMAN_INLINE void RixFresnelDielectric(
369  RixShadingContext& sCtx,
370  float eta,
371  float* Kr,
372  float* Kt, // reflect and refract coeffs
373  RtVector3* R,
374  RtVector3* T) // reflect and refract dirs
375 {
376  RtNormal3 const* Nn;
377  RtVector3 const* Vn;
380  int nPts = sCtx.numPts;
381  if (R && T)
382  {
383  for (int i = 0; i < nPts; ++i)
384  {
385  RixFresnelDielectric(Vn[i], Nn[i], eta, Kr + i, R + i, T + i);
386  Kt[i] = 1.0f - Kr[i];
387  }
388  }
389  else
390  {
391  for (int i = 0; i < nPts; ++i)
392  {
393  RixFresnelDielectric(Vn[i], Nn[i], eta, Kr + i);
394  Kt[i] = 1.0f - Kr[i];
395  }
396  }
397 }
398 
399 
400 //
401 // RixFresnelConductor:
402 // calculate the reflection coefficient for a conductor (metal)
403 // incoming eta, kappa are assumed ior_i / ior_t (for consistency
404 // with pre-existing dielectric convention). Internally eta and
405 // kappa are ior_t / ior_i.
406 //
407 PRMAN_INLINE void
408 RixFresnelConductorApprox(float VdN, float eta, float kappa, float* Kr)
409 {
410  if (kappa > 0.01f)
411  {
412  // approximation for dielectric/conductor interface
413  if (eta > 0.0f)
414  eta = 1.0f / eta;
415 
416  kappa = 1.0f / kappa;
417  float cosSq = VdN * VdN;
418  float cos2eta = 2.0f * eta * VdN;
419  float t0 = eta * eta + kappa * kappa;
420  float t1 = t0 * cosSq;
421  float rperp = (t0 - cos2eta + cosSq) / (t0 + cos2eta + cosSq);
422  float rpar = (t1 - cos2eta + 1.0f) / (t1 + cos2eta + 1.0f);
423  *Kr = 0.5f * (rpar + rperp);
424  }
425  else
426  {
427  // when kappa is small, we're dielectric
428  RixFresnelDielectric(VdN, eta, Kr);
429  }
430 }
431 
432 
433 //
434 // RixFresnelConductor:
435 // more expensive computation of fresnel conductor, usually the
436 // approximation is quite good (except for small kappa).
437 // See: Moeller's Optics.
438 //
439 PRMAN_INLINE void
440 RixFresnelConductor(float VdN, float eta, float kappa, float* Kr)
441 {
442  if (kappa > .01f)
443  {
444  float cosSq = VdN * VdN, sinSq = 1.0f - cosSq, sin4 = sinSq * sinSq;
445 
446  float t0 = eta * eta - kappa * kappa - sinSq;
447  float aSqPlusbSq = std::sqrt(t0 * t0 + 4.0f * kappa * kappa * eta * eta);
448  float a = std::sqrt(0.5f * (aSqPlusbSq + t0));
449 
450  float t1 = aSqPlusbSq + cosSq;
451  float t2 = 2.0f * a * VdN;
452 
453  float rperpSq = (t1 - t2) / (t1 + t2);
454 
455  float t3 = aSqPlusbSq * cosSq + sin4;
456  float t4 = t2 * sinSq;
457 
458  float rparSq = rperpSq * (t3 - t4) / (t3 + t4);
459 
460  *Kr = 0.5f * (rperpSq + rparSq);
461  }
462  else
463  {
464  // when kappa is small, we're dielectric
465  RixFresnelDielectric(VdN, eta, Kr);
466  }
467 }
468 
469 
470 //
471 // RixFresnelConductor:
472 // a version of RixFresnelConductor with the same interface
473 // as RixFresnelDielectric.
474 //
475 PRMAN_INLINE void
477  const RtVector3& Vn,
478  const RtNormal3& Nn,
479  float eta,
480  float kappa,
481  float* Kr,
482  RtVector3* Rn = NULL)
483 {
484  float VdN = Dot(Nn, Vn);
485  RixFresnelConductorApprox(VdN, eta, kappa, Kr);
486  if (Rn)
487  *Rn = 2.0f * VdN * Nn - Vn;
488 }
489 
490 
491 PRMAN_INLINE void
493  float VdN,
494  RtColorRGB const& eta,
495  RtColorRGB const& kappa,
496  RtColorRGB* Kr)
497 {
498  RtColorRGB kr;
499  RixFresnelConductorApprox(VdN, eta.r, kappa.r, &kr.r);
500 
501  // Make sure we compute other bands only when necessary.
502  // if eta and kappa are monochromatic, we only compute one band and the cost
503  // is the same as a RixFresnelDielectric.
504  if (eta.g == eta.r && kappa.g == kappa.r)
505  kr.g = kr.r;
506  else
507  RixFresnelConductorApprox(VdN, eta.g, kappa.g, &kr.g);
508  if (eta.b == eta.r && kappa.b == kappa.r)
509  kr.b = kr.r;
510  else if (eta.b == eta.g && kappa.b == kappa.g)
511  kr.b = kr.g;
512  else
513  RixFresnelConductorApprox(VdN, eta.b, kappa.b, &kr.b);
514 
515  *Kr = kr;
516 }
517 
518 
519 //
520 // RixFresnelConductor:
521 // compute the reflection coefficient for three spectral bands (RGB).
522 // Similar interface as RixFresnelDielectric.
523 //
524 PRMAN_INLINE void
526  RtVector3 const& Vn,
527  RtNormal3 const& Nn,
528  RtColorRGB const& eta,
529  RtColorRGB const& kappa,
530  RtColorRGB* Kr,
531  RtVector3* Rn = NULL)
532 {
533  float VdN = Dot(Nn, Vn);
534  RixFresnelConductor(VdN, eta, kappa, Kr);
535  if (Rn)
536  *Rn = 2.0f * VdN * Nn - Vn;
537 }
538 
539 
540 //
541 // Schlick's approximate Fresnel (only the weighting function).
542 // 0 at normal incidence angle. 1 at grazing angle.
543 // F(cosTheta, rper) = rper + (1-rper) * RixSchlickFresnelWeight
544 // where rper = (ior1-ior2)^2 / (ior1+ior2)
545 //
546 PRMAN_INLINE float
548 {
549  if (NdV <= 0.0f)
550  return 1.0f;
551 
552  if (NdV >= 1.0f)
553  return 0.0f; // dot prod can be slightly larger than 1.0
554 
555  float f = 1.0f - NdV;
556  float f2 = f * f;
557  return f2 * f2 * f; // std::pow(f, 5); -- result between 0.0 and 1.0
558 }
559 
560 
561 //
562 // Reflection direction: standalone computation, useful when Fresnel weights
563 // aren't needed
564 //
565 PRMAN_INLINE RtVector3
566 RixReflect(const RtVector3& Vn, const RtNormal3& Nn)
567 {
568  float VdN = Dot(Nn, Vn);
569  return 2.0f * VdN * Nn - Vn; // reflection direction
570 }
571 
572 
573 //
574 // Reflection direction: an alternate interface, faster when VdN is already
575 // available
576 //
577 PRMAN_INLINE RtVector3
578 RixReflect(RtVector3 const& Vn, RtVector3 const& Nn, float VdN)
579 {
580  return 2.0f * VdN * Nn - Vn; // reflection direction
581 }
582 
583 
584 //
585 // Refraction direction: standalone computation using Snell's law.
586 // All vectors have unit length. Input Vn and result Tn all point
587 // away from the surface. Return value is 1 and Tn = (0,0,0) if total
588 // internal reflection occured.
589 //
590 PRMAN_INLINE int
591 RixRefract(const RtVector3& Vn, const RtNormal3& Nn, float eta, RtVector3& Tn)
592 {
593  int err = 0;
594  float VdN = Dot(Vn, Nn);
595  float rcos_i, sign;
596 
597  if (VdN < 0.0f)
598  {
599  rcos_i = -VdN;
600  sign = -1.0f;
601  }
602  else
603  {
604  rcos_i = VdN;
605  sign = 1.0f;
606  }
607 
608  float etaSq = eta * eta;
609  float rcos_tSq = 1.0f - etaSq * (1.0f - rcos_i * rcos_i);
610  if (rcos_tSq <= 0.0f)
611  {
612  Tn = RtVector3(0.0f);
613  err = 1; // total internal reflection: no refraction
614  }
615  else
616  {
617  float rcos_t = std::sqrt(rcos_tSq);
618  Tn = sign * (eta * rcos_i - rcos_t) * Nn - eta * Vn; // refraction dir
619  Tn.Normalize();
620  }
621  return err;
622 }
623 
624 
625 PRMAN_INLINE RtNormal3
627  RtVector3 const& Vn,
628  RtNormal3 const& Nn,
629  float* VdotNf = NULL)
630 {
631  RtNormal3 Nf;
632  float d = Dot(Vn, Nn);
633 
634  if (d > 0.0f)
635  Nf = Nn;
636  else
637  {
638  Nf = -Nn;
639  d = -d;
640  }
641 
642  if (VdotNf)
643  *VdotNf = d;
644 
645  return Nf;
646 }
647 
648 
649 PRMAN_INLINE RtNormal3
651  RtVector3 const& Vn,
652  RtNormal3 const& Nn,
653  float* VdotNb = NULL)
654 {
655  RtNormal3 Nb;
656  float d = Dot(Vn, Nn);
657 
658  if (d < 0.0f)
659  Nb = Nn;
660  else
661  {
662  Nb = -Nn;
663  d = -d;
664  }
665 
666  if (VdotNb)
667  *VdotNb = d;
668 
669  return Nb;
670 }
671 
672 
673 #define ALMOSTZERO 0.005f
674 //
675 // Given two random numbers, generate a vector from a cosine distribution
676 // on the upper hemisphere.
677 // The normal n and two tangent vectors t0 and t1 are assumed to form an
678 // orthonormal basis: |n| = |t0| = |t1| = 1; n.t1 = n.t2 = t1.t2 = 0.
679 // The output outDir has unit length.
680 //
681 PRMAN_INLINE void
683  const RtFloat2& xi,
684  const RtVector3& n,
685  const RtVector3& t0,
686  const RtVector3& t1,
687  RtVector3& outDir,
688  float& cosTheta)
689 {
690  // In debug mode, assertion will help us identify unexpected inputs
691  // where n, t0, t1 do not form an orthonormal basis.
692  // Since this func is in the API, any bxdf or plugins that use this func
693  // will get the assertion, which probably indicates a bug in the caller.
694  assert(n.IsUnitLength()); // close to 1 enough
695  assert(t0.IsUnitLength()); // close to 1 enough
696  assert(t1.IsUnitLength()); // close to 1 enough
697  assert(n.AbsDot(t0) < ALMOSTZERO); // orthogonal enough
698  assert(t0.AbsDot(t1) < ALMOSTZERO); // orthogonal enough
699  assert(n.AbsDot(t1) < ALMOSTZERO); // orthogonal enough
700 
701  float e1 = xi.x * F_TWOPI;
702  float z = std::sqrt(xi.y);
703  float r = std::sqrt(std::max(0.0f, 1.0f - xi.y)); // = sqrt(1 - z^2)
704  float x = r * cosf(e1);
705  float y = r * sinf(e1);
706  if (z < 1.e-12f)
707  z = 1.e-12f;
708 
709  outDir = x * t0 + y * t1 + z * n;
710  cosTheta = z;
711 
712  assert(outDir.IsUnitLength()); // close to 1 enough
713 }
714 
715 
716 //
717 // Given two random numbers, generate a vector from a cosine distribution
718 // on the upper hemisphere. The normal n is assumed to have unit length.
719 // The output outDir has unit length.
720 //
721 PRMAN_INLINE void
723  const RtFloat2& xi,
724  const RtVector3& n,
725  RtVector3& outDir,
726  float& cosTheta)
727 {
728  RtVector3 t0, t1;
729  n.CreateOrthonormalBasis(t0, t1);
730  RixCosDirectionalDistribution(xi, n, t0, t1, outDir, cosTheta);
731 }
732 
733 
734 //
735 // Given two random numbers, generate a vector from a uniform distribution
736 // on the upper hemisphere.
737 // The normal n and two tangent vectors t0 and t1 are assumed to form an
738 // orthonormal basis: |n| = |t0| = |t1| = 1; n.t1 = n.t2 = t1.t2 = 0.
739 // The output outDir has unit length.
740 //
741 PRMAN_INLINE void
743  const RtFloat2& xi,
744  const RtVector3& n,
745  const RtVector3& t0,
746  const RtVector3& t1,
747  RtVector3& outDir,
748  float& cosTheta)
749 {
750  float e1 = xi.x * F_TWOPI;
751  float z = xi.y;
752  float r = std::sqrt(std::max(0.0f, 1.0f - z * z));
753  float x = r * cosf(e1);
754  float y = r * sinf(e1);
755  if (z < 1.e-12f)
756  z = 1.e-12f;
757 
758  outDir = x * t0 + y * t1 + z * n;
759  cosTheta = z;
760 }
761 
762 
763 //
764 // Given two random numbers, generate a vector from a uniform distribution
765 // on the upper hemisphere. The normal n is assumed to have unit length.
766 // The output outDir has unit length.
767 //
768 PRMAN_INLINE void
770  const RtFloat2& xi,
771  const RtVector3& n,
772  RtVector3& outDir,
773  float& cosTheta)
774 {
775  RtVector3 t0, t1;
776  n.CreateOrthonormalBasis(t0, t1);
777  RixUniformDirectionalDistribution(xi, n, t0, t1, outDir, cosTheta);
778 }
779 
780 
781 //
782 // Given two random numbers and a cone angle, generate a vector from a
783 // uniform distribution over the cone angle around a normal.
784 // The normal n and two tangent vectors t0 and t1 are assumed to form an
785 // orthonormal basis: |n| = |t0| = |t1| = 1; n.t1 = n.t2 = t1.t2 = 0.
786 // The output outDir has unit length.
787 //
788 PRMAN_INLINE void
789 RixUniformConeDistribution(const RtFloat2& xi, const float coneAngle,
790  const RtVector3& n, const RtVector3& t0,
791  const RtVector3& t1, RtVector3& outDir,
792  float& cosTheta)
793 {
794  float e1 = xi.x * F_TWOPI;
795  float cosAngle = cosf(coneAngle);
796  float z = xi.y * (1.0f - cosAngle) + cosAngle;
797  float r = std::sqrt(std::max(0.0f, 1.0f - z * z));
798  float x = r * cosf(e1);
799  float y = r * sinf(e1);
800  if (z < 1.e-12f)
801  z = 1.e-12f;
802 
803  outDir = x * t0 + y * t1 + z * n;
804  cosTheta = z;
805 }
806 
807 
808 //
809 // Given two random numbers and a cone angle, generate a vector from a
810 // uniform distribution over the cone angle around a normal. The
811 // normal n is assumed to have unit length. The output outDir has
812 // unit length.
813 //
814 PRMAN_INLINE void
816  const RtFloat2& xi, const float coneAngle,
817  const RtVector3& n,
818  RtVector3& outDir,
819  float& cosTheta)
820 {
821  RtVector3 t0, t1;
822  n.CreateOrthonormalBasis(t0, t1);
823  RixUniformConeDistribution(xi, coneAngle, n, t0, t1, outDir, cosTheta);
824 }
825 
826 
827 //
828 // Given two random numbers, generate a vector from a uniform distribution
829 // on the entire sphere.
830 //
831 PRMAN_INLINE RtVector3
832 RixSphericalDistribution(const RtFloat2& xi)
833 {
834  RtVector3 outDir;
835  outDir.z = 2.0f * xi.y - 1.0f; // cosTheta
836  float sinTheta = 1.0f - outDir.z * outDir.z; // actually sinTheta^2 here
837 
838  if (sinTheta > 0.0f)
839  {
840  sinTheta = std::sqrt(sinTheta);
841  float phi = xi.x * F_TWOPI;
842  outDir.x = sinTheta * cosf(phi);
843  outDir.y = sinTheta * sinf(phi);
844  }
845  else // rare case
846  {
847  outDir.x = 0.0f;
848  outDir.y = 0.0f;
849  }
850 
851  return outDir;
852 }
853 
854 
855 //
856 // Randomly choose between numThresholds+1 scattering lobes using xi,
857 // and remap xi back to [0,1).
858 // Making a random selection this way and stretching the random numbers
859 // preserves stratification properties of a well-distributed set.
860 //
861 PRMAN_INLINE int
862 RixChooseAndRemap(float& xi, int numThresholds, float* thresholds)
863 {
864  // below lowest threshold?
865  if (xi < thresholds[0])
866  {
867  xi /= thresholds[0];
868  return 0; // chose lobe 0
869  }
870  // between thresholds?
871  for (int i = 1; i < numThresholds; i++)
872  {
873  if (thresholds[i - 1] <= xi && xi < thresholds[i])
874  {
875  xi = (xi - thresholds[i - 1]) / (thresholds[i] - thresholds[i - 1]);
876  return i; // chose lobe i
877  }
878  }
879  // must be above highest threshold
880  float lastThres = thresholds[numThresholds - 1];
881  xi = (xi - lastThres) / (1.0f - lastThres);
882  return numThresholds; // chose last lobe
883 }
884 
885 
886 //
887 // Compute ray-tracing bias amount
888 //
889 PRMAN_INLINE float
891  const RtPoint3& /* org */,
892  const RtNormal3& N,
893  const RtVector3& dir,
894  float biasR,
895  float biasT)
896 {
897  return (N.Dot(dir) < 0.0f) ? biasT : biasR;
898 }
899 
900 
901 //
902 // Compute ray-tracing bias amount and apply it to the ray origin
903 //
904 PRMAN_INLINE RtPoint3
906  const RtPoint3& org,
907  const RtNormal3& N,
908  const RtVector3& dir,
909  const float biasR,
910  const float biasT)
911 {
912  float biasAmt = RixTraceBias(org, N, dir, biasR, biasT);
913 
914  // Currently we bias in the ray direction, but in some cases we might
915  // want to bias along the surface normal (which is also provided as an
916  // input to this routine). Note that in the case of a ray in the opposite
917  // direction to the normal, we always want to bias in the ray direction
918  return org + biasAmt * dir;
919 }
920 
921 
922 //
923 // Compute sin and cos of the angle phi at the same time.
924 // This is more efficient than calling sin and cos separately.
925 //
926 PRMAN_INLINE void
927 RixSinCos(float phi, float* sinPhi, float* cosPhi)
928 {
929 #ifdef LINUX
930  sincosf(phi, sinPhi, cosPhi);
931 #elif (defined(OSX) && defined(__clang__))
932  __sincosf(phi, sinPhi, cosPhi);
933 #else
934  *sinPhi = sinf(phi);
935  *cosPhi = cosf(phi);
936 #endif
937 }
938 
939 
940 //
941 // Return a unit vector specified by angles theta and phi.
942 //
943 PRMAN_INLINE RtVector3
945  float sinTheta,
946  float cosTheta,
947  float sinPhi,
948  float cosPhi)
949 {
950  return RtVector3(sinTheta * cosPhi, sinTheta * sinPhi, cosTheta);
951 }
952 
953 
954 //
955 // Return a unit vector specified by angles theta and phi.
956 //
957 PRMAN_INLINE RtVector3
958 RixSphericalDirection(float sinTheta, float cosTheta, float phi)
959 {
960  float sinPhi, cosPhi;
961  RixSinCos(phi, &sinPhi, &cosPhi);
962  return RixSphericalDirection(sinTheta, cosTheta, sinPhi, cosPhi);
963 }
964 
965 
966 //
967 // RixChangeBasisFrom:
968 // transform a vector defined relative to the basis vectors
969 // to the embedding space (local to global).
970 //
971 PRMAN_INLINE RtVector3
973  RtVector3 const& in,
974  RtVector3 const& X,
975  RtVector3 const& Y,
976  RtVector3 const& Z)
977 {
978  RtVector3 result;
979  result.x = in.x * X.x + in.y * Y.x + in.z * Z.x;
980  result.y = in.x * X.y + in.y * Y.y + in.z * Z.y;
981  result.z = in.x * X.z + in.y * Y.z + in.z * Z.z;
982  return result;
983 }
984 
985 
986 PRMAN_INLINE RtVector3
988  RtVector3 const& in,
989  RtVector3 const& X,
990  RtVector3 const& Y,
991  RtVector3 const& Z)
992 {
993  return RixChangeBasisFrom(in, X, Y, Z);
994 }
995 
996 
997 //
998 // RixChangeBasisTo:
999 // transform a vector defined in the embedding space to be relative
1000 // to the provided basis vectors. (global to local)
1001 //
1002 PRMAN_INLINE RtVector3
1004  RtVector3 const& in,
1005  RtVector3 const& X,
1006  RtVector3 const& Y,
1007  RtVector3 const& Z)
1008 {
1009  return RtVector3(Dot(in, X), Dot(in, Y), Dot(in, Z));
1010 }
1011 
1012 
1013 //
1014 // Templated mix: T must define multiply and add (*, + operators)
1015 //
1016 template <typename T>
1017 PRMAN_INLINE T
1018 RixMix(const T& v0, const T& v1, float m)
1019 {
1020  return (1.0f - m) * v0 + m * v1;
1021 }
1022 
1023 
1024 //
1025 // Templated smooth (hermite) mix: T must define *, +, plus scalar +, -)
1026 // This is also known as the "ease" function.
1027 //
1028 template <typename T>
1029 PRMAN_INLINE T
1030 RixSmoothMix(const T& x1, const T& x2, float t)
1031 {
1032  if (t <= 0.0f)
1033  return x1;
1034  else if (t >= 1.0f)
1035  return x2;
1036  else
1037  {
1038  T x3;
1039  T dx = x2 - x1;
1040  x3 = x1 + dx * t * t * (3.0f - 2.0f * t);
1041  return x3;
1042  }
1043 }
1044 
1045 
1046 //
1047 // RixEaseInMix:
1048 // Templated ease-in: T must define *, +, plus scalar +, -)
1049 // interpolate from x1 to x2, with tangent at x1 of 0
1050 //
1051 template <typename T>
1052 PRMAN_INLINE T
1053 RixEaseInMix(const T& x1, const T& x2, float t)
1054 {
1055  if (t <= 0.0f)
1056  return x1;
1057  else if (t >= 1.0f)
1058  return x2;
1059  else
1060  {
1061  T x3;
1062  T dx = x2 - x1;
1063  x3 = x1 + dx * t * t;
1064  return x3;
1065  }
1066 }
1067 
1068 
1069 //
1070 // RixEaseOutMix:
1071 // Templated ease-in: T must define *, +, plus scalar +, -)
1072 // interpolate from x1 to x2, with tangent at x2 of 0
1073 //
1074 template <typename T>
1075 PRMAN_INLINE T
1076 RixEaseOutMix(const T& x1, const T& x2, float t)
1077 {
1078  if (t <= 0.0f)
1079  return x1;
1080  else if (t >= 1.0f)
1081  return x2;
1082  else
1083  {
1084  T x3;
1085  T dx = x2 - x1;
1086  x3 = t * dx * (2.0f - t) + x1;
1087  return x3;
1088  }
1089 }
1090 
1091 
1092 // -------------------
1093 // Threshold functions
1094 // -------------------
1095 
1096 
1097 //
1098 // RixBoxStep: returns 0 when val < min and 1 otherwise
1099 //
1100 PRMAN_INLINE float
1101 RixBoxStep(float min, float val)
1102 {
1103  return val < min ? 0.0f : 1.0f;
1104 }
1105 
1106 
1107 //
1108 // RixLinearStep: returns 0 when val < min, 1 when val > max and
1109 // a linearly interpolated value between 0 and 1 for val between min and max.
1110 //
1111 PRMAN_INLINE float
1112 RixLinearStep(float min, float max, float val)
1113 {
1114  if (min < max)
1115  {
1116  return val <= min
1117  ? 0.0f
1118  : (val >= max ? 1.0f : (val - min) / (max - min));
1119  }
1120  else if (min > max)
1121  {
1122  return 1.0f - (
1123  val <= max
1124  ? 0.0f
1125  : (val >= min ? 1.0f : (val - max) / (min - max)));
1126  }
1127  else
1128  return RixBoxStep(min, val);
1129 }
1130 
1131 
1132 //
1133 // RixSmoothStep: returns 0 when val < min, 1 when val > max and
1134 // a smooth Hermite interpolated value between 0 and 1 for val between
1135 // min and max. The slope at both ends of the cubic curve is zero.
1136 //
1137 PRMAN_INLINE float
1138 RixSmoothStep(float min, float max, float val)
1139 {
1140  if (min < max)
1141  {
1142  if (val <= min)
1143  return 0.0f;
1144  if (val >= max)
1145  return 1.0f;
1146  val = (val - min) / (max - min);
1147  }
1148  else if (min > max)
1149  {
1150  if (val <= max)
1151  return 1.0f;
1152  if (val >= min)
1153  return 0.0f;
1154  val = 1.0f - (val - max) / (min - max);
1155  }
1156  else
1157  return RixBoxStep(min, val);
1158 
1159  return val * val * (3.0f - 2.0f * val);
1160 }
1161 
1162 
1163 //
1164 // RixGaussStep: returns 0 when val < min, 1 when val > max and
1165 // an exponential curve between 0 and 1 for val between min and max.
1166 // Strictly speaking, this isn't a gaussian curve.
1167 //
1168 PRMAN_INLINE float
1169 RixGaussStep(float min, float max, float val)
1170 {
1171  if (min < max)
1172  {
1173  if (val < min)
1174  return 0.0f;
1175  if (val >= max)
1176  return 1.0f;
1177  val = 1.0f - (val - min) / (max - min);
1178  }
1179  else if (min > max)
1180  {
1181  if (val <= max)
1182  return 1.0f;
1183  if (val > min)
1184  return 0.0f;
1185  val = (val - max) / (min - max);
1186  }
1187  else
1188  return RixBoxStep(min, val);
1189 
1190  return std::pow(2.0f, -8.0f * val * val);
1191 }
1192 
1193 
1194 //
1195 // Convert a solid angle to a corresponding ray spread
1196 //
1197 PRMAN_INLINE float
1198 RixSolidAngle2Spread(float solidangle)
1199 {
1200  // To convert from angle to solid angle we use
1201  // cone-endcap formulation, assuming radius of 1
1202  //
1203  // omega = 2.pi.(1-cos(theta))
1204  //
1205  // therefore
1206  //
1207  // cos(theta) = 1 - omega/(2.pi)
1208  //
1209  // we want tan(theta)
1210  //
1211  // tan(theta) = + sqrt(1-cos^2(theta)) / cos(theta)
1212  // or - sqrt(1-cos^2(theta)) / cos(theta)
1213 
1214  // Clamp spread to 1. The solid angle corresponding to spread 1 is
1215  // 2 pi (1 - cos(pi/4)) ~ 1.840302
1216  if (solidangle > 1.840302f)
1217  return 1.0f;
1218 
1219  // Divide solidangle by 2*pi
1220  float omega_div_2pi = solidangle * 0.15915494f;
1221 
1222  // Compute cos(theta)
1223  float cosTheta = 1.0f - omega_div_2pi;
1224  assert(cosTheta > 0.0f);
1225 
1226  // Return tan(theta)
1227  return std::sqrt(1.0f - cosTheta * cosTheta) / cosTheta;
1228 }
1229 
1230 
1231 //
1232 // RixAlloca() is a thin veneer atop alloca(). Callers should take
1233 // care to not allocate beyond the platform-specific limits
1234 // on stack size. To avoid this concern, the ShadingContext
1235 // offers a heap-based memory pool. We implement this as a macro
1236 // instead of an inlined function since it's difficult to enforce
1237 // the requisite inlining in a portable fashion. The value of
1238 // this veneer is merely that the windows header contortions are
1239 // centralized in this utility header.
1240 //
1241 #define RixAlloca(s) alloca(s)
1242 
1243 
1244 //
1245 // Inputs Nf and Tn are assumed to be normalised, but are not
1246 // necessarily orthogonal. Parallel Nf and Tn are dealt with
1247 // by ignoring Tn.
1248 //
1249 PRMAN_INLINE void
1251  RtNormal3 const& Nf,
1252  RtVector3 const& Tn,
1253  RtVector3& TX,
1254  RtVector3& TY)
1255 {
1256  // In debug mode, assertion will help us identify unnormalized
1257  // Nf and Tn inputs.
1258  // Since this function is in the API, any bxdf or plugins that this
1259  // will get the assertion, which probably indicates a bug in the caller.
1260  assert(Nf.IsUnitLength()); // length close to 1
1261  assert(Tn.IsUnitLength()); // length close to 1
1262 
1263  if (Nf.AbsDot(Tn) < 0.995f)
1264  {
1265  TY = Cross(Nf, Tn);
1266  TY.Normalize();
1267  TX = Cross(TY, Nf);
1268  }
1269  else
1270  {
1271  // Under rare circumstances, the input vectors
1272  // can be parallel. In this case, we generate
1273  // a basis using only the normal.
1274  Nf.CreateOrthonormalBasis(TX, TY);
1275  }
1276 }
1277 
1278 
1279 PRMAN_INLINE void
1281  RixShadingContext* sc,
1282  RtPoint3& o,
1283  RtVector3& x,
1284  RtVector3& y,
1285  RtVector3& z)
1286 {
1287  PIXAR_ARGUSED(sc);
1288  PIXAR_ARGUSED(o);
1289  PIXAR_ARGUSED(x);
1290  PIXAR_ARGUSED(y);
1291  PIXAR_ARGUSED(z);
1292 
1293 #ifndef NDEBUG
1294  float orthonormalCheck = z.Dot(Cross(x, y));
1295  if (orthonormalCheck < 0.98f)
1296  {
1297  const RtColorRGB r = RtColorRGB(1, 0, 0);
1298  const RtColorRGB g = RtColorRGB(0, 1, 0);
1299  const RtColorRGB b = RtColorRGB(0, 0, 1);
1300  RixGeoDebugger* gdb =
1302  gdb->EmitPointNormal(o, x, r);
1303  gdb->EmitPointNormal(o, y, g);
1304  gdb->EmitPointNormal(o, z, b);
1305  }
1306 #endif
1307 }
1308 
1309 
1310 //
1311 // Modify the shading context so that u is shifted
1312 // by one differential.
1313 //
1314 PRMAN_INLINE void
1316 {
1317  float const* u;
1318  float const* du;
1321 
1322  int numPts = sCtx->numPts;
1323  RixShadingContext::Allocator pool(sCtx);
1324  float* newu = (float*)pool.AllocForPattern<float>(numPts);
1325  for (int i = 0; i < numPts; i++)
1326  {
1327  newu[i] = u[i] + du[i];
1328  }
1330 }
1331 
1332 
1333 //
1334 // Modify the shading context so that v is shifted
1335 // by one differential.
1336 //
1337 PRMAN_INLINE void
1339 {
1340  float const* v;
1341  float const* dv;
1344 
1345  int numPts = sCtx->numPts;
1346  RixShadingContext::Allocator pool(sCtx);
1347  float* newv = (float*)pool.AllocForPattern<float>(numPts);
1348  for (int i = 0; i < numPts; i++)
1349  {
1350  newv[i] = v[i] + dv[i];
1351  }
1353 }
1354 
1355 
1356 //
1357 // Classic Blinn formulation of bumped normal from a height field.
1358 // The three displacements represent the height at the original point,
1359 // at a point du units in the dPdu direction, and at a point dv units
1360 // in the dPdv direction.
1361 //
1362 PRMAN_INLINE void
1364  RixShadingContext const* sCtx,
1365  float const* disp,
1366  float const* dispU,
1367  float const* dispV,
1368  RtNormal3* Nn) // result: bumped normal (normalized)
1369 {
1370  int numPts = sCtx->numPts;
1371  float const* du;
1372  float const* dv;
1373  RtVector3 const* dPdu;
1374  RtVector3 const* dPdv;
1375  RtVector3 const* Norig;
1376  RtNormal3 const* Ngn;
1377  RtNormal3 const* Naon;
1382  sCtx->GetBuiltinVar(RixShadingContext::k_Nn, &Norig);
1385 
1386  // Get primvar N, ie. interpolated vertex normal, if present (not normalized).
1387  RtNormal3 fill(0,0,0);
1388  RtNormal3 const *Nuser;
1389  RixSCDetail nDetail = sCtx->GetPrimVar(Rix::k_N, fill, &Nuser);
1390  bool hasUserNormals = (nDetail != k_RixSCInvalidDetail);
1391 
1392  for (int i = 0; i < numPts; i++)
1393  {
1394  // Only skip computations if all disp values are zero
1395  if(disp[i] == 0.0f && dispU[i] == 0.0f && dispV[i] == 0.0f)
1396  {
1397  Nn[i] = Norig[i];
1398  }
1399  else
1400  {
1401  // We currently assume the normal does not change
1402  // significantly over the neighborhood of P + du and P + dv.
1403  // Should this assumption be invalid a further call to
1404  // evaluate the normal at each location may be warranted.
1405  RtPoint3 P0 = Norig[i] * disp[i];
1406  RtPoint3 P1 = du[i] * dPdu[i] + Norig[i] * dispU[i];
1407  RtPoint3 P2 = dv[i] * dPdv[i] + Norig[i] * dispV[i];
1408  Nn[i] = Cross(P1 - P0, P2 - P0);
1409  Nn[i].Normalize();
1410 
1411  // In some cases, Cross(dPdu, dPdv) is *not* the same as Nn, nor Ngn, mostly because of
1412  // the camera-to-object transform determinant.
1413  RtNormal3 computedNgn = Cross(du[i] * dPdu[i], dv[i] * dPdv[i]);
1414  computedNgn.Normalize();
1415 
1416  float const dotNg = Dot(computedNgn, Ngn[i]);
1417 
1418  if (hasUserNormals)
1419  {
1420  // Compensate for faceted renders of coarse polygon meshes (large faces)
1421 
1422  RtNormal3 Nuser_i = Nuser[i];
1423  RtNormal3 Naon_i = Naon[i];
1424 
1425  // Flip Naon if needed for calculation of delta
1426  if (dotNg < 0.0f)
1427  {
1428  Naon_i = -Naon_i;
1429  }
1430 
1431  // Interpolated user-provided vertex normals aren't usually normalized,
1432  // so normalize now
1433  Nuser_i.Normalize();
1434 
1435  // Compute difference between user-provided smooth normal and polymesh
1436  // face normal
1437  RtNormal3 delta = Nuser_i - Naon_i;
1438 
1439  // Use vertex normals to smooth out faceted renders of coarse polygon meshes
1440  if (delta != RtNormal3(0.0f))
1441  {
1442  Nn[i] += delta;
1443  Nn[i].Normalize();
1444  }
1445  }
1446  else
1447  {
1448  // Compensate for faceted renders of coarsely tessellated geometry (large
1449  // micropolygons)
1450 
1451  // Flip Nn and computedNgn if needed for calculation of delta
1452  if (dotNg < 0.0f)
1453  {
1454  Nn[i] = -Nn[i];
1455  computedNgn = -computedNgn;
1456  }
1457 
1458  RtNormal3 const delta = Norig[i] - computedNgn;
1459 
1460  // Smooth out coarsely tessellated polygon meshes by adding difference
1461  // between Nn and Ngn
1462  if (delta != RtNormal3(0.0f))
1463  {
1464  Nn[i] += delta;
1465  Nn[i].Normalize();
1466  }
1467  }
1468 
1469  }
1470  }
1471 }
1472 
1473 
1474 //
1475 // This routine determines whether the shading points in the provided
1476 // shading context belong to a matte object. Zero is returned if not,
1477 // while a positive value indicates a matte object. A negative value is
1478 // returned on error.
1479 //
1480 PRMAN_INLINE int
1482 {
1483  static const RtUString k_matteName("Ri:Matte");
1484  static const int k_matteLen = sizeof(float);
1485  static const int k_matteDef = 0;
1486 
1487  int matte = k_matteDef;
1488 
1489  if (RixRenderState* state =
1491  {
1492  RixRenderState::Type matteType;
1493  float matteVal;
1494  int matteRet;
1495  int matteCount;
1496 
1497  matteRet = state->GetAttribute(
1498  k_matteName, &matteVal, k_matteLen, &matteType, &matteCount);
1499 
1500  if (matteRet != 0)
1501  matte = -1;
1502  else if (matteCount == 1)
1503  matte = (int)matteVal;
1504  }
1505  else
1506  {
1507  matte = -1;
1508  }
1509 
1510  return matte;
1511 }
1512 
1513 
1514 PRMAN_INLINE int
1516 {
1517  static const RtUString k_holdoutName("trace:holdout");
1518  static const int k_holdoutLen = sizeof(float);
1519  static const int k_holdoutDef = 0;
1520  int holdout = k_holdoutDef;
1521  if (RixRenderState* state =
1523  {
1524  RixRenderState::Type holdoutType;
1525  float holdoutVal;
1526  int holdoutCount;
1527  int holdoutRet = state->GetAttribute(
1528  k_holdoutName, &holdoutVal, k_holdoutLen, &holdoutType, &holdoutCount);
1529  if (holdoutRet)
1530  holdout = -1;
1531  else
1532  holdout = (int)holdoutVal;
1533  }
1534  return holdout;
1535 }
1536 
1537 
1538 PRMAN_INLINE unsigned long
1539 RixImod(const unsigned long a, const unsigned long b)
1540 {
1541  unsigned long n = a/b;
1542  return (a - n*b);
1543 }
1544 
1545 
1546 //
1547 // Compute a hashed float value based on an input string.
1548 // djb2
1549 // http://www.cse.yorku.ca/~oz/hash.html
1550 // This algorithm (k=33) was first reported by dan bernstein many years ago in
1551 // comp.lang.c. Another version of this algorithm (now favored by Bernstein) uses
1552 // xor: hash(i) = hash(i - 1) * 33 ^ str[i]; the magic of number 33 (why it works
1553 // better than many other constants, prime or not) has never been adequately
1554 // explained.
1555 //
1556 PRMAN_INLINE float
1557 RixHash(const char *bufPtr, unsigned long range=65535)
1558 {
1559  unsigned long hash = 5381;
1560  int c;
1561  while ((c = int(*bufPtr++)))
1562  hash = ((hash << 5) + hash) ^ c; // hash * 33 + c
1563 
1564  return float(RixImod(hash,range));
1565 }
1566 
1567 
1568 //
1569 // This function mixes and clamps the color result between a and b to avoid issues
1570 // with floating point precision.
1571 //
1572 PRMAN_INLINE RtColorRGB
1573 RixLerpRGB(RtColorRGB const &a, RtColorRGB const &b, float const mix)
1574 {
1575  RtColorRGB result = b + mix * (a - b);
1576  result.r = a.r < b.r ? RixClamp(result.r, a.r, b.r) : RixClamp(result.r, b.r, a.r);
1577  result.g = a.g < b.g ? RixClamp(result.g, a.g, b.g) : RixClamp(result.g, b.g, a.g);
1578  result.b = a.b < b.b ? RixClamp(result.b, a.b, b.b) : RixClamp(result.b, b.b, a.b);
1579  return result;
1580 }
1581 
1582 
1583 //
1584 // This function adjusts the normals when the geometric normals are facing away
1585 // from the camera.
1586 //
1587 PRMAN_INLINE void
1588 RixAdjustNormal(float const amount, RtVector3 const &Vn, RtVector3 const &Ngn,
1589  RtNormal3 &Nn)
1590 {
1591  if (amount == 0.0f)
1592  return;
1593 
1594  if (Dot(Vn, Ngn) >= 0.0f)
1595  {
1596  float VdotN = Dot(Vn, Nn);
1597  if (VdotN <= 0.0f)
1598  {
1599  // If the input normal faces away from camera, nudge it back
1600  // pad an extra 1% towards V
1601  Nn -= amount * 1.01f * VdotN * Vn;
1602  Nn.Normalize();
1603  }
1604  }
1605 }
1606 
1607 PRMAN_INLINE RtFloat
1608 RixBumpShadowingFactor(RtNormal3 shadingNormal, RtNormal3 bumpNormal, RtVector3 Ln)
1609 {
1610  // Code from the original paper:
1611  // "A Microfacet-Based Shadowing Function to Solve the Bump Terminator Problem".
1612  // Estevez, et al 2019.
1613  float cos_d = RixMin(std::abs(shadingNormal.Dot(bumpNormal)), 1.0f);
1614  float tan2_d = (1.0f - cos_d * cos_d) / (cos_d * cos_d);
1615  float alpha2 = RixClamp(0.125f * tan2_d , 0.0f , 1.0f);
1616 
1617  float cos_i = RixMax(std::abs(shadingNormal.Dot(Ln)), 1e-6f);
1618  float tan2_i_square = (cos_i * cos_i);
1619  float tan2_i = (1.0f - cos_i * cos_i) / tan2_i_square;
1620  if (tan2_i_square < 1e-6f)
1621  {
1622  // Division by ZERO undifined;
1623  tan2_i = 1.0f;
1624  }
1625 
1626  return (2.0f / (1.0f + sqrtf(1.0f + alpha2 * tan2_i)));
1627 }
1628 
1629 // Procedural may have a "user:procprimid" attribute. This is a scene-level
1630 // per-instance hash that may be combined with a procedural-level hash to build
1631 // a globally unique one and create random variations.
1632 PRMAN_INLINE RtFloat
1634 {
1635  float instanceId = 0;
1636  RixRenderState::Type type;
1637  int count;
1638  rstate->GetAttribute(RtUString("user:procprimid"), &instanceId, sizeof(RtFloat), &type, &count);
1639  return instanceId;
1640 }
1641 
1642 //
1643 // Convert ray spread, ray radius, and surface curvature to an equivalent
1644 // (squared) surface roughness.
1645 //
1646 PRMAN_INLINE float
1647 RixRayCurvatureToRoughnessSq(float multiplier, float curvature,
1648  float incidentRayRadius, float incidentRaySpread)
1649 {
1650  float sinTheta = std::max(fabsf(incidentRaySpread), fabsf(incidentRayRadius*curvature));
1651  sinTheta *= multiplier;
1652 
1653  if (sinTheta == 0.0f) return 0.0f;
1654 
1655  sinTheta = std::min(1.0f, sinTheta);
1656  float cosTheta = sqrtf(std::max(0.0f, 1.0f-sinTheta*sinTheta));
1657  // Precision issue, use limit:
1658  // sin(0.01) ~ 0.0099998 so we could even go a little larger to be safer
1659  float theta = (sinTheta < 0.01f) ? sinTheta : asinf(sinTheta);
1660 
1661  float sigmaSq = (theta*theta-2.0f) + 2.0f*cosTheta*(theta/sinTheta);
1662 
1663  // sigmaSq can be 0.0 or slightly negative due to precision: clamp at 0.0
1664  return std::max(0.0f, 2.0f*sigmaSq);
1665 }
1666 
1667 
1668 //
1669 // Combine material roughness with a (squared) roughness computed from the ray
1670 // derivatives and local surface curvature. Returns a new, larger roughness.
1671 // The colloquial term for this is "roughness mollification"; it is sometimes
1672 // also called "path regularization".
1673 // (Note that for many bxdfs, the material roughness may already have been squared
1674 // for a more uniform parameter space -- don't let that confuse you.)
1675 //
1676 PRMAN_INLINE float
1677 RixMollifyRoughness(float roughness, float rayCurvatureRoughnessSq)
1678 {
1679  return sqrtf(roughness*roughness + rayCurvatureRoughnessSq);
1680 }
1681 
1682 
1683 #endif // RixShadingUtils_h