LearnOpenGL-光照-5.投光物
本人刚学OpenGL不久且自学,文中定有代码、术语等错误,欢迎指正
我写的项目地址:https://github.com/liujianjie/LearnOpenGLProject
文章目录
- 投光物
- 平行光
- 点光源
- 聚光
- 不平滑的例子
- 平滑例子
投光物
-
前面几节使用的光照都来自于空间中的一个点
即把光源当做一个点
但现实世界中,我们有很多种类的光照,每种的表现都不同。
-
投光物
将光投射(Cast)到物体的光源叫做投光物
-
小结
我做个小总结,与前面几节把光源当做一个点的区别
-
平行光
-
与一个点做光源不一样
点光源需要位置
平行光需要方向
所以在实现计算光源对片段的漫反射、镜面光影响,要得到光源的方向方式会不一样
-
-
点光源
-
与一个点做光源一样需要位置
在实现计算光源对片段的漫反射、镜面光影响,要得到光源的方向方式会一样
-
点光源会衰减,前面的点光不会
-
-
聚光灯
-
与一个点做光源一样需要位置
在实现计算光源对片段的漫反射、镜面光影响,要得到光源的方向方式会一样
-
聚光灯照射一个特点方向的范围,前面的点光没有范围且四周散射
-
-
平行光
这里需要定义平行光的方向向下,才符合太阳的光照照射(指向)方向,所以计算漫反射和镜面光强度的时候需要取反得到光源的方向向量。
-
简介
当我们使用一个假设光源处于无限远处的模型时,它就被称为定向光,因为它的所有光线都有着相同的方向,它与光源的位置是没有关系的。
-
图示
计算漫反射和镜面光分量时光源的方向
-
特点
因为所有的光线都是平行的,所以物体与光源的相对位置是不重要的,因为对场景中每一个物体光的方向都是一致的。
-
例子
定义一个光线方向向量而不是位置向量来模拟一个定向光。
这个光线方向是从光源指向像素点的方向,若要模仿太阳光从上往下照射,各个分量值应该为负的
cpp
lightingShader.setVec3("light.direction", -0.2f, -1.0f, -0.3f);// 太阳光向下
glsl
#version 330 core out vec4 FragColor;in vec3 Normal; in vec3 FragPos; in vec2 TexCoords;// 纹理坐标uniform vec3 viewPos;struct Material {sampler2D diffuse; // 纹理单元sampler2D specular;// 镜面光照颜色分量从纹理采样float shininess; }; uniform Material material;// 光照强度 struct Light {// vec3 position; // 使用平行光就不再需要位置了vec3 direction; // 从光源出发到全局的方向vec3 ambient;vec3 diffuse;vec3 specular; };uniform Light light; void main() {// 取负变为光源的方向向量,用在计算漫反射和镜面光分量时vec3 lightDir = normalize(-light.direction);// 环境光光照分量float ambientStrength = 0.1;// 从漫反射纹理读取颜色分量vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords)); // 漫反射光照分量vec3 norm = normalize(Normal);// vec3 lightDir = normalize(light.position - FragPos);// 一个点做光源才需要这样相减计算片段到光源的方向向量float diff = max(dot(norm, lightDir), 0.0); // 得到光源对当前片段实际的漫反射影响vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));// 从漫反射纹理读取颜色分量// 镜面光照分量float specularStrength = 0.5;vec3 viewDir = normalize(viewPos - FragPos); // 是观察者方向,不是观察者看向的方向vec3 reflectDir = reflect(-lightDir, norm);float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);// 光源对当前片段的镜面光影响// vec3 specular = light.specular * (spec * material.specular); // 改变在这里// 采样镜面光纹理颜色作为镜面光照颜色分量vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords)); vec3 result = (ambient + diffuse + specular) ;FragColor = vec4(result, 1.0); }
-
说明
依旧是冯氏光照模型
vec3 lightDir = normalize(-light.direction);
因为direction是光源指向像素点,加了负号以后成为像素点指向光源(光源的方向),这样才能与前面小节相符,正确计算光源对片段的漫反射和镜面光影响。
对应开头的小结
在实现计算光源对片段的漫反射、镜面光影响,要得到光源的方向方式会不一样
// vec3 lightDir = normalize(light.position - FragPos);// 一个点做光源才需要这样相减计算片段到光源的方向向量 // 取负变为光源的方向向量,用在计算漫反射和镜面光分量时 vec3 lightDir = normalize(-light.direction); float diff = max(dot(norm, lightDir), 0.0); // 得到光源对当前片段实际的漫反射影响
-
点光源
这里算距离与衰减,无论是光源的方向还是光源的指向方向都可以,但是计算漫反射和镜面光强度还是依旧用光的方向向量。
-
介绍
处于世界中某一个位置的光源,它会朝着所有方向发光,但光线会随着距离逐渐衰减
-
图
计算漫反射和镜面光分量时光源的方向图就不用画了,就是片段指向灯泡
-
重点在于如何定义衰减,即距离与衰减系数关系
-
若用线性
-
距离的增长线性地减少光的强度,从而让远处的物体更暗
-
这样的线性方程通常会看起来比较假
-
-
用以下公式才是稍好的选择
定义3个(可配置的)项:常数项Kc、一次项Kl和二次项Kq。
-
解读
-
常数项Kc通常保持为1.0,它的主要作用是保证分母永远不会比1小,否则的话在某些距离上它反而会增加强度,这肯定不是我们想要的效果。
-
一次项Kl会与距离值相乘,以线性的方式减少强度。
-
二次项Kq会与距离的平方相乘,让光源以二次递减的方式减少强度。
二次项在距离比较小的时候影响会比一次项小很多,但当距离值比较大的时候它就会比一次项更大了。
-
-
效果
光在近距离时亮度很高、随着距离变远亮度迅速降低、最后会以更慢的速度减少亮度
匹配
现实:灯在近处通常会非常亮、随着距离的增加光源的亮度一开始会下降非常快、但在远处时剩余的光强度就会下降的非常缓慢
-
选择正确的值
距离 常数项 一次项 二次项 7 1.0 0.7 1.8 13 1.0 0.35 0.44 20 1.0 0.22 0.20 32 1.0 0.14 0.07 50 1.0 0.09 0.032 65 1.0 0.07 0.017 100 1.0 0.045 0.0075 160 1.0 0.027 0.0028 200 1.0 0.022 0.0019 325 1.0 0.014 0.0007 600 1.0 0.007 0.0002 3250 1.0 0.0014 0.000007
-
-
-
例子
-
glsl
#version 330 core out vec4 FragColor; struct Material {sampler2D diffuse; // 纹理单元sampler2D specular;// 镜面光照颜色分量从纹理采样float shininess; }; // 点光源 struct Light {vec3 position; // 需要位置vec3 ambient; vec3 diffuse;vec3 specular;float constant; // 常数float linear; // 一次项float quadratic;// 二次项 };in vec3 FragPos; in vec3 Normal; in vec2 TexCoords;// 纹理坐标uniform vec3 viewPos; uniform Material material; uniform Light light; void main() {// 环境光光照分量// 从漫反射纹理读取颜色分量vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords)); // 漫反射光照分量vec3 norm = normalize(Normal);vec3 lightDir = normalize(light.position - FragPos); // 得到光源的方向,与一个点做光源一样float diff = max(dot(norm, lightDir), 0.0); // 得到光源对当前片段实际的漫反射影响vec3 diffuse = light.diffuse * diff * texture(material.diffuse, TexCoords).rgb;// 从漫反射纹理读取颜色分量// 镜面光照分量vec3 viewDir = normalize(viewPos - FragPos); // 是观察者方向,不是观察者看向的方向vec3 reflectDir = reflect(-lightDir, norm); // reflect要求第一个参数是光源指向像素点的向量float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);// 光源对当前片段的镜面光影响// 采样镜面光纹理颜色作为镜面光照颜色分量//vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords)); // 这句也行vec3 specular = light.specular * spec * texture(material.specular, TexCoords).rgb; // 计算衰减float distance = length(light.position - FragPos); // 得到光源到片段长度float attenuation = 1.0 / (light.constant + light.linear * distance // 根据公式+ light.quadratic * distance * distance);// 光照分量随距离衰减ambient *= attenuation;diffuse *= attenuation;specular *= attenuation;vec3 result = (ambient + diffuse + specular) ;FragColor = vec4(result, 1.0); }
-
说明
与一个点做光源一样,用光源的位置减去片段位置得到光源的方向
vec3 lightDir = normalize(light.position - FragPos); // 得到光源的方向,与一个点做光源一样
cpp
lightingShader.setFloat("light.constant", 1.0f); lightingShader.setFloat("light.linear", 0.09f); lightingShader.setFloat("light.quadratic", 0.032f);
-
-
重要bug
箱子发生旋转,法线也要跟随着变换,不然法线不再垂直顶点,会导致如下不正确效果
所以需要在vs阶段需计算发生变换后的法线
#version 330 core layout (location = 0) in vec3 aPos; layout (location = 1) in vec3 aNormal; layout (location = 2) in vec2 aTexCoords;uniform mat4 view; uniform mat4 projection; uniform mat4 model;out vec3 FragPos; out vec3 Normal; out vec2 TexCoords; void main() {gl_Position = projection * view * model * vec4(aPos, 1.0);FragPos = vec3(model * vec4(aPos, 1.0));// Normal = aNormal;// 只有顶点只发生位移时才可以保持不变Normal = mat3(transpose(inverse(model))) * aNormal;TexCoords = aTexCoords; }
以下正确结果
-
聚光
这里定义光源的位置为摄像机的位置向量,计算漫反射和镜面光反射,得摄像机的位置减去像素点的位置就成光的方向向量。
-
简介
位于环境中某个位置的光源,它只朝一个特定方向而不是所有方向照射光线。
这样的结果就是只有在聚光方向的特定半径内的物体才会被照亮,其它的物体都会保持黑暗。
聚光很好的例子就是路灯或手电筒
-
opengl上表示
OpenGL中聚光是用一个世界空间位置、一个方向和一个切光角来表示,切光角指定了聚光的半径
-
实现思路
对于每个片段,我们会计算片段是否位于聚光的切光方向之间(也就是在锥形内),如果是的话,我们就会相应地照亮片段
-
图示
LightDir
:从片段指向光源的向量。SpotDir
:聚光所指向的方向。(但实际计算时,取反方向)Phi
ϕ:指定了聚光半径的切光角。落在这个角度之外的物体都不会被这个聚光所照亮。Theta
θ:LightDir向量和SpotDir向量之间的夹角。在聚光内部的话θ值应该比ϕ值小。
要做的就是计算LightDir向量和SpotDir向量之间的点积,等于cosθ值,将cosθ值与切光角cosϕ值对比
不平滑的例子
-
计算向量图示
算theta时,为了与光的方向向量对应,dot(光的方向向量,取反光源照射前方向量)
-
代码
#version 330 core out vec4 FragColor; struct Material {sampler2D diffuse; // 漫反射颜色分量从纹理采样sampler2D specular;// 镜面光照颜色分量从纹理采样float shininess; }; // 聚光灯 struct Light {vec3 position; // 需要位置vec3 direction;// 需要照射方向float cutOff;vec3 ambient;vec3 diffuse;vec3 specular;float constant; // 常数float linear; // 一次项float quadratic;// 二次项 };in vec3 FragPos; in vec3 Normal; in vec2 TexCoords;// 纹理坐标uniform vec3 viewPos; uniform Material material; uniform Light light; void main() {// 光源的方向向量:像素点指向光源vec3 lightDir = normalize(light.position - FragPos);// 算出theta,dot(像素点指向光源,光源照射的方向取反)float theta = dot(lightDir, normalize(-light.direction)); // float theta=dot(-lightDir, normalize(light.direction));// dot(光源指向像素点, 光源照射的方向)// 执行正常光照计算:由于theta是cos值,cutOff也是cos值,cos(0-90)递减,所以theta>,而不是<if(theta > light.cutOff){// 片段在切角内// 从漫反射纹理读取颜色分量vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords)); // 漫反射光照分量vec3 norm = normalize(Normal);vec3 lightDir = normalize(light.position - FragPos); // 得到光源的方向,与一个点做光源一样float diff = max(dot(norm, lightDir), 0.0); // 得到光源对当前片段实际的漫反射影响vec3 diffuse = light.diffuse * diff * texture(material.diffuse, TexCoords).rgb;// 从漫反射纹理读取颜色分量// 镜面光照分量vec3 viewDir = normalize(viewPos - FragPos); // 是观察者方向,不是观察者看向的方向vec3 reflectDir = reflect(-lightDir, norm); // reflect要求第一个参数是光源指向像素点的向量float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);// 光源对当前片段的镜面光影响// 采样镜面光纹理颜色作为镜面光照颜色分量//vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords)); // 这句也行vec3 specular = light.specular * spec * texture(material.specular, TexCoords).rgb; // 计算衰减float distance = length(light.position - FragPos); // 得到光源到片段长度float attenuation = 1.0 / (light.constant + light.linear * distance // 根据公式+ light.quadratic * distance * distance);// 光照分量随距离衰减ambient *= attenuation;diffuse *= attenuation;specular *= attenuation;vec3 result = (ambient + diffuse + specular) ;FragColor = vec4(result, 1.0);}else{// 片段不在切角内:计算环境光,以免全黑FragColor = vec4(light.ambient * vec3(texture(material.diffuse, TexCoords)), 1.0) ;} }
上传数据
lightingShader.setVec3("light.position", camera.Position); lightingShader.setVec3("light.direction", camera.Front); lightingShader.setFloat("light.cutOff", glm::cos(glm::radians(12.5f)));
-
说明
算theta时,为了与光的方向向量对应,dot(像素点指向光源,光源照射的方向取反)
float theta = dot(lightDir, normalize(-light.direction));
与一个点做光源一样,用光源的位置减去片段位置得到光源的方向
vec3 lightDir = normalize(light.position - FragPos); // 得到光源的方向,与一个点做光源一样
-
注意点theta > light.cutOff
因为上传给cutOff的是已经计算好了的cos值,且theta也是cosθ值(cosθ=dot(lightDir, normalize(-light.direction)))
cos(0-90内)递减,所以theta >light.cutOff,代表当前夹角要比规定的范围角度要小,需要照亮
-
-
效果
-
疑问点
为什么,计算cos角度要用弧度值
lightingShader.setFloat("light.cutOff", glm::cos(glm::radians(12.5f)));
glm::cos();接收的参数需要是弧度值
-
-
测试点积两个向量的方向
glm::vec3 lightDir = camera.Position; glm::vec3 lightdirection = camera.Front; float theta1 = glm::dot(lightDir, glm::normalize(-lightdirection));// 对应第一个图 cout << "像素点指向光源:" << theta1 << endl; float theta2 = glm::dot(-lightDir, glm::normalize(lightdirection));// 对应第二个图 cout << "光源指向像素点:" << theta2 << endl;
方向一样,点积值一样
平滑例子
-
引入
如上一个例子,发现聚光灯的光圈边缘并不平滑
-
解决方法
我们可以将内圆锥设置为上一个例子聚光灯的圆锥,但我们也需要一个外圆锥,来让光从内圆锥逐渐减暗,直到外圆锥的边界。
-
融入代码中
为了创建一个外圆锥,我们只需要再定义一个余弦值来代表聚光灯方向向量和外圆锥向量(等于它的半径)的夹角
-
边缘平滑且圆锥内正常思路
如果一个片段处于内外圆锥之间,将会给它计算出一个0.0到1.0之间的强度值。
如果片段在内圆锥之内,它的强度就是1.0。
如果在外圆锥之外强度值就是0.0。
-
公式来计算边缘平滑且圆锥内正常
-
理解方式一
θ = dot(像素点指向光源,光源照射的方向取反)= cos(它们之间的夹角)
γ = cos(外圆角度)
ϵ(Epsilon) = cos(内圆角度) - cos(外圆角度)
-
结合下方图表理解
θ = cos(θ(角度) = dot(像素点指向光源,光源照射的方向取反)= cos(它们之间的夹角)
γ = cos(γ(角度))= γ(外光切)
ϵ(Epsilon) = ϕ(内光切)- γ(外光切)
θ θ(角度) ϕ(内光切) ϕ(角度) γ(外光切) γ(角度) ϵ I 0.87 30 0.91 25 0.82 35 0.91 - 0.82 = 0.09 0.87 - 0.82 / 0.09 = 0.56 0.9 26 0.91 25 0.82 35 0.91 - 0.82 = 0.09 0.9 - 0.82 / 0.09 = 0.89 0.97 14 0.91 25 0.82 35 0.91 - 0.82 = 0.09 0.97 - 0.82 / 0.09 = 1.67 0.83 34 0.91 25 0.82 35 0.91 - 0.82 = 0.09 0.83 - 0.82 / 0.09 = 0.11 0.64 50 0.91 25 0.82 35 0.91 - 0.82 = 0.09 0.64 - 0.82 / 0.09 = -2.0 0.966 15 0.9978 12.5 0.953 17.5 0.9978 - 0.953 = 0.0448 0.966 - 0.953 / 0.0448 = 0.29 -
个人发现图表有错(也许没错)
最后一行:cos值计算错了
cos(12.5)=0.976,而表中的0.9978是cos(12.5rad),把12.5当做弧度来计算cos值
-
-
转换为代码
glsl
#version 330 core out vec4 FragColor; struct Material {sampler2D diffuse; // 漫反射颜色分量从纹理采样sampler2D specular;// 镜面光照颜色分量从纹理采样float shininess; }; // 聚光灯 struct Light {vec3 position; // 需要位置vec3 direction;// 需要照射方向float cutOff; // ϕ(内光切)float outerCutOff;// γ(外光切)vec3 ambient;vec3 diffuse;vec3 specular;float constant; // 常数float linear; // 一次项float quadratic;// 二次项 }; in vec3 FragPos; in vec3 Normal; in vec2 TexCoords;// 纹理坐标uniform vec3 viewPos; uniform Material material; uniform Light light; void main() {// 光源的方向向量:像素点指向光源vec3 lightDir = normalize(light.position - FragPos);// 算出theta,dot(像素点指向光源,光源照射的方向取反)float theta = dot(lightDir, normalize(-light.direction));// float theta=dot(-lightDir, normalize(light.direction));// dot(光源指向像素点, 光源照射的方向)// 从漫反射纹理读取颜色分量vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords)); // 漫反射光照分量vec3 norm = normalize(Normal);// vec3 lightDir = normalize(light.position - FragPos); // 得到光源的方向float diff = max(dot(norm, lightDir), 0.0);vec3 diffuse = light.diffuse * diff * texture(material.diffuse, TexCoords).rgb;// 从漫反射纹理读取颜色分量// 镜面光照分量vec3 viewDir = normalize(viewPos - FragPos); // 是观察者方向,不是观察者看向的方向vec3 reflectDir = reflect(-lightDir, norm); // reflect要求第一个参数是光源指向像素点的向量float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);// 光源对当前片段的镜面光影响// 采样镜面光纹理颜色作为镜面光照颜色分量//vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords)); // 这句也行vec3 specular = light.specular * spec * texture(material.specular, TexCoords).rgb; // 计算衰减float distance = length(light.position - FragPos); // 得到光源到片段长度float attenuation = 1.0 / (light.constant + light.linear * distance // 根据公式+ light.quadratic * distance * distance);// 光照分量随距离衰减ambient *= attenuation;diffuse *= attenuation;specular *= attenuation;// 为了边缘平滑且圆锥内正常float epsilon = light.cutOff - light.outerCutOff;float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0);// 将不对环境光做出影响,让它总是能有一点光diffuse *= intensity;specular *= intensity;// 聚光灯受影响vec3 result = (ambient + diffuse + specular) ;FragColor = vec4(result, 1.0); }
lightingShader.use(); lightingShader.setVec3("viewPos", camera.Position); lightingShader.setVec3("light.position", camera.Position); lightingShader.setVec3("light.direction", camera.Front);// direction是光照射方向 lightingShader.setFloat("light.cutOff", glm::cos(glm::radians(12.5f))); //ϕ(内光切) lightingShader.setFloat("light.outerCutOff", glm::cos(glm::radians(17.5f)));// γ(外光切)
-
效果
相关文章:

LearnOpenGL-光照-5.投光物
本人刚学OpenGL不久且自学,文中定有代码、术语等错误,欢迎指正 我写的项目地址:https://github.com/liujianjie/LearnOpenGLProject 文章目录投光物平行光点光源聚光不平滑的例子平滑例子投光物 前面几节使用的光照都来自于空间中的一个点 即…...

【C语言】每日刷题 —— 牛客语法篇(1)
前言 大家好,今天带来一篇新的专栏c_牛客,不出意外的话每天更新十道题,难度也是从易到难,自己复习的同时也希望能帮助到大家,题目答案会根据我所学到的知识提供最优解。 🏡个人主页:悲伤的猪大…...

【深度学习】Subword Tokenization算法
在自然语言处理中,面临的首要问题是如何让模型认识我们的文本信息,词,是自然语言处理中基本单位,神经网络模型的训练和预测都需要借助词表来对句子进行表示。 1.构建词表的传统方法 在字词模型问世之前,做自然语言处理…...

五分钟了解支付、交易、清算、银行等专业名词的含义?
五分钟了解支付、交易、清算、银行等专业名词的含义?1. 支付类名词01 支付应用02 支付场景03 交易类型04 支付类型(按通道类型)05 支付类型(按业务双方类型)06 支付方式07 支付产品08 收银台类型09 支付通道10 通道类型…...
4个工具,让 ChatGPT 如虎添翼!
LightGBM中文文档 机器学习统计学,476页 机器学习圣经PRML中文版...
初识PO、VO、DAO、BO、DTO、POJO时
PO、VO、DAO、BO、DTO、POJO 区别分层领域模型规约DO(Data Object)DTO(Data Transfer Object)BO(Business Object)AO(ApplicationObject)VO(View Object)Query领域模型命名规约:一、PO :(persistant object ),持久对象二、VO :(value object) ࿰…...

[2.2.4]进程管理——FCFS、SJF、HRRN调度算法
文章目录第二章 进程管理FCFS、SJF、HRRN调度算法(一)先来先服务(FCFS, First Come First Serve)(二)短作业优先(SJF, Shortest Job First)对FCFS和SJF两种算法的思考(三…...
【代码随想录Day55】动态规划
583 两个字符串的删除操作 https://leetcode.cn/problems/delete-operation-for-two-strings/72 编辑距离https://leetcode.cn/problems/edit-distance/...
Java开发 - 消息队列前瞻
前言 学完了Redis,那你一定不能错过消息队列,要说他俩之间的关联?关联是有的,但也不见得很大,只是他们都是大数据领域常用的一种工具,一种用来提高程序运行效率的工具。常见于高并发,大数据&am…...

MySQL连接IDEA详细教程
使用IDEA的时候,需要连接Database,连接时遇到了一些小问题,下面记录一下操作流程以及遇到的问题的解决方法。 目录 MySQL连接IDEA详细教程 MySQL连接IDEA详细教程 打开idea,点击右侧的 Database 或者 选择 View --> Tool Wind…...

线程(操作系统408)
基本概念 我们说引入进程的目的是更好的使用多道程序并发执行,提高资源的利用率和系统吞吐量;而引入线程的目的则是减小程序在并发执行的时候所付出的时间开销,提高操作系统的并发性能。 线程可以理解成"轻量级进程",…...

功耗降低99%,Panamorph超清VR光学架构解析
近期,投影仪变形镜头厂商Panamorph获得新型VR显示技术专利(US11493773B2),该专利方案采用了紧凑的结构,结合了Pancake透镜和光波导显示模组,宣称比传统VR方案的功耗、发热减少99%以上,可显著提高…...

【数据结构】带你深入理解栈
一. 栈的基本概念💫栈是一种特殊的线性表。其只允许在固定的一端进行插入和删除元素的操作,进行数据的插入和删除的一端称作栈顶,另外一端称作栈底。栈不支持随机访问,栈的数据元素遵循后进先出的原则,即LIFOÿ…...

认识CSS之如何提高写前端代码的效率
🌟所属专栏:前端只因变凤凰之路🐔作者简介:rchjr——五带信管菜只因一枚😮前言:该系列将持续更新前端的相关学习笔记,欢迎和我一样的小白订阅,一起学习共同进步~👉文章简…...
Vue中watch和computed
首先这里进行声明,这个讲的是vue2的内容,在vue3发生了什么变动与此无关 这里是官网: https://v2.cn.vuejs.org/v2/guide/installation.html computed > 计算属性 watch > 侦听器(也叫监视器) 其区别如下&…...
华为鲲鹏+银河麒麟v10 安装 docker-ce
设备:硬件:仅有ARM处理器,无GPU和NPU,操作系统麒麟银河V10,Kunpeng-920 #######参考原链接######### 华为鲲鹏银河麒麟v10 安装 docker-ce 踩坑 - akiyaの博客 在 arm64(aarch64) 架构服务器上基于国产化操作系统安…...
Lambda,Stream,响应式编程从入门到放弃
Lambda表达式 Java8新引入的语法糖 Lambda表达式*(关于lambda表达式是否属于语法糖存在很多争议,有人说他并不是语法糖,这里我们不纠结于字面表述)*。Lambda表达式是一种用于取代匿名类,把函数行为表述为函数式编程风…...
C语言枚举使用技巧
什么是C语言枚举 C语言枚举是一种用户自定义数据类型,它允许程序员定义一个变量,并将其限制为一组预定义的常量。这些常量被称为“枚举值”,并且可以通过名称进行引用。 在C语言中,枚举值是整数类型,它们的值默认从0…...

保姆级使用PyTorch训练与评估自己的EfficientNetV2网络教程
文章目录前言0. 环境搭建&快速开始1. 数据集制作1.1 标签文件制作1.2 数据集划分1.3 数据集信息文件制作2. 修改参数文件3. 训练4. 评估5. 其他教程前言 项目地址:https://github.com/Fafa-DL/Awesome-Backbones 操作教程:https://www.bilibili.co…...

【9】基础语法篇 - VL9 使用子模块实现三输入数的大小比较
VL9 使用子模块实现三输入数的大小比较 【报错】官方平台得背锅 官方平台是真的会搞事情,总是出一些平台上的莫名其妙的错误。 当然如果官方平台是故意考察我们的细心程度,那就当我没有说!! 在这个程序里,仿真时一直在报错 错误:无法在“test”中绑定wire/reg/memory“t…...

工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...

vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...

Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...

使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...

Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...

解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用
在工业制造领域,无损检测(NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统,以非接触式光学麦克风技术为核心,打破传统检测瓶颈,为半导体、航空航天、汽车制造等行业提供了高灵敏…...