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 总结

  本节我们从如何将立方体每个面的颜色改为相同的颜色开始,介绍到了如何将图片贴到立方体的表面,系统的分析了为什么不能再共用顶点,并将代码进行了修改,以及讲解了纹理坐标的使用。这一节的内容相对较多,但理解起来并不难,希望读者认真体会,回见~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/879019.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

TDengine 首席架构师肖波演讲整理:探索新型电力系统的五大关键场景与挑战

在 7 月 26 日的 TDengine 用户大会上&#xff0c;涛思数据&#xff08;TDengine&#xff09;首席架构师肖波进行了题为《TDengine 助力新型电力系统高质量发展》的主题演讲。他不仅分享了 TDengine 在新型电力系统中的应用案例&#xff0c;还深入探讨了如何利用 TDengine 的高…

构建响应式API:FastAPI Webhooks如何改变你的应用程序

FastAPI&#xff0c;作为一个现代、快速&#xff08;高性能&#xff09;的Web框架&#xff0c;为Python开发者提供了构建API的卓越工具。特别是&#xff0c;它的app.webhooks.post装饰器为处理实时Webhooks提供了一种简洁而强大的方法。在本文中&#xff0c;我们将探讨如何使用…

后端开发刷题 | 打家劫舍

描述 你是一个经验丰富的小偷&#xff0c;准备偷沿街的一排房间&#xff0c;每个房间都存有一定的现金&#xff0c;为了防止被发现&#xff0c;你不能偷相邻的两家&#xff0c;即&#xff0c;如果偷了第一家&#xff0c;就不能再偷第二家&#xff1b;如果偷了第二家&#xff0…

new/delete和malloc/free到底有什么区别

new和malloc 文章目录 new和malloc前言一、属性上的区别二、使用上的区别三、内存位置的区别四、返回类型的区别五、分配失败的区别六、扩张内存的区别七、系统调度过程的区别总结 前言 new和malloc的知识点&#xff0c;作为一个嵌入式工程师是必须要了解清楚的。new和malloc的…

优惠充值话费api对接如何选择对接平台?

优惠充值话费接口通常由电信运营商、第三方支付平台或专业的充值服务提供商提供。这些平台通过API接口允许开发者将话费充值功能集成到应用程序或网站中。 选择哪个平台比较好&#xff0c;取决于以下几个因素&#xff1a; 覆盖范围&#xff1a;选择能够覆盖你需要服务的地区和…

[Unity Demo]从零开始制作空洞骑士Hollow Knight第二集:通过InControl插件实现绑定玩家输入以及制作小骑士移动空闲动画

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、通过InControl插件实现绑定玩家输入二、制作小骑士移动和空闲动画 1.制作动画2.玩家移动和翻转图像3.状态机思想实现动画切换总结 前言 好久没来CSDN看看&…

【图像匹配】基于SURF算法的图像匹配,matlab实现

博主简介&#xff1a;matlab图像代码项目合作&#xff08;扣扣&#xff1a;3249726188&#xff09; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 本次案例是基于基于SURF算法的图像匹配&#xff0c;用matlab实现。 一、案例背景和算法介绍 前…

办了房屋抵押经营贷,空壳公司不怕被查吗?续贷不上怎么办?

很多有房的朋友&#xff0c;想必都办理过抵押经营贷款。但是&#xff0c;当办完房屋抵押经营贷款之后&#xff0c;钱到手了&#xff0c;别光顾着乐呵&#xff0c;贷后管理可是门大学问&#xff0c;稍有不慎&#xff0c;麻烦就找上门了。咱得确保资金用得对路&#xff0c;征信亮…

零宽字符应用场景及前端解决方案

零宽字符&#xff08;Zero Width Characters&#xff09;是一类在文本中不可见但具有特定功能的特殊字符。称为零宽字符&#xff0c;也叫幽灵字符。它们在显示时不占据任何空间&#xff0c;但在文本处理和显示中发挥着重要作用。这些字符主要包括零宽度空格、零宽度非连接符、零…

2024 VMpro 虚拟机中如何给Ubuntu Linux操作系统配置联网

现在这是一个联网的状态 可以在商店里面下载东西 也能ping成功 打开虚拟网络编辑器 放管理员权限 进行设置的更改 选择DNS设置 按提示修改即可 注意的是首选的DNS服务器必须是114.114.114.114 原因 这边刚刚去查了一下 114.114.114.114 是国内的IP地址 8.8.8.8 是国外的I…

鸿蒙媒体开发系列04——音频播放

如果你也对鸿蒙开发感兴趣&#xff0c;加入“Harmony自习室”吧&#xff01;扫描下方名片&#xff0c;关注公众号&#xff0c;公众号更新更快&#xff0c;同时也有更多学习资料和技术讨论群。 1、如何选择音频播放开发方式 在HarmonyOS系统中&#xff0c;多种API都提供了音频播…

QUIC的loss detection学习

PTO backoff backoff 补偿 /ˈbkɒf/PTO backoff 是QUIC&#xff08;Quick UDP Internet Connections&#xff09;协议中的一种机制&#xff0c;用于处理探测超时&#xff08;Probe Timeout, PTO&#xff09;重传策略 它逐步增加探测超时的等待时间&#xff0c;以避免网络拥塞…

Web开发:使用C#创建、安装、调试和卸载服务

目录 一、创建服务 1.创建项目&#xff08;.NET Framework&#xff09; 2.重命名 3.编写逻辑代码 二、安装服务 1.方案一&#xff1a;利用VS2022安装文件的配置 选择添加安装程序 安装文件的介绍及配置 ​编辑​ 重新编译 工具安装 2.方案二&#xff1a;编写bat脚本安…

【嘉立创EDA】画PCB板中为什么要两面铺铜为GND,不能一面GND一面VCC吗?

在新手画板子铺铜时&#xff0c;经常会铺一面GND一面VCC。但一般情况下我们不会这样铺铜。下面将详细分析为什么要两面铺铜为GND&#xff0c;而不是一面GND一面VCC的原因&#xff1a; 提高散热能力 金属导热性&#xff1a;金属具有良好的导热性&#xff0c;铺铜可以有效分散PCB…

Oracle 19c异常恢复—ORA-01209/ORA-65088---惜分飞

由于raid卡bug故障,导致文件系统异常,从而使得数据库无法正常启动,客户找到我之前已经让多人分析,均未恢复成功,查看alert日志,发现他们恢复的时候尝试resetlogs库,然后报ORA-600 kcbzib_kcrsds_1错误 2024-09-15T17:07:32.55321508:00 alter database open resetlogs 2024-09-…

Debian11之DolphinScheduler使用

登录 默认用户名和密码 admin/dolphinscheduler123 http://192.168.111.180:12345/dolphinscheduler/ui基础配置 1、创建Worker【admin用户下】 创建项目的时候会指定Worker&#xff0c;这个配置决定了项目中的任务在哪个服务器执行 2、创建环境【admin用户下】 - 如果涉…

Linux搭建邮箱服务器(简易版)

本章是上一文档的简易版本搭建方式更为快速简洁&#xff08;只需要两条命令即可搭建&#xff09;&#xff0c;如果想了解更详细一些可以看我上一文档 Linux接发邮件mailx_linux mailx o365-CSDN博客文章浏览阅读857次&#xff0c;点赞25次&#xff0c;收藏19次。本文详细描述了…

spring security OAuth2 搭建资源服务器以及授权服务器/jdbc/jwt两种方案

一、认证服务器基于jdbc方式 如果不懂请移步上一篇文章&#xff1a;Spring security OAuth2 授权服务器搭建-CSDN博客 在上一篇文章中&#xff0c;TokenStore的默认实现为 InHenoryTokenStore 即内存存储&#xff0c;对于 CLient 信息&#xff0c;userDetaitsServce 接负责从存…

mqtt整体了解

整个系统的分布及功能 参考太极创客视频 整体分为三部分&#xff1a; 发布&#xff1a;实时发送到云平台&#xff1b;实现主体是传感器或被控对象 订阅&#xff1a;得到能够访问发布信息&#xff1b;主体是有查看和控制权限的对象 云平台&#xff1a;可以理解为有控制订阅者权…

Python 爬虫入门 - Request 静态页面数据获取

在现代 Web 开发中,HTTP 请求(Request)是与服务器进行通信的核心操作。无论是在前端还是后端开发中,数据的获取、传递以及处理都离不开请求的应用。特别是在静态页面的数据获取中,使用请求可以将页面变得更加动态和互动,从而大大提升用户体验,使得页面内容更加丰富和灵活…