123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293 |
- #ifndef UNITY_SAMPLING_INCLUDED
- #define UNITY_SAMPLING_INCLUDED
- //-----------------------------------------------------------------------------
- // Sample generator
- //-----------------------------------------------------------------------------
- #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Sampling/Fibonacci.hlsl"
- #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Sampling/Hammersley.hlsl"
- //-----------------------------------------------------------------------------
- // Coordinate system conversion
- //-----------------------------------------------------------------------------
- // Transforms the unit vector from the spherical to the Cartesian (right-handed, Z up) coordinate.
- real3 SphericalToCartesian(real cosPhi, real sinPhi, real cosTheta)
- {
- real sinTheta = SinFromCos(cosTheta);
- return real3(real2(cosPhi, sinPhi) * sinTheta, cosTheta);
- }
- real3 SphericalToCartesian(real phi, real cosTheta)
- {
- real sinPhi, cosPhi;
- sincos(phi, sinPhi, cosPhi);
- return SphericalToCartesian(cosPhi, sinPhi, cosTheta);
- }
- // Converts Cartesian coordinates given in the right-handed coordinate system
- // with Z pointing upwards (OpenGL style) to the coordinates in the left-handed
- // coordinate system with Y pointing up and Z facing forward (DirectX style).
- real3 TransformGLtoDX(real3 v)
- {
- return v.xzy;
- }
- // Performs conversion from equiareal map coordinates to Cartesian (DirectX cubemap) ones.
- real3 ConvertEquiarealToCubemap(real u, real v)
- {
- real phi = TWO_PI - TWO_PI * u;
- real cosTheta = 1.0 - 2.0 * v;
- return TransformGLtoDX(SphericalToCartesian(phi, cosTheta));
- }
- // Convert a texel position into normalized position [-1..1]x[-1..1]
- real2 CubemapTexelToNVC(uint2 unPositionTXS, uint cubemapSize)
- {
- return 2.0 * real2(unPositionTXS) / real(max(cubemapSize - 1, 1)) - 1.0;
- }
- // Map cubemap face to world vector basis
- static const real3 CUBEMAP_FACE_BASIS_MAPPING[6][3] =
- {
- //XPOS face
- {
- real3(0.0, 0.0, -1.0),
- real3(0.0, -1.0, 0.0),
- real3(1.0, 0.0, 0.0)
- },
- //XNEG face
- {
- real3(0.0, 0.0, 1.0),
- real3(0.0, -1.0, 0.0),
- real3(-1.0, 0.0, 0.0)
- },
- //YPOS face
- {
- real3(1.0, 0.0, 0.0),
- real3(0.0, 0.0, 1.0),
- real3(0.0, 1.0, 0.0)
- },
- //YNEG face
- {
- real3(1.0, 0.0, 0.0),
- real3(0.0, 0.0, -1.0),
- real3(0.0, -1.0, 0.0)
- },
- //ZPOS face
- {
- real3(1.0, 0.0, 0.0),
- real3(0.0, -1.0, 0.0),
- real3(0.0, 0.0, 1.0)
- },
- //ZNEG face
- {
- real3(-1.0, 0.0, 0.0),
- real3(0.0, -1.0, 0.0),
- real3(0.0, 0.0, -1.0)
- }
- };
- // Convert a normalized cubemap face position into a direction
- real3 CubemapTexelToDirection(real2 positionNVC, uint faceId)
- {
- real3 dir = CUBEMAP_FACE_BASIS_MAPPING[faceId][0] * positionNVC.x
- + CUBEMAP_FACE_BASIS_MAPPING[faceId][1] * positionNVC.y
- + CUBEMAP_FACE_BASIS_MAPPING[faceId][2];
- return normalize(dir);
- }
- //-----------------------------------------------------------------------------
- // Sampling function
- // Reference : http://www.cs.virginia.edu/~jdl/bib/globillum/mis/shirley96.pdf + PBRT
- //-----------------------------------------------------------------------------
- // Performs uniform sampling of the unit disk.
- // Ref: PBRT v3, p. 777.
- real2 SampleDiskUniform(real u1, real u2)
- {
- real r = sqrt(u1);
- real phi = TWO_PI * u2;
- real sinPhi, cosPhi;
- sincos(phi, sinPhi, cosPhi);
- return r * real2(cosPhi, sinPhi);
- }
- real3 SampleConeUniform(real u1, real u2, real cos_theta)
- {
- float r0 = cos_theta + u1 * (1.0f - cos_theta);
- float r = sqrt(max(0.0, 1.0 - r0 * r0));
- float phi = TWO_PI * u2;
- return float3(r * cos(phi), r * sin(phi), r0);
- }
- real3 SampleSphereUniform(real u1, real u2)
- {
- real phi = TWO_PI * u2;
- real cosTheta = 1.0 - 2.0 * u1;
- return SphericalToCartesian(phi, cosTheta);
- }
- // Performs cosine-weighted sampling of the hemisphere.
- // Ref: PBRT v3, p. 780.
- real3 SampleHemisphereCosine(real u1, real u2)
- {
- real3 localL;
- // Since we don't really care about the area distortion,
- // we substitute uniform disk sampling for the concentric one.
- localL.xy = SampleDiskUniform(u1, u2);
- // Project the point from the disk onto the hemisphere.
- localL.z = sqrt(1.0 - u1);
- return localL;
- }
- // Cosine-weighted sampling without the tangent frame.
- // Ref: http://www.amietia.com/lambertnotangent.html
- real3 SampleHemisphereCosine(real u1, real u2, real3 normal)
- {
- real3 pointOnSphere = SampleSphereUniform(u1, u2);
- return normalize(normal + pointOnSphere);
- }
- real3 SampleHemisphereUniform(real u1, real u2)
- {
- real phi = TWO_PI * u2;
- real cosTheta = 1.0 - u1;
- return SphericalToCartesian(phi, cosTheta);
- }
- void SampleSphere(real2 u,
- real4x4 localToWorld,
- real radius,
- out real lightPdf,
- out real3 P,
- out real3 Ns)
- {
- real u1 = u.x;
- real u2 = u.y;
- Ns = SampleSphereUniform(u1, u2);
- // Transform from unit sphere to world space
- P = radius * Ns + localToWorld[3].xyz;
- // pdf is inverse of area
- lightPdf = 1.0 / (FOUR_PI * radius * radius);
- }
- void SampleHemisphere(real2 u,
- real4x4 localToWorld,
- real radius,
- out real lightPdf,
- out real3 P,
- out real3 Ns)
- {
- real u1 = u.x;
- real u2 = u.y;
- // Random point at hemisphere surface
- Ns = -SampleHemisphereUniform(u1, u2); // We want the y down hemisphere
- P = radius * Ns;
- // Transform to world space
- P = mul(real4(P, 1.0), localToWorld).xyz;
- Ns = mul(Ns, (real3x3)(localToWorld));
- // pdf is inverse of area
- lightPdf = 1.0 / (TWO_PI * radius * radius);
- }
- // Note: The cylinder has no end caps (i.e. no disk on the side)
- void SampleCylinder(real2 u,
- real4x4 localToWorld,
- real radius,
- real width,
- out real lightPdf,
- out real3 P,
- out real3 Ns)
- {
- real u1 = u.x;
- real u2 = u.y;
- // Random point at cylinder surface
- real t = (u1 - 0.5) * width;
- real theta = 2.0 * PI * u2;
- real cosTheta = cos(theta);
- real sinTheta = sin(theta);
- // Cylinder are align on the right axis
- P = real3(t, radius * cosTheta, radius * sinTheta);
- Ns = normalize(real3(0.0, cosTheta, sinTheta));
- // Transform to world space
- P = mul(real4(P, 1.0), localToWorld).xyz;
- Ns = mul(Ns, (real3x3)(localToWorld));
- // pdf is inverse of area
- lightPdf = 1.0 / (TWO_PI * radius * width);
- }
- void SampleRectangle(real2 u,
- real4x4 localToWorld,
- real width,
- real height,
- out real lightPdf,
- out real3 P,
- out real3 Ns)
- {
- // Random point at rectangle surface
- P = real3((u.x - 0.5) * width, (u.y - 0.5) * height, 0);
- Ns = real3(0, 0, -1); // Light down (-Z)
- // Transform to world space
- P = mul(real4(P, 1.0), localToWorld).xyz;
- Ns = mul(Ns, (real3x3)(localToWorld));
- // pdf is inverse of area
- lightPdf = 1.0 / (width * height);
- }
- void SampleDisk(real2 u,
- real4x4 localToWorld,
- real radius,
- out real lightPdf,
- out real3 P,
- out real3 Ns)
- {
- // Random point at disk surface
- P = real3(radius * SampleDiskUniform(u.x, u.y), 0);
- Ns = real3(0.0, 0.0, -1.0); // Light down (-Z)
- // Transform to world space
- P = mul(real4(P, 1.0), localToWorld).xyz;
- Ns = mul(Ns, (real3x3)(localToWorld));
- // pdf is inverse of area
- lightPdf = 1.0 / (PI * radius * radius);
- }
- // Solid angle cone sampling.
- // Takes the cosine of the aperture as an input.
- void SampleCone(real2 u, real cosHalfAngle,
- out real3 dir, out real rcpPdf)
- {
- real cosTheta = lerp(1, cosHalfAngle, u.x);
- real phi = TWO_PI * u.y;
- dir = SphericalToCartesian(phi, cosTheta);
- rcpPdf = TWO_PI * (1 - cosHalfAngle);
- }
- #endif // UNITY_SAMPLING_INCLUDED
|