RixShadingUtils.h Source File

RixShadingUtils.h
1 #ifndef RixShadingUtils_h
2 #define RixShadingUtils_h
3 
4 /* $Revision: #4 $ $Date: 2016/03/07 $
5 # ------------------------------------------------------------------------------
6 #
7 # Copyright (c) 2012-2014 Pixar Animation Studios. All rights reserved.
8 #
9 # The information in this file (the "Software") is provided for the
10 # exclusive use of the software licensees of Pixar. Licensees have
11 # the right to incorporate the Software into other products for use
12 # by other authorized software licensees of Pixar, without fee.
13 # Except as expressly permitted herein, the Software may not be
14 # disclosed to third parties, copied or duplicated in any form, in
15 # whole or in part, without the prior written permission of
16 # Pixar Animation Studios.
17 #
18 # The copyright notices in the Software and this entire statement,
19 # including the above license grant, this restriction and the
20 # following disclaimer, must be included in all copies of the
21 # Software, in whole or in part, and all permitted derivative works of
22 # the Software, unless such copies or derivative works are solely
23 # in the form of machine-executable object code generated by a
24 # source language processor.
25 #
26 # PIXAR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
27 # ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT
28 # SHALL PIXAR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES
29 # OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
30 # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
31 # ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
32 # SOFTWARE.
33 #
34 # Pixar
35 # 1200 Park Ave
36 # Emeryville CA 94608
37 #
38 # ------------------------------------------------------------------------------
39 */
40 
41 // RixShadingUtils:
42 //
43 // utility/portability functions for RixShading plugins.
44 //
45 
46 #include "RixShading.h"
47 
48 #if defined(WIN32)
49 #include <malloc.h>
50 #else
51 #include <alloca.h>
52 #endif
53 
54 #include <cmath>
55 #include <cassert>
56 #include <algorithm>
57 
58 // single-precision floating point constants
59 #define F_PI ( 3.14159265f )
60 #define F_TWOPI ( 6.283185307f )
61 #define F_FOURPI ( 12.56637061f )
62 #define F_INVPI ( 0.318309886f )
63 #define F_INVPISQ ( 0.1013211836f )
64 #define F_INVTWOPI ( 0.15915494309f )
65 #define F_INVFOURPI ( 0.0795774715f )
66 #define F_PIDIV2 ( 1.57079632679f )
67 #define F_PIDIV4 ( 0.785398163397f )
68 #define F_DEGTORAD ( 0.017453292520f )
69 #define F_RADTODEG ( 57.2957795131f )
70 #define F_INVLN2 ( 1.44269504089f )
71 #define F_INVLN4 ( 0.72134752f )
72 #define F_LOG2E ( 1.44269504088896f )
73 #define F_SQRT2 ( 1.41421356237f )
74 #define F_MAXDIST ( 1.0e10f )
75 #define F_SQRTMIN ( 1.0842021721e-19f )
76 #define F_MINDIVISOR ( 1.0e-6f )
77 
78 namespace RixConstants {
79 
80 // some additional constants
81 
82 static const RtColorRGB k_ZeroRGB(0.0f);
83 static const RtColorRGB k_OneRGB(1.0f);
84 static const RtFloat3 k_ZeroF3(0.0f);
85 
86 } // namespace RixConstants
87 
88 PRMAN_INLINE RtFloat
89 RixDegreesToRadians(RtFloat degrees)
90 {
91  return degrees * F_DEGTORAD;
92 }
93 
94 PRMAN_INLINE RtFloat
95 RixRadiansToDegress(RtFloat rads)
96 {
97  return rads * F_RADTODEG;
98 }
99 
100 template<typename T> PRMAN_INLINE T
101 RixSignum(T x)
102 {
103  if(x > T(0)) return T(1);
104  if(x < T(0)) return T(-1);
105  return T(0);
106 }
107 
108 // RixIsFinite is helpful in diagnosing bugs that produce NaNs
109 // and other exotic breads.
110 PRMAN_INLINE int
111 RixIsFinite(float x)
112 {
113 #if defined(WIN32)
114  return (x == x) &&
115  (x != std::numeric_limits<float>::infinity()) &&
116  (x != -std::numeric_limits<float>::infinity());
117 #else
118  return std::isfinite(x);
119 #endif
120 }
121 
122 PRMAN_INLINE int
123 RixIsFinite(RtFloat3 const &v)
124 {
125  return RixIsFinite(v.x) && RixIsFinite(v.y) && RixIsFinite(v.z);
126 }
127 
128 PRMAN_INLINE RtFloat
129 RixMin(RtFloat x, RtFloat y)
130 {
131  return x < y ? x : y;
132 }
133 
134 PRMAN_INLINE RtFloat
135 RixMax(RtFloat x, RtFloat y)
136 {
137  return x > y ? x : y;
138 }
139 
140 PRMAN_INLINE RtFloat
141 RixClamp(RtFloat x, RtFloat min, RtFloat max)
142 {
143  return x < min ? min : (x > max) ? max : x;
144 }
145 
146 PRMAN_INLINE RtFloat
147 RixFractional(RtFloat x)
148 {
149  return (x - floorf(x));
150 }
151 
186 PRMAN_INLINE void
187 RixFresnelDielectric(RtFloat VdN, RtFloat eta, RtFloat *Kr)
188 {
189  RtFloat rcos_i;
190  if(VdN < 0.f)
191  rcos_i = -VdN;
192  else
193  rcos_i = VdN;
194 
195  RtFloat etaSq = eta * eta;
196  RtFloat rcos_tSq = 1.0f - etaSq * (1.0f - rcos_i*rcos_i);
197  if (rcos_tSq <= 0.0f)
198  *Kr = 1.0f; // total internal reflection
199  else
200  {
201  RtFloat rcos_t = std::sqrt(rcos_tSq);
202  RtFloat rpar = (eta*rcos_t - rcos_i) / (eta*rcos_t + rcos_i);
203  RtFloat rper = (eta*rcos_i - rcos_t) / (eta*rcos_i + rcos_t);
204  *Kr = 0.5f * (rpar*rpar + rper*rper);
205  }
206 }
207 
208 PRMAN_INLINE void
209 RixFresnelDielectric(const RtVector3 &Vn, const RtNormal3 &Nn, RtFloat eta,
210  RtFloat *Kr, RtVector3 *Rn=NULL, RtVector3 *Tn=NULL)
211 {
212  RtFloat VdN = Dot(Nn, Vn);
213  RtFloat rcos_i, sign;
214  if(VdN < 0.f)
215  {
216  rcos_i = -VdN;
217  sign = -1.f;
218  }
219  else
220  {
221  rcos_i = VdN;
222  sign = 1.f;
223  }
224 
225  // reflection direction, formula works if Nn and Vn are on
226  // opposite or same sides
227  if(Rn) *Rn = 2.0f * VdN * Nn - Vn;
228 
229  RtFloat etaSq = eta * eta;
230  RtFloat rcos_tSq = 1.0f - etaSq * (1.0f - rcos_i*rcos_i);
231  if (rcos_tSq <= 0.0f)
232  {
233  *Kr = 1.0f; // total internal reflection
234  if(Tn) *Tn = RtVector3(0.0f); // no refraction (transmission) dir
235  }
236  else
237  {
238  RtFloat rcos_t = std::sqrt(rcos_tSq);
239  RtFloat rpar = (eta*rcos_t - rcos_i) / (eta*rcos_t + rcos_i);
240  RtFloat rper = (eta*rcos_i - rcos_t) / (eta*rcos_i + rcos_t);
241  *Kr = 0.5f * (rpar*rpar + rper*rper);
242  if(Tn) *Tn = sign * (eta * rcos_i - rcos_t) * Nn - eta * Vn;
243  }
244 }
245 
250 PRMAN_INLINE void
251 RixFresnelDielectric(RixShadingContext &sCtx, RtFloat eta,
252  RtFloat *Kr, RtFloat *Kt, // reflect and refract coeffs
253  RtVector3 *R, RtVector3 *T) // reflect and refract dirs
254 {
255  RtNormal3 const *Nn;
256  RtVector3 const *Vn;
257  sCtx.GetBuiltinVar(RixShadingContext::k_Nn, &Nn);
258  sCtx.GetBuiltinVar(RixShadingContext::k_Vn, &Vn);
259  RtInt nPts = sCtx.numPts;
260  if(R && T)
261  {
262  for(int i = 0; i < nPts; ++i)
263  {
264  RixFresnelDielectric(Vn[i], Nn[i], eta, Kr+i, R+i, T+i);
265  Kt[i] = 1.0f - Kr[i];
266  }
267  }
268  else
269  {
270  for(int i = 0; i < nPts; ++i)
271  {
272  RixFresnelDielectric(Vn[i], Nn[i], eta, Kr+i);
273  Kt[i] = 1.0f - Kr[i];
274  }
275  }
276 }
277 
285 PRMAN_INLINE void
286 RixFresnelConductorApprox(RtFloat VdN, RtFloat eta, RtFloat kappa, RtFloat *Kr)
287 {
288  if(kappa > .01f)
289  {
290  // approximation for dielectric/conductor interface
291  if(eta > 0.f)
292  eta = 1.f / eta;
293  kappa = 1.f / kappa;
294  float cosSq = VdN*VdN;
295  float cos2eta = 2.f * eta * VdN;
296  RtFloat t0 = eta * eta + kappa * kappa;
297  RtFloat t1 = t0 * cosSq;
298  RtFloat rperp = (t0 - cos2eta + cosSq) / (t0 + cos2eta + cosSq);
299  RtFloat rpar = (t1 - cos2eta + 1.f) / (t1 + cos2eta + 1.f);
300  *Kr = 0.5f * (rpar + rperp);
301  }
302  else
303  {
304  // when kappa is small, we're dielectric
305  RixFresnelDielectric(VdN, eta, Kr);
306  }
307 }
308 
309 // RixFresnelConductor:
310 // more expensive computation of fresnel conductor, usually the
311 // approximation is quite good (except for small kappa).
312 // See: Moeller's Optics
313 PRMAN_INLINE void
314 RixFresnelConductor(RtFloat VdN, RtFloat eta, RtFloat kappa, RtFloat *Kr)
315 {
316  if(kappa > .01f)
317  {
318  float cosSq = VdN * VdN,
319  sinSq = 1.f-cosSq,
320  sin4 = sinSq*sinSq;
321 
322  float t0 = eta*eta - kappa*kappa - sinSq;
323  float aSqPlusbSq = std::sqrt(t0*t0 + 4.f*kappa*kappa*eta*eta);
324  float a = std::sqrt(0.5f * (aSqPlusbSq + t0));
325 
326  float t1 = aSqPlusbSq + cosSq;
327  float t2 = 2.0f*a*VdN;
328 
329  float rperpSq = (t1 - t2) / (t1 + t2);
330 
331  float t3 = aSqPlusbSq*cosSq + sin4;
332  float t4 = t2*sinSq;
333 
334  float rparSq = rperpSq * (t3 - t4) / (t3 + t4);
335 
336  *Kr = 0.5f * (rperpSq + rparSq);
337  }
338  else
339  {
340  // when kappa is small, we're dielectric
341  RixFresnelDielectric(VdN, eta, Kr);
342  }
343 }
344 
350 PRMAN_INLINE void
351 RixFresnelConductor(const RtVector3 &Vn, const RtNormal3 &Nn,
352  RtFloat eta, RtFloat kappa,
353  RtFloat *Kr, RtVector3 *Rn=NULL)
354 {
355  RtFloat VdN = Dot(Nn, Vn);
356  RixFresnelConductorApprox(VdN, eta, kappa, Kr);
357  if(Rn) *Rn = 2.0f * VdN * Nn - Vn;
358 }
359 
360 PRMAN_INLINE void
361 RixFresnelConductor(RtFloat VdN,
362  RtColorRGB const &eta, RtColorRGB const &kappa,
363  RtColorRGB *Kr)
364 {
365  RtColorRGB kr;
366  RixFresnelConductorApprox(VdN, eta.r, kappa.r, &kr.r);
367 
368  // Make sure we compute other bands only when necessary.
369  // if eta and kappa are monochromatic, we only compute one band and the cost
370  // is the same as a RixFresnelDielectric.
371  if (eta.g == eta.r && kappa.g == kappa.r)
372  kr.g = kr.r;
373  else
374  RixFresnelConductorApprox(VdN, eta.g, kappa.g, &kr.g);
375  if (eta.b == eta.r && kappa.b == kappa.r)
376  kr.b = kr.r;
377  else if (eta.b == eta.g && kappa.b == kappa.g)
378  kr.b = kr.g;
379  else
380  RixFresnelConductorApprox(VdN, eta.b, kappa.b, &kr.b);
381 
382  *Kr = kr;
383 }
384 
390 PRMAN_INLINE void
391 RixFresnelConductor(RtVector3 const &Vn, RtNormal3 const &Nn,
392  RtColorRGB const &eta, RtColorRGB const &kappa,
393  RtColorRGB *Kr, RtVector3 *Rn=NULL)
394 {
395  RtFloat VdN = Dot(Nn, Vn);
396  RixFresnelConductor(VdN, eta, kappa, Kr);
397  if(Rn) *Rn = 2.0f * VdN * Nn - Vn;
398 }
399 
404 PRMAN_INLINE RtFloat
405 RixSchlickFresnelWeight(RtFloat NdV)
406 {
407  if (NdV <= 0.f) return 1.f;
408  if (NdV >= 1.f) return 0.f; // dot prod can be slightly larger than 1.0
409  float f = 1.0f - NdV;
410  float f2 = f*f;
411  return f2*f2*f; // std::pow(f, 5); -- result between 0.0 and 1.0
412 }
413 
416 PRMAN_INLINE RtVector3
417 RixReflect(const RtVector3 &Vn, const RtNormal3 &Nn)
418 {
419  RtFloat VdN = Dot(Nn, Vn);
420  return 2.0f * VdN * Nn - Vn; // reflection direction
421 }
422 
425 PRMAN_INLINE RtVector3
426 RixReflect(RtVector3 const &Vn, RtVector3 const &Nn, RtFloat VdN)
427 {
428  return 2.0f * VdN * Nn - Vn; // reflection direction
429 }
430 
435 PRMAN_INLINE int
436 RixRefract(const RtVector3 &Vn, const RtNormal3 &Nn, RtFloat eta, RtVector3 &Tn)
437 {
438  int err = 0;
439  RtFloat VdN = Dot(Vn, Nn);
440  RtFloat rcos_i, sign;
441  if (VdN < 0.f)
442  {
443  rcos_i = -VdN;
444  sign = -1.f;
445  }
446  else
447  {
448  rcos_i = VdN;
449  sign = 1.f;
450  }
451 
452  RtFloat etaSq = eta*eta;
453  RtFloat rcos_tSq = 1.0f - etaSq * (1.0f - rcos_i*rcos_i);
454  if (rcos_tSq <= 0.0f)
455  {
456  Tn = RtVector3(0.0f);
457  err = 1; // total internal reflection: no refraction
458  }
459  else
460  {
461  RtFloat rcos_t = std::sqrt(rcos_tSq);
462  Tn = sign * (eta * rcos_i - rcos_t) * Nn - eta * Vn; // refraction dir
463  Tn.Normalize();
464  }
465  return err;
466 }
467 
468 PRMAN_INLINE RtNormal3
469 RixGetForwardFacingNormal(RtVector3 const &Vn, RtNormal3 const &Nn,
470  RtFloat *VdotNf=NULL)
471 {
472  RtNormal3 Nf;
473  float d = Dot(Vn, Nn);
474  if(d > 0.f)
475  Nf = Nn;
476  else
477  {
478  Nf = -Nn;
479  d = -d;
480  }
481  if(VdotNf)
482  *VdotNf = d;
483  return Nf;
484 }
485 
486 PRMAN_INLINE RtNormal3
487 RixGetBackwardFacingNormal(RtVector3 const &Vn, RtNormal3 const &Nn,
488  RtFloat *VdotNb=NULL)
489 {
490  RtNormal3 Nb;
491  float d = Dot(Vn, Nn);
492  if(d < 0.f)
493  Nb = Nn;
494  else
495  {
496  Nb = -Nn;
497  d = -d;
498  }
499  if(VdotNb)
500  *VdotNb = d;
501  return Nb;
502 }
503 
509 PRMAN_INLINE void
510 RixCosDirectionalDistribution(const RtFloat2 &xi, const RtVector3 &n,
511  const RtVector3 &t0, const RtVector3 &t1,
512  RtVector3 &outDir, float &cosTheta)
513 {
514  float e1 = xi.x * F_TWOPI;
515  float z = std::sqrt(xi.y);
516  float r = std::sqrt(std::max(0.0f, 1.0f-xi.y)); // = sqrt(1 - z^2)
517  float x = r*cosf(e1);
518  float y = r*sinf(e1);
519  if (z < 1.e-12f) z = 1.e-12f;
520  outDir = x * t0 + y * t1 + z * n;
521  cosTheta = z;
522 }
523 
527 PRMAN_INLINE void
528 RixCosDirectionalDistribution(const RtFloat2 &xi, const RtVector3 &n,
529  RtVector3 &outDir, float &cosTheta)
530 {
531  RtVector3 t0, t1;
532  n.CreateOrthonormalBasis(t0, t1);
533  RixCosDirectionalDistribution(xi, n, t0, t1, outDir, cosTheta);
534 }
535 
536 PRMAN_INLINE void
537 RixUniformDirectionalDistribution(const RtFloat2 &xi, const RtVector3 &n,
538  const RtVector3 &t0, const RtVector3 &t1,
539  RtVector3 &outDir, float &cosTheta)
540 {
541  float e1 = xi.x * F_TWOPI;
542  float z = xi.y;
543  float r = std::sqrt(std::max(0.0f,1.0f - z*z));
544  float x = r*cosf(e1);
545  float y = r*sinf(e1);
546  if(z < 1.e-12f) z = 1.e-12f;
547  outDir = x * t0 + y * t1 + z * n;
548  cosTheta = z;
549 }
550 
551 PRMAN_INLINE void
552 RixUniformDirectionalDistribution(const RtFloat2 &xi, const RtVector3 &n,
553  RtVector3 &outDir, float &cosTheta)
554 {
555  RtVector3 t0, t1;
556  n.CreateOrthonormalBasis(t0, t1);
557  RixUniformDirectionalDistribution(xi, n, t0, t1, outDir, cosTheta);
558 }
559 
560 PRMAN_INLINE RtVector3
561 RixSphericalDistribution(const RtFloat2 &xi)
562 {
563  RtVector3 outDir;
564  outDir.z = xi.y * 2.0f - 1.0f; // cosTheta
565  float sinTheta = 1.0f - outDir.z * outDir.z;
566  if (sinTheta <= 0.0f)
567  {
568  outDir.x = 0.0f;
569  outDir.y = 0.0f;
570  }
571  else
572  {
573  sinTheta = std::sqrt(sinTheta);
574  float phi = xi.x * F_TWOPI;
575  outDir.x = sinTheta * cosf(phi);
576  outDir.y = sinTheta * sinf(phi);
577  }
578  return outDir;
579 }
580 
585 PRMAN_INLINE int
586 RixChooseAndRemap(RtFloat &xi, int numThresholds, float *thresholds)
587 {
588  // below lowest threshold?
589  if (xi < thresholds[0])
590  {
591  xi /= thresholds[0];
592  return 0; // chose lobe 0
593  }
594  // between thresholds?
595  for (int i = 1; i < numThresholds; i++)
596  {
597  if (thresholds[i-1] <= xi && xi < thresholds[i])
598  {
599  xi = (xi - thresholds[i-1]) / (thresholds[i] - thresholds[i-1]);
600  return i; // chose lobe i
601  }
602  }
603  // must be above highest threshold
604  float lastThres = thresholds[numThresholds-1];
605  xi = (xi - lastThres) / (1.0f - lastThres);
606  return numThresholds; // chose last lobe
607 }
608 
609 // Compute ray-tracing bias amount
610 PRMAN_INLINE RtFloat
611 RixTraceBias(const RtPoint3 & /* org */, const RtNormal3 &N, const RtVector3 &dir,
612  RtFloat biasR, RtFloat biasT)
613 {
614  return (N.Dot(dir) < 0.0f) ? biasT : biasR;
615 }
616 
617 // Compute ray-tracing bias amount and apply it to the ray origin
618 PRMAN_INLINE RtPoint3
619 RixApplyTraceBias(const RtPoint3 &org, const RtNormal3 &N,
620  const RtVector3 &dir,
621  const RtFloat biasR,
622  const RtFloat biasT)
623 {
624  RtFloat biasAmt = RixTraceBias(org, N, dir, biasR, biasT);
625 
630  return org + biasAmt * dir;
631 }
632 
633 
634 PRMAN_INLINE void
635 RixSinCos(RtFloat phi, RtFloat *sinphi, RtFloat *cosphi)
636 {
637 #ifdef LINUX
638  sincosf(phi, sinphi, cosphi);
639 #else
640  *sinphi = sinf(phi);
641  *cosphi = cosf(phi);
642 #endif
643 }
644 
645 PRMAN_INLINE RtVector3
646 RixSphericalDirection(RtFloat sintheta, RtFloat costheta,
647  RtFloat sinphi, RtFloat cosphi)
648 {
649  return RtVector3(sintheta*cosphi, sintheta*sinphi, costheta);
650 }
651 
652 PRMAN_INLINE RtVector3
653 RixSphericalDirection(RtFloat sintheta, RtFloat costheta, RtFloat phi)
654 {
655  RtFloat sinphi, cosphi;
656  RixSinCos(phi, &sinphi, &cosphi);
657  return RixSphericalDirection(sintheta, costheta, sinphi, cosphi);
658 }
659 
663 
664 PRMAN_INLINE RtVector3
665 RixChangeBasisFrom(RtVector3 const &in,
666  RtVector3 const &X, RtVector3 const &Y, RtVector3 const &Z)
667 {
668  RtVector3 result;
669  result.x = in.x*X.x + in.y*Y.x + in.z*Z.x;
670  result.y = in.x*X.y + in.y*Y.y + in.z*Z.y;
671  result.z = in.x*X.z + in.y*Y.z + in.z*Z.z;
672  return result;
673 }
674 
675 PRMAN_INLINE RtVector3
676 RixChangeBasis(RtVector3 const &in,
677  RtVector3 const &X, RtVector3 const &Y, RtVector3 const &Z)
678 {
679  return RixChangeBasisFrom(in, X, Y, Z);
680 }
681 
685 PRMAN_INLINE RtVector3
686 RixChangeBasisTo(RtVector3 const &in,
687  RtVector3 const &X, RtVector3 const &Y, RtVector3 const &Z)
688 {
689  return RtVector3(Dot(in, X), Dot(in, Y), Dot(in, Z));
690 }
691 
692 // Templated mix: T must define multiply and add (*, + operators)
693 template <typename T>
694 PRMAN_INLINE T RixMix(const T &v0, const T &v1, RtFloat m)
695 {
696  return (1.0f-m) * v0 + m * v1;
697 }
698 
699 // Templated smooth (hermite) mix: T must define *, +, plus scalar +, -)
700 // This is also known as the "ease" function.
701 template <typename T>
702 PRMAN_INLINE T RixSmoothMix(const T &x1, const T &x2, RtFloat t)
703 {
704  if(t <= 0.0f)
705  return x1;
706  else
707  if (t >= 1.0f)
708  return x2;
709  else
710  {
711  T x3;
712  T dx = x2 - x1;
713  x3 = x1 + dx*t*t*(3.f - 2.f*t);
714  return x3;
715  }
716 }
717 
718 // RixEaseInMix:
719 // Templated ease-in: T must define *, +, plus scalar +, -)
720 // interpolate from x1 to x2, with tangent at x1 of 0
721 template <typename T>
722 PRMAN_INLINE T RixEaseInMix(const T &x1, const T &x2, RtFloat t)
723 {
724  if(t <= 0.0f)
725  return x1;
726  else
727  if (t >= 1.0f)
728  return x2;
729  else
730  {
731  T x3;
732  T dx = x2 - x1;
733  x3 = x1 + dx*t*t;
734  return x3;
735  }
736 }
737 
738 // RixEaseOutMix:
739 // Templated ease-in: T must define *, +, plus scalar +, -)
740 // interpolate from x1 to x2, with tangent at x2 of 0
741 template <typename T>
742 PRMAN_INLINE T RixEaseOutMix(const T &x1, const T &x2, RtFloat t)
743 {
744  if(t <= 0.0f)
745  return x1;
746  else
747  if (t >= 1.0f)
748  return x2;
749  else
750  {
751  T x3;
752  T dx = x2 - x1;
753  x3 = t * dx*(2.f - t) + x1;
754  return x3;
755  }
756 }
757 
758 // Threshold functions
759 // -------------------
760 
761 // RixBoxStep: returns 0 when val < min and 1 otherwise
762 PRMAN_INLINE RtFloat
763 RixBoxStep(RtFloat min, RtFloat val)
764 {
765  return val < min ? 0.0f : 1.0f;
766 }
767 
768 // RixLinearStep: returns 0 when val < min, 1 when val > max and
769 // a linearly interpolated value between 0 and 1 for val between min and max.
770 PRMAN_INLINE RtFloat
771 RixLinearStep(RtFloat min, RtFloat max, RtFloat val)
772 {
773  if (min < max)
774  {
775  return val <= min ? 0.0f :
776  (val >= max ? 1.0f : (val - min)/(max - min));
777  }
778  else
779  if (min > max)
780  {
781  return 1.0f - (val <= max ? 0.0f :
782  (val >= min ? 1.0f : (val - max)/(min - max)));
783  }
784  else
785  return RixBoxStep(min, val);
786 }
787 
788 // RixSmoothStep: returns 0 when val < min, 1 when val > max and
789 // a smooth Hermite interpolated value between 0 and 1 for val between
790 // min and max. The slope at both ends of the cubic curve is zero.
791 PRMAN_INLINE RtFloat
792 RixSmoothStep(RtFloat min, RtFloat max, RtFloat val)
793 {
794  if (min < max)
795  {
796  if (val <= min) return 0.f;
797  if (val >= max) return 1.f;
798  val = (val - min)/(max - min);
799  }
800  else
801  if (min > max)
802  {
803  if (val <= max) return 1.f;
804  if (val >= min) return 0.f;
805  val = 1.0f - (val - max)/(min - max);
806  }
807  else
808  return RixBoxStep(min, val);
809 
810  return val*val * (3.0f - 2.0f * val);
811 }
812 
813 // RixGaussStep: returns 0 when val < min, 1 when val > max and
814 // an exponential curve between 0 and 1 for val between min and max.
815 // Strictly speaking, this isn't a gaussian curve.
816 PRMAN_INLINE RtFloat
817 RixGaussStep(RtFloat min, RtFloat max, RtFloat val)
818 {
819  if (min < max)
820  {
821  if (val < min) return 0.0f;
822  if (val >= max) return 1.0f;
823  val = 1.0f - (val - min)/(max - min);
824  }
825  else
826  if (min > max)
827  {
828  if (val <= max) return 1.0f;
829  if (val > min) return 0.0f;
830  val = (val - max)/(min - max);
831  }
832  else
833  return RixBoxStep(min, val);
834 
835  return std::pow(2.0f, -8.0f * val*val);
836 }
837 
838 PRMAN_INLINE RtFloat
839 RixSolidAngle2Spread(RtFloat solidangle)
840 {
857  // Clamp spread to 1. The solid angle corresponding to spread 1 is
858  // 2 pi (1 - cos(pi/4)) ~ 1.840302
859  if (solidangle > 1.840302f) return 1.0f;
860 
861  // Divide solidangle by 2*pi
862  RtFloat omega_div_2pi = solidangle * 0.15915494f;
863 
864  // Compute cos(theta)
865  RtFloat costheta = 1.0f - omega_div_2pi;
866  assert(costheta > 0.0f);
867 
868  // Return tan(theta)
869  return std::sqrt(1.0f-costheta*costheta) / costheta;
870 }
871 
880 
881 #define RixAlloca(s) alloca(s)
882 
883 // Inputs Nf and Tn are assumed to be normalised, but are not
884 // necessarily orthogonal. They must not be parallel however.
885 PRMAN_INLINE void
886 RixComputeShadingBasis(RtNormal3 const &Nf, RtVector3 const &Tn,
887  RtVector3 &TX, RtVector3 &TY)
888 {
889  TY = Cross(Nf, Tn);
890  TY.Normalize();
891  TX = Cross(TY, Nf);
892 }
893 
894 PRMAN_INLINE void
895 RixDebugBasis(RixShadingContext *sc, RtPoint3 &o,
896  RtVector3 &x, RtVector3 &y, RtVector3 &z)
897 {
898 #ifndef NDEBUG
899  RtFloat orthonormalCheck = z.Dot(Cross(x, y));
900  if(orthonormalCheck < 0.98f)
901  {
902  const RtColorRGB r = RtColorRGB(1,0,0);
903  const RtColorRGB g = RtColorRGB(0,1,0);
904  const RtColorRGB b = RtColorRGB(0,0,1);
905  RixGeoDebugger *gdb = (RixGeoDebugger *)
906  sc->GetRixInterface(k_RixGeoDebugger);
907  gdb->EmitPointNormal(o, x, r);
908  gdb->EmitPointNormal(o, y, g);
909  gdb->EmitPointNormal(o, z, b);
910  }
911 #endif
912 }
913 
914 // Modify the shading context so that u is shifted
915 // by one differential.
916 PRMAN_INLINE void
917 RixShiftCtxInU(RixShadingContext *sCtx)
918 {
919  RtFloat const *u;
920  RtFloat const *du;
921  sCtx->GetBuiltinVar(RixShadingContext::k_u, &u);
922  sCtx->GetBuiltinVar(RixShadingContext::k_du, &du);
923 
924  int numPts = sCtx->numPts;
925  RixShadingContext::Allocator pool(sCtx);
926  RtFloat* newu = (RtFloat*)pool.AllocForPattern<RtFloat>(numPts);
927  for(int i = 0; i < numPts; i++)
928  {
929  newu[i] = u[i] + du[i];
930  }
931  sCtx->SetBuiltinVar(RixShadingContext::k_u, newu);
932 }
933 
934 // Modify the shading context so that v is shifted
935 // by one differential.
936 PRMAN_INLINE void
937 RixShiftCtxInV(RixShadingContext *sCtx)
938 {
939  RtFloat const *v;
940  RtFloat const *dv;
941  sCtx->GetBuiltinVar(RixShadingContext::k_v, &v);
942  sCtx->GetBuiltinVar(RixShadingContext::k_dv, &dv);
943 
944  int numPts = sCtx->numPts;
945  RixShadingContext::Allocator pool(sCtx);
946  RtFloat* newv = (RtFloat*)pool.AllocForPattern<RtFloat>(numPts);
947  for(int i = 0; i < numPts; i++)
948  {
949  newv[i] = v[i] + dv[i];
950  }
951  sCtx->SetBuiltinVar(RixShadingContext::k_v, newv);
952 }
953 
958 PRMAN_INLINE void
959 RixBump(RixShadingContext const *sCtx, RtFloat const* disp,
960  RtFloat const* dispU, RtFloat const* dispV,
961  RtNormal3* Nn)
962 {
963  int numPts = sCtx->numPts;
964  RtFloat const *du;
965  RtFloat const *dv;
966  RtVector3 const *dPdu;
967  RtVector3 const *dPdv;
968  RtVector3 const *Norig;
969  sCtx->GetBuiltinVar(RixShadingContext::k_du, &du);
970  sCtx->GetBuiltinVar(RixShadingContext::k_dv, &dv);
971  sCtx->GetBuiltinVar(RixShadingContext::k_dPdu, &dPdu);
972  sCtx->GetBuiltinVar(RixShadingContext::k_dPdv, &dPdv);
973  sCtx->GetBuiltinVar(RixShadingContext::k_Nn, &Norig);
974  for(int i = 0; i < numPts; i++)
975  {
980  RtPoint3 P0 = Norig[i] * disp[i];
981  RtPoint3 P1 = du[i] * dPdu[i] + Norig[i] * dispU[i];
982  RtPoint3 P2 = dv[i] * dPdv[i] + Norig[i] * dispV[i];
983  Nn[i] = Cross(P1 - P0, P2 - P0);
984  Nn[i].Normalize();
985  }
986 }
987 
992 PRMAN_INLINE RtInt
993 RixIsMatte(RixShadingContext const &sCtx)
994 {
995  static const char *k_matteName = "Matte";
996  static const int k_matteLen = sizeof(RtFloat);
997  static const RtInt k_matteDef = 0;
998 
999  RtInt matte = k_matteDef;
1000 
1001  if (RixRenderState *state =
1002  (RixRenderState *) sCtx.GetRixInterface(k_RixRenderState))
1003  {
1004  RixRenderState::Type matteType;
1005  RtFloat matteVal;
1006  RtInt matteRet;
1007  RtInt matteCount;
1008 
1009  matteRet = state->GetAttribute(k_matteName, &matteVal,
1010  k_matteLen, &matteType, &matteCount);
1011 
1012  if (matteRet != 0)
1013  matte = -1;
1014  else if (matteCount == 1)
1015  matte = (RtInt) matteVal;
1016  }
1017  else
1018  {
1019  matte = -1;
1020  }
1021 
1022  return matte;
1023 }
1024 
1025 #endif // RixShadingUtils_h