当前位置: 首页 > news >正文

[图形学]smallpt代码详解(2)

一、简介

本文紧接在[图形学]smallpt代码详解(1)之后,继续详细讲解smallpt中的代码,包括自定义函数(第41到47行)递归路径跟踪函数(第48到74行)部分。

二、smallpt代码详解

1.自定义函数(第41到47行)

smallpt源代码在第41到47行声明定义了clamp()toInt()intersect()三个函数:

  • double clamp(double x)
    inline double clamp(double x){ return x<0 ? 0 : x>1 ? 1 : x; }
    
    clamp()函数将输入参数x限制在[0,1]范围内,避免浮点数计算出错,出现小于0.0或者大于1.0的计算结果。
  • int toInt(double x)
    inline int toInt(double x){ return int(pow(clamp(x),1/2.2)*255+.5); } 
    
    toInt()函数将输入的在[0,1]范围内的输入参数x先进行伽马矫正(Gamma Correction),伽马校正线性颜色空间转换为 sRGB 颜色空间。伽马校正有助于提高图像在显示器上的视觉效果。,然后映射到范围[0,255]
  • bool intersect(const Ray &r, double &t, int &id)
    inline bool intersect(const Ray &r, double &t, int &id){ 
    // n 为场景中的球面物体个数
    // d 用来记录场景中与光线相交的第一个物体id
    // t 用来记录场景中与光线相交的第一个交点到光线原点的距离
    double n=sizeof(spheres)/sizeof(Sphere), d, inf=t=1e20; 
    // 遍历场景中的所有球面对象,然后使用 sphere[i] 对象中的函数interscet() 函数计算
    // 光线是否与 球面对象 sphere[i] 相交,并找到距离光线原点最近的交点距离 t 和球面对象 i
    for(int i=int(n);i--;) if((d=spheres[i].intersect(r))&&d<t){t=d;id=i;} 
    return t<inf; 
    } 
    
    intersect()函数用于计算光线r与整个渲染场景中所有球面对象的相交计算,如果光线r与场景存在交点,则返回true,并且将交点到光线原点的距离t,写入输入的变量double &t中,并且返回相交球面物体的id,写入输入的变量int &id中。
    代码首先确定场景中的球面物体个数n:
    double n=sizeof(spheres)/sizeof(Sphere), d, inf=t=1e20;
    
    然后遍历场景中的所有球面对象,然后使用 sphere[i] 对象中的interscet() 函数计算光线是否与球面对象 sphere[i] 相交,对于sphere[i]对象中的intersect()函数的讲解请查看[图形学]smallpt代码详解(1)中的三、smallpt代码详解-1.自定义数据结构部分(第4到第22行)部分,并找到距离光线原点最近的交点距离 t 和球面对象 i
    for(int i=int(n);i--;) if((d=spheres[i].intersect(r))&&d<t){t=d;id=i;} 
    

2.递归路径跟踪函数(第48到74行)

radiance()函数是光线跟踪(路径跟踪)中最主要的代码,该函数使用递归的方式实现路径跟踪,对场景进行渲染。
函数Vec radiance(const Ray &r, int depth, unsigned short *Xi)的返回值和参数介绍如下:

  • 返回值 Vec:radiance() 函数计算的光线在此次传播中的辐射值;
  • 参数 r:要处理的光线
  • 参数 depth:此光线的传播深度
  • 参数 Xi:随机数,作为随机采样种子值

radiance()函数整体可以分为四个部分是否结束递归(与场景无交点或者俄罗斯轮盘赌失败)(红色)处理漫反射(绿色)处理镜面反射(蓝色)处理折射(橙色)部分。流程如下:
radiance()函数

radiance()函数代码流程:
radiance()函数流程图
下面介绍各部分的详细代码实现:

2.1) 是否结束递归(与场景无交点或者俄罗斯轮盘赌失败)

double t;                               // distance to intersection 
int id=0;                               // id of intersected object 
// 计算当前光线 r 和场景的交点,如果没有交点,则返回 Vec(),即返回 (0,0,0)
if (!intersect(r, t, id)) return Vec(); // if miss, return black 
// 如果 r 与场景有交点,那么记录交点对应的球面对象 obj
const Sphere &obj = spheres[id];        // the hit object 
// x 为光线 r 与 obj的交点位置
// n 为交点 x 处的球面法向
// nl 为定向法向,用来描述光线r是从球外射向球内,还是从球外射向球内
//    假如 r 为从球外射向球内,则 nl 为朝向球外的法向
//    假如 r 为从球内射向球外,则 nl 为朝向球内的法向
// f 为 obj 的漫辐射颜色
Vec x=r.o+r.d*t, n=(x-obj.p).norm(), nl=n.dot(r.d)<0?n:n*-1, f=obj.c; 
/* 使用俄罗斯轮盘赌策略确定是否结束递归 */
double p = f.x>f.y && f.x>f.z ? f.x : f.y>f.z ? f.y : f.z; // max refl 
if (++depth>5) if (erand48(Xi)<p) f=f*(1/p); else return obj.e; //R.R.

代码中首先判断光线r是否与场景相交:

  • 1). 如果不相交则说明光线射出到场景之外,因此直接返回(0,0,0)
  • 2). 如果光线r与场景相交,则计算得到交点位置x,交点所处的球面对象obj,和交点处的法向n,与r在球面同边的法向nl
    • 2.1) 如果此时的递归深度大于5,那么使用俄罗斯轮盘赌确定是否结束递归。在俄罗斯轮盘赌策略中,smallpt使用交点处颜色f的(r,g,b)三个颜色分量中的最大值作为阈值p,然后使用erand48()函数生成一个在[0,1]范围内的随机数。此处之所以使用颜色(r,g,b)中最大值作为阈值p是考虑假如交点处材质颜色接近黑色,可以尽可能地结束递归,因为此时(r,g,b)三个分量值都很小,因此该点最终反射的radiance很小,对渲染地结果影响也很小。反之,该交点颜色接近白色,说明该交点最终反射的radiance可能很大,因此要尽可能地让光线继续传播下去。
      • 2.1.1) 假如该随机数小于p,说明赢得此次俄罗斯轮盘赌,将交点处的颜色值f变为原来的(1/p)倍数,然后继续往下运行;
      • 2.1.2) 假如该随机数大于p,说明败于此次俄罗斯轮盘赌,直接返回交点处的自发光颜色obj.e
    • 2.2) 如果此时的递归深度小于等于5,则继续往下运行。

2.2) 处理漫反射

if (obj.refl == DIFF){                  // Ideal DIFFUSE reflection // r1 是在范围 [0,2Pi] 范围内的随机数// r2 是在范围 [0,1] 范围内的随机数double r1=2*M_PI*erand48(Xi), r2=erand48(Xi), r2s=sqrt(r2); Vec w=nl, u=((fabs(w.x)>.1?Vec(0,1):Vec(1))%w).norm(), v=w%u; Vec d = (u*cos(r1)*r2s + v*sin(r1)*r2s + w*sqrt(1-r2)).norm(); return obj.e + f.mult(radiance(Ray(x,d),depth,Xi)); 

在处理漫反射材质表面时,在交点处的上半球面上的cos加权采样,采样得到光线r对应的入射方向d,然后递归地计算光线下一次传播radiance(Ray(x,d),...)的结果。
半球面上的cos加权采样,即各方向的采样概率密度与 c o s ( θ ) cos(\theta) cos(θ)成正比, θ \theta θ为采样方向与交点处法向nl的夹角。

采样步骤如下:

  • 首先采样方位角r1和半球对应的圆平面半径长度r2s
  • 然后计算以交点处法向nl为(0,0,1)轴的坐标系(u,v,w)
  • 再之后根据采样的方位角r1和圆平面半径长度r2s在u-v平面的圆平面上采样得到采样点p,该方法即在平面u-v上的圆平面内均匀采样得到采样p采样点p对应到半球面上的映射点P的向量即为目标方向向量d
    该方法与半球面上的cos加权采样等效的原因请查看博客[图形学]在半球面上均匀采样和cos加权采样中的3.在半球面上的cos加权采样:方法二部分。

半球面上cos加权采样示意图

采样点p在(u,v,w)坐标系下的坐标为:
( c o s ( r 1 ) ∗ r 2 s , s i n ( r 1 ) ∗ r 2 s , 0 ) (cos(r1)*r2s, sin(r1)*r2s, 0) (cos(r1)r2s,sin(r1)r2s,0)
映射点P在(u,v,w)坐标系下的坐标即为:
( c o s ( r 1 ) ∗ r 2 s , s i n ( r 1 ) ∗ r 2 s , s q r t ( 1 − r 2 s 2 ) ) = ( c o s ( r 1 ) ∗ r 2 s , s i n ( r 1 ) ∗ r 2 s , s q r t ( 1 − r 2 ) ) (cos(r1)*r2s, sin(r1)*r2s, sqrt(1-r2s^2))=(cos(r1)*r2s, sin(r1)*r2s, sqrt(1-r2)) (cos(r1)r2s,sin(r1)r2s,sqrt(1r2s2))=(cos(r1)r2s,sin(r1)r2s,sqrt(1r2))
那么在世界坐标系(x,y,z)下,半球面上的映射点P坐标即为:
( u ∗ c o s ( r 1 ) ∗ r 2 s , v ∗ s i n ( r 1 ) ∗ r 2 s , w ∗ s q r t ( 1 − r 2 ) ) (u*cos(r1)*r2s,v*sin(r1)*r2s,w*sqrt(1-r2)) (ucos(r1)r2s,vsin(r1)r2s,wsqrt(1r2))
由于我们是使用交点处的法向nl作为坐标系w轴,暗含了以该交点为坐标系原点,因此映射点P的坐标即采样向量,即代码中的变量d
最后返回:该交点处的自发光obj.e+该交点处的颜色值f乘以光线下一次传播计算得到的radiance值。

2.3) 处理镜面反射

} else if (obj.refl == SPEC)            // Ideal SPECULAR reflection return obj.e + f.mult(radiance(Ray(x,r.d-n*2*n.dot(r.d)),depth,Xi));

处理镜面反射相对比较简单,根据光线r方向和交点处法向n可以方便地计算得到入射光线方向。
根据反射光方向和法向计算入射光方向(或者根据入射光方向和法向计算反射光方向)的算法示意图如下所示:
反射光线计算示意图
最后返回:该交点处的自发光obj.e+该交点处的颜色值f乘以光线下一次传播计算得到的radiance值。

2.4) 处理折射

Ray reflRay(x, r.d-n*2*n.dot(r.d));     // Ideal dielectric REFRACTION 
bool into = n.dot(nl)>0;                // Ray from outside going in? 
double nc=1, nt=1.5, nnt=into?nc/nt:nt/nc, ddn=r.d.dot(nl), cos2t; 
if ((cos2t=1-nnt*nnt*(1-ddn*ddn))<0)    // Total internal reflection return obj.e + f.mult(radiance(reflRay,depth,Xi)); 
Vec tdir = (r.d*nnt - n*((into?1:-1)*(ddn*nnt+sqrt(cos2t)))).norm(); 
double a=nt-nc, b=nt+nc, R0=a*a/(b*b), c = 1-(into?-ddn:tdir.dot(n)); 
double Re=R0+(1-R0)*c*c*c*c*c,Tr=1-Re,P=.25+.5*Re,RP=Re/P,TP=Tr/(1-P); 
return obj.e + f.mult(depth>2 ? (erand48(Xi)<P ?   // Russian roulette radiance(reflRay,depth,Xi)*RP:radiance(Ray(x,tdir),depth,Xi)*TP) : radiance(reflRay,depth,Xi)*Re+radiance(Ray(x,tdir),depth,Xi)*Tr); 

处理折射时,首先判断光线是否发生全内反射,如果发生全内反射,那么就直接根据理想的反射方向继续在玻璃内传播。如果没有发生全内反射则基于斯涅尔定律计算折射方向,然后使用 菲涅尔方程和Schlick近似 计算折射和反射的比例
折射示意图

  • 全内反射判断
    根据全内反射定律,当入射角 θ a > θ c \theta_{a}>\theta_{c} θa>θc时发生全内反射。而 θ c = a r c s i n ( n b n a ) \theta_{c}=arcsin(\frac{n_b}{n_a}) θc=arcsin(nanb)
    即当:
    θ a > θ c = a r c s i n ( n b n a ) θ a > a r c s i n ( n b n a ) s i n ( θ a ) > n b n a s i n 2 ( θ a ) > ( n b n a ) 2 1 − c o s 2 ( θ a ) > ( n b n a ) 2 ( n a n b ) 2 ( 1 − c o s 2 ( θ a ) ) > 1 1 − ( n a n b ) 2 ( 1 − c o s 2 ( θ a ) ) < 0 (1) \theta_{a} > \theta_{c}=arcsin(\frac{n_b}{n_a}) \\\ \theta_{a} > arcsin(\frac{n_b}{n_a}) \\ sin(\theta_{a}) > \frac{n_b}{n_a} \\ sin^2(\theta_{a}) > (\frac{n_b}{n_a})^2 \\ 1-cos^{2}(\theta_{a})>(\frac{n_b}{n_a})^2 \\ (\frac{n_a}{n_b})^2(1-cos^{2}(\theta_{a}))>1 \\ 1 - (\frac{n_a}{n_b})^2(1-cos^{2}(\theta_{a})) < 0 \tag{1} θa>θc=arcsin(nanb) θa>arcsin(nanb)sin(θa)>nanbsin2(θa)>(nanb)21cos2(θa)>(nanb)2(nbna)2(1cos2(θa))>11(nbna)2(1cos2(θa))<0(1)
    时,发生全内反射。
    而代码中nnt n a n b \frac{n_a}{n_b} nbnaddn等于 − c o s ( θ a ) -cos(\theta_{a}) cos(θa)ddn*ddn c o s 2 ( θ a ) cos^{2}(\theta_{a}) cos2(θa)
    因此,当cos2t=1 - nnt * nnt * (1 - ddn * ddn)<0时,发生全内反射。

  • 计算折射方向
    根据斯涅尔定律,假如入射光方向为 D D D,折射光方向为 T T T,那么应该满足如下公式:
    n a ∗ s i n ( θ a ) = n b ∗ s i n ( θ b ) (2) n_{a}*sin(\theta_{a}) = n_{b}*sin(\theta_{b}) \tag{2} nasin(θa)=nbsin(θb)(2)
    其中 θ a \theta_{a} θa为入射角, t h e t a b theta_{b} thetab为折射角, n a n_a na为入射介质折射率, n b n_b nb为出射介质折射率。
    折射示意图

    如上图所示,我们可以得到:
    s i n ( θ a ) = 1 − c o s 2 ( θ a ) = 1 − ( D ∗ N ) 2 s i n ( θ b ) = n a n b s i n ( θ a ) = n a n b 1 − ( D ∗ N ) 2 c o s ( θ b ) = 1 − s i n 2 ( θ b ) = 1 − n a 2 n b 2 ( 1 − ( D ∗ N ) 2 ) (3) sin(\theta_a)=\sqrt{1-cos^2(\theta_a)}=\sqrt{1-(D*N)^2}\\ sin(\theta_b)=\frac{n_a}{n_b}sin(\theta_a) = \frac{n_a}{n_b}\sqrt{1-(D*N)^2} \\ cos(\theta_b) = \sqrt{1-sin^2(\theta_b)}=\sqrt{1-\frac{n_{a}^2}{n_b^2}(1-(D*N)^2)} \tag{3} sin(θa)=1cos2(θa) =1(DN)2 sin(θb)=nbnasin(θa)=nbna1(DN)2 cos(θb)=1sin2(θb) =1nb2na2(1(DN)2) (3)
    单位向量 B B B等于:
    B = n o r m ( D − ∣ c o s ( θ a ) ∣ N ) = D − ∣ c o s ( θ a ) ∣ N s i n ( θ a ) = D + ( D ⋅ N ) N 1 − ( D ⋅ N ) 2 (4) B = norm(D - |cos(\theta_a)| N) = \frac{D - |cos(\theta_a)| N}{sin(\theta_a)}=\frac{D +(D\cdot N)N}{\sqrt{1-(D\cdot N)^2}} \tag{4} B=norm(Dcos(θa)N)=sin(θa)Dcos(θa)N=1(DN)2 D+(DN)N(4)
    目标折射光向量 T T T等于:
    T = B s i n ( θ b ) − N c o s ( θ b ) = D + ( D ⋅ N ) N 1 − ( D ⋅ N ) 2 ∗ n a n b 1 − ( D ⋅ N ) 2 − N 1 − n a 2 n b 2 ( 1 − ( D ⋅ N ) 2 ) = n a n b ∗ ( D + D ⋅ N ) N − N 1 − n a 2 n b 2 ( 1 − ( D ⋅ N ) 2 ) = n a n b D + n a n b N ( D ⋅ N ) − N 1 − n a 2 n b 2 ( 1 − ( D ⋅ N ) 2 ) = n a n b D + N ( n a n b ( D ⋅ N ) − 1 − n a 2 n b 2 ( 1 − ( D ⋅ N ) 2 ) ) (5) T = Bsin(\theta_b)-Ncos(\theta_b) = \frac{D +(D\cdot N)N}{\sqrt{1-(D\cdot N)^2}} * \frac{n_a}{n_b}\sqrt{1-(D \cdot N)^2} - N\sqrt{1-\frac{n_{a}^2}{n_b^2}(1-(D\cdot N)^2)} \\ = \frac{n_a}{n_b}*(D+D\cdot N)N-N\sqrt{1-\frac{n_{a}^2}{n_b^2}(1-(D\cdot N)^2)} \\ = \frac{n_a}{n_b}D+\frac{n_a}{n_b}N(D\cdot N)-N\sqrt{1-\frac{n_{a}^2}{n_b^2}(1-(D\cdot N)^2)} \\ = \frac{n_a}{n_b}D+N \left( \frac{n_a}{n_b}(D\cdot N)-\sqrt{1-\frac{n_{a}^2}{n_b^2}(1-(D\cdot N)^2) } \right) \tag{5} T=Bsin(θb)Ncos(θb)=1(DN)2 D+(DN)Nnbna1(DN)2 N1nb2na2(1(DN)2) =nbna(D+DN)NN1nb2na2(1(DN)2) =nbnaD+nbnaN(DN)N1nb2na2(1(DN)2) =nbnaD+N(nbna(DN)1nb2na2(1(DN)2) )(5)
    因为代码中nnt= n a n b \frac{n_a}{n_b} nbnaddn= − c o s ( θ a ) = − ( D ⋅ N ) -cos(\theta_{a})=-(D\cdot N) cos(θa)=(DN)cos2t=1 - nnt * nnt * (1 - ddn * ddn)= 1 − n a 2 n b 2 ( 1 − ( D ⋅ N ) 2 ) 1-\frac{n_{a}^2}{n_b^2}(1-(D\cdot N)^2) 1nb2na2(1(DN)2)
    因此,结果折射光线 T T T就等于代码中的:

    	Vec tdir = (r.d*nnt - n*((into?1:-1)*(ddn*nnt+sqrt(cos2t)))).norm(); 
    
  • 计算折射和反射的比例
    根据菲涅尔方程和Schlick近似,可以计算得到光线发生折射和反射的比例,Schlick近似公式如下:
    n = n a n b R 0 = ( n − 1 ) 2 ( n + 1 ) 2 = ( n a − n b ) / n b ( n a + n b ) / n b = n a − n b n a + n b R r ( θ a ) = R o + ( 1 − R o ) ( 1 − c o s ( θ a ) ) 5 (6) n=\frac{n_a}{n_b} \\ R_{0}=\frac{(n-1)^2}{(n+1)^2}=\frac{(n_a-n_b)/n_b}{(n_a+n_b)/n_b}=\frac{n_a-n_b}{n_a+n_b} \\ R_{r}(\theta_{a}) = R_{o} + (1-R_{o})(1-cos(\theta_{a}))^{5} \tag{6} n=nbnaR0=(n+1)2(n1)2=(na+nb)/nb(nanb)/nb=na+nbnanbRr(θa)=Ro+(1Ro)(1cos(θa))5(6)
    其中 R 0 R_{0} R0为光线垂直入射(即入射角 θ a = 0 \theta_{a}=0 θa=0)时的反射率,即代码中的变量R0 R r ( θ a ) R_{r}(\theta_{a}) Rr(θa)为入射角为 θ a \theta_{a} θa时的反射率,即代码中的变量Re

    double Re=R0+(1-R0)*c*c*c*c*c,Tr=1-Re,P=.25+.5*Re,RP=Re/P,TP=Tr/(1-P); 
    
  • 其他

    return obj.e + f.mult(depth>2 ? (erand48(Xi)<P ?   // Russian roulette radiance(reflRay,depth,Xi)*RP:radiance(Ray(x,tdir),depth,Xi)*TP) : radiance(reflRay,depth,Xi)*Re+radiance(Ray(x,tdir),depth,Xi)*Tr); 
    

    在结束折射部分代码时,由于smallpt中规定折射材质的颜色c=(1.0,1.0,1.0),在radiance()函数开始,使用p=max(f.r, f.g,f.b)进行俄罗斯轮盘赌时肯定无法失败、结束递归。因此在此处增加了一次俄罗斯轮盘赌,使用P=0.25+0.5*Re作为俄罗斯轮盘赌的阈值。
    当递归深度大于2时使用P作为阈值进行俄罗斯轮盘赌,决定是否结束递归。如果不结束,就将Re比例的光线用于接下来的镜面反射,Tr=1-Re比例的光线用于接下来的折射。

在接下来的 [图形学]smallpt代码详解(3) 中,将继续讲解 smallpt 中的main函数部分,包括渲染场景的定义相机的设置光线的生成滤波处理减少噪点保存最终渲染结果几部分。

三、参考

[1].smallpt: Global Illumination in 99 lines of C++
[2].smallpt: Global Illumination in 99 lines of C+±Presentation slides
[3].光线跟踪smallpt详解 (一)
[4].斯涅尔定律
[5].菲涅尔方程
[6].Schlick近似

相关文章:

[图形学]smallpt代码详解(2)

一、简介 本文紧接在[图形学]smallpt代码详解&#xff08;1&#xff09;之后&#xff0c;继续详细讲解smallpt中的代码&#xff0c;包括自定义函数&#xff08;第41到47行&#xff09;和递归路径跟踪函数&#xff08;第48到74行&#xff09;部分。 二、smallpt代码详解 1.自…...

vmstat命令:系统性能监控

一、命令简介 ​vmstat​ 是一种在类 Unix 系统上常用的性能监控工具&#xff0c;它可以报告虚拟内存统计信息&#xff0c;包括进程、内存、分页、块 IO、陷阱&#xff08;中断&#xff09;和 CPU 活动等。 ‍ 二、命令参数 2.1 命令格式 vmstat [选项] [ 延迟 [次数] ]2…...

linux部署NFS和autofs自动挂载

目录 &#xff08;一&#xff09;NFS&#xff1a; 1. 什么是NFS 2. NFS守护进程 3. RPC服务 4. 原理 5. 部署 5.1 安装NFS服务 5.2 配置防火墙 5.3 创建服务端共享目录 5.4 修改服务端配置文件 (1). /etc/exports (2). nfs.conf 5.5 启动nfs并加入自启 5.6 客户端…...

WPF RadioButton 绑定boolean值

<RadioButtonMargin"5"Content"替换"IsChecked"{Binding CorrectionOption.ReCorrectionMode}" /> <RadioButtonMargin"5"Content"平均"IsChecked"{Binding CorrectionOption.ReCorrectionMode, Converter{St…...

2024 ciscn WP

一、MISC 1.火锅链观光打卡 打开后连接自己的钱包&#xff0c;然后点击开始游戏&#xff0c;答题八次后点击获取NFT&#xff0c;得到有flag的图片 没什么多说的&#xff0c;知识问答题 兑换 NFT Flag{y0u_ar3_hotpot_K1ng} 2.Power Trajectory Diagram 方法1&#xff1a; 使用p…...

代码随想录--字符串--重复的子字符串

题目 给定一个非空的字符串&#xff0c;判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母&#xff0c;并且长度不超过10000。 示例 1: 输入: "abab" 输出: True 解释: 可由子字符串 "ab" 重复两次构成。示例 2: 输入: "…...

No.5 笔记 | 网络端口协议概览:互联网通信的关键节点

1. 常用端口速览表 端口范围主要用途1-1023系统或特权端口1024-49151注册端口49152-65535动态或私有端口 远程访问类&#xff08;20-23&#xff09; 端口服务记忆技巧安全风险21FTP"File Transfer Port"爆破、嗅探、溢出、后门22SSH"Secure Shell"爆破、…...

手机地址IP显示不对?别急,这里有解决方案

在当今的数字化生活中&#xff0c;手机已成为我们连接世界的重要工具。而手机的IP地址&#xff0c;作为我们在网络上的“身份证”&#xff0c;其准确性对于网络体验至关重要。然而&#xff0c;有时我们可能会遇到手机IP地址显示不正确的问题&#xff0c;这不仅会影响网络连接质…...

人工智能对未来工作影响的四种可能性

随着人工智能&#xff08;AI&#xff09;技术的迅速发展&#xff0c;其对人类工作的影响已成为讨论的热点话题。我们经常听到有关AI威胁论的观点&#xff0c;担心它将取代人类工作&#xff0c;但也有专家认为AI将成为一种辅助工具&#xff0c;帮助人类提升工作效率。宾夕法尼亚…...

SpringBoot+ElasticSearch7.12.1+Kibana7.12.1简单使用

案例简介 本案例是把日志数据保存到Elasticsearch的索引中&#xff0c;并通过Kibana图形化界面的开发工具给查询出来添加的日志数据&#xff0c;完成从0到1的简单使用 ElasticSearch职责用法简介 ElasticSearch用在哪 ElasticSearch在我这个案例中&#xff0c;不是用来缓解增…...

RESTful风格接口+Swagger生成Web API文档

RESTful风格接口Swagger生成Web API文档 文章目录 RESTful风格接口Swagger生成Web API文档1.RESTful风格接口RESTful简介RESTful详细图示常见http状态码springboot实现RESTfulRESTful springboot设计实例demo 2.Swagger生产Web API文档Swagger简介使用Swagger1.加入依赖2.配置S…...

性能测试学习2:常见的性能测试策略(基准测试/负载测试/稳定性测试/压力测试/并发测试)

一.基准测试 1&#xff09;概念 狭义上讲&#xff1a;就是单用户测试。测试环境确定后&#xff0c;对业务模型中的重要业务做单独的测试&#xff0c;获取单用户运行时的各项性能指标。 广义上&#xff1a;是一种测量和评估软件性能指标的活动。可以在某个时刻通过基准测试建立…...

【C++】—— 继承(上)

【C】—— 继承&#xff08;上&#xff09; 1 继承的概念与定义1.1 继承的概念1.2 继承定义1.2.1 定义格式1.2.2 继承父类成员访问方式的变化 1.3 继承类模板 2 父类和子类对象赋值兼容转换3 继承中的作用域3.1 隐藏规则3.2 例题 4 子类的默认成员函数4.1 构造函数4.1.1 父类有…...

【2024保研经验帖】东南大学计算机学院夏令营

前言 背景&#xff1a;末211&#xff0c;专业计算机科学与技术&#xff0c;rk前5%&#xff0c;无科研&#xff0c;只有几个竞赛 东南大学计算机学院夏令营需要老师推荐&#xff0c;一个老师的推荐名额感觉应该挺多的&#xff0c;因为学硕和专硕都进了两百多人&#xff0c;总共…...

dz论坛可可积分商城插件价值399元

界面简洁美观大方&#xff0c;适合各类站点。支持多用户商城&#xff0c;可让商家入驻站点发布商品&#xff0c;亦可站长自己发布商品。支持向商家抽佣抽成功能&#xff0c;可设置商家在成交商品后按一定比例扣除抽成&#xff0c;达到网站盈利目的采用队列技术处理&#xff0c;…...

python的extend和append

在Python中&#xff0c;list的append和extend方法都是用来向列表添加元素的&#xff0c;但它们之间有一些关键的区别&#xff1a; append方法&#xff1a; append方法用于将一个对象添加到列表的末尾。无论添加的对象是什么类型&#xff08;整数、字符串、列表等&#xff09;&a…...

贪心算法相关知识

目录 基础 定义 工作原理 步骤一&#xff1a;分解问题 步骤二&#xff1a;确定贪心策略 步骤三&#xff1a;求解子问题 步骤四&#xff1a;合并结果 适用场景 活动安排问题 找零问题 哈夫曼编码 局限性 高级 与动态规划的对比 决策方式 最优性保证 时间复杂度和…...

济南比较出名的人物颜廷利:全球最具影响力的思想家起名大师

颜廷利教授是一位在思想、哲学、教育、易学、国学、心理学、命名学等多个领域具有深远影响的学者。他被誉为“世界点赞第一人”&#xff0c;在国内外享有极高的声誉&#xff0c;被认为是现代易经三大泰斗之首。山东目前比较厉害的名人颜廷利教授的学术成就和影响力横跨哲学、思…...

第100+27步 ChatGPT学习:概率校准 Temperature Scaling

基于Python 3.9版本演示 一、写在前面 最近看了一篇在Lancet子刊《eClinicalMedicine》上发表的机器学习分类的文章&#xff1a;《Development of a novel dementia risk prediction model in the general population: A large, longitudinal, population-based machine-learn…...

Python知识点:如何应用Python工具,使用NLTK进行语言模型构建

开篇&#xff0c;先说一个好消息&#xff0c;截止到2025年1月1日前&#xff0c;翻到文末找到我&#xff0c;赠送定制版的开题报告和任务书&#xff0c;先到先得&#xff01;过期不候&#xff01; 如何使用NLTK进行语言模型构建 在自然语言处理&#xff08;NLP&#xff09;中&a…...

TDengine 快速体验(Docker 镜像方式)

简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能&#xff0c;本节首先介绍如何通过 Docker 快速体验 TDengine&#xff0c;然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker&#xff0c;请使用 安装包的方式快…...

MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例

一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

听写流程自动化实践,轻量级教育辅助

随着智能教育工具的发展&#xff0c;越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式&#xff0c;也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建&#xff0c;…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)

船舶制造装配管理现状&#xff1a;装配工作依赖人工经验&#xff0c;装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书&#xff0c;但在实际执行中&#xff0c;工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...

适应性Java用于现代 API:REST、GraphQL 和事件驱动

在快速发展的软件开发领域&#xff0c;REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名&#xff0c;不断适应这些现代范式的需求。随着不断发展的生态系统&#xff0c;Java 在现代 API 方…...

tomcat指定使用的jdk版本

说明 有时候需要对tomcat配置指定的jdk版本号&#xff0c;此时&#xff0c;我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...

消防一体化安全管控平台:构建消防“一张图”和APP统一管理

在城市的某个角落&#xff0c;一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延&#xff0c;滚滚浓烟弥漫开来&#xff0c;周围群众的生命财产安全受到严重威胁。就在这千钧一发之际&#xff0c;消防救援队伍迅速行动&#xff0c;而豪越科技消防一体化安全管控平台构建的消防“…...

二维FDTD算法仿真

二维FDTD算法仿真&#xff0c;并带完全匹配层&#xff0c;输入波形为高斯波、平面波 FDTD_二维/FDTD.zip , 6075 FDTD_二维/FDTD_31.m , 1029 FDTD_二维/FDTD_32.m , 2806 FDTD_二维/FDTD_33.m , 3782 FDTD_二维/FDTD_34.m , 4182 FDTD_二维/FDTD_35.m , 4793...

云原生安全实战:API网关Envoy的鉴权与限流详解

&#x1f525;「炎码工坊」技术弹药已装填&#xff01; 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关 作为微服务架构的统一入口&#xff0c;负责路由转发、安全控制、流量管理等核心功能。 2. Envoy 由Lyft开源的高性能云原生…...