WebGL系列教程六(纹理映射与立方体贴图)
目录
- 1 前言
- 2 思考题
- 3 纹理映射介绍
- 4 怎么映射?
- 5 开始绘制
- 5.1 声明顶点着色器和片元着色器
- 5.2 修改顶点的颜色为纹理坐标
- 5.3 指定顶点位置和纹理坐标的值
- 5.4 获取图片成功后进行绘制
- 5.5 效果
- 5.6 完整代码
- 6 总结
1 前言
上一讲我们讲了如何使用索引绘制彩色立方体,还留了一个思考题:怎么让立方体的每个面都保持一个颜色?这一讲我们就来解决这个问题,并引出纹理映射和立方体贴图。
2 思考题
怎么让立方体的每个面都保持一个颜色?那当然是让每个面的两个三角形都保持一个颜色就行了,那怎么让每个三角形都保持一个颜色呢?因为三角形的颜色是通过顶点的颜色插值出来的,自然是让三角形的每个顶点都保持一个颜色就可以了。
但是这样又产生了新问题,因为顶点是公用的,难道给每个顶点多个颜色吗?答:是的。
比如v0
这个顶点,它被三个面公用,分别是前面、上面、右面。那么也就意味着它会有三个颜色,因为我们要让立方体每个表面都是一个颜色。回顾一下上一讲我们是怎么给顶点颜色的:
//顶点和颜色
let verticesColors = new Float32Array([1.0, 1.0, 1.0, 1.0,1.0,1.0,//v0 近平面 右上 颜色-1.0, 1.0, 1.0, 1.0,0.0,1.0,//v1 近平面 左上 颜色-1.0,-1.0, 1.0, 1.0,0.0,1.0,//v2 近平面 左下 颜色1.0,-1.0, 1.0, 1.0,1.0,0.0,//v3 近平面 右下 颜色1.0,-1.0,-1.0, 1.0,0.0,1.0,//v4 远平面 右下 颜色-1.0,-1.0,-1.0, 1.0,1.0,1.0,//v5 远平面 左下 颜色-1.0, 1.0,-1.0, 0.0,0.0,1.0,//v6 远平面 左上 颜色1.0, 1.0,-1.0, 0.0,1.0,1.0 //v7 远平面 右上 颜色
]);
//顶点索引
let indices = new Uint8Array([0,1,2, 0,2,3,//近平面4,5,6, 4,6,7,//远平面1,2,5, 1,5,6,//左平面0,3,4, 0,4,7,//右平面3,4,2, 3,5,2,//下平面0,7,6, 0,1,6 //上平面
]);
现在一个顶点三个颜色,那岂不是说顶点不够用了?是的,所以每个顶点我们要写三次。也就是说,这次顶点不能公用了。我们对上述代码进行修改
const verticesColors = new Float32Array([// 前面-1.0, -1.0, 1.0, 1.0, 0.0,1.0,//v2 红色1.0, -1.0, 1.0, 1.0, 0.0,1.0,//v3 红色1.0, 1.0, 1.0, 1.0, 0.0,1.0,//v0 红色-1.0, 1.0, 1.0, 1.0, 0.0,1.0,//v1 红色// 后面-1.0, -1.0, -1.0, 0.0, 1.0, 0.0,//v5 绿色1.0, -1.0, -1.0, 0.0, 1.0, 0.0,//v4 绿色1.0, 1.0, -1.0, 0.0, 1.0, 0.0,//v7 绿色-1.0, 1.0, -1.0, 0.0, 1.0, 0.0,//v6 绿色// 上面-1.0, 1.0, 1.0, 0.0, 0.0,1.0,//v1 蓝色1.0, 1.0, 1.0, 0.0, 0.0,1.0,//v0 蓝色1.0, 1.0, -1.0, 0.0, 0.0,1.0,//v7 蓝色-1.0, 1.0, -1.0, 0.0, 0.0,1.0,//v6 蓝色// 下面-1.0, -1.0, 1.0, 0.0, 0.0,0.0,//v2 黑色1.0, -1.0, 1.0, 0.0, 0.0,0.0,//v3 黑色1.0, -1.0, -1.0, 0.0, 0.0,0.0,//v4 黑色-1.0, -1.0, -1.0, 0.0, 0.0,0.0,//v5 黑色// 左面-1.0, -1.0, -1.0, 0.0, 1.0,1.0,//v5 青色-1.0, -1.0, 1.0, 0.0, 1.0,1.0,//v2 青色-1.0, 1.0, 1.0, 0.0, 1.0,1.0,//v1 青色-1.0, 1.0, -1.0, 0.0, 1.0,1.0,//v6 青色// 右面1.0, -1.0, 1.0, 1.0, 1.0,1.0,//v3 白色1.0, -1.0, -1.0, 1.0, 1.0,1.0,//v4 白色1.0, 1.0, -1.0, 1.0, 1.0,1.0,//v7 白色1.0, 1.0, 1.0, 1.0, 1.0,1.0,//v0 白色
]);
//顶点索引
let indices = 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 // 右面
]);
看下效果,prefect!
3 纹理映射介绍
其实这个词语还是比较好理解。见名知意,大概意思就是把纹理映射到某个地方,纹理是什么?现在你可以简单的认为纹理就是一张图片。把一张二维的图片映射到一个三维物体的表面,就叫纹理映射。
4 怎么映射?
很简单,你只需要将立方体的的和图片的位置对应起来告诉WebGL就可以了。比如立方体的左上角对应图片的左上角,立方体右上角对应图片右上角,左下角、右下角类似。那么中间的怎么办?中间的WebGL
会自动帮我们去映射。纹理坐标我们用uv
来表示,相当于xy
。不论图片是什么尺寸的,图片的左下角uv始终是【0,0】,右上角始终是【1,1】,这一点也是WebGL
帮我们实现的。
5 开始绘制
5.1 声明顶点着色器和片元着色器
<script id="vertex-shader" type="x-shader/x-vertex">//顶点位置attribute vec4 a_Position;//纹理坐标attribute vec2 a_TexCoord;//传递纹理坐标varying vec2 v_TexCoord;void main(){gl_Position = a_Position;//直接将纹理坐标赋值给传递变量v_TexCoord = a_TexCoord;}
</script>
<script id="fragment-shader" type="x-shader/x-fragment">precision highp float;//采样器,固定写法uniform sampler2D u_Sampler;//接收顶点着色器传过来的值varying vec2 v_TexCoord;void main(){//到某个纹理坐标去采样,也是固定写法gl_FragColor = texture2D(u_Sampler,v_TexCoord);}
</script>
5.2 修改顶点的颜色为纹理坐标
前面我们给立方体的表面赋值的是颜色,现在我们把它变为纹理坐标
const verticesColors = new Float32Array([// 前面-1.0, -1.0, 1.0, 0.0, 0.0,//v2 图片左下角纹理坐标1.0, -1.0, 1.0, 1.0, 0.0,//v3 图片左下角纹理坐标1.0, 1.0, 1.0, 1.0, 1.0,//v0 图片右下角纹理坐标-1.0, 1.0, 1.0, 0.0, 1.0,//v1 图片左上角纹理坐标// 后面-1.0, -1.0, -1.0, 0.0, 0.0,//v5 同上1.0, -1.0, -1.0, 1.0, 0.0,//v4 同上1.0, 1.0, -1.0, 1.0, 1.0,//v7 同上-1.0, 1.0, -1.0, 0.0, 1.0,//v6 同上// 上面-1.0, 1.0, 1.0, 0.0, 0.0,//v1 同上1.0, 1.0, 1.0, 1.0, 0.0,//v0 同上1.0, 1.0, -1.0, 1.0, 1.0,//v7 同上-1.0, 1.0, -1.0, 0.0, 1.0,//v6 同上// 下面-1.0, -1.0, 1.0, 0.0, 0.0,//v2 同上1.0, -1.0, 1.0, 1.0, 0.0,//v3 同上1.0, -1.0,-1.0, 1.0, 1.0,//v4 同上-1.0, -1.0,-1.0, 0.0, 1.0,//v5 同上// 左面-1.0, -1.0, -1.0, 0.0, 0.0,//v5 同上-1.0, -1.0, 1.0, 1.0, 0.0,//v2 同上-1.0, 1.0, 1.0, 1.0, 1.0,//v1 同上-1.0, 1.0, -1.0, 0.0, 1.0,//v6 同上// 右面1.0, -1.0, 1.0, 0.0, 0.0,//v3 同上1.0, -1.0, -1.0, 1.0, 0.0,//v4 同上1.0, 1.0, -1.0, 1.0, 1.0,//v7 同上1.0, 1.0, 1.0, 0.0, 1.0,//v0 同上
]);const indices = 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 // 右面
]);
5.3 指定顶点位置和纹理坐标的值
//顶点let vertexColorBuffer = gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER,vertexColorBuffer);gl.bufferData(gl.ARRAY_BUFFER,verticesColors,gl.STATIC_DRAW);let FSIZE = verticesColors.BYTES_PER_ELEMENT;let a_Position = gl.getAttribLocation(program,'a_Position');gl.vertexAttribPointer(a_Position,3,gl.FLOAT,false,FSIZE*5,0);gl.enableVertexAttribArray(a_Position);//指定纹理坐标值let a_TexCoord = gl.getAttribLocation(program,'a_TexCoord');gl.vertexAttribPointer(a_TexCoord,2,gl.FLOAT,false,5*FSIZE,3*FSIZE);gl.enableVertexAttribArray(a_TexCoord);
5.4 获取图片成功后进行绘制
let image = new Image();
image.src = 'static/sky.jpg';
image.onload = function(){console.log('image ok');//创建纹理对象let texture = gl.createTexture();//获取采样器let u_Sampler = gl.getUniformLocation(program,'u_Sampler');//反转Y轴,canvas的Y轴和WebGL的Y轴方向是反的gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,1);//启用0号纹理gl.activeTexture(gl.TEXTURE0);gl.bindTexture(gl.TEXTURE_2D,texture);//设置纹理为,缩小纹理时,取纹理坐标周围四个像素的颜色均值gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR);//设置对象使用的图片,mipmap层级,图像的格式,纹理的格式,纹理数据类型,图片gl.texImage2D(gl.TEXTURE_2D,0,gl.RGB,gl.RGB,gl.UNSIGNED_BYTE,image);//将0号纹理赋值给采样器gl.uniform1i(u_Sampler,0);//绑定索引缓冲let indexBuffer = gl.createBuffer();gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,indexBuffer);gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,indices,gl.STATIC_DRAW);//清空颜色缓冲和深度缓冲gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);//绘制//顶点索引数组如果是Uint8Array,就是UNSIGNED_BYTE,表示数组里的值在0-2^8-1(255)//................Uint16Array,就是UNSIGNED_SHORT,表示数组里的值在0-2^16-1(65535)//................Uint32Array,就是UNSIGNED_INT,表示数组里的值在0-2^32-1(4294967295)gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_BYTE, 0);
};
5.5 效果
为了能看到明显的效果,我将立方体进行了旋转,具体如何旋转,我们后面的文章会进行介绍。
5.6 完整代码
// Create a cube
// v6----- v7
// /| /|
// v1------v0|
// | | | |
// | |v5---|-|v4
// |/ |/
// v2------v3
const verticesColors = new Float32Array([// 前面-1.0, -1.0, 1.0, 0.0, 0.0,//v2 图片左下角纹理坐标1.0, -1.0, 1.0, 1.0, 0.0,//v3 图片左下角纹理坐标1.0, 1.0, 1.0, 1.0, 1.0,//v0 图片右下角纹理坐标-1.0, 1.0, 1.0, 0.0, 1.0,//v1 图片左上角纹理坐标// 后面-1.0, -1.0, -1.0, 0.0, 0.0,//v5 同上1.0, -1.0, -1.0, 1.0, 0.0,//v4 同上1.0, 1.0, -1.0, 1.0, 1.0,//v7 同上-1.0, 1.0, -1.0, 0.0, 1.0,//v6 同上// 上面-1.0, 1.0, 1.0, 0.0, 0.0,//v1 同上1.0, 1.0, 1.0, 1.0, 0.0,//v0 同上1.0, 1.0, -1.0, 1.0, 1.0,//v7 同上-1.0, 1.0, -1.0, 0.0, 1.0,//v6 同上// 下面-1.0, -1.0, 1.0, 0.0, 0.0,//v2 同上1.0, -1.0, 1.0, 1.0, 0.0,//v3 同上1.0, -1.0,-1.0, 1.0, 1.0,//v4 同上-1.0, -1.0,-1.0, 0.0, 1.0,//v5 同上// 左面-1.0, -1.0, -1.0, 0.0, 0.0,//v5 同上-1.0, -1.0, 1.0, 1.0, 0.0,//v2 同上-1.0, 1.0, 1.0, 1.0, 1.0,//v1 同上-1.0, 1.0, -1.0, 0.0, 1.0,//v6 同上// 右面1.0, -1.0, 1.0, 0.0, 0.0,//v3 同上1.0, -1.0, -1.0, 1.0, 0.0,//v4 同上1.0, 1.0, -1.0, 1.0, 1.0,//v7 同上1.0, 1.0, 1.0, 0.0, 1.0,//v0 同上
]);const indices = 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 // 右面
]);
gl.viewport(0, 0, canvas.width, canvas.height);
gl.enable(gl.DEPTH_TEST);
//顶点
let vertexColorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,vertexColorBuffer);
gl.bufferData(gl.ARRAY_BUFFER,verticesColors,gl.STATIC_DRAW);
let FSIZE = verticesColors.BYTES_PER_ELEMENT;
let a_Position = gl.getAttribLocation(program,'a_Position');
gl.vertexAttribPointer(a_Position,3,gl.FLOAT,false,FSIZE*5,0);
gl.enableVertexAttribArray(a_Position);
//指定纹理坐标值
let a_TexCoord = gl.getAttribLocation(program,'a_TexCoord');
gl.vertexAttribPointer(a_TexCoord,2,gl.FLOAT,false,5*FSIZE,3*FSIZE);
gl.enableVertexAttribArray(a_TexCoord);
let image = new Image();
image.src = 'static/sky.jpg';
image.onload = function(){console.log('image ok');//创建纹理对象let texture = gl.createTexture();//获取采样器let u_Sampler = gl.getUniformLocation(program,'u_Sampler');//反转Y轴,canvas的Y轴和WebGL的Y轴方向是反的gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,1);//启用0号纹理gl.activeTexture(gl.TEXTURE0);gl.bindTexture(gl.TEXTURE_2D,texture);//设置纹理为,缩小纹理时,取纹理坐标周围四个像素的颜色均值gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR);//设置对象使用的图片,mipmap层级,图像的格式,纹理的格式,纹理数据类型,图片gl.texImage2D(gl.TEXTURE_2D,0,gl.RGB,gl.RGB,gl.UNSIGNED_BYTE,image);//将0号纹理赋值给采样器gl.uniform1i(u_Sampler,0);//绑定索引缓冲let indexBuffer = gl.createBuffer();gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,indexBuffer);gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,indices,gl.STATIC_DRAW);//清空颜色缓冲和深度缓冲gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);//绘制//顶点索引数组如果是Uint8Array,就是UNSIGNED_BYTE,表示数组里的值在0-2^8-1(255)//................Uint16Array,就是UNSIGNED_SHORT,表示数组里的值在0-2^16-1(65535)//................Uint32Array,就是UNSIGNED_INT,表示数组里的值在0-2^32-1(4294967295)gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_BYTE, 0);
};
6 总结
本节我们从如何将立方体每个面的颜色改为相同的颜色开始,介绍到了如何将图片贴到立方体的表面,系统的分析了为什么不能再共用顶点,并将代码进行了修改,以及讲解了纹理坐标的使用。这一节的内容相对较多,但理解起来并不难,希望读者认真体会,回见~
相关文章:

WebGL系列教程六(纹理映射与立方体贴图)
目录 1 前言2 思考题3 纹理映射介绍4 怎么映射?5 开始绘制5.1 声明顶点着色器和片元着色器5.2 修改顶点的颜色为纹理坐标5.3 指定顶点位置和纹理坐标的值5.4 获取图片成功后进行绘制5.5 效果5.6 完整代码 6 总结 1 前言 上一讲我们讲了如何使用索引绘制彩色立方体&a…...

为什么nii.gz转.nrrd标签体积变大?
import SimpleITK as sitk # nii nii.gz nrrd格式之间互相转换 def nii2nii(oripath, savepath):data sitk.ReadImage(oripath)img sitk.GetArrayFromImage(data)out sitk.GetImageFromArray(img)sitk.WriteImage(out, savepath)if __name__ __main__:oripath 00292625.ni…...

软件安装攻略:EmEditor编辑器下载安装与使用
EmEditor是一款在Windows平台上运行的文字编辑程序。EmEditor以运作轻巧、敏捷而又功能强大、丰富著称,得到许多用户的好评。Windows内建的记事本程式由于功能太过单薄,所以有不少用户直接以EmEditor取代,emeditor是一个跨平台的文本编辑器&a…...

Redis的watch机制详解
WATCH 是 Redis 提供的一个用于实现 乐观锁 (Optimistic Lock) 的命令,通常用于实现事务中的并发控制。它允许客户端监控一个或多个键的变化,并确保事务(MULTI/EXEC)中执行的操作在这些键没有发生改变的情况下才能成功提交。若在事…...

UnrealEngine 打包Android平台应用
虚幻引擎 支持将项目发布到 安卓(Android) 移动设备上,并且提供了若干功能帮你将项目发布到 谷歌游戏商店。本节包含了如何设置Android开发环境、如何使用Android功能和服务、以及如何为发布游戏做准备相关的指南。 当前SDK要求 当前UE版本…...

Linux:git
hello,各位小伙伴,本篇文章跟大家一起学习《Linux:git》,感谢大家对我上一篇的支持,如有什么问题,还请多多指教 ! 如果本篇文章对你有帮助,还请各位点点赞!!&…...

electron有关mac构建
针对 Mac M1/2/3 芯片的设备,proces.archarm64. 执行下面命令,检查下按照的 node.js 版本是不是 intel x64 指令集,如果是的话安装下 arm64 指令集的 node.js终端中执行以下命令:node -p process.arch 对应的node版本也是arm版 …...

C语言-数据结构 弗洛伊德算法(Floyd)邻接矩阵存储
弗洛伊德算法相比迪杰斯特拉相似的地方都是遍历邻接矩阵不断调整最短路径的信息,并且两种算法面对多源最短路径的时间复杂度都是O(n^3),Floyd采用的是动态规划而Dijkstra是采用贪心的思想。在Floyd中我们将创建两个数组进行辅助,一个path二维…...

pyspark 安装记录
1、安装软件 1、python 3.10 2、hadoop-3.3.4 里面的winutils 要记得添加 3、java-17 4、spark-3.5.1-bin-hadoop3 python 安装 pyspark,Jupyter notebook pip install pyspark pip install jupyter notebook 2、添加环境变量 JAVA_HOME=C:\PySparkService\java-17H…...

高度可定制的电竞鼠标,雷柏VT1 PRO MAX体验
不管是菜鸟还是老鸟,游戏玩到某个阶段很容易出现瓶颈,在游戏的某个阶段,这里面制约最大的除了操作之外,实际上还是我们用的硬件。比如在PC游戏中,鼠标的影响就非常大,像是在游戏中如果鼠标延迟过高…...

经验笔记:SOA(面向服务的架构)
SOA(面向服务的架构)经验笔记 引言 SOA(Service-Oriented Architecture, 面向服务的架构)是一种设计原则,用于构建灵活且可扩展的分布式系统。SOA强调将应用程序的不同功能封装为独立的服务,这些服务通过…...

triton之ttir学习
一 基本语句 1 常量 %cst arith.constant dense<520192> : tensor<4096xi32> %c127_i32 arith.constant 127 : i32 %cst arith.constant dense<520192> : tensor<4096xi32> 解释:这条语句定义了一个名为 %cst 的常量,它…...

如何在AWS账户上进行充值:一份详尽指南
大家好,小编今天给大家带来一份关于如何在AWS账户上进行充值的详尽指南。对于使用AWS服务的用户来说,保持账户余额充足是确保服务不中断的关键。下面,九河云将详细讲解具体的操作步骤。 步骤一:登录AWS管理控制台 首先ÿ…...

(六十四)第 10 章 内部排序(静态链表的插入排序)
示例代码 staticLinkList.h // 静态链表的插入排序实现头文件#ifndef STATIC_LINK_LIST_H #define STATIC_LINK_LIST_H#include "errorRecord.h"#define SIZE 100 #define NUM 8typedef int InfoType; typedef int KeyType;typedef struct {KeyType key;InfoType inf…...

appium历史版本地址链接
appium / Appium.app / Downloads — Bitbucket ios的appium界面图 链接: https://pan.baidu.com/s/1i8BRaZgQA3ImLUhKZjfhiA 提取码: 5c8b...

TCPIP网络编程(尹圣雨)UDP 轮流收发消息(windows)
端口号写的是 2345 客户端 #include <iostream> #include <winsock2.h> #pragma comment(lib, "ws2_32.lib")using std::cout; using std::endl; using std::cin;int main() {WSADATA wsa;if (WSAStartup(MAKEWORD(2, 2), &wsa) ! 0){cout <<…...

【相机方案(2)】V4L2 支持相机图像直接进入GPU内存吗?DeepStream 确实可以将图像数据高效地放入GPU内存进行处理!
V4L2 支持相机图像直接进入GPU内存吗? V4L2(Video4Linux Two)是Linux内核中用于视频捕获和播放的API,它本身并不直接支持将相机捕获的图像数据直接拷贝到GPU内存而不经过CPU内存。V4L2主要关注于视频设备的控制、数据的捕获和播放…...

UEFI——PEI阶段
一、PEI介绍 Pre-EFI Initialization(PEI)在引导的早期被调用,仅利用CPU资源调用PEIM,这些PEIM负责: (1)初始化一些永久内存 (2)在HOBs中描述内存信息 (3…...

Nacos下载和启动
Nacos是什么? 一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台 下载 https://github.com/alibaba/nacos/releases/tag/2.1.1启动 将下载好的Nacos解压缩,然后到bin目录下打开cmd 输入指令:startup.cmd -m standalone 出…...

怎么选择适合的服务器
大家都知道,不管是公司还是个人,在数字化浪潮已经席卷全球的环境下,大家对服务器的需求是日渐增长的。很多人在买服务器的时候,多少都有点选择困难,今天我们就来对比下物理服务器和弹性云服务器,看看选哪个…...

通义千问大模型Java调用,百炼
文章目录 一、大模型服务平台[百炼](https://help.aliyun.com/zh/model-studio/getting-started)二、Java sdk调用与eventStream三、百炼平台其它 一、大模型服务平台百炼 百炼是阿里新出的一个大模型服务平台,聚合了多个千问大模型及其它一些大模型的调用…...

新发现!一键管理所有远程会话的神器——1Remote
大家好,今天给大家介绍一款非常实用的工具——1Remote,这是一款现代化的个人远程会话管理器与启动器,让您的远程工作变得更加轻松高效! 项目介绍 🚀 核心功能概览 多协议支持:1Remote支持RDP、SSH、VNC、…...

华为 HCIP 认证费用和报名资格
在当今竞争激烈的信息技术领域,华为 HCIP认证备受关注。它不仅能提升个人的技术实力与职业竞争力,也为企业选拔优秀人才提供了重要依据。以下将详细介绍华为 HCIP 认证的费用和报名资格。 一、HCIP 认证费用 华为HCIP认证的费用主要由考试费和培训费构成…...

Linux下载压缩包:tar.gz、zip、tar.bz2格式全攻略
在 Linux 中,下载各种格式的压缩包(如 .tar.gz、.zip、.tar.bz2 等)通常使用命令行工具如 wget 和 curl。 1. 使用 wget 下载压缩包 wget 是 Linux 中最常用的文件下载工具,支持 HTTP、HTTPS、FTP 等协议,可以直接从…...

运行PaddleOCR报错:requests.exceptions.SSLError: HTTPSconnectionPool……
文章目录 问题描述解决方法 问题描述 在运行以下代码时报错: ocr PaddleOCR(lang"en")解决方法 打开cmd,输入以下命令,查找Python解释器所在路径。 找到 Lib\site-packages\paddleocr\ppocr\utils\network.py,将代码…...

基于STM32L431小熊派设计的智能花盆(微信小程序+腾讯云IOT)(223)
文章目录 一、前言1.1 项目介绍【1】项目背景【2】设计实现的功能【3】项目硬件模块组成1.2 设计思路【1】整体设计思路【2】ESP8266工作模式配置1.3 项目开发背景【1】选题的意义【2】可行性分析【3】参考文献1.4 开发工具的选择【1】设备端开发【2】上位机开发1.5 系统框架图…...

CentOS 入门必备基础知识
CentOS(Community ENTerprise Operating System)是一个基于Red Hat Enterprise Linux(RHEL)的免费开源操作系统,广泛用于服务器环境。它以其稳定性、安全性和社区支持而闻名,对于初学者来说掌握一些基础知识…...

快速排序
一:基本思想 任取待排序元素序列中的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右 子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元…...

钢琴灯有必要买很贵的吗?五款值得入手的护眼灯分享
钢琴灯有必要买很贵的吗?首先在这里先回答一下众多家长们提出问题,护眼灯钢琴灯并不是越贵越好!护眼灯钢琴灯这种比较大的电器虽然在生产中的用材用料存在一定的成本,但是并不是价格越贵的会越好,价格并不是决定产品质…...

C和指针:指针
内存和地址 程序视角看内存是一个大的字节数组,每个字节包含8个位,可以存储无符号值0至255,或有符号值-128至127。 多个字节可以合成一个字,许多机器以字为单位存储整数,每个字一般由2个或4个字节组成。 由于它们包含了更多的位&…...