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

GAMES202作业1

目录

  • Shadow Map
    • CalcLightMVP函数
    • useShadowMap函数
      • Bias函数
    • 最终效果
  • PCF
    • 两个采样函数
    • PCF函数
    • 最终效果
  • PCSS
    • findBlocker函数
    • PCSS函数
    • 最终效果
  • 参考

先放上公式:
在这里插入图片描述
后面的积分项是我们在作业0中就做好的blinnphong项,我们要求的就是积分项前,等号后的可见项。
最终体现在代码中便是

  • gl_FragColor = vec4(visibility * phongColor, 1.0);

这部分代码在homework1\src\shaders\phongShader\phongFragment.glsl中

Shadow Map

第一部分是使用Shadow Map的方法来渲染阴影,也就是渲染硬阴影,经典的Two Pass Shadow Map方法。
在这里插入图片描述
在这里插入图片描述
简单来说,shadow map主要分为两步操作:

  • 第一部分,我们需要将摄像机移动到光源的位置,从光源视角出发看向场景。视线能看到的各最小深度就是光源能直接照射到的物体深度,获得这个视角下的场景深度图。(记录场景中距离光源最近的每一点,形成一张图)
    在这里插入图片描述
  • 第二部分,绘制时需要将相机挪到眼睛的位置再观测,得到视线与物体交点,再将该点的深度,如下图中深黄色所示,与第一趟绘制得到的该点的深度比较,如果此次得到的深度更深(或者说值更大),则判断为阴影,如果相比更浅(或者说值更小或相等),则判断为非阴影可直接着色。
    在这里插入图片描述

先看src\renderers\WebGLRenderer.js,两次Pass计算阴影的主要代码:
在这里插入图片描述


CalcLightMVP函数

首先是src/lights/DirectionalLight.js的矩阵变换部分,该矩阵参与了第一步从光源处渲染场景从而构造 ShadowMap 的过程。

CalcLightMVP(translate, scale) {let lightMVP = mat4.create();let modelMatrix = mat4.create();let viewMatrix = mat4.create();let projectionMatrix = mat4.create();// Model transform 模型矩阵,对相机先平移,再缩放mat4.translate(modelMatrix,modelMatrix,translate);mat4.scale(modelMatrix,modelMatrix,scale);// View transform 视图矩阵mat4.lookAt(viewMatrix,this.lightPos,this.focalPoint,this.lightUp);// Projection transform 投影矩阵mat4.ortho(projectionMatrix,-100,100,-100,100,1e-2,400);mat4.multiply(lightMVP, projectionMatrix, viewMatrix);mat4.multiply(lightMVP, lightMVP, modelMatrix);return lightMVP;}
  • 因为我们需要获取从光源处看世界的坐标。所以在直射光中需要补充一个获得转换到光源处空间的矩阵。我们可以调用API来快速生成translate和scale矩阵。
  • 再调用lookAt函数得到viewMatrix矩阵。关于lookAt()函数可以参考:learnopengl教程
  • 最后使用projectionMatrix正交投影矩阵得到Shadow Map。关于正交矩阵和透视矩阵的选取:投影矩阵,由于透视投影会产生深度精度问题,因此作业中选择正交投影。

完成该矩阵的输出后,我们就可以在片元着色器中获取到Shadow Map:
在这里插入图片描述

useShadowMap函数

src\shaders\phongShader\phongFragment.glsl
在这里插入图片描述

  • shadowCoord —— 纹理图片上像素对应的坐标
  • 在着色时我们使用了可见项对blinnPhong得到的颜色进行一个可见性衰减。
  • 我们在useShadowMap函数中可以看到我们需要使用到当前着色片元在光源坐标系下的坐标shadowCoord,这个坐标是在片元着色器前插值生成的。为了在贴图采样中使用该坐标,我们需要将向量的各个分量从( -1 , 1 ),强制转化到( 0 , 1 )(uv坐标的范围都是0-1)。

在代码里发现是调用了useShadowMap方法,

float useShadowMap(sampler2D shadowMap, vec4 shadowCoord){float mapDepth = unpack(texture2D(shadowMap,shadowCoord.xy));//shadow map中各点的最小深度,unpack将RGBA值转换成[0,1]的floatfloat shadingDepth = shadowCoord.z; //当前着色点的深度float visibility1 = ((mapDepth + EPS) < shadingDepth) ? 0.0 : 1.0;  return visibility1;
}
  • 先获取第一步已经获取到的shadow map中的深度。unpack()用来将RGBA值转换成在范围[0,1]的float值。
  • 再获取第二次从相机出发观察到的点离光源的深度。
  • 然后进行比较,EPS考虑精度问题。
  • 返回visibility。

效果:
在这里插入图片描述

Bias函数

放大之后会发现会有很多锯齿,因为发生了自遮挡现象:

  • 其一是处理器的数值精度的限制

  • 还有一个原因是因为shadow map本身保存的值是离散值,也就是说shadow map上每个采样点都代表着一块范围内图元的深度值,因此在第二个pass比较深度的时候,shadow map中的深度可能会略低于物体表面的深度,部分片元就会被误计算为阴影,导致自遮挡。该现象在光源与平面趋于平行时(掠射)尤为严重。
    在这里插入图片描述
    在这里插入图片描述

  • 为了解决这个问题,课上也说了,使用bias(偏移值)方法。

  • 在shadow map中引入一个偏移值(bias),使得每次在比较深度大小的时候,都将一定区间内的shadow map深度认作与屏幕空间深度相等,强行减弱阴影判定。

  • 但这样做又会引入一个新的问题——detached shadow,或者说,peter panning(阴影悬浮)——即丢失部分原本可能发生遮挡的阴影
    在这里插入图片描述
    在这里插入图片描述

那来看一下怎么做这个bias,还是在src\shaders\phongShader\phongFragment.glsl中直接添加一个Bias方法:
在这里插入图片描述

放两个,其实没多大区别,差别在于这个阴影的出现程度,第二个的阴影区域会比第一个小:

float Bias(float CDepth){vec3 lightDir1 = normalize(uLightPos);vec3 normal1 = normalize(vNormal);float m = 200.0 / 2048.0 / 2.0; // 正交矩阵宽高/shadowmap分辨率/2float bias1 = max(m * (1.0-dot(normal1,lightDir1)),m) * CDepth;return bias1;
}float Bias1(){vec3 lightDir1 = normalize(uLightPos);vec3 normal1 = normalize(vNormal);float bias1 = max(0.08 * (1.0-dot(normal1,lightDir1)),0.08);return bias1;
}

然后修改useShadowMap方法:

float useShadowMap(sampler2D shadowMap, vec4 shadowCoord){float mapDepth = unpack(texture2D(shadowMap,shadowCoord.xy));//shadow map中各点的最小深度,unpack将RGBA值转换成[0,1]的floatfloat shadingDepth = shadowCoord.z; //当前着色点的深度//float visibility1 = ((mapDepth + EPS) < shadingDepth) ? 0.0 : 1.0;float bias = Bias(1.4);float visibility1 = ((mapDepth + EPS) <= (shadingDepth - bias)) ? 0.2 : 0.9;return visibility1;
}

最终效果

采用Bias方法后的效果:
在这里插入图片描述

放大之后,虽然不会产生严重的锯齿现象,但还是有锯齿:
在这里插入图片描述
但很明显,腿部的阴影没有了,因为发生了我们上面说的阴影悬浮现象,这就可以通过修改bias方法来改善,但不可避免。


完成了硬阴影的two pass shadow map方法后,在实际生活中我们更希望我们得到的是软阴影,接下来就是写软阴影部分的代码,软阴影又分为PCF和PCSS两种。

PCF

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
我们通过SM生成了一个硬阴影,但是在实际生活中我们希望我们得到的是软阴影,而在我们刚才的硬阴影的计算中我们得到的visibility项非0即1.如果我们着色点周围的一圈像素进行一个加权平均,我们就可以得到一个相对来说较软的阴影——visibility项不再是非0即1。

请注意,这个过程发生在采样过程中:

    1. 滤波对象既不是Shadow Map自身(对shadow map滤完波再做深度测试,结果仍是二值化数据,相当于什么都没做);
    1. 也不是深度测试结束后得到的阴影图(非但不会消除锯齿,还会让阴影变糊,在101中有提到过);
    1. 而是找我们选定的点对应于shadow map中周围一圈邻域的点,将领域中的每个点与我们选定的点进行比较,进行一个二值化处理。比较完成之后,对这一圈邻域内的二值化数据进行求和平均(也就是filter,其实叫filter不够准确,就是做一个求和平均罢了)。

两个采样函数

作业中建议用泊松圆盘采样和均匀圆盘采样,代码里都给出来了:

  • 泊松圆盘
    在这里插入图片描述
    在这里插入图片描述

  • 均匀圆盘
    在这里插入图片描述
    在这里插入图片描述

实话说没看懂哈,会用就行了,要是有小伙伴感兴趣的可以看下面的链接:

  • 三维点云泊松圆盘采样(Poisson-Disk Sampling)
  • 泊松盘采样(Poisson Disk Sampling)生成均匀随机点
  • 需要注意的是,两个采样方法都把数据存储到了下面这个数组中:
    在这里插入图片描述
    所以不管我们用哪个方法,都可以直接使用这个数组来取数据。

PCF函数

课上老师也提到过,PCF其实是基于shadow map做AA(Anti-Aliasing,即反走样)。PCF就是在做卷积,把卷积核也叫做过滤器,也就是filter。

卷积原理看这个:卷积 (Convolution) 填充 (Padding) 步长 (Stride)

在进行shading point的深度与shadowmap比较时,不只比较一个方向的值,而是与周围像素做卷积,在周围采样多个点的深度值,逐一比较之后求平均值,就能得到一个[0,1]的连续分布,可以表示不同明暗程度的阴影,不再是硬阴影那样非0即1对比强烈的感觉,阴影就变得柔和起来,也就实现了人工软阴影化。

在这里插入图片描述

  • filter size 卷积核大小
    • 作业1中filter的大小由采样数量决定,也就是一开始给定的NUM_SAMPLES,初始值设置成了20。
    • filter的大小、个数一般都是先设定一个初始值,再根据实验效果进行调整。
    • 在进行卷积时,在输出要求相同的情况下,filter越大参与计算的参数越多,那么对于作业1来说达到的阴影柔和的效果越明显。
float PCF(sampler2D shadowMap, vec4 coords) {float stride = 2.0;           //定义步长float shadowMapSize = 2048.0;  //shadowmap分辨率float visibility1 = 0.0;        //初始可见项float cur_depth = coords.z;    //卷积范围内当前点的深度float filterRange = stride / shadowMapSize; //滤波窗口的范围//泊松圆盘采样得到采样点poissonDiskSamples(coords.xy);//均匀圆盘采样得到采样点//uniformDiskSamples(coords.xy);//对每个点进行比较深度值并累加for(int i = 0; i < NUM_SAMPLES; i++){float shadow_depth = unpack(texture2D(shadowMap,coords.xy + poissonDisk[i] * filterRange));float res = (cur_depth < shadow_depth + EPS) ? 1.0 : 0.0;visibility1 += res;}//返回均值float avgVisibility = visibility1 / float(NUM_SAMPLES);return avgVisibility;
}
  • 采样偏移值 -> 与步长Sride关系
    • 在卷积过程中,将每次卷积核滑动的行数/列数称为Stride(步长)。有时需要在卷积时通过设置的Stride来压缩一部分信息,成倍缩小尺寸。
    • 对于作业1而言,由于PCF输入的坐标coords归一到了[0,1]的范围,那么给定采样点的偏移值poissonDiskSamples[i]也需要缩小一定范围以迎合coords坐标的尺寸,因此需要给定Stride以缩小尺寸。缩小比例当然是stride/shaodowMapSize,框架中shadowMapSize=2048,Stride可以给定一个初始值1,根据效果进行调整。

额,最后别忘了在main函数里改一下:
在这里插入图片描述

最终效果

用泊松圆盘采样的结果:
NUM_SAMPLES=80,stride=10:
在这里插入图片描述

要是更改一下参数:NUM_SAMPLES=80,stride=2:
在这里插入图片描述
用均匀圆盘采样的结果:
NUM_SAMPLES=80,stride=2:
在这里插入图片描述

NUM_SAMPLES=80,stride=2:
在这里插入图片描述

  • 可以发现NUM_SAMPLES越小或者stride越大 阴影边缘噪点越多,有兴趣可以自己试试调整这两个参数值。

PCSS

然后就是最后的PCSS方法了。为了达到前实后虚的软阴影效果,就可以采用PCSS(Percentage Closer Soft Shadow),通过计算投影平面与遮挡物之间的距离,来确定滤波范围的大小(自适应的filter size)。

算法的整体思路是:

  • 首先将shading point点x投应到shadow map上,找到其对应的像素点p。
  • 在点p附近取一个范围(这个范围是自己定义或动态计算的),将范围内各像素的最小深度与x的实际深度比较,从而判断哪些像素是遮挡物,把所有遮挡物的深度记下来取个平均值作为blocker distance。(Blocker search)
  • 第二步:用取得的遮挡物深度距离来算在PCF中filtering的范围。
  • 第三步:进行pcf操作。

这里有个问题,filter size可以按上述方法确定了,那么计算filter size时需要用到的d(blocker)同样需要在一定范围内做平均,这个范围又怎么确定呢?我们可以认为规定一个固定的大小,如4 * 4,16 * 16等,但这么做绝对不是最优解,更好的方法是在光源处设置一个视锥,将shadow map置于近平面上,接着连接着色点和光源,以其在shadow map上所截得的范围作为样本,来计算平均深度。

这么做有一个非常大的好处,就是计算d(blocker)也采用了自适应的方法,离光源越远,遮挡物越多,计算blocker所用的样本范围就越小;而离光源越近,遮挡物越少,计算blocker所用的样本空间就越大,非常合理。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述


在这里插入图片描述

  • W(Light)是光源的大小。
  • W(Penumbra)是filter的大小,某种程度算是阴影软硬程度的表现,该值越大,阴影就越软。
  • d(Receiver)是阴影接受物的深度。
  • d(Blocker)是遮挡物,也就是阴影投射物的深度。
    • 遮挡物Blocker越接近接受物Receiver,W(Penumbra)越小,阴影越硬;
    • 遮挡物Blocker越接近光源Light,W(Penumbra)越大,阴影越软;

由相似三角形就能得到:
在这里插入图片描述

所以PCSS的具体步骤为:

  • 首先依据着色点选择一块范围,对Shadow Map做一次局部深度测试,找到范围内的blocker并计算其平均深度(计算平均深度的目的是减小遮挡物自身的几何影响,避免漏光)。
  • 得到d(blocker)后代入公式计算滤波范围, d(blocker)越小, [d(receiver)-d(blocker)] 越大,卷积核越大,得到的阴影就越软。
  • 重新进行深度测试,继续完成PCF的过程。

那作业需要我们完成findBlocker(sampler2D shadowMap,vec2 uv, float zReceiver) 和 PCSS(sampler2D shadowMap, vec4 shadowCoord)函数。

findBlocker函数

看一下findBlocker函数,需要完成对遮挡物平均深度的计算,也就是上面的d(Blocker)。

  • 首先给定基数BlockerNum和总的Block_depth。
  • 从当前的shading point连向方向光源light,方向上击中位于shadow map上的一点P,取点P周围的一个区域(利用到了泊松圆盘采样),判断区域里的点是否在阴影里,如果在则BlockerNum加一、Block_depth加上cur_depth;如果不在,则不纳入计算。
    以发现这个判断过程跟前面的shadowmap和PCF都是一样的,但是目的不同,这里是在求blocker的深度!
float findBlocker( sampler2D shadowMap,  vec2 uv, float zReceiver ) {int blockerNum = 0;           //着色点对应到shadow map中后,周围一圈邻域内为blocker的点的数量float blocker_depth = 0.0;    //blocker的深度float shadowMapSize = 2048.0; //shadow map的分辨率float stride = 50.0;          //采样的步长float filterRange = stride / shadowMapSize; //滤波窗口的范围//泊松圆盘采样得到采样点poissonDiskSamples(uv);//均匀圆盘采样得到采样点//uniformDiskSamples(uv);//判断着色点对应到shadow map中后,邻域中的点是否为blocker,如果是就累加for(int i = 0; i < NUM_SAMPLES; i++){float shadow_depth = unpack(texture2D(shadowMap,uv+ poissonDisk[i] * filterRange)); if(zReceiver > shadow_depth + 0.01){blockerNum++;blocker_depth += shadow_depth;}}if(blockerNum == 0){return 1.0;}blocker_depth = blocker_depth / float(blockerNum);return blocker_depth;
}

PCSS函数

float PCSS(sampler2D shadowMap, vec4 coords){// STEP 1: avgblocker depthfloat avgBlocker_depth = findBlocker(shadowMap,coords.xy,coords.z);   //在这步里我们已经做好了采样,后面就能直接调用数据float wLight = 1.0; //光源大小float dReceiver = coords.z;// STEP 2: penumbra sizefloat wPenumbra = wLight * (dReceiver - avgBlocker_depth) / avgBlocker_depth;// STEP 3: filtering 就是做PCF,不过加入了wPenumra的影响//首先定义变量float stride = 10.0;float shadowMapSize = 2048.0;float visibility1 = 0.0;float cur_depth = coords.z;float filterRange = stride / shadowMapSize;//做采样,前面已经做好了//poissonDiskSamples(coords.xy);//然后循环比较for(int i = 0; i < NUM_SAMPLES; i++){float shadow_depth = unpack(texture2D(shadowMap,coords.xy + poissonDisk[i] * filterRange * wPenumbra));float res = cur_depth < shadow_depth+0.01 ? 1.0 : 0.0;visibility1 += res;}//求平均visibility1 /= float(NUM_SAMPLES);return visibility1;
}

最终效果

最后main函数改一下记得,结果图:
下面这个是NUM_SAMPLES=80
在这里插入图片描述
这个是让cur_depth < shadow_depth+EPS,NUM_SAMPLES=20的结果:
在这里插入图片描述
在这里插入图片描述
也可以加bias,但是得调…

参考

  • GAMES202作业1-实现过程详细步骤
  • GAMES202 作业1解答
  • GAMES202作业1-万字分析代码框架
  • GAMES202高质量实时渲染-个人笔记:实时阴影
  • GAMES202 Real-Time High Quality Rendrting 高质量实时渲染课程笔记Lecture 4: Shadow 02
  • GAMES202-高质量实时渲染

相关文章:

GAMES202作业1

目录 Shadow MapCalcLightMVP函数useShadowMap函数Bias函数 最终效果 PCF两个采样函数PCF函数最终效果 PCSSfindBlocker函数PCSS函数最终效果 参考 先放上公式&#xff1a; 后面的积分项是我们在作业0中就做好的blinnphong项&#xff0c;我们要求的就是积分项前&#xff0c;等…...

Android 12.0状态栏居中显示时间和修改时间显示样式

1.概述 在12.0的系统rom定制化开发中,在systemui状态栏系统时间默认显示在左边和通知显示在一起,但是客户想修改显示位置,想显示在中间,所以就要修改SystemUI 的Clock.java 文件这个就是管理显示时间的,居中显示的话就得修改布局文件了 效果图如下: 在这里插入图片描述 …...

湍流的数值模拟方法概述

湍流&#xff0c;又称紊流&#xff0c;是一种极其复杂、极不规则、极不稳定的三维流动。湍流场内充满着尺度大小不同的旋涡&#xff0c;大旋涡尺度可以与整个流畅区域相当&#xff0c;而小漩涡尺度往往只有流场尺度千分之一的数量级&#xff0c;最小尺度旋涡的尺度通过其耗散掉…...

openFast中的陆上风电机组5MW_Land_DLL_WTurb参数详解

文章目录 一、openFAST是什么&#xff1f;二、参数截图三、参数详解 一、openFAST是什么&#xff1f; openFAST是一种开放源代码的工具&#xff0c;为风能工程师提供了用于模拟和设计风力涡轮机的框架。它可以计算风力涡轮机在各种环境条件下的性能&#xff0c;并提供对风力涡…...

“卷”还是“躺平”?职场人如何在工作中找到价值感?

今天不谈技术&#xff0c;只谈进步。 曾经看过一个回答说“职场人最好的姿势是仰卧起坐”。 卷累的就躺&#xff0c;休息好了再继续卷&#xff0c;卷是常态&#xff0c;“仰卧起坐”也好&#xff0c;“卷的姿势”也好&#xff0c;都是在反复“卷起”的过程中寻找一些舒适和平衡…...

《Opencv3编程入门》学习笔记—第二章

《Opencv3编程入门》学习笔记 记录一下在学习《Opencv3编程入门》这本书时遇到的问题或重要的知识点。 第二章 OpenCV 官方例程引导与赏析 openv官方提供的示例程序&#xff1a;具体位于..\opencv\sources\samples\cpp ..\opencv\sources\samples\cpp\tutorial_code路径下存…...

ABP VNext种子数据按顺序插入

ABP VNext种子数据按顺序插入 1.Domain层1.1 新加Author和Book实体1.2 CustomDataSeedDbMigrationService新加方法1.3新加ISowSeed接口1.4 作者和图书种子数据逻辑1.5 新加CustomDataSeedDataSeederContributor 2.EntityFrameworkCore2.1 CustomDataSeedDbContext2.2 生成迁移脚…...

Verilog | FIFO简单实现

FIFO( First Input First Output)简单说就是指先进先出&#xff0c;也是缓存机制的一种&#xff0c;下面是我总结的 FIFO 的三大用途&#xff1a; 1)提高传输效率&#xff0c;增加 DDR 带宽的利用率。比如我们有 4 路视频数据缓存到 DDR 中去&#xff0c;比较笨的方法是&#x…...

设计模式应用场景

设计模式简介 工厂模式&#xff08;Factory Pattern&#xff09;&#xff1a;使用工厂方法创建对象&#xff0c;而不是使用new关键字直接实例化对象。 抽象工厂模式&#xff08;Abstract Factory Pattern&#xff09;&#xff1a;提供一个创建一系列相关对象的接口&#xff0c;…...

还在老一套?STM32使用新KEIL5的IDE,全新开发模式RTE介绍及使用

Keil新版本出来了&#xff0c;推出了一种全新开发模式RTE框架( Run-Time Environment)&#xff0c;更好用了。然而网上的教程资料竟还都是把Keil5当成Keil4来用&#xff0c;直接不使用这个功能。当前正点原子或野火的教程提供的例程虽有提到Keil5&#xff0c;但也是基本上当Kei…...

Java时间类(十一) -- Date类工具类 -- Java获取当天、本周、本月、本年 开始及结束时间

目录 1. 今天的日期如下: 2. DateUtils工具类的源代码: 3. 测试类 1. 今天的日期如下:...

Alma Linux 9.2、Rocky Linux 9.2现在是RHEL 9.2的替代品

随着Red Hat Enterprise Linux (RHEL) 9.2的发布&#xff0c;Alma Linux 9.2和Rocky Linux 9.2成为了RHEL 9.2的备选替代品。这两个Linux发行版旨在提供与RHEL兼容的功能和稳定性&#xff0c;以满足那些需要企业级操作系统的用户需求。本文将详细介绍Alma Linux 9.2和Rocky Lin…...

推荐5款提高生活和工作效率的好帮手

在这个数字化时代,软件工具已经深深地影响和改变了我们的生活和工作。有着各种各样的软件工具,它们都可以在特定的领域内让我们变得更加高效,完成复杂的任务。选择一款适合你的软件工具,不但可以极大地释放生产力,也可以让生活变得更加便捷。 1.桌面图标管理工具——TileIconi…...

美团小组长薪资被应届生员工倒挂7K,不把老员工当人?

一位美团的小管理爆出&#xff0c;无意中看到了整个部门薪资&#xff0c;本以为自己算比较高的&#xff0c;但看完之后整个人都傻眼了。小组长的职位月薪28K&#xff0c;而手下组员却是35K&#xff0c;当天晚上抽了一包烟也没想明白是为什么。 楼主表示&#xff0c;自己是美团的…...

【Java多线程案例】使用阻塞队列实现生产者消费者模型

前言 本篇文章讲解多线程案例之阻塞队列。主要讲解阻塞队列的特性、实际开发中常用的到的生产者消费者模型&#xff0c;以及生产者消费者模型解耦合、削峰填谷的好处。并且使用 Java 多线程模拟实现一个生产者消费者模型、阻塞队列版的生产者消费者模型。 文章从什么是阻塞队列…...

Spark 3:Spark Core RDD持久化

RDD 的数据是过程数据 RDD 的缓存 # coding:utf8 import timefrom pyspark import SparkConf, SparkContext from pyspark.storagelevel import StorageLevelif __name__ __main__:conf SparkConf().setAppName("test").setMaster("local[*]")sc SparkC…...

字节跳动五面都过了,结果被刷了,问了hr原因竟说是...

摘要 说在前面&#xff0c;面试时最好不要虚报工资。本来字节跳动是很想去的&#xff0c;几轮面试也通过了&#xff0c;最后没offer&#xff0c;自己只想到几个原因&#xff1a;1、虚报工资&#xff0c;比实际高30%&#xff1b;2、有更好的人选&#xff0c;这个可能性不大&…...

Python日期带时区转换工具类总结

文章目录 1.背景2. 遇到的坑3. 一些小案例3.1 当前日期、日期时间、UTC日期时间3.2 昨天、昨天UTC日期、昨天现在这个时间点的时间戳3.3 日期转时间戳3.4 时间戳转日期3.5 日期加减、小时的加减 4. 总结5. 完整的编码 1.背景 最近项目是国际项目&#xff0c;所以需要经常需要用…...

视频会议产品对比分析

内网视频会议系统如何选择&#xff1f;有很多单位为了保密&#xff0c;只能使用内部网络&#xff0c;无法连接互联网&#xff0c;那些SaaS视频会议就无法使用。在内网的优秀视频会议也有很多可供选择&#xff0c;以下是几个常用的&#xff1a; 1. 宝利通&#xff1a;它支持多种…...

每日一练 | 华为认证真题练习Day47

1、某台路由器输出信息如下&#xff0c;下列说法错误的是&#xff1f;&#xff08;多选&#xff09; A. 本路由器开启了区域认证 B. 本设备出现故障&#xff0c;配置的Router Id和实际生效的Router ID不一致 C. 本设备生效的Router Id为10.0.12.1 D. 本设备生效的Router Id为…...

简易版抽奖活动的设计技术方案

1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

第25节 Node.js 断言测试

Node.js的assert模块主要用于编写程序的单元测试时使用&#xff0c;通过断言可以提早发现和排查出错误。 稳定性: 5 - 锁定 这个模块可用于应用的单元测试&#xff0c;通过 require(assert) 可以使用这个模块。 assert.fail(actual, expected, message, operator) 使用参数…...

Unit 1 深度强化学习简介

Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库&#xff0c;例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体&#xff0c;比如 SnowballFight、Huggy the Do…...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

站群服务器的应用场景都有哪些?

站群服务器主要是为了多个网站的托管和管理所设计的&#xff0c;可以通过集中管理和高效资源的分配&#xff0c;来支持多个独立的网站同时运行&#xff0c;让每一个网站都可以分配到独立的IP地址&#xff0c;避免出现IP关联的风险&#xff0c;用户还可以通过控制面板进行管理功…...

Redis:现代应用开发的高效内存数据存储利器

一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发&#xff0c;其初衷是为了满足他自己的一个项目需求&#xff0c;即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源&#xff0c;Redis凭借其简单易用、…...

脑机新手指南(七):OpenBCI_GUI:从环境搭建到数据可视化(上)

一、OpenBCI_GUI 项目概述 &#xff08;一&#xff09;项目背景与目标 OpenBCI 是一个开源的脑电信号采集硬件平台&#xff0c;其配套的 OpenBCI_GUI 则是专为该硬件设计的图形化界面工具。对于研究人员、开发者和学生而言&#xff0c;首次接触 OpenBCI 设备时&#xff0c;往…...

云原生周刊:k0s 成为 CNCF 沙箱项目

开源项目推荐 HAMi HAMi&#xff08;原名 k8s‑vGPU‑scheduler&#xff09;是一款 CNCF Sandbox 级别的开源 K8s 中间件&#xff0c;通过虚拟化 GPU/NPU 等异构设备并支持内存、计算核心时间片隔离及共享调度&#xff0c;为容器提供统一接口&#xff0c;实现细粒度资源配额…...

VisualXML全新升级 | 新增数据库编辑功能

VisualXML是一个功能强大的网络总线设计工具&#xff0c;专注于简化汽车电子系统中复杂的网络数据设计操作。它支持多种主流总线网络格式的数据编辑&#xff08;如DBC、LDF、ARXML、HEX等&#xff09;&#xff0c;并能够基于Excel表格的方式生成和转换多种数据库文件。由此&…...