webgl——给场景添加光
文章目录
- 前言
- 光照理论介绍
- 光照效果
- 光源类型
- 反射光颜色
- 向场景中添加光
- 向场景中添加环境光和点光源
- 逐片元光照——更加逼真
- 总结
前言
在之前的学习中已经将三维物体添加到了场景中,但是并没有在场景中使用光,照可以使模型更具有立体感,本文主要介绍 webgl 中的光照理论和计算方式,并展示如何在三维场景中添加光照。
光照理论介绍
光照效果
现实世界中的物体被光线照射时,会反射一部分光。只有当反射光线进入你的眼睛时,你才能够看到物体并辩认出它的颜色。比如,白色的盒子会反射白光,当白光进入你的眼睛时,你才能看到盒子是白色的。
当光线照射到物体上时,发生了两个重要的现象
- 根据光源和光线方向,物体不同表面的明暗程度变得不一致。
- 根据光源和光线方向,物体向地面投下了影子。
添加光源前:只有基本环境光

添加光源后

在片元着色(shading)时,不仅要根据片元着色器给像素上色,还要根据光照条件重建物体各表面明暗不一的效果 。物体向地面投下影子的现象,又被称为阴影(shadowing)。
光源类型

如图,光源主要有以下几种类型:
- 平行光(directional light),类似于自然中的太阳光;
平行光的光线是
相互平行的,平行光具有方向。平行光可以看作是无限远处的光源(比如太阳)发出的光。平行光很简单,只需要光照的方向和颜色来定义。
- 点光源光(point light),类似于人造灯泡的光。
点光源光是从一个
点向周围的所有方向发出的光。点光源光可以用来表示现实中的灯泡、火焰等。我们需要指定点光源的位置和颜色。光线的方向将根据点光源的位置和被照射之处的位置计算出来,因为点光源的光线的方向在场景内的不同位置是不同的。
- 环境光(ambient light),模拟真实世界中的非直射光(光源发出后经过墙壁或其他物体反射后的光)。致的“。比如说,在夜间打开冰箱的门,整个厨房都会有些微微亮,这就是环境光的作用。环境光不用指定位置和方向,只需要指定颜色即可。
环境光(间接光)是指那些经光源(点光源或平行光源)发出后,被墙壁等物体多次反射,然后照到物体表面上的光。环境光从各个角度照射物体,其
强度都是一致的。比如说。环境光不用指定位置和方向,只需要指定颜色即可。
反射光颜色
物体向哪个方向反射光,反射的光是什么颜色,取决于以下两个因素:入射光和物体表面的类型。入射光的信息包括入射光的方向和颜色,而物体表面的信息包括表面的固有颜色(也称基底色)和反射特性。
物体表面反射光线的方式有两种:环境反射 和 漫反射
- 环境反射
环境反射是针对环境光而言的。在环境反射中,反射光的方向可以认为就是入射光的反方向。由于环境光照射物体的方式就是各方向均匀、强度相等的,所以反射光也是各向均匀的。
<环境反射光颜色> = <入射光颜色> × <表面基底色>

- 漫反射
漫反射是针对平行光或点光源而言的。漫反射的反射光在各个方向上是均匀(强度相等)的,现实中的大部分材质表面都是粗糙的,在这种情况下反射光就会以不固定的角度反射出去。漫反射就是针对这种情况而建立的理想反射模型。
在漫反射中,反射光的颜色取决于1 入射光的颜色、2 表面的基底色、3 入射光与表面形成的入射角。入射角 θ 的定义为入射光与表面的法线形成的夹角
<漫反射光颜色> = <入射光颜色> × <表面基底色> × cos θ
= <入射光颜色> × <表面基底色> × ( <光线方向> * <法线方向>)
使用上面公式计算时,有两点需要特别注意:
1 <光线方向> 与 <法线方向> 两个矢量必须是经过归一化矢量的,即长度必须为1。
2 光线方向是入射方向的反方向,如下图。

- 漫反射 + 环境反射
在大多数情况下,漫反射和环境反射同时存在,二者相加就是物体映入人眼的真实颜色
<物体反射光颜色> = <漫反射光颜色> + <环境光反射颜色>
向场景中添加光
接前一文章:webgl三维绘制——彩色立方体,将物体的颜色改为纯色。
const vertex = `attribute vec4 aPosition;uniform mat4 uPerspectiveMatrix;uniform mat4 uViewMatrix;attribute vec4 aColor;varying vec4 (1.0,0.0,0.0,1.0);void main() {gl_Position = uPerspectiveMatrix * uViewMatrix * aPosition ;// v_Color = aPosition;}`const fragment = `precision highp float;// varying vec4 v_Color;void main(){gl_FragColor = v_Color;}`

向场景中添加环境光和点光源
为了实现添加光源后的效果,我们需要:
- 定义立方体每个面的法方向
- 在顶点着色器中添加点光源和环境光源,并按照之前的公式计算出点光源颜色和环境光源颜色
- 物体的真实颜色 = 点光源颜色 + 环境光颜色
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>webgl</title><script src="./lib.js"></script><meta name="viewport" content="width=device-width, initial-scale=1.0" /><style>body {margin: 0;padding: 0;}canvas {margin: 50px 30px;width: 500px;height: 500px;}</style>
</head><body><canvas id="canvas"></canvas><script>/** @type {HTMLCanvasElement} *///------------------------------------------------------创建画布// 获取canvas元素对象let canvas = document.getElementById('canvas');let ctx = document.getElementById('canvas')// 获取webgl绘图上下文const gl = canvas.getContext('webgl');if (!gl) {throw new Error('WebGL not supported');}canvas.width = 500;canvas.height = 500;gl.viewport(0, 0, canvas.width, canvas.height)// 设置背景色gl.clearColor(0.0, 0.0, 0.0, 1.0)gl.enable(gl.DEPTH_TEST);// 清空缓冲区gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)const vertex = `attribute vec4 aPosition; // attribute vec4 aNormal; // 法方向uniform mat4 uViewMatrix; // 视图矩阵uniform mat4 uPerspectiveMatrix; // 投影矩阵varying vec4 v_Color;void main() {vec4 cubeColor = vec4(1.0,0.0,0.0,1.0); // 物体颜色vec3 lightColor = vec3(1.0, 1.0, 1.0); // 点光源颜色vec3 lightPosition = vec3(5.0, 10.0, 10.0); // 点光源位置vec3 ambientColor = vec3(0.1, 0.1, 0.1); // 环境光颜色vec4 worldPosition = uPerspectiveMatrix * uViewMatrix * aPosition ; // 世界坐标vec3 lightDirection = normalize(lightPosition - vec3(worldPosition)) ; // 点光源光束方向vec3 ambientColors = ambientColor * vec3(cubeColor) ;// 环境光颜色float deg = dot(lightDirection, vec3(aNormal));vec3 diffColor = lightColor * vec3(cubeColor) * deg; // 漫反射光颜色gl_Position = uPerspectiveMatrix * uViewMatrix * aPosition ;v_Color = vec4(ambientColors + diffColor, 1.0); // 最终颜色//v_Color = vec4(1.0,0.0,0.0,1.0); // 最终颜色}`const fragment = `precision highp float;varying vec4 v_Color;void main(){gl_FragColor = v_Color;}`// 创建programconst program = initShader(gl, vertex, fragment)// 获取attribute变量的数据存储位置const aPosition = gl.getAttribLocation(program, 'aPosition');const aColor = gl.getAttribLocation(program, 'aColor');const aNormal = gl.getAttribLocation(program, 'aNormal');// 获取uniform变量的数据存储位置const uPerspectiveMatrix = gl.getUniformLocation(program, 'uPerspectiveMatrix');const uViewMatrix = gl.getUniformLocation(program, 'uViewMatrix');// 创建顶点缓冲区对象const vertices = new Float32Array([1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, // 前面1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, // 右面1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, // 上面-1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, // 左面-1, -1, 1, 1, -1, 1, 1, -1, -1, -1, -1, -1, // 下面1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1 // 后面])const buffer = gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER, buffer);const BYTES = vertices.BYTES_PER_ELEMENT;gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW)gl.vertexAttribPointer(aPosition, 3, gl.FLOAT, false, 0, 0)gl.enableVertexAttribArray(aPosition)// 创建索引缓冲区对象const index = new Uint8Array([0, 1, 2, 0, 2, 3, // 前4, 5, 6, 4, 6, 7, // 右8, 9, 10, 8, 10, 11, // 上12, 13, 14, 12, 14, 15,// 左16, 17, 18, 16, 18, 19,// 下20, 21, 22, 20, 22, 23,// 后]);const indexBuffer = gl.createBuffer();gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, index, gl.STATIC_DRAW)// 向量const normals = new Float32Array([0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, // 前1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, // 右0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, // 上-1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, // 左0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, // 下0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0 // 后]);const normalBuffer = gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);const BYTES_NORMAL = normals.BYTES_PER_ELEMENT;gl.bufferData(gl.ARRAY_BUFFER, normals, gl.STATIC_DRAW)gl.vertexAttribPointer(aNormal, 3, gl.FLOAT, false, 0, 0)gl.enableVertexAttribArray(aNormal)const viewMatrix = createViewMatrix(new Float32Array([5.0, 5.0, 5.0]), // 视点位置new Float32Array([0.0, 0.0, 0.0]), // 目标点位置new Float32Array([0.0, 1.0, 0.0]), // 上方向)const perspectiveMatrix = createPerspective(30, ctx.width / ctx.height, 1, 100)gl.uniformMatrix4fv(uPerspectiveMatrix, false, perspectiveMatrix,)gl.uniformMatrix4fv(uViewMatrix, false, viewMatrix,)// 开始绘制gl.drawElements(gl.TRIANGLES, index.length, gl.UNSIGNED_BYTE, 0)</script>
</body></html>

逐片元光照——更加逼真
在片元着色器逐片元地进行计算光照产生的颜色,将会产生更加逼真的光照效果。
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>webgl</title><script src="./lib.js"></script><meta name="viewport" content="width=device-width, initial-scale=1.0" /><style>body {margin: 0;padding: 0;}canvas {margin: 50px 30px;width: 500px;height: 500px;}</style>
</head><body><canvas id="canvas"></canvas><script>/** @type {HTMLCanvasElement} *///------------------------------------------------------创建画布// 获取canvas元素对象let canvas = document.getElementById('canvas');let ctx = document.getElementById('canvas')// 获取webgl绘图上下文const gl = canvas.getContext('webgl');if (!gl) {throw new Error('WebGL not supported');}canvas.width = 500;canvas.height = 500;gl.viewport(0, 0, canvas.width, canvas.height)// 设置背景色gl.clearColor(0.0, 0.0, 0.0, 1.0)gl.enable(gl.DEPTH_TEST);// 清空缓冲区gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)const vertex = `attribute vec4 aPosition; // attribute vec4 aNormal; // 法方向uniform mat4 uViewMatrix; // 视图矩阵uniform mat4 uPerspectiveMatrix; // 投影矩阵varying vec4 v_CubeColor; // 物体颜色varying vec4 v_WorldPosition; // 世界坐标varying vec4 v_Normal; // 法方向void main() {v_Normal = aNormal;v_CubeColor = vec4(1.0,0.0,0.0,1.0); // 物体颜色v_WorldPosition = uPerspectiveMatrix * uViewMatrix * aPosition ; // 世界坐标gl_Position = uPerspectiveMatrix * uViewMatrix * aPosition ;}`const fragment = `precision highp float;varying vec4 v_CubeColor; // 物体颜色varying vec4 v_WorldPosition; // 世界坐标varying vec4 v_Normal; // 法方向void main(){vec3 lightColor = vec3(1.0, 1.0, 1.0); // 点光源颜色vec3 lightPosition = vec3(5.0, 10.0, 10.0); // 点光源位置vec3 ambientColor = vec3(0.1, 0.1, 0.1); // 环境光颜色vec3 lightDirection = normalize(lightPosition - vec3(v_WorldPosition)) ; // 点光源光束方向vec3 ambientColors = ambientColor * vec3(v_CubeColor) ;// 环境光颜色float deg = dot(lightDirection, vec3(v_Normal)); vec3 diffColor = lightColor * vec3(v_CubeColor) * deg; // 漫反射光颜色gl_FragColor = vec4(ambientColors + diffColor, 1.0); // 最终颜色;}`// 创建programconst program = initShader(gl, vertex, fragment)// 获取attribute变量的数据存储位置const aPosition = gl.getAttribLocation(program, 'aPosition');const aColor = gl.getAttribLocation(program, 'aColor');const aNormal = gl.getAttribLocation(program, 'aNormal');// 获取uniform变量的数据存储位置const uPerspectiveMatrix = gl.getUniformLocation(program, 'uPerspectiveMatrix');const uViewMatrix = gl.getUniformLocation(program, 'uViewMatrix');// 创建顶点缓冲区对象const vertices = new Float32Array([1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1, // 前面1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, // 右面1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1, // 上面-1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1, // 左面-1, -1, 1, 1, -1, 1, 1, -1, -1, -1, -1, -1, // 下面1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1 // 后面])const buffer = gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER, buffer);const BYTES = vertices.BYTES_PER_ELEMENT;gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW)gl.vertexAttribPointer(aPosition, 3, gl.FLOAT, false, 0, 0)gl.enableVertexAttribArray(aPosition)// 创建索引缓冲区对象const index = new Uint8Array([0, 1, 2, 0, 2, 3, // 前4, 5, 6, 4, 6, 7, // 右8, 9, 10, 8, 10, 11, // 上12, 13, 14, 12, 14, 15,// 左16, 17, 18, 16, 18, 19,// 下20, 21, 22, 20, 22, 23,// 后]);const indexBuffer = gl.createBuffer();gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, index, gl.STATIC_DRAW)// 向量const normals = new Float32Array([0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, // 前1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, // 右0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, // 上-1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, // 左0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, // 下0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0 // 后]);const normalBuffer = gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);const BYTES_NORMAL = normals.BYTES_PER_ELEMENT;gl.bufferData(gl.ARRAY_BUFFER, normals, gl.STATIC_DRAW)gl.vertexAttribPointer(aNormal, 3, gl.FLOAT, false, 0, 0)gl.enableVertexAttribArray(aNormal)const viewMatrix = createViewMatrix(new Float32Array([5.0, 5.0, 5.0]), // 视点位置new Float32Array([0.0, 0.0, 0.0]), // 目标点位置new Float32Array([0.0, 1.0, 0.0]), // 上方向)const perspectiveMatrix = createPerspective(30, ctx.width / ctx.height, 1, 100)gl.uniformMatrix4fv(uPerspectiveMatrix, false, perspectiveMatrix,)gl.uniformMatrix4fv(uViewMatrix, false, viewMatrix,)// 开始绘制gl.drawElements(gl.TRIANGLES, index.length, gl.UNSIGNED_BYTE, 0)</script>
</body></html>

总结
光照理论介绍
- 光照效果
- 光源类型
- 反射光颜色
向场景中添加光
- 向场景中添加环境光和点光源
- 逐片元光照——更加逼真
相关文章:
webgl——给场景添加光
文章目录前言光照理论介绍光照效果光源类型反射光颜色向场景中添加光向场景中添加环境光和点光源逐片元光照——更加逼真总结前言 在之前的学习中已经将三维物体添加到了场景中,但是并没有在场景中使用光,照可以使模型更具有立体感,本文主要…...
Vue实战【Vue项目开发时常见的几个错误】
目录🌟前言🌟安装超时(install timeout)🌟can’t not find ‘xxModule’ - 找不到某些依赖或者模块🌟data functions should return an object🌟给组件内的原生控件添加事件,不生效了🌟我在函数内用了this.…...
【多线程】常见的锁策略
✨个人主页:bit me👇 ✨当前专栏:Java EE初阶👇 ✨每日一语:老当益壮,宁移白首之心;穷且益坚,不坠青云之志。 目 录🏳️一. 乐观锁 vs 悲观锁🏴二. 普通的互斥…...
如何让虚拟机里的Ubuntu通过连接手机USB数据线上网
目录 一 前言 二 Windows联网方法 三 Ubuntu联网方法 一 前言 最近遇到了这样一个问题,有一台台式机,地插网口无法访问外网,周边也没有无线路由器,要访问外网,该如何做?进一步的,这台台式机…...
windows渗透(sam、system文件导出)
通过本地PC中渗透测试平台Kali对服务器场景Windows进行系统服务及版本扫描渗透测试,并将该操作显示结果中Telnet服务对应的端口号作为FLAG提交;通过本地PC中渗透测试平台Kali对服务器场景Windows进行系统服...
b01lers(php.galf)
目录 前文 正文 前文 <?phpclass A{public $codeNULL;public $argsNULL;public function __construct($code,$argsNULL){$this->code$code;$this->args$args;print_r("2333") ;} public function __invoke($code,$args){echo $code;print_r("执行inv…...
记一次若依后台管理系统渗透
前言 最近客户开始hw前的风险排查,让我们帮他做个渗透测试,只给一个单位名称。通过前期的信息收集,发现了这个站点: 没有验证码,再加上这个图标,吸引了我注意: 从弱口令开始 若依默认口令为ad…...
Mybatis(四):自定义映射resultMap
自定义映射resultMap前言一、处理字段和属性的映射关系问题:方案一:使用别名方案二:在mybatis-config.xml中设置mapUnderscoreToCamelCase方案三:在映射文件中设置redultMap二、多对一映射处理问题:方案一:…...
机器学习---降维算法
知其然知其所以然【写在前面】主成分分析(PCA)原理部分代码部分可视化部分线性判别分析(LDA)原理部分代码部分可视化部分独立成分分析(ICA)原理部分代码部分可视化部分t-SNE降维算法原理部分代码部分可视化…...
【Vue2从入门到精通】详解Vue.js的15种常用指令及其使用场景
文章目录前言1. v-text / {{ expression }}2.v-html3.v-bind4.v-on5. v-model6.v-for7.v-if / v-else-if / v-else9.v-show10.v-cloak11.v-pre12.组件注册指令13.动态组件指令14.自定义指令15.过滤器指令前言 Vue.js 是一款流行的前端框架,它通过指令(Di…...
数据库知识总结
数据库知识点总结个人向。 目录第一章 绪论第二章 关系数据库第三章 关系数据库标准语言SQL第四章 数据库安全性第五章 数据库完整性第六章 关系数据理论第七章 数据库设计第十章 数据库恢复技术第十一章 并发控制第一章 绪论 数据(data): 描述事物的符号记录。 数据库(DataB…...
处理数组循环中删除元素导致索引错位情况
就是很多时候我们对一个数组进行操作的时候,在for遍历的过程中删掉了一个元素,那么在删掉那个元素之后的所有元素的索引值都会减少一位,数组长度缩短一位,删完之后,正在进行的循环会继续循环下去,但是循环的…...
快速排序,分治法实际应用(含码源与解析)
🎊【数据结构与算法】专题正在持续更新中,各种数据结构的创建原理与运用✨,经典算法的解析✨都在这儿,欢迎大家前往订阅本专题,获取更多详细信息哦🎏🎏🎏 🪔本系列专栏 -…...
linux入门---操作体统的概念
什么是操作系统 操作系统是一个对软硬件资源进行管理的软件。计算机由一堆硬件组成,这些硬件遵循着冯诺依曼体系结构 在这个硬件的基础上还有一个软件叫做操作系统 操作系统的任务是对硬件进行管理,既然是管理的话操作系统得访问到底层的硬件…...
《Qt 6 C++开发指南》提供4个版本的示例程序
《Qt 6 C开发指南》包含丰富的示例项目,为了方便读者使用《Qt 6 C开发指南》学习Qt编程,本书提供了4个版本的示例程序。读者可在人民邮电出版社异步社区本书的配套资源(如图1)里下载这4个版本的示例程序。图1 异步社区本书配套资源…...
chartgpt 告诉我的,loss 函数的各种知识
一、libtorch中常见的损失函数及其使用场景的总结1. CrossEntropyLoss:CrossEntropyLoss(交叉熵损失)主要用于分类任务。它适用于多分类问题,其中每个样本只属于一个类别(互斥)。该损失函数将预测概率与真实标签的one-…...
旅行推销员问题的遗传算法中的完整子路线顺序交叉
摘要 旅行商问题(TSP)是许多著名的组合问题之一。TSP可以解释为很难找到从第一个城市出发,经过所有城市,然后返回起点的最短距离。在标准问题中,TSP通常用于确定新算法的效率。遗传算法是求解TSP问题的一种成功算法。…...
Python实现词频统计
词频统计是自然语言处理的基本任务,针对一段句子、一篇文章或一组文章,统计文章中每个单词出现的次数,在此基础上发现文章的主题词、热词。 1. 单句的词频统计 思路:首先定义一个空字典my_dict,然后遍历文章…...
微信小程序面试题(day08)
文章目录微信小程序自定义组件的使用?微信小程序事件通道的使用?微信小程序如何使用vant组件库?微信小程序自定义组件父传子子传父?微信小程序自定义组件生命周期有哪些?微信小程序授权登录流程?web-view。…...
最强的Python可视化神器,你有用过么?
数据分析离不开数据可视化,我们最常用的就是Pandas,Matplotlib,Pyecharts当然还有Tableau,看到一篇文章介绍Plotly制图后我也跃跃欲试,查看了相关资料开始尝试用它制图。 1、Plotly Plotly是一款用来做数据分析和可视…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
html-<abbr> 缩写或首字母缩略词
定义与作用 <abbr> 标签用于表示缩写或首字母缩略词,它可以帮助用户更好地理解缩写的含义,尤其是对于那些不熟悉该缩写的用户。 title 属性的内容提供了缩写的详细说明。当用户将鼠标悬停在缩写上时,会显示一个提示框。 示例&#x…...
用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...
毫米波雷达基础理论(3D+4D)
3D、4D毫米波雷达基础知识及厂商选型 PreView : https://mp.weixin.qq.com/s/bQkju4r6med7I3TBGJI_bQ 1. FMCW毫米波雷达基础知识 主要参考博文: 一文入门汽车毫米波雷达基本原理 :https://mp.weixin.qq.com/s/_EN7A5lKcz2Eh8dLnjE19w 毫米波雷达基础…...
离线语音识别方案分析
随着人工智能技术的不断发展,语音识别技术也得到了广泛的应用,从智能家居到车载系统,语音识别正在改变我们与设备的交互方式。尤其是离线语音识别,由于其在没有网络连接的情况下仍然能提供稳定、准确的语音处理能力,广…...
Java详解LeetCode 热题 100(26):LeetCode 142. 环形链表 II(Linked List Cycle II)详解
文章目录 1. 题目描述1.1 链表节点定义 2. 理解题目2.1 问题可视化2.2 核心挑战 3. 解法一:HashSet 标记访问法3.1 算法思路3.2 Java代码实现3.3 详细执行过程演示3.4 执行结果示例3.5 复杂度分析3.6 优缺点分析 4. 解法二:Floyd 快慢指针法(…...
