A game about forced loneliness, made by TACStudios
1#ifndef UNITY_SAMPLING_INCLUDED 2#define UNITY_SAMPLING_INCLUDED 3 4#if SHADER_API_MOBILE || SHADER_API_GLES3 || SHADER_API_SWITCH || defined(UNITY_UNIFIED_SHADER_PRECISION_MODEL) 5#pragma warning (disable : 3205) // conversion of larger type to smaller 6#endif 7 8//----------------------------------------------------------------------------- 9// Sample generator 10//----------------------------------------------------------------------------- 11 12#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Sampling/Fibonacci.hlsl" 13#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Sampling/Hammersley.hlsl" 14 15//----------------------------------------------------------------------------- 16// Coordinate system conversion 17//----------------------------------------------------------------------------- 18 19// Transforms the unit vector from the spherical to the Cartesian (right-handed, Z up) coordinate. 20real3 SphericalToCartesian(real cosPhi, real sinPhi, real cosTheta) 21{ 22 real sinTheta = SinFromCos(cosTheta); 23 24 return real3(real2(cosPhi, sinPhi) * sinTheta, cosTheta); 25} 26 27real3 SphericalToCartesian(real phi, real cosTheta) 28{ 29 real sinPhi, cosPhi; 30 sincos(phi, sinPhi, cosPhi); 31 32 return SphericalToCartesian(cosPhi, sinPhi, cosTheta); 33} 34 35// Converts Cartesian coordinates given in the right-handed coordinate system 36// with Z pointing upwards (OpenGL style) to the coordinates in the left-handed 37// coordinate system with Y pointing up and Z facing forward (DirectX style). 38real3 TransformGLtoDX(real3 v) 39{ 40 return v.xzy; 41} 42 43// Performs conversion from equiareal map coordinates to Cartesian (DirectX cubemap) ones. 44real3 ConvertEquiarealToCubemap(real u, real v) 45{ 46 real phi = TWO_PI - TWO_PI * u; 47 real cosTheta = 1.0 - 2.0 * v; 48 49 return TransformGLtoDX(SphericalToCartesian(phi, cosTheta)); 50} 51 52// Convert a texel position into normalized position [-1..1]x[-1..1] 53real2 CubemapTexelToNVC(uint2 unPositionTXS, uint cubemapSize) 54{ 55 return 2.0 * real2(unPositionTXS) / real(max(cubemapSize - 1, 1)) - 1.0; 56} 57 58// Map cubemap face to world vector basis 59static const real3 CUBEMAP_FACE_BASIS_MAPPING[6][3] = 60{ 61 //XPOS face 62 { 63 real3(0.0, 0.0, -1.0), 64 real3(0.0, -1.0, 0.0), 65 real3(1.0, 0.0, 0.0) 66 }, 67 //XNEG face 68 { 69 real3(0.0, 0.0, 1.0), 70 real3(0.0, -1.0, 0.0), 71 real3(-1.0, 0.0, 0.0) 72 }, 73 //YPOS face 74 { 75 real3(1.0, 0.0, 0.0), 76 real3(0.0, 0.0, 1.0), 77 real3(0.0, 1.0, 0.0) 78 }, 79 //YNEG face 80 { 81 real3(1.0, 0.0, 0.0), 82 real3(0.0, 0.0, -1.0), 83 real3(0.0, -1.0, 0.0) 84 }, 85 //ZPOS face 86 { 87 real3(1.0, 0.0, 0.0), 88 real3(0.0, -1.0, 0.0), 89 real3(0.0, 0.0, 1.0) 90 }, 91 //ZNEG face 92 { 93 real3(-1.0, 0.0, 0.0), 94 real3(0.0, -1.0, 0.0), 95 real3(0.0, 0.0, -1.0) 96 } 97}; 98 99// Convert a normalized cubemap face position into a direction 100real3 CubemapTexelToDirection(real2 positionNVC, uint faceId) 101{ 102 real3 dir = CUBEMAP_FACE_BASIS_MAPPING[faceId][0] * positionNVC.x 103 + CUBEMAP_FACE_BASIS_MAPPING[faceId][1] * positionNVC.y 104 + CUBEMAP_FACE_BASIS_MAPPING[faceId][2]; 105 106 return normalize(dir); 107} 108 109//----------------------------------------------------------------------------- 110// Sampling function 111// Reference : http://www.cs.virginia.edu/~jdl/bib/globillum/mis/shirley96.pdf + PBRT 112//----------------------------------------------------------------------------- 113 114// Performs uniform sampling of the unit disk. 115// Ref: PBRT v3, p. 777. 116real2 SampleDiskUniform(real u1, real u2) 117{ 118 real r = sqrt(u1); 119 real phi = TWO_PI * u2; 120 121 real sinPhi, cosPhi; 122 sincos(phi, sinPhi, cosPhi); 123 124 return r * real2(cosPhi, sinPhi); 125} 126 127// Performs cubic sampling of the unit disk. 128real2 SampleDiskCubic(real u1, real u2) 129{ 130 real r = u1; 131 real phi = TWO_PI * u2; 132 133 real sinPhi, cosPhi; 134 sincos(phi, sinPhi, cosPhi); 135 136 return r * real2(cosPhi, sinPhi); 137} 138 139real3 SampleConeUniform(real u1, real u2, real cos_theta) 140{ 141 float r0 = cos_theta + u1 * (1.0f - cos_theta); 142 float r = sqrt(max(0.0, 1.0 - r0 * r0)); 143 float phi = TWO_PI * u2; 144 return float3(r * cos(phi), r * sin(phi), r0); 145} 146 147real3 SampleSphereUniform(real u1, real u2) 148{ 149 real phi = TWO_PI * u2; 150 real cosTheta = 1.0 - 2.0 * u1; 151 152 return SphericalToCartesian(phi, cosTheta); 153} 154 155// Performs cosine-weighted sampling of the hemisphere. 156// Ref: PBRT v3, p. 780. 157real3 SampleHemisphereCosine(real u1, real u2) 158{ 159 real3 localL; 160 161 // Since we don't really care about the area distortion, 162 // we substitute uniform disk sampling for the concentric one. 163 localL.xy = SampleDiskUniform(u1, u2); 164 165 // Project the point from the disk onto the hemisphere. 166 localL.z = sqrt(1.0 - u1); 167 168 return localL; 169} 170 171// Cosine-weighted sampling without the tangent frame. 172// Ref: http://www.amietia.com/lambertnotangent.html 173real3 SampleHemisphereCosine(real u1, real u2, real3 normal) 174{ 175 // This function needs to used safenormalize because there is a probability 176 // that the generated direction is the exact opposite of the normal and that would lead 177 // to a nan vector otheriwse. 178 real3 pointOnSphere = SampleSphereUniform(u1, u2); 179 return SafeNormalize(normal + pointOnSphere); 180} 181 182real3 SampleHemisphereUniform(real u1, real u2) 183{ 184 real phi = TWO_PI * u2; 185 real cosTheta = 1.0 - u1; 186 187 return SphericalToCartesian(phi, cosTheta); 188} 189 190void SampleSphere(real2 u, 191 real4x4 localToWorld, 192 real radius, 193 out real lightPdf, 194 out real3 P, 195 out real3 Ns) 196{ 197 real u1 = u.x; 198 real u2 = u.y; 199 200 Ns = SampleSphereUniform(u1, u2); 201 202 // Transform from unit sphere to world space 203 P = radius * Ns + localToWorld[3].xyz; 204 205 // pdf is inverse of area 206 lightPdf = 1.0 / (FOUR_PI * radius * radius); 207} 208 209void SampleHemisphere(real2 u, 210 real4x4 localToWorld, 211 real radius, 212 out real lightPdf, 213 out real3 P, 214 out real3 Ns) 215{ 216 real u1 = u.x; 217 real u2 = u.y; 218 219 // Random point at hemisphere surface 220 Ns = -SampleHemisphereUniform(u1, u2); // We want the y down hemisphere 221 P = radius * Ns; 222 223 // Transform to world space 224 P = mul(real4(P, 1.0), localToWorld).xyz; 225 Ns = mul(Ns, (real3x3)(localToWorld)); 226 227 // pdf is inverse of area 228 lightPdf = 1.0 / (TWO_PI * radius * radius); 229} 230 231// Note: The cylinder has no end caps (i.e. no disk on the side) 232void SampleCylinder(real2 u, 233 real4x4 localToWorld, 234 real radius, 235 real width, 236 out real lightPdf, 237 out real3 P, 238 out real3 Ns) 239{ 240 real u1 = u.x; 241 real u2 = u.y; 242 243 // Random point at cylinder surface 244 real t = (u1 - 0.5) * width; 245 real theta = 2.0 * PI * u2; 246 real cosTheta = cos(theta); 247 real sinTheta = sin(theta); 248 249 // Cylinder are align on the right axis 250 P = real3(t, radius * cosTheta, radius * sinTheta); 251 Ns = normalize(real3(0.0, cosTheta, sinTheta)); 252 253 // Transform to world space 254 P = mul(real4(P, 1.0), localToWorld).xyz; 255 Ns = mul(Ns, (real3x3)(localToWorld)); 256 257 // pdf is inverse of area 258 lightPdf = 1.0 / (TWO_PI * radius * width); 259} 260 261void SampleRectangle(real2 u, 262 real4x4 localToWorld, 263 real width, 264 real height, 265 out real lightPdf, 266 out real3 P, 267 out real3 Ns) 268{ 269 // Random point at rectangle surface 270 P = real3((u.x - 0.5) * width, (u.y - 0.5) * height, 0); 271 Ns = real3(0, 0, -1); // Light down (-Z) 272 273 // Transform to world space 274 P = mul(real4(P, 1.0), localToWorld).xyz; 275 Ns = mul(Ns, (real3x3)(localToWorld)); 276 277 // pdf is inverse of area 278 lightPdf = 1.0 / (width * height); 279} 280 281void SampleDisk(real2 u, 282 real4x4 localToWorld, 283 real radius, 284 out real lightPdf, 285 out real3 P, 286 out real3 Ns) 287{ 288 // Random point at disk surface 289 P = real3(radius * SampleDiskUniform(u.x, u.y), 0); 290 Ns = real3(0.0, 0.0, -1.0); // Light down (-Z) 291 292 // Transform to world space 293 P = mul(real4(P, 1.0), localToWorld).xyz; 294 Ns = mul(Ns, (real3x3)(localToWorld)); 295 296 // pdf is inverse of area 297 lightPdf = 1.0 / (PI * radius * radius); 298} 299 300// Solid angle cone sampling. 301// Takes the cosine of the aperture as an input. 302void SampleCone(real2 u, real cosHalfAngle, 303 out real3 dir, out real rcpPdf) 304{ 305 real cosTheta = lerp(1, cosHalfAngle, u.x); 306 real phi = TWO_PI * u.y; 307 308 dir = SphericalToCartesian(phi, cosTheta); 309 rcpPdf = TWO_PI * (1 - cosHalfAngle); 310} 311 312// Returns uniformly distributed sample vectors in a cone using 313// "golden angle spiral method" described here: http://blog.marmakoide.org/?p=1 314// note: the first sample is always [0, 0, 1] 315real3 SampleConeStrata(uint sampleIdx, real rcpSampleCount, real cosHalfApexAngle) 316{ 317 real z = 1.0f - ((1.0f - cosHalfApexAngle) * sampleIdx) * rcpSampleCount; 318 real r = sqrt(1.0f - z * z); 319 real a = sampleIdx * 2.3999632297286f; // pi*(3-sqrt(5)) 320 real sphi = sin(a); 321 real cphi = cos(a); 322 return real3(r * cphi, r * sphi, z); 323} 324 325#if SHADER_API_MOBILE || SHADER_API_GLES3 || SHADER_API_SWITCH 326#pragma warning (enable : 3205) // conversion of larger type to smaller 327#endif 328 329#endif // UNITY_SAMPLING_INCLUDED