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