光照章节学习
颜色与自然光一样物体的颜色是因为反射了这种颜色的光我们也赋予物体一个颜色使用乘法使物体的颜色得以呈现glm::vec3 lightColor(0.0f, 1.0f, 0.0f);glm::vec3 toyColor(1.0f, 0.5f, 0.31f);glm::vec3 result lightColor * toyColor; // (0.0f, 0.5f, 0.0f);我们可以定义物体的颜色为物体从一个光源反射各个颜色分量的大小比如010就是只反射绿色的光创建一个光照场景1.顶点着色器创建箱子#version 330 corelayout (location 0) in vec3 aPos;uniform mat4 model;uniform mat4 view;uniform mat4 projection;void main(){gl_Position projection * view * model * vec4(aPos, 1.0);}2.绑定VBO设置灯的VAOunsigned int lightVAO;glGenVertexArrays(1, lightVAO);glBindVertexArray(lightVAO);// 只需要绑定VBO不用再次设置VBO的数据因为箱子的VBO数据中已经包含了正确的立方体顶点数据glBindBuffer(GL_ARRAY_BUFFER, VBO);// 设置灯立方体的顶点属性对我们的灯来说仅仅只有位置数据glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);3.创建片段着色器#version 330 coreout vec4 FragColor;uniform vec3 objectColor;uniform vec3 lightColor;void main(){//光和物体颜色相乘就是实际的颜色FragColor vec4(lightColor * objectColor, 1.0);}创建灯的着色器#version 330 coreout vec4 FragColor;void main(){FragColor vec4(1.0); // 将向量的四个分量全部设置为1.0}4.使用// 在此之前不要忘记首先 use 对应的着色器程序来设定uniformlightingShader.use();lightingShader.setVec3(“objectColor”, 1.0f, 0.5f, 0.31f);lightingShader.setVec3(“lightColor”, 1.0f, 1.0f, 1.0f);5.更改灯的位置glm::vec3 lightPos(1.2f, 1.0f, 2.0f);然后我们把灯位移到这里然后将它缩小一点让它不那么明显model glm::mat4();model glm::translate(model, lightPos);model glm::scale(model, glm::vec3(0.2f));6.绘制灯立方体lampShader.use();// 设置模型、视图和投影矩阵uniform…// 绘制灯立方体对象glBindVertexArray(lightVAO);glDrawArrays(GL_TRIANGLES, 0, 36);基础光照冯氏光照模型环境光照(Ambient Lighting)即使在黑暗的情况下世界上通常也仍然有一些光亮月亮、远处的光所以物体几乎永远不会是完全黑暗的。为了模拟这个我们会使用一个环境光照常量它永远会给物体一些颜色。漫反射光照(Diffuse Lighting)模拟光源对物体的方向性影响(Directional Impact)。它是冯氏光照模型中视觉上最显著的分量。物体的某一部分越是正对着光源它就会越亮。镜面光照(Specular Lighting)模拟有光泽物体上面出现的亮点。镜面光照的颜色相比于物体的颜色会更倾向于光的颜色。环境光照自然光可以反弹全局光照但算法太耗所以弄个简单的把环境光照添加到场景里非常简单。我们用光的颜色乘以一个很小的常量环境因子再乘以物体的颜色然后将最终结果作为片段的颜色void main(){float ambientStrength 0.1;vec3 ambient ambientStrength * lightColor;vec3 result ambient * objectColor; FragColor vec4(result, 1.0);}漫反射光照根据法向量计算光源夹角夹角越小光对颜色影响越大法向量1.我们能够使用一个小技巧使用叉乘对立方体所有的顶点计算法向量但是由于3D立方体不是一个复杂的形状所以我们可以简单地把法线数据手工添加到顶点数据中2.更新光照的顶点着色器#version 330 corelayout (location 0) in vec3 aPos;layout (location 1) in vec3 aNormal;…3.我们只想使用每个顶点的前三个float并且忽略后三个float所以我们只需要把步长参数改成float大小的6倍就行了。glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);glEnableVertexAttribArray(0);4.传递给片段着色器out vec3 Normal;void main(){gl_Position projection * view * model * vec4(aPos, 1.0);Normal aNormal;}5.片段着色器中拿两个向量计算角度vec3 norm normalize(Normal);vec3 lightDir normalize(lightPos - FragPos)6.对norm和lightDir向量进行点乘计算光源对当前片段实际的漫发射影响。结果值再乘以光的颜色得到漫反射分量。两个向量之间的角度越大漫反射分量就会越小float diff max(dot(norm, lightDir), 0.0);vec3 diffuse diff * lightColor;;最后一件事片段着色器都是在世界坐标下计算的我们法向量也要变换到世界空间坐标下对于法向量位移没有意义所以只需要旋转和缩放所以直接抛弃模型矩阵中的w分量或者设为0可以保证不位移其次如果模型矩阵执行了不等比缩放顶点的改变会导致法向量不再垂直于表面了。因此我们不能用这样的模型矩阵来变换法向量。下面的图展示了应用了不等比缩放的模型矩阵对法向量的影响修复这个行为的诀窍是使用一个为法向量专门定制的模型矩阵。这个矩阵称之为法线矩阵(Normal Matrix)在顶点着色器中我们可以使用inverse和transpose函数自己生成这个法线矩阵Normal mat3(transpose(inverse(model))) * aNormal;矩阵求逆是一项对于着色器开销很大的运算因为它必须在场景中的每一个顶点上进行所以应该尽可能地避免在着色器中进行求逆运算。以学习为目的的话这样做还好但是对于一个高效的应用来说你最好先在CPU上计算出法线矩阵再通过uniform把它传递给着色器就像模型矩阵一样。镜面光照通过根据法向量翻折入射光的方向来计算反射向量。然后我们计算反射向量与观察方向的角度差它们之间夹角越小镜面光的作用就越大所以多一个观察向量//传入观察向量uniform vec3 viewPos;lightingShader.setVec3(“viewPos”, camera.Position);//设置镜面反射强度float specularStrength 0.5;//计算反射vec3 viewDir normalize(viewPos - FragPos);vec3 reflectDir reflect(-lightDir, norm);//求反射和观察的夹角float spec pow(max(dot(viewDir, reflectDir), 0.0), 32);vec3 specular specularStrength * spec * lightColor;//剩下的最后一件事情是把它加到环境光分量和漫反射分量里再用结果乘以物体的颜色vec3 result (ambient diffuse specular) * objectColor;FragColor vec4(result, 1.0);材质在上一节中我们定义了一个物体和光的颜色并结合环境光与镜面强度分量来决定物体的视觉输出。当描述一个表面时我们可以分别为三个光照分量定义一个材质颜色(Material Color)环境光照(Ambient Lighting)、漫反射光照(Diffuse Lighting)和镜面光照(Specular Lighting)#version 330 corestruct Material {vec3 ambient;vec3 diffuse;vec3 specular;float shininess;};uniform Material material;ambient材质向量定义了在环境光照下这个表面反射的是什么颜色通常与表面的颜色相同。diffuse材质向量定义了在漫反射光照下表面的颜色。漫反射颜色和环境光照一样也被设置为我们期望的物体颜色。specular材质向量设置的是表面上镜面高光的颜色或者甚至可能反映一个特定表面的颜色。最后shininess影响镜面高光的散射/半径。我们在片段着色器中创建了一个材质结构体的uniform所以下面我们希望修改一下光照的计算来遵从新的材质属性。由于所有材质变量都储存在一个结构体中我们可以从uniform变量material中访问它们void main(){// 环境光vec3 ambient lightColor * material.ambient;// 漫反射 vec3 norm normalize(Normal); vec3 lightDir normalize(lightPos - FragPos); float diff max(dot(norm, lightDir), 0.0); vec3 diffuse lightColor * (diff * material.diffuse); // 镜面光 vec3 viewDir normalize(viewPos - FragPos); vec3 reflectDir reflect(-lightDir, norm); float spec pow(max(dot(viewDir, reflectDir), 0.0), material.shininess); vec3 specular lightColor * (spec * material.specular); vec3 result ambient diffuse specular; FragColor vec4(result, 1.0);}设置材质结构体的uniformlightingShader.setVec3(“material.ambient”, 1.0f, 0.5f, 0.31f);lightingShader.setVec3(“material.diffuse”, 1.0f, 0.5f, 0.31f);lightingShader.setVec3(“material.specular”, 0.5f, 0.5f, 0.5f);lightingShader.setFloat(“material.shininess”, 32.0f);我们可以用同样的方式影响光源的漫反射和镜面光强度。这和我们在上一节中所做的极为相似你可以认为我们已经创建了一些光照属性来影响各个光照分量。我们希望为光照属性创建类似材质结构体的东西struct Light {vec3 position;vec3 ambient; vec3 diffuse; vec3 specular;};uniform Light light;vec3 ambient light.ambient * material.ambient;vec3 diffuse light.diffuse * (diff * material.diffuse);vec3 specular light.specular * (spec * material.specular);lightingShader.setVec3(“light.ambient”, 0.2f, 0.2f, 0.2f);lightingShader.setVec3(“light.diffuse”, 0.5f, 0.5f, 0.5f); // 将光照调暗了一些以搭配场景lightingShader.setVec3(“light.specular”, 1.0f, 1.0f, 1.0f);光照贴图漫反射贴图在着色器中使用漫反射贴图的方法和纹理教程中是完全一样的。但这次我们会将纹理储存为Material结构体中的一个sampler2D。我们将之前定义的vec3漫反射颜色向量替换为漫反射贴图struct Material {sampler2D diffuse;vec3 specular;float shininess;};…in vec2 TexCoords;//通过纹理采样器拿到颜色值vec3 diffuse light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));//不要忘记将环境光的材质颜色设置为漫反射材质颜色同样的值。vec3 ambient light.ambient * vec3(texture(material.diffuse, TexCoords));镜面光贴图一张黑白贴图根据黑白获取反射颜色.采样镜面光贴图lightingShader.setInt(“material.specular”, 1);…glActiveTexture(GL_TEXTURE1);# 使用不同的纹理单元1单元glBindTexture(GL_TEXTURE_2D, specularMap);接下来更新片段着色器的材质属性让其接受一个sampler2D而不是vec3作为镜面光分量struct Material {sampler2D diffuse;sampler2D specular;float shininess;};最后采样镜面光贴图来获取片段所对应的镜面光强度vec3 ambient light.ambient * vec3(texture(material.diffuse, TexCoords));vec3 diffuse light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));vec3 specular light.specular * spec * vec3(texture(material.specular, TexCoords));FragColor vec4(ambient diffuse specular, 1.0);投光物平行光无限远的平行光struct Light {// vec3 position; // 使用定向光就不再需要了vec3 direction;vec3 ambient; vec3 diffuse; vec3 specular;};…void main(){vec3 lightDir normalize(-light.direction);…}点光源衰减Fatt1.0/KcKl∗dKq∗d2在这里d代表了片段距光源的距离。接下来为了计算衰减值我们定义3个可配置的项常数项Kc、一次项Kl和二次项Kq。常数项通常保持为1.0它的主要作用是保证分母永远不会比1小否则的话在某些距离上它反而会增加强度这肯定不是我们想要的效果。一次项会与距离值相乘以线性的方式减少强度。二次项会与距离的平方相乘让光源以二次递减的方式减少强度。二次项在距离比较小的时候影响会比一次项小很多但当距离值比较大的时候它就会比一次项更大了。距离 常数项 一次项 二次项7 1.0 0.7 1.813 1.0 0.35 0.4420 1.0 0.22 0.2032 1.0 0.14 0.0750 1.0 0.09 0.03265 1.0 0.07 0.017100 1.0 0.045 0.0075160 1.0 0.027 0.0028200 1.0 0.022 0.0019325 1.0 0.014 0.0007600 1.0 0.007 0.00023250 1.0 0.0014 0.000007实现衰减为了实现衰减在片段着色器中我们还需要三个额外的值也就是公式中的常数项、一次项和二次项。储存在光的结构体中struct Light {vec3 position;vec3 ambient; vec3 diffuse; vec3 specular; float constant; float linear; float quadratic;};我们仍需要公式中距光源的距离还记得我们是怎么计算一个向量的长度的吗我们可以通过获取片段和光源之间的向量差并获取结果向量的长度作为距离项。我们可以使用GLSL内建的length函数来完成这一点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;聚光LightDir从片段指向光源的向量。SpotDir聚光所指向的方向。Phiϕ指定了聚光半径的切光角。落在这个角度之外的物体都不会被这个聚光所照亮。ThetaθLightDir向量和SpotDir向量之间的夹角。在聚光内部的话θ值应该比ϕ值小。手电筒需要的值有聚光的位置向量来计算光的方向向量、聚光的方向向量和一个切光角struct Light {vec3 position;vec3 direction;float cutOff;…};接下来我们将合适的值传到着色器中lightingShader.setVec3(“light.position”, camera.Position);lightingShader.setVec3(“light.direction”, camera.Front);lightingShader.setFloat(“light.cutOff”, glm::cos(glm::radians(12.5f)));接下来就是计算θ值并将它和切光角ϕ对比来决定是否在聚光的内部float theta dot(lightDir, normalize(-light.direction));if(theta light.cutOff){// 执行光照计算}else // 否则使用环境光让场景在聚光之外时不至于完全黑暗color vec4(light.ambient * vec3(texture(material.diffuse, TexCoords)), 1.0);平滑/软化边缘内圆外圆通过余弦值的差做插值根据插值计算从内圆到外圆的聚光衰减…Iθ−γϵ这里ϵ(Epsilon)是内ϕ和外圆锥γ之间的余弦值差ϵϕ−γ。最终的I值就是在当前片段聚光的强度。很难去表现这个公式是怎么工作的所以我们用一些实例值来看看θ θ角度 ϕ内光切 ϕ角度 γ外光切 γ角度 ϵ I0.87 30 0.91 25 0.82 35 0.91 - 0.82 0.09 0.87 - 0.82 / 0.09 0.560.9 26 0.91 25 0.82 35 0.91 - 0.82 0.09 0.9 - 0.82 / 0.09 0.890.97 14 0.91 25 0.82 35 0.91 - 0.82 0.09 0.97 - 0.82 / 0.09 1.670.83 34 0.91 25 0.82 35 0.91 - 0.82 0.09 0.83 - 0.82 / 0.09 0.110.64 50 0.91 25 0.82 35 0.91 - 0.82 0.09 0.64 - 0.82 / 0.09 -2.00.966 15 0.9978 12.5 0.953 17.5 0.9978 - 0.953 0.0448 0.966 - 0.953 / 0.0448 0.29float theta dot(lightDir, normalize(-light.direction));float epsilon light.cutOff - light.outerCutOff;float intensity clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0);…// 将不对环境光做出影响让它总是能有一点光diffuse * intensity;specular * intensity;…多光源out vec4 FragColor;平行光点光源定向光全加进去void main(){// 定义一个输出颜色值vec3 output;// 将定向光的贡献加到输出中output someFunctionToCalculateDirectionalLight();// 对所有的点光源也做相同的事情for(int i 0; i nr_of_point_lights; i)output someFunctionToCalculatePointLight();// 也加上其它的光源比如聚光output someFunctionToCalculateSpotLight();FragColor vec4(output, 1.0);}平行光struct DirLight {vec3 direction;vec3 ambient; vec3 diffuse; vec3 specular;};uniform DirLight dirLight;接下来我们可以将dirLight传入一个有着以下原型的函数。vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir);和C/C一样如果我们想调用一个函数这里是在main函数中调用这个函数需要在调用者的行数之前被定义过。vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir){vec3 lightDir normalize(-light.direction);// 漫反射着色float diff max(dot(normal, lightDir), 0.0);// 镜面光着色vec3 reflectDir reflect(-lightDir, normal);float spec pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);// 合并结果vec3 ambient light.ambient * vec3(texture(material.diffuse, TexCoords));vec3 diffuse light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));vec3 specular light.specular * spec * vec3(texture(material.specular, TexCoords));return (ambient diffuse specular);}点光源struct PointLight {vec3 position;float constant; float linear; float quadratic; vec3 ambient; vec3 diffuse; vec3 specular;};#define NR_POINT_LIGHTS 4uniform PointLight pointLights[NR_POINT_LIGHTS];函数vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir){vec3 lightDir normalize(light.position - fragPos);// 漫反射着色float diff max(dot(normal, lightDir), 0.0);// 镜面光着色vec3 reflectDir reflect(-lightDir, normal);float spec pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);// 衰减float distance length(light.position - fragPos);float attenuation 1.0 / (light.constant light.linear * distance light.quadratic * (distance * distance));// 合并结果vec3 ambient light.ambient * vec3(texture(material.diffuse, TexCoords));vec3 diffuse light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));vec3 specular light.specular * spec * vec3(texture(material.specular, TexCoords));ambient * attenuation;diffuse * attenuation;specular * attenuation;return (ambient diffuse specular);}合并结果void main(){// 属性vec3 norm normalize(Normal);vec3 viewDir normalize(viewPos - FragPos);// 第一阶段定向光照 vec3 result CalcDirLight(dirLight, norm, viewDir); // 第二阶段点光源 for(int i 0; i NR_POINT_LIGHTS; i) result CalcPointLight(pointLights[i], norm, FragPos, viewDir); // 第三阶段聚光 //result CalcSpotLight(spotLight, norm, FragPos, viewDir); FragColor vec4(result, 1.0);}

相关新闻

React Native 源码分析(一)——启动流程

React Native 源码分析(一)——启动流程

本系列文章,是分析Android 的 React Native 的源码,主要包括以下文章,和以往的源码系列一样,分析主流程的代码,不会细致到每一行(但相比上一篇的Gradle源码分析,要细致很多),会涉及到java、C++、js等源码。 前三篇RN版本是0.64.0,后面是0.72.0 1、React Native 源码…

2026/8/2 19:07:06 阅读更多 →
JMeter+InfluxDB压测数据写入瓶颈:配置优化与全链路监控实战

JMeter+InfluxDB压测数据写入瓶颈:配置优化与全链路监控实战

1. 压测场景下的数据写入:一个被忽视的性能瓶颈 最近在复盘一个线上压测项目时,又遇到了一个典型的“压测后遗症”——JMeter的测试结果数据无法正常写入InfluxDB。这已经不是第一次了,每次排查都发现,问题根源往往不是工具本身&a…

2026/8/2 19:07:06 阅读更多 →
Unity2022安装DOTween报错?四种可靠解决方案与深度排查指南

Unity2022安装DOTween报错?四种可靠解决方案与深度排查指南

1. 项目概述:Unity2022与DOTween的“水土不服”如果你正在用Unity2022开发游戏,尤其是想给UI或者角色动作加点丝滑的动画效果,那么DOTween这个插件大概率是你的首选。它几乎是Unity社区里做补间动画的“瑞士军刀”,功能强大&#…

2026/8/2 19:07:06 阅读更多 →

最新新闻

Web自动化测试实战:从Selenium到Playwright的工程化实践

Web自动化测试实战:从Selenium到Playwright的工程化实践

1. 项目概述:为什么Web自动化测试是每个测试工程师的必修课?如果你是一名测试工程师,或者正在向这个方向发展,那么“Web自动化测试”这个词对你来说一定不陌生。它几乎出现在每一个测试岗位的招聘要求里,也是技术面试中…

2026/8/2 19:50:30 阅读更多 →
Go语言结合Selenium实现Web自动化测试的实战指南

Go语言结合Selenium实现Web自动化测试的实战指南

1. 项目概述:当Go遇上Selenium,一场自动化测试的深度对话 最近在帮团队面试Golang研发岗,特别是到了二面环节,发现很多候选人对Go语言在自动化测试,尤其是结合Selenium进行Web UI自动化方面的理解,还停留在…

2026/8/2 19:50:30 阅读更多 →
Unity AssetReference实战:根治包体膨胀,实现资源按需加载

Unity AssetReference实战:根治包体膨胀,实现资源按需加载

1. 项目概述:当包体成为压垮项目的最后一根稻草 在移动游戏和应用的开发中,资源管理是一个永恒的话题。我经历过不止一个项目,在临近上线时,美术和策划同学还在疯狂地往项目里塞高清贴图、4K视频和复杂的特效预制体,而…

2026/8/2 19:50:30 阅读更多 →
5分钟掌握全网歌词下载:163MusicLyrics终极歌词管理指南

5分钟掌握全网歌词下载:163MusicLyrics终极歌词管理指南

5分钟掌握全网歌词下载:163MusicLyrics终极歌词管理指南 【免费下载链接】163MusicLyrics 云音乐歌词获取处理工具【网易云、QQ音乐】 项目地址: https://gitcode.com/GitHub_Trending/16/163MusicLyrics 还在为找不到心爱歌曲的歌词而烦恼吗?你是…

2026/8/2 19:49:29 阅读更多 →
从黑盒到白盒:CSAPP学习路径与底层系统实践指南

从黑盒到白盒:CSAPP学习路径与底层系统实践指南

1. 从“黑盒”到“白盒”:我为什么选择啃下CSAPP在计算机领域摸爬滚打多年,我发现自己陷入了一个尴尬的境地:能用各种框架和库快速搭建应用,能解决大部分业务层的“疑难杂症”,但一旦问题深入到性能瓶颈、内存泄漏、并…

2026/8/2 19:49:29 阅读更多 →
终极指南:如何用Boss Show Time插件快速掌握招聘信息时效性

终极指南:如何用Boss Show Time插件快速掌握招聘信息时效性

终极指南:如何用Boss Show Time插件快速掌握招聘信息时效性 【免费下载链接】boss-show-time 展示boss直聘岗位的发布时间 项目地址: https://gitcode.com/GitHub_Trending/bo/boss-show-time 还在为错过最新发布的优质职位而烦恼吗?Boss Show Ti…

2026/8/2 19:49:29 阅读更多 →

日新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/2 0:00:38 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/2 0:00:38 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/2 0:00:38 阅读更多 →

周新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/2 0:00:38 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/2 0:00:38 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/2 0:00:38 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/2 6:34:16 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/2 2:47:48 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/2 0:23:22 阅读更多 →