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.rhkb.cn/news/423128.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于SpringBoot+Vue+MySQL的画师约稿平台系统

系统展示 用户界面 画师界面 管理员界面 系统背景 基于SpringBootVueMySQL的画师约稿平台系统的背景&#xff0c;主要源于数字艺术行业的快速发展与画师、客户双方需求的日益增长。在传统的约稿方式中&#xff0c;往往存在沟通效率低下、交易过程不透明等问题&#xff0c;这限制…

C++---string类常见接口

介绍 string类详情>>>https://cplusplus.com/reference/string/string/?kwstring 1. string是表示字符串的字符串类&#xff08;感觉就像一个动态的字符数组&#xff09; 2. 该类的接口与常规容器的接口基本相同&#xff0c;再添加了一些专门用来操作string的常规操作…

Cloudflare Pages 部署 Next.js 应用教程

Cloudflare Pages 部署 Next.js 应用教程 本教程将指导你如何将现有的 Next.js 应用部署到 Cloudflare Pages。 准备工作 安装部署依赖 首先,安装 cloudflare/next-on-pages: npm install --save-dev cloudflare/next-on-pages添加 wrangler.toml 配置文件 在项目根目录创建 …

力扣139-单词拆分(Java详细题解)

题目链接&#xff1a;139. 单词拆分 - 力扣&#xff08;LeetCode&#xff09; 前情提要&#xff1a; 因为本人最近都来刷dp类的题目所以该题就默认用dp方法来做。 最近刚学完背包&#xff0c;所以现在的题解都是以背包问题为基础再来写的。 如果大家不懂背包问题的话&#…

【LoRA】浅谈大模型微调之LoRA技术

在当今的信息时代中&#xff0c;大型语言模型扮演着至关重要的角色&#xff0c;它们在自然语言处理任务中展现出强大的能力。LoRA&#xff0c;英文全称Low-Rank Adaptation of Large Language Models&#xff0c;是一种用于微调大型语言模型的低秩适应技术&#xff0c;由微软的…

Java Enterprise System 体系结构

本章概述了 Java Enterprise System 部署所基于的体系结构概念。 章中描述了一个框架,在此框架内从三维角度对 Java Enterprise System部署体系结构进行了分析,它们分别是:逻辑层、基础结构服务级别和服务质量。这三维在下图中以图解形式显示为正交坐标轴,它们有助于在体系…

jmeter之TPS计算公式

需求&#xff1a; 如何确定环境当中的TPS指标 PV:&#xff08;Page View&#xff09;即页面访问量&#xff0c;每打开一次页面PV计数1&#xff0c;刷新页面也是。PV只统计页面访问次 数。 UV(Unique Visitor),唯一访问用户数&#xff0c;用来衡量真实访问网站的用户数量。 一般…

大模型的第一个杀手级应用场景出来了

大家终于都意识到大模型首先改变的是软件行业自己&#xff0c;而软件的根基是代码生成。代码生成第一波就是AI辅助开发&#xff0c;这个会是大模型第一个杀手级应用。大家苦苦逼问自己的大模型杀手级应用&#xff0c;为什么会是辅助编程&#xff0c;这里说下什么&#xff1a; 必…

vscode 使用git bash,路径分隔符缺少问题

window使用bash --login -i 使用bash时候&#xff0c;在系统自带的terminal里面进入&#xff0c;测试conda可以正常输出&#xff0c;但是在vscode里面输入conda发现有问题 bash: C:\Users\marswennaconda3\Scripts: No such file or directory实际路径应该要为 C:\Users\mars…

PyTorch安装指南:轻松上手深度学习框架(CUDA)

PyTorch 是一个非常流行的开源深度学习框架&#xff0c;它支持动态图&#xff0c;这使得开发者能够更容易地构建和调试复杂的模型。PyTorch 可以运行在 CPU 上&#xff0c;也可以利用 NVIDIA 的 CUDA 平台加速计算&#xff0c;从而在 GPU 上执行。下面是如何在你的系统上安装 P…

质量体系和质量过程管理及SCIOT平台质量管理功能简介

原创 团长团 AI智造AI编程 2024年09月13日 21:04 北京 用爱编程30年&#xff0c;倾心打造工业和智能智造软件研发平台SCIOT,用创新的方案、大幅的让利和极致的营销&#xff0c;致力于为10000家的中小企业实现数字化转型&#xff0c;打造数字化企业和智能工厂&#xff0c;点击上…

预报名来啦!25届考研所有重要时间节点和注意事项一览

预报名即将开始&#xff0c;学姐给大家准备了&#xff0c;详细的报考流程及常见问题&#xff0c;每年都有学生因为报名出问题导致没法参加考试&#xff0c;大家一定要认真对待哦~ 一.报名时间及流程 01 预报名时间 2024年9月24日至9月27日&#xff0c;9:00—22:00 02 预报名…

Vue的学习(三)

目录 一、for循环中key的作用 1‌.提高性能‌&#xff1a; ‌2.优化用户体验‌&#xff1a; ‌3.辅助Vue进行列表渲染‌&#xff1a; 4‌.方便可复用组件的使用‌&#xff1a; 二、methods及computed及wacth的区别 三、过滤器 1.Vue 2 过滤器简介 定义过滤器 使用过滤…

map与set

目录 关联式容器 键值对 树形结构的关联式容器 set 注意 set的使用 set的模板参数列表 set的构造 set的迭代器 set修改操作 set的使用举例 map map的使用 map的迭代器 map的容量与元素访问 注意 map中元素的修改 总结 multiset 注意 multiset的使用 multi…

基于中心点的目标检测方法CenterNet—CVPR2019

Anchor Free目标检测算法—CenterNet Objects as Points论文解析 Anchor Free和Anchor Base方法的区别在于是否在检测的过程中生成大量的先验框。CenterNet直接预测物体的中心点的位置坐标。 CenterNet本质上类似于一种关键点的识别。识别的是物体的中心点位置。 有了中心点之…

【重学 MySQL】二十二、limit 实现分页

【重学 MySQL】二十二、limit 实现分页 基本语法实现分页第一页第二页通用公式注意事项在 MySQL 中,LIMIT 子句非常强大,它允许你限制查询结果的数量,同时也经常被用来实现分页功能。分页是 Web 开发中常见的需求,它允许用户浏览大量数据时,一次只查看一小部分数据。 基本…

unity3d入门教程四

unity3d入门教程四 10.1坐标与旋转10.2物体的运动10.3&#xff08;练习&#xff09;掉头飞行11.1向量11.2向量间运算11.3向量夹角11.4物体的指向11.5&#xff08;练习&#xff09;飞向目标12.1屏幕坐标12.2屏幕的边界 10.1坐标与旋转 比如&#xff0c;节点的坐标用 Vector3 类型…

数据结构-线性表顺序单项链表双向链表循环链表

1数据结构概述 数据结构是计算机组织、存储数据的方式。是思想层面的东西&#xff0c;和具体的计算机编程语言没有关系。可以用任何计算机编程语言去实现这些思想。 1.1 数据逻辑结构 反映数据逻辑之间的逻辑关系&#xff0c;这些逻辑关系和他们咱在计算机中的存储位置无关。…

apache文件共享和访问控制

实现apache文件共享 文件共享路径 <Directory "/var/www/html"> #默认发布路径&#xff0c;功能限制 Options Indexes FollowSymLinks #indexes支持文件共享功能 AllowOverride None Require all granted </Directory> 进入到该路径下 cd…

为什么sqlynx是连接国产数据库的最佳选择?

1. 广泛的国产数据库支持 SQLynx除了国际上的主流数据库外&#xff0c;还支持多种国产数据库&#xff0c;如达梦、人大金仓、OceanBase、openGauss等。随着国产数据库市场的不断发展和成熟&#xff0c;越来越多的企业和机构开始选择国产数据库来满足其数据管理需求。SQLynx通过…