1 #ifndef RixShadingUtils_h
2 #define RixShadingUtils_h
46 #include "RixShading.h"
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 )
78 namespace RixConstants {
82 static const RtColorRGB k_ZeroRGB(0.0f);
83 static const RtColorRGB k_OneRGB(1.0f);
84 static const RtFloat3 k_ZeroF3(0.0f);
89 RixDegreesToRadians(RtFloat degrees)
91 return degrees * F_DEGTORAD;
95 RixRadiansToDegress(RtFloat rads)
97 return rads * F_RADTODEG;
100 template<
typename T> PRMAN_INLINE T
103 if(x > T(0))
return T(1);
104 if(x < T(0))
return T(-1);
115 (x != std::numeric_limits<float>::infinity()) &&
116 (x != -std::numeric_limits<float>::infinity());
118 return std::isfinite(x);
123 RixIsFinite(RtFloat3
const &v)
125 return RixIsFinite(v.x) && RixIsFinite(v.y) && RixIsFinite(v.z);
129 RixMin(RtFloat x, RtFloat y)
131 return x < y ? x : y;
135 RixMax(RtFloat x, RtFloat y)
137 return x > y ? x : y;
141 RixClamp(RtFloat x, RtFloat min, RtFloat max)
143 return x < min ? min : (x > max) ? max : x;
147 RixFractional(RtFloat x)
149 return (x - floorf(x));
187 RixFresnelDielectric(RtFloat VdN, RtFloat eta, RtFloat *Kr)
195 RtFloat etaSq = eta * eta;
196 RtFloat rcos_tSq = 1.0f - etaSq * (1.0f - rcos_i*rcos_i);
197 if (rcos_tSq <= 0.0f)
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);
209 RixFresnelDielectric(
const RtVector3 &Vn,
const RtNormal3 &Nn, RtFloat eta,
210 RtFloat *Kr, RtVector3 *Rn=NULL, RtVector3 *Tn=NULL)
212 RtFloat VdN = Dot(Nn, Vn);
213 RtFloat rcos_i, sign;
227 if(Rn) *Rn = 2.0f * VdN * Nn - Vn;
229 RtFloat etaSq = eta * eta;
230 RtFloat rcos_tSq = 1.0f - etaSq * (1.0f - rcos_i*rcos_i);
231 if (rcos_tSq <= 0.0f)
234 if(Tn) *Tn = RtVector3(0.0f);
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;
252 RtFloat *Kr, RtFloat *Kt,
253 RtVector3 *R, RtVector3 *T)
257 sCtx.GetBuiltinVar(RixShadingContext::k_Nn, &Nn);
258 sCtx.GetBuiltinVar(RixShadingContext::k_Vn, &Vn);
262 for(
int i = 0; i < nPts; ++i)
264 RixFresnelDielectric(Vn[i], Nn[i], eta, Kr+i, R+i, T+i);
265 Kt[i] = 1.0f - Kr[i];
270 for(
int i = 0; i < nPts; ++i)
272 RixFresnelDielectric(Vn[i], Nn[i], eta, Kr+i);
273 Kt[i] = 1.0f - Kr[i];
286 RixFresnelConductorApprox(RtFloat VdN, RtFloat eta, RtFloat kappa, RtFloat *Kr)
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);
305 RixFresnelDielectric(VdN, eta, Kr);
314 RixFresnelConductor(RtFloat VdN, RtFloat eta, RtFloat kappa, RtFloat *Kr)
318 float cosSq = VdN * VdN,
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));
326 float t1 = aSqPlusbSq + cosSq;
327 float t2 = 2.0f*a*VdN;
329 float rperpSq = (t1 - t2) / (t1 + t2);
331 float t3 = aSqPlusbSq*cosSq + sin4;
334 float rparSq = rperpSq * (t3 - t4) / (t3 + t4);
336 *Kr = 0.5f * (rperpSq + rparSq);
341 RixFresnelDielectric(VdN, eta, Kr);
351 RixFresnelConductor(
const RtVector3 &Vn,
const RtNormal3 &Nn,
352 RtFloat eta, RtFloat kappa,
353 RtFloat *Kr, RtVector3 *Rn=NULL)
355 RtFloat VdN = Dot(Nn, Vn);
356 RixFresnelConductorApprox(VdN, eta, kappa, Kr);
357 if(Rn) *Rn = 2.0f * VdN * Nn - Vn;
361 RixFresnelConductor(RtFloat VdN,
362 RtColorRGB
const &eta, RtColorRGB
const &kappa,
366 RixFresnelConductorApprox(VdN, eta.r, kappa.r, &kr.r);
371 if (eta.g == eta.r && kappa.g == kappa.r)
374 RixFresnelConductorApprox(VdN, eta.g, kappa.g, &kr.g);
375 if (eta.b == eta.r && kappa.b == kappa.r)
377 else if (eta.b == eta.g && kappa.b == kappa.g)
380 RixFresnelConductorApprox(VdN, eta.b, kappa.b, &kr.b);
391 RixFresnelConductor(RtVector3
const &Vn, RtNormal3
const &Nn,
392 RtColorRGB
const &eta, RtColorRGB
const &kappa,
393 RtColorRGB *Kr, RtVector3 *Rn=NULL)
395 RtFloat VdN = Dot(Nn, Vn);
396 RixFresnelConductor(VdN, eta, kappa, Kr);
397 if(Rn) *Rn = 2.0f * VdN * Nn - Vn;
405 RixSchlickFresnelWeight(RtFloat NdV)
407 if (NdV <= 0.f)
return 1.f;
408 if (NdV >= 1.f)
return 0.f;
409 float f = 1.0f - NdV;
416 PRMAN_INLINE RtVector3
417 RixReflect(
const RtVector3 &Vn,
const RtNormal3 &Nn)
419 RtFloat VdN = Dot(Nn, Vn);
420 return 2.0f * VdN * Nn - Vn;
425 PRMAN_INLINE RtVector3
426 RixReflect(RtVector3
const &Vn, RtVector3
const &Nn, RtFloat VdN)
428 return 2.0f * VdN * Nn - Vn;
436 RixRefract(
const RtVector3 &Vn,
const RtNormal3 &Nn, RtFloat eta, RtVector3 &Tn)
439 RtFloat VdN = Dot(Vn, Nn);
440 RtFloat rcos_i, sign;
452 RtFloat etaSq = eta*eta;
453 RtFloat rcos_tSq = 1.0f - etaSq * (1.0f - rcos_i*rcos_i);
454 if (rcos_tSq <= 0.0f)
456 Tn = RtVector3(0.0f);
461 RtFloat rcos_t = std::sqrt(rcos_tSq);
462 Tn = sign * (eta * rcos_i - rcos_t) * Nn - eta * Vn;
468 PRMAN_INLINE RtNormal3
469 RixGetForwardFacingNormal(RtVector3
const &Vn, RtNormal3
const &Nn,
470 RtFloat *VdotNf=NULL)
473 float d = Dot(Vn, Nn);
486 PRMAN_INLINE RtNormal3
487 RixGetBackwardFacingNormal(RtVector3
const &Vn, RtNormal3
const &Nn,
488 RtFloat *VdotNb=NULL)
491 float d = Dot(Vn, Nn);
510 RixCosDirectionalDistribution(
const RtFloat2 &xi,
const RtVector3 &n,
511 const RtVector3 &t0,
const RtVector3 &t1,
512 RtVector3 &outDir,
float &cosTheta)
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));
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;
528 RixCosDirectionalDistribution(
const RtFloat2 &xi,
const RtVector3 &n,
529 RtVector3 &outDir,
float &cosTheta)
532 n.CreateOrthonormalBasis(t0, t1);
533 RixCosDirectionalDistribution(xi, n, t0, t1, outDir, cosTheta);
537 RixUniformDirectionalDistribution(
const RtFloat2 &xi,
const RtVector3 &n,
538 const RtVector3 &t0,
const RtVector3 &t1,
539 RtVector3 &outDir,
float &cosTheta)
541 float e1 = xi.x * F_TWOPI;
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;
552 RixUniformDirectionalDistribution(
const RtFloat2 &xi,
const RtVector3 &n,
553 RtVector3 &outDir,
float &cosTheta)
556 n.CreateOrthonormalBasis(t0, t1);
557 RixUniformDirectionalDistribution(xi, n, t0, t1, outDir, cosTheta);
560 PRMAN_INLINE RtVector3
561 RixSphericalDistribution(
const RtFloat2 &xi)
564 outDir.z = xi.y * 2.0f - 1.0f;
565 float sinTheta = 1.0f - outDir.z * outDir.z;
566 if (sinTheta <= 0.0f)
573 sinTheta = std::sqrt(sinTheta);
574 float phi = xi.x * F_TWOPI;
575 outDir.x = sinTheta * cosf(phi);
576 outDir.y = sinTheta * sinf(phi);
586 RixChooseAndRemap(RtFloat &xi,
int numThresholds,
float *thresholds)
589 if (xi < thresholds[0])
595 for (
int i = 1; i < numThresholds; i++)
597 if (thresholds[i-1] <= xi && xi < thresholds[i])
599 xi = (xi - thresholds[i-1]) / (thresholds[i] - thresholds[i-1]);
604 float lastThres = thresholds[numThresholds-1];
605 xi = (xi - lastThres) / (1.0f - lastThres);
606 return numThresholds;
611 RixTraceBias(
const RtPoint3 & ,
const RtNormal3 &N,
const RtVector3 &dir,
612 RtFloat biasR, RtFloat biasT)
614 return (N.Dot(dir) < 0.0f) ? biasT : biasR;
618 PRMAN_INLINE RtPoint3
619 RixApplyTraceBias(
const RtPoint3 &org,
const RtNormal3 &N,
620 const RtVector3 &dir,
624 RtFloat biasAmt = RixTraceBias(org, N, dir, biasR, biasT);
630 return org + biasAmt * dir;
635 RixSinCos(RtFloat phi, RtFloat *sinphi, RtFloat *cosphi)
638 sincosf(phi, sinphi, cosphi);
645 PRMAN_INLINE RtVector3
646 RixSphericalDirection(RtFloat sintheta, RtFloat costheta,
647 RtFloat sinphi, RtFloat cosphi)
649 return RtVector3(sintheta*cosphi, sintheta*sinphi, costheta);
652 PRMAN_INLINE RtVector3
653 RixSphericalDirection(RtFloat sintheta, RtFloat costheta, RtFloat phi)
655 RtFloat sinphi, cosphi;
656 RixSinCos(phi, &sinphi, &cosphi);
657 return RixSphericalDirection(sintheta, costheta, sinphi, cosphi);
664 PRMAN_INLINE RtVector3
665 RixChangeBasisFrom(RtVector3
const &in,
666 RtVector3
const &X, RtVector3
const &Y, RtVector3
const &Z)
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;
675 PRMAN_INLINE RtVector3
676 RixChangeBasis(RtVector3
const &in,
677 RtVector3
const &X, RtVector3
const &Y, RtVector3
const &Z)
679 return RixChangeBasisFrom(in, X, Y, Z);
685 PRMAN_INLINE RtVector3
686 RixChangeBasisTo(RtVector3
const &in,
687 RtVector3
const &X, RtVector3
const &Y, RtVector3
const &Z)
689 return RtVector3(Dot(in, X), Dot(in, Y), Dot(in, Z));
693 template <
typename T>
694 PRMAN_INLINE T RixMix(
const T &v0,
const T &v1, RtFloat m)
696 return (1.0f-m) * v0 + m * v1;
701 template <
typename T>
702 PRMAN_INLINE T RixSmoothMix(
const T &x1,
const T &x2, RtFloat t)
713 x3 = x1 + dx*t*t*(3.f - 2.f*t);
721 template <
typename T>
722 PRMAN_INLINE T RixEaseInMix(
const T &x1,
const T &x2, RtFloat t)
741 template <
typename T>
742 PRMAN_INLINE T RixEaseOutMix(
const T &x1,
const T &x2, RtFloat t)
753 x3 = t * dx*(2.f - t) + x1;
763 RixBoxStep(RtFloat min, RtFloat val)
765 return val < min ? 0.0f : 1.0f;
771 RixLinearStep(RtFloat min, RtFloat max, RtFloat val)
775 return val <= min ? 0.0f :
776 (val >= max ? 1.0f : (val - min)/(max - min));
781 return 1.0f - (val <= max ? 0.0f :
782 (val >= min ? 1.0f : (val - max)/(min - max)));
785 return RixBoxStep(min, val);
792 RixSmoothStep(RtFloat min, RtFloat max, RtFloat val)
796 if (val <= min)
return 0.f;
797 if (val >= max)
return 1.f;
798 val = (val - min)/(max - min);
803 if (val <= max)
return 1.f;
804 if (val >= min)
return 0.f;
805 val = 1.0f - (val - max)/(min - max);
808 return RixBoxStep(min, val);
810 return val*val * (3.0f - 2.0f * val);
817 RixGaussStep(RtFloat min, RtFloat max, RtFloat val)
821 if (val < min)
return 0.0f;
822 if (val >= max)
return 1.0f;
823 val = 1.0f - (val - min)/(max - min);
828 if (val <= max)
return 1.0f;
829 if (val > min)
return 0.0f;
830 val = (val - max)/(min - max);
833 return RixBoxStep(min, val);
835 return std::pow(2.0f, -8.0f * val*val);
839 RixSolidAngle2Spread(RtFloat solidangle)
859 if (solidangle > 1.840302f)
return 1.0f;
862 RtFloat omega_div_2pi = solidangle * 0.15915494f;
865 RtFloat costheta = 1.0f - omega_div_2pi;
866 assert(costheta > 0.0f);
869 return std::sqrt(1.0f-costheta*costheta) / costheta;
881 #define RixAlloca(s) alloca(s)
886 RixComputeShadingBasis(RtNormal3
const &Nf, RtVector3
const &Tn,
887 RtVector3 &TX, RtVector3 &TY)
896 RtVector3 &x, RtVector3 &y, RtVector3 &z)
899 RtFloat orthonormalCheck = z.Dot(Cross(x, y));
900 if(orthonormalCheck < 0.98f)
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);
921 sCtx->GetBuiltinVar(RixShadingContext::k_u, &u);
922 sCtx->GetBuiltinVar(RixShadingContext::k_du, &du);
924 int numPts = sCtx->
numPts;
926 RtFloat* newu = (RtFloat*)pool.AllocForPattern<RtFloat>(numPts);
927 for(
int i = 0; i < numPts; i++)
929 newu[i] = u[i] + du[i];
941 sCtx->GetBuiltinVar(RixShadingContext::k_v, &v);
942 sCtx->GetBuiltinVar(RixShadingContext::k_dv, &dv);
944 int numPts = sCtx->
numPts;
946 RtFloat* newv = (RtFloat*)pool.AllocForPattern<RtFloat>(numPts);
947 for(
int i = 0; i < numPts; i++)
949 newv[i] = v[i] + dv[i];
960 RtFloat
const* dispU, RtFloat
const* dispV,
963 int numPts = sCtx->
numPts;
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++)
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);
995 static const char *k_matteName =
"Matte";
996 static const int k_matteLen =
sizeof(RtFloat);
997 static const RtInt k_matteDef = 0;
999 RtInt matte = k_matteDef;
1001 if (RixRenderState *state =
1002 (RixRenderState *) sCtx.GetRixInterface(k_RixRenderState))
1004 RixRenderState::Type matteType;
1009 matteRet = state->GetAttribute(k_matteName, &matteVal,
1010 k_matteLen, &matteType, &matteCount);
1014 else if (matteCount == 1)
1015 matte = (RtInt) matteVal;
1025 #endif // RixShadingUtils_h