路径追踪 低差异序列 sobol序列采样
2021/10/19 23:40:10
本文主要是介绍路径追踪 低差异序列 sobol序列采样,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
sobol 是一种均匀数组替代随机半球采样,对降噪非常好
引用如下
vec2 ua=sobolVec2(int(frameCounter)+1,maxBounce);
vec3 L = SampleCosineHemisphere(ua.x, ua.y, N);
完整项目代码https://blog.csdn.net/asaqlp/article/details/120828724
fshader.fsh
#version 330 core in vec3 pix; out vec4 fragColor; // ----------------------------------------------------------------------------- // uniform uint frameCounter; uniform int nTriangles; uniform int nNodes; uniform int width; uniform int height; uniform samplerBuffer triangles; uniform samplerBuffer nodes; uniform sampler2D lastFrame; uniform sampler2D hdrMap; uniform vec3 eye; uniform mat4 cameraRotate; // ----------------------------------------------------------------------------- // #define PI 3.1415926 #define INF 114514.0 #define SIZE_TRIANGLE 12 #define SIZE_BVHNODE 4 // ----------------------------------------------------------------------------- // // Triangle 数据格式 struct Triangle { vec3 p1, p2, p3; // 顶点坐标 vec3 n1, n2, n3; // 顶点法线 }; // BVH 树节点 struct BVHNode { int left; // 左子树 int right; // 右子树 int n; // 包含三角形数目 int index; // 三角形索引 vec3 AA, BB; // 碰撞盒 }; // 物体表面材质定义 struct Material { vec3 emissive; // 作为光源时的发光颜色 vec3 baseColor; float subsurface; float metallic; float specular; float specularTint; float roughness; float anisotropic; float sheen; float sheenTint; float clearcoat; float clearcoatGloss; float IOR; float transmission; }; // 光线 struct Ray { vec3 startPoint; vec3 direction; }; // 光线求交结果 struct HitResult { bool isHit; // 是否命中 bool isInside; // 是否从内部命中 float distance; // 与交点的距离 vec3 hitPoint; // 光线命中点 vec3 normal; // 命中点法线 vec3 viewDir; // 击中该点的光线的方向 Material material; // 命中点的表面材质 }; // ----------------------------------------------------------------------------- // /* * 生成随机向量,依赖于 frameCounter 帧计数器 * 代码来源:https://blog.demofox.org/2020/05/25/casual-shadertoy-path-tracing-1-basic-camera-diffuse-emissive/ */ uint seed = uint( uint((pix.x * 0.5 + 0.5) * width) * uint(1973) + uint((pix.y * 0.5 + 0.5) * height) * uint(9277) + uint(frameCounter) * uint(26699)) | uint(1); uint wang_hash(inout uint seed) { seed = uint(seed ^ uint(61)) ^ uint(seed >> uint(16)); seed *= uint(9); seed = seed ^ (seed >> 4); seed *= uint(0x27d4eb2d); seed = seed ^ (seed >> 15); return seed; } float rand() { return float(wang_hash(seed)) / 4294967296.0; } // ----------------------------------------------------------------------------- // // 半球均匀采样 vec3 SampleHemisphere() { float z = rand(); float r = max(0, sqrt(1.0 - z*z)); float phi = 2.0 * PI * rand(); return vec3(r * cos(phi), r * sin(phi), z); } /* vec3 toNormalHemisphere(vec3 v, vec3 N) { vec3 tangent = vec3(0); if(N.yz==vec2(0)) tangent = vec3(0, 0, -N.x); else if(N.xz==vec2(0)) tangent = vec3(0, 0, N.y); else if(N.xy==vec2(0)) tangent = vec3(-N.z, 0, 0); else if(abs(N.x)>abs(N.y)) tangent = normalize(vec3(0, N.z, -N.y)); else tangent = normalize(vec3(-N.z, 0, N.x)); vec3 bitangent = cross(N, tangent); return normalize(v.x * tangent + v.y * bitangent + v.z * N); } */ // 将向量 v 投影到 N 的法向半球 vec3 toNormalHemisphere(vec3 v, vec3 N) { vec3 helper = vec3(1, 0, 0); if(abs(N.x)>0.999) helper = vec3(0, 0, 1); vec3 tangent = normalize(cross(N, helper)); vec3 bitangent = normalize(cross(N, tangent)); return v.x * tangent + v.y * bitangent + v.z * N; } // ----------------------------------------------------------------------------- // // 将三维向量 v 转为 HDR map 的纹理坐标 uv vec2 SampleSphericalMap(vec3 v) { vec2 uv = vec2(atan(v.z, v.x), asin(v.y)); uv /= vec2(2.0 * PI, PI); uv += 0.5; uv.y = 1.0 - uv.y; return uv; } // 获取 HDR 环境颜色 vec3 sampleHdr(vec3 v) { vec2 uv = SampleSphericalMap(normalize(v)); vec3 color = texture2D(hdrMap, uv).rgb; color = min(color, vec3(10)); return color; } // ----------------------------------------------------------------------------- // // 获取第 i 下标的三角形 Triangle getTriangle(int i) { int offset = i * SIZE_TRIANGLE; Triangle t; // 顶点坐标 t.p1 = texelFetch(triangles, offset + 0).xyz; t.p2 = texelFetch(triangles, offset + 1).xyz; t.p3 = texelFetch(triangles, offset + 2).xyz; // 法线 t.n1 = texelFetch(triangles, offset + 3).xyz; t.n2 = texelFetch(triangles, offset + 4).xyz; t.n3 = texelFetch(triangles, offset + 5).xyz; return t; } // 获取第 i 下标的三角形的材质 Material getMaterial(int i) { Material m; int offset = i * SIZE_TRIANGLE; vec3 param1 = texelFetch(triangles, offset + 8).xyz; vec3 param2 = texelFetch(triangles, offset + 9).xyz; vec3 param3 = texelFetch(triangles, offset + 10).xyz; vec3 param4 = texelFetch(triangles, offset + 11).xyz; m.emissive = texelFetch(triangles, offset + 6).xyz; m.baseColor = texelFetch(triangles, offset + 7).xyz; m.subsurface = param1.x; m.metallic = param1.y; m.specular = param1.z; m.specularTint = param2.x; m.roughness = param2.y; m.anisotropic = param2.z; m.sheen = param3.x; m.sheenTint = param3.y; m.clearcoat = param3.z; m.clearcoatGloss = param4.x; m.IOR = param4.y; m.transmission = param4.z; return m; } // 获取第 i 下标的 BVHNode 对象 BVHNode getBVHNode(int i) { BVHNode node; // 左右子树 int offset = i * SIZE_BVHNODE; ivec3 childs = ivec3(texelFetch(nodes, offset + 0).xyz); ivec3 leafInfo = ivec3(texelFetch(nodes, offset + 1).xyz); node.left = int(childs.x); node.right = int(childs.y); node.n = int(leafInfo.x); node.index = int(leafInfo.y); // 包围盒 node.AA = texelFetch(nodes, offset + 2).xyz; node.BB = texelFetch(nodes, offset + 3).xyz; return node; } // ----------------------------------------------------------------------------- // // 光线和三角形求交 HitResult hitTriangle(Triangle triangle, Ray ray) { HitResult res; res.distance = INF; res.isHit = false; res.isInside = false; vec3 p1 = triangle.p1; vec3 p2 = triangle.p2; vec3 p3 = triangle.p3; vec3 S = ray.startPoint; // 射线起点 vec3 d = ray.direction; // 射线方向 vec3 N = normalize(cross(p2-p1, p3-p1)); // 法向量 // 从三角形背后(模型内部)击中 if (dot(N, d) > 0.0f) { N = -N; res.isInside = true; } // 如果视线和三角形平行 if (abs(dot(N, d)) < 0.00001f) return res; // 距离 float t = (dot(N, p1) - dot(S, N)) / dot(d, N); if (t < 0.0005f) return res; // 如果三角形在光线背面 // 交点计算 vec3 P = S + d * t; // 判断交点是否在三角形中 vec3 c1 = cross(p2 - p1, P - p1); vec3 c2 = cross(p3 - p2, P - p2); vec3 c3 = cross(p1 - p3, P - p3); bool r1 = (dot(c1, N) > 0 && dot(c2, N) > 0 && dot(c3, N) > 0); bool r2 = (dot(c1, N) < 0 && dot(c2, N) < 0 && dot(c3, N) < 0); // 命中,封装返回结果 if (r1 || r2) { res.isHit = true; res.hitPoint = P; res.distance = t; res.normal = N; res.viewDir = d; // 根据交点位置插值顶点法线 float alpha = (-(P.x-p2.x)*(p3.y-p2.y) + (P.y-p2.y)*(p3.x-p2.x)) / (-(p1.x-p2.x-0.00005)*(p3.y-p2.y+0.00005) + (p1.y-p2.y+0.00005)*(p3.x-p2.x+0.00005)); float beta = (-(P.x-p3.x)*(p1.y-p3.y) + (P.y-p3.y)*(p1.x-p3.x)) / (-(p2.x-p3.x-0.00005)*(p1.y-p3.y+0.00005) + (p2.y-p3.y+0.00005)*(p1.x-p3.x+0.00005)); float gama = 1.0 - alpha - beta; vec3 Nsmooth = alpha * triangle.n1 + beta * triangle.n2 + gama * triangle.n3; Nsmooth = normalize(Nsmooth); res.normal = (res.isInside) ? (-Nsmooth) : (Nsmooth); } return res; } // 和 aabb 盒子求交,没有交点则返回 -1 float hitAABB(Ray r, vec3 AA, vec3 BB) { vec3 invdir = 1.0 / r.direction; vec3 f = (BB - r.startPoint) * invdir; vec3 n = (AA - r.startPoint) * invdir; vec3 tmax = max(f, n); vec3 tmin = min(f, n); float t1 = min(tmax.x, min(tmax.y, tmax.z)); float t0 = max(tmin.x, max(tmin.y, tmin.z)); return (t1 >= t0) ? ((t0 > 0.0) ? (t0) : (t1)) : (-1); } // ----------------------------------------------------------------------------- // // 暴力遍历数组下标范围 [l, r] 求最近交点 HitResult hitArray(Ray ray, int l, int r) { HitResult res; res.isHit = false; res.distance = INF; for(int i=l; i<=r; i++) { Triangle triangle = getTriangle(i); HitResult r = hitTriangle(triangle, ray); if(r.isHit && r.distance<res.distance) { res = r; res.material = getMaterial(i); } } return res; } // 遍历 BVH 求交 HitResult hitBVH(Ray ray) { HitResult res; res.isHit = false; res.distance = INF; // 栈 int stack[256]; int sp = 0; stack[sp++] = 1; while(sp>0) { int top = stack[--sp]; BVHNode node = getBVHNode(top); // 是叶子节点,遍历三角形,求最近交点 if(node.n>0) { int L = node.index; int R = node.index + node.n - 1; HitResult r = hitArray(ray, L, R); if(r.isHit && r.distance<res.distance) res = r; continue; } // 和左右盒子 AABB 求交 float d1 = INF; // 左盒子距离 float d2 = INF; // 右盒子距离 if(node.left>0) { BVHNode leftNode = getBVHNode(node.left); d1 = hitAABB(ray, leftNode.AA, leftNode.BB); } if(node.right>0) { BVHNode rightNode = getBVHNode(node.right); d2 = hitAABB(ray, rightNode.AA, rightNode.BB); } // 在最近的盒子中搜索 if(d1>0 && d2>0) { if(d1<d2) { // d1<d2, 左边先 stack[sp++] = node.right; stack[sp++] = node.left; } else { // d2<d1, 右边先 stack[sp++] = node.left; stack[sp++] = node.right; } } else if(d1>0) { // 仅命中左边 stack[sp++] = node.left; } else if(d2>0) { // 仅命中右边 stack[sp++] = node.right; } } return res; } // float a[5] = float[5](3.4, 4.2, 5.0, 5.2, 1.1); // 1 ~ 8 维的 sobol 生成矩阵 const int V[8*32] =int [8*32]( 2147483648, 1073741824, 536870912, 268435456, 134217728, 67108864, 33554432, 16777216, 8388608, 4194304, 2097152, 1048576, 524288, 262144, 131072, 65536, 32768, 16384, 8192, 4096, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1, 2147483648, 3221225472, 2684354560, 4026531840, 2281701376, 3422552064, 2852126720, 4278190080, 2155872256, 3233808384, 2694840320, 4042260480, 2290614272, 3435921408, 2863267840, 4294901760, 2147516416, 3221274624, 2684395520, 4026593280, 2281736192, 3422604288, 2852170240, 4278255360, 2155905152, 3233857728, 2694881440, 4042322160, 2290649224, 3435973836, 2863311530, 4294967295, 2147483648, 3221225472, 1610612736, 2415919104, 3892314112, 1543503872, 2382364672, 3305111552, 1753219072, 2629828608, 3999268864, 1435500544, 2154299392, 3231449088, 1626210304, 2421489664, 3900735488, 1556135936, 2388680704, 3314585600, 1751705600, 2627492864, 4008611328, 1431684352, 2147543168, 3221249216, 1610649184, 2415969680, 3892340840, 1543543964, 2382425838, 3305133397, 2147483648, 3221225472, 536870912, 1342177280, 4160749568, 1946157056, 2717908992, 2466250752, 3632267264, 624951296, 1507852288, 3872391168, 2013790208, 3020685312, 2181169152, 3271884800, 546275328, 1363623936, 4226424832, 1977167872, 2693105664, 2437829632, 3689389568, 635137280, 1484783744, 3846176960, 2044723232, 3067084880, 2148008184, 3222012020, 537002146, 1342505107, 2147483648, 1073741824, 536870912, 2952790016, 4160749568, 3690987520, 2046820352, 2634022912, 1518338048, 801112064, 2707423232, 4038066176, 3666345984, 1875116032, 2170683392, 1085997056, 579305472, 3016343552, 4217741312, 3719483392, 2013407232, 2617981952, 1510979072, 755882752, 2726789248, 4090085440, 3680870432, 1840435376, 2147625208, 1074478300, 537900666, 2953698205, 2147483648, 1073741824, 1610612736, 805306368, 2818572288, 335544320, 2113929216, 3472883712, 2290089984, 3829399552, 3059744768, 1127219200, 3089629184, 4199809024, 3567124480, 1891565568, 394297344, 3988799488, 920674304, 4193267712, 2950604800, 3977188352, 3250028032, 129093376, 2231568512, 2963678272, 4281226848, 432124720, 803643432, 1633613396, 2672665246, 3170194367, 2147483648, 3221225472, 2684354560, 3489660928, 1476395008, 2483027968, 1040187392, 3808428032, 3196059648, 599785472, 505413632, 4077912064, 1182269440, 1736704000, 2017853440, 2221342720, 3329785856, 2810494976, 3628507136, 1416089600, 2658719744, 864310272, 3863387648, 3076993792, 553150080, 272922560, 4167467040, 1148698640, 1719673080, 2009075780, 2149644390, 3222291575, 2147483648, 1073741824, 2684354560, 1342177280, 2281701376, 1946157056, 436207616, 2566914048, 2625634304, 3208642560, 2720006144, 2098200576, 111673344, 2354315264, 3464626176, 4027383808, 2886631424, 3770826752, 1691164672, 3357462528, 1993345024, 3752330240, 873073152, 2870150400, 1700563072, 87021376, 1097028000, 1222351248, 1560027592, 2977959924, 23268898, 437609937 ); // 格林码 int grayCode(int i) { return i ^ (i>>1); } // 生成第 d 维度的第 i 个 sobol 数 float sobol(int d, int i) { int result = 0; int offset = d * 32; for(int j = 0; i!=0; i >>= 1, j++) { if((i & 1)!=0) result ^= V[j+offset]; } return float(result) * (1.0f/float(0xFFFFFFFFU)); } // 生成第 i 帧的第 b 次反弹需要的二维随机向量 vec2 sobolVec2(int i, int b) { float u = sobol(b*2, grayCode(i)); float v = sobol(b*2+1, grayCode(i)); return vec2(u, v); } float GTR1(float NdotH, float a) { if (a >= 1) return 1/PI; float a2 = a*a; float t = 1 + (a2-1)*NdotH*NdotH; return (a2-1) / (PI*log(a2)*t); } float GTR2(float NdotH, float a) { float a2 = a*a; float t = 1 + (a2-1)*NdotH*NdotH; return a2 / (PI * t*t); } float SchlickFresnel(float u) { float m = clamp(1-u, 0, 1); float m2 = m*m; return m2*m2*m; // pow(m,5) } float smithG_GGX(float NdotV, float alphaG) { float a = alphaG*alphaG; float b = NdotV*NdotV; return 1 / (NdotV + sqrt(a + b - a*b)); } vec3 BRDF_Evaluate(vec3 V, vec3 N, vec3 L, in Material material) { float NdotL = dot(N, L); float NdotV = dot(N, V); if(NdotL < 0 || NdotV < 0) return vec3(0); vec3 H = normalize(L + V); float NdotH = dot(N, H); float LdotH = dot(L, H); vec3 Cdlin = material.baseColor; float Cdlum = 1.0 * Cdlin.r + 1.0 * Cdlin.g + 1.0 * Cdlin.b; vec3 Ctint = (Cdlum > 0) ? (Cdlin/Cdlum) : (vec3(1)); vec3 Cspec = material.specular * mix(vec3(1), Ctint, material.specularTint); vec3 Cspec0 = mix(0.08*Cspec, Cdlin, material.metallic); // 0° 镜面反射颜色 // 镜面反射 float alpha = material.roughness * material.roughness; float Ds = GTR2(NdotH, alpha); float FH = SchlickFresnel(LdotH); vec3 Fs = mix(Cspec0, vec3(1), FH); float Gs = smithG_GGX(NdotL, material.roughness); Gs *= smithG_GGX(NdotV, material.roughness); vec3 specular = Gs * Fs * Ds; // 漫反射 float Fd90 = 0.5 + 2.0 * LdotH * LdotH * material.roughness; float FL = SchlickFresnel(NdotL); float FV = SchlickFresnel(NdotV); float Fd = mix(1.0, Fd90, FL) * mix(1.0, Fd90, FV); // 次表面散射 float Fss90 = LdotH * LdotH * material.roughness; float Fss = mix(1.0, Fss90, FL) * mix(1.0, Fss90, FV); float ss = 1.25 * (Fss * (1.0 / (NdotL + NdotV) - 0.5) + 0.5); // 清漆 float Dr = GTR1(NdotH, mix(0.1, 0.001, material.clearcoatGloss)); float Fr = mix(0.04, 1.0, FH); float Gr = smithG_GGX(NdotL, 0.25) * smithG_GGX(NdotV, 0.25); vec3 clearcoat = vec3(0.25 * Gr * Fr * Dr * material.clearcoat); vec3 Csheen = mix(vec3(1), Ctint, material.sheenTint); // 织物颜色 // sheen 织物光泽 vec3 Fsheen = FH * material.sheen * Csheen; //各向异性(anisotropic) vec3 diffuse = (1.0/PI) * mix(Fd, ss, material.subsurface) * Cdlin; diffuse += Fsheen; return diffuse * (1.0 - material.metallic) + specular + clearcoat; } // 余弦加权的法向半球采样 vec3 SampleCosineHemisphere(float xi_1, float xi_2, vec3 N) { // 均匀采样 xy 圆盘然后投影到 z 半球 float r = sqrt(xi_1); float theta = xi_2 * 2.0 * PI; float x = r * cos(theta); float y = r * sin(theta); float z = sqrt(1.0 - x*x - y*y); // 从 z 半球投影到法向半球 vec3 L = toNormalHemisphere(vec3(x, y, z), N); return L; } float rand(vec2 co){ return fract(sin(dot(co.xy, vec2(12.9898,78.233))) * 43758.5453); } // GTR2 重要性采样 vec3 SampleGTR2(float xi_1, float xi_2, vec3 V, vec3 N, float alpha) { float phi_h = 2.0 * PI * xi_1; float sin_phi_h = sin(phi_h); float cos_phi_h = cos(phi_h); float cos_theta_h = sqrt((1.0-xi_2)/(1.0+(alpha*alpha-1.0)*xi_2)); float sin_theta_h = sqrt(max(0.0, 1.0 - cos_theta_h * cos_theta_h)); // 采样 "微平面" 的法向量 作为镜面反射的半角向量 h vec3 H = vec3(sin_theta_h*cos_phi_h, sin_theta_h*sin_phi_h, cos_theta_h); H = toNormalHemisphere(H, N); // 投影到真正的法向半球 // 根据 "微法线" 计算反射光方向 vec3 L = reflect(-V, H); return L; } // GTR1 重要性采样 vec3 SampleGTR1(float xi_1, float xi_2, vec3 V, vec3 N, float alpha) { float phi_h = 2.0 * PI * xi_1; float sin_phi_h = sin(phi_h); float cos_phi_h = cos(phi_h); float cos_theta_h = sqrt((1.0-pow(alpha*alpha, 1.0-xi_2))/(1.0-alpha*alpha)); float sin_theta_h = sqrt(max(0.0, 1.0 - cos_theta_h * cos_theta_h)); // 采样 "微平面" 的法向量 作为镜面反射的半角向量 h vec3 H = vec3(sin_theta_h*cos_phi_h, sin_theta_h*sin_phi_h, cos_theta_h); H = toNormalHemisphere(H, N); // 投影到真正的法向半球 // 根据 "微法线" 计算反射光方向 vec3 L = reflect(-V, H); return L; } float sqr(float x) { return x*x; } float GTR2_aniso(float NdotH, float HdotX, float HdotY, float ax, float ay) { return 1 / (PI * ax*ay * sqr( sqr(HdotX/ax) + sqr(HdotY/ay) + NdotH*NdotH )); } // 按照辐射度分布分别采样三种 BRDF vec3 SampleBRDF(float xi_1, float xi_2, float xi_3, vec3 V, vec3 N, in Material material) { float alpha_GTR1 = mix(0.1, 0.001, material.clearcoatGloss); float alpha_GTR2 = max(0.001, sqr(material.roughness)); // 辐射度统计 float r_diffuse = (1.0 - material.metallic); float r_specular = 1.0; float r_clearcoat = 0.25 * material.clearcoat; float r_sum = r_diffuse + r_specular + r_clearcoat; // 根据辐射度计算概率 float p_diffuse = r_diffuse / r_sum; float p_specular = r_specular / r_sum; float p_clearcoat = r_clearcoat / r_sum; // 按照概率采样 float rd = xi_3; // 漫反射 if(rd <= p_diffuse) { return SampleCosineHemisphere(xi_1, xi_2, N); } // 镜面反射 else if(p_diffuse < rd && rd <= p_diffuse + p_specular) { return SampleGTR2(xi_1, xi_2, V, N, alpha_GTR2); } // 清漆 else if(p_diffuse + p_specular < rd) { return SampleGTR1(xi_1, xi_2, V, N, alpha_GTR1); } return vec3(0, 1, 0); } // 获取 BRDF 在 L 方向上的概率密度 float BRDF_Pdf(vec3 V, vec3 N, vec3 L, in Material material) { float NdotL = dot(N, L); float NdotV = dot(N, V); if(NdotL < 0 || NdotV < 0) return 0; vec3 H = normalize(L + V); float NdotH = dot(N, H); float LdotH = dot(L, H); // 镜面反射 -- 各向同性 float alpha = max(0.001, sqr(material.roughness)); float Ds = GTR2(NdotH, alpha); float Dr = GTR1(NdotH, mix(0.1, 0.001, material.clearcoatGloss)); // 清漆 // 分别计算三种 BRDF 的概率密度 float pdf_diffuse = NdotL / PI; float pdf_specular = Ds * NdotH / (4.0 * dot(L, H)); float pdf_clearcoat = Dr * NdotH / (4.0 * dot(L, H)); // 辐射度统计 float r_diffuse = (1.0 - material.metallic); float r_specular = 1.0; float r_clearcoat = 0.25 * material.clearcoat; float r_sum = r_diffuse + r_specular + r_clearcoat; // 根据辐射度计算选择某种采样方式的概率 float p_diffuse = r_diffuse / r_sum; float p_specular = r_specular / r_sum; float p_clearcoat = r_clearcoat / r_sum; // 根据概率混合 pdf float pdf = p_diffuse * pdf_diffuse + p_specular * pdf_specular + p_clearcoat * pdf_clearcoat; pdf = max(1e-10, pdf); return pdf; } // ----------------------------------------------------------------------------- // // 路径追踪 // 路径追踪 -- 重要性采样版本 vec3 pathTracingImportanceSampling(HitResult hit, int maxBounce) { vec3 Lo = vec3(0); // 最终的颜色 vec3 history = vec3(1); // 递归积累的颜色 for(int bounce=0; bounce<maxBounce; bounce++) { vec3 V = -hit.viewDir; vec3 N = hit.normal; // 获取 3 个随机数 float xi_1; float xi_2; float xi_3; xi_1 =rand(vec2(777.9898,5125.233)); xi_2 =rand(vec2(777.9898,5125.233)); xi_3 =rand(vec2(777.9898,5125.233)); //vec3 L = SampleCosineHemisphere(xi_1, xi_2, N); // 采样 BRDF 得到一个方向 L vec3 L = SampleBRDF(xi_1, xi_2, xi_3, V, N, hit.material); float NdotL = dot(N, L); if(NdotL <= 0.0) break; // 发射光线 Ray randomRay; randomRay.startPoint = hit.hitPoint; randomRay.direction = L; HitResult newHit = hitBVH(randomRay); // 获取 L 方向上的 BRDF 值和概率密度 vec3 f_r = BRDF_Evaluate(V, N, L, hit.material); float pdf_brdf = BRDF_Pdf(V, N, L, hit.material); if(pdf_brdf <= 0.0) break; // 未命中 if(!newHit.isHit) { //vec3 color = vec3(0.5,0.0,0.5);// vec3 color = hdrColor(L); Lo += history * f_r * NdotL / pdf_brdf; break; } // 命中光源积累颜色 vec3 Le = newHit.material.emissive; Lo += history * Le * f_r * NdotL / pdf_brdf; // 递归(步进) hit = newHit; history *= f_r * NdotL / pdf_brdf; // 累积颜色 } return Lo; } // 路径追踪 vec3 pathTracing(HitResult hit, int maxBounce) { vec3 Lo = vec3(0); // 最终的颜色 vec3 history = vec3(1); // 递归积累的颜色 for(int bounce=0; bounce<maxBounce; bounce++) { // 随机出射方向 wi vec3 wi = toNormalHemisphere(SampleHemisphere(), hit.normal); // 漫反射: 随机发射光线 Ray randomRay; randomRay.startPoint = hit.hitPoint; randomRay.direction = wi; HitResult newHit = hitBVH(randomRay); float pdf = 1.0 / (2.0 * PI); // 半球均匀采样概率密度 float cosine_o = max(0, dot(-hit.viewDir, hit.normal)); // 入射光和法线夹角余弦 float cosine_i = max(0, dot(randomRay.direction, hit.normal)); // 出射光和法线夹角余弦 //vec3 f_r = hit.material.baseColor / PI; // 漫反射 BRDF vec3 V = -hit.viewDir; vec3 N = hit.normal; //vec3 L = toNormalHemisphere(SampleHemisphere(), hit.normal); // 随机出射方向 wi vec2 ua=sobolVec2(int(frameCounter)+1,maxBounce); vec3 L = SampleCosineHemisphere(ua.x, ua.y, N); vec3 f_r = BRDF_Evaluate(V, N, L, hit.material); // 未命中 if(!newHit.isHit) { vec3 skyColor = sampleHdr(randomRay.direction); Lo += history * skyColor * f_r * cosine_i / pdf; break; } // 命中光源积累颜色 vec3 Le = newHit.material.emissive; Lo += history * Le * f_r * cosine_i / pdf; // 递归(步进) hit = newHit; history *= f_r * cosine_i / pdf; // 累积颜色 } return Lo; } // ----------------------------------------------------------------------------- // void main() { // 投射光线 Ray ray; ray.startPoint = eye; vec2 AA = vec2((rand()-0.5)/float(width), (rand()-0.5)/float(height)); vec4 dir = cameraRotate * vec4(pix.xy+AA, -1.5, 0.0); ray.direction = normalize(dir.xyz); // primary hit HitResult firstHit = hitBVH(ray); vec3 color; if(!firstHit.isHit) { color = vec3(0); color = sampleHdr(ray.direction); } else { vec3 Le = firstHit.material.emissive; vec3 Li = pathTracing(firstHit, 4); // vec3 Li = pathTracingImportanceSampling(firstHit, 4);//路径追踪重要性采样 color = Le + Li; } // 和上一帧混合 vec3 lastColor = texture2D(lastFrame, pix.xy*0.5+0.5).rgb; color = mix(lastColor, color, 1.0/(float(frameCounter)+1)); // 输出 gl_FragData[0] = vec4(color, 1.0); }
这篇关于路径追踪 低差异序列 sobol序列采样的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南