WebGL图形编程实战【5】:层次构建 × Shader初始化深度剖析
层次结构模型
三维模型和现实中的人类或机器人不一样,它的部件并没有真正连接在一起。如果直接转动上臂,那么肘部以下的部分,包括前臂、手掌和手指,只会留在原地,这样手臂就断开了。
所以,当上臂绕肩关节转动时,需要在代码中实现“肘部以下部分跟随上臂转动“的逻辑。具体地,上臂绕肩关节转动了多少度,肘部以下的部分也应该绕肩关节转动多少度。
简单情况
实现“部件A转动带动部件B转动”可以很直接,只要对部件B也施以部件A的旋转矩阵即可。比如,使用模型矩阵使上臂绕肩关节转动30度,然后在绘制肘关节以下的各部位时,为它们施加同一个模型矩阵,也令其绕肩关节转动30度,这样,肘关节以下的部分就能自动跟随上臂转动了。
复杂情况
比如先使上臂绕肩关节转动30度,然后使前臂绕肘关节转动10度,那么对肘关节以下的部分,你就得先施加上臂绕肩关节转动30度的矩阵(可称为“肩关节模型矩阵”),然后再施加前臂绕肘关节转动10度的矩阵。将这两个矩阵相乘,其结果可称为“肘关节模型矩阵”,那么在绘制肘关节以下部分的时候,直接应用这个所谓的“肘关节模型矩阵”(而不考虑肩关节,因为肩关节的转动信息已经包含在该矩阵中了)作为模型矩阵就可以了。
单关节模型
单关节完整代码案例在这:singleNode.html
绘制长方体作为上臂
还是采用drawElement的方法,绘制长方体,和之前绘制正方体的绘制方式一样。只是调整了一个顶点坐标的值。
function initBuffer() {var vertices = new Float32Array([1.5, 10.0, 1.5, -1.5, 10.0, 1.5, -1.5, 0.0, 1.5, 1.5, 0.0, 1.5, // v0-v1-v2-v3 front1.5, 10.0, 1.5, 1.5, 0.0, 1.5, 1.5, 0.0, -1.5, 1.5, 10.0, -1.5, // v0-v3-v4-v5 right1.5, 10.0, 1.5, 1.5, 10.0, -1.5, -1.5, 10.0, -1.5, -1.5, 10.0, 1.5, // v0-v5-v6-v1 up-1.5, 10.0, 1.5, -1.5, 10.0, -1.5, -1.5, 0.0, -1.5, -1.5, 0.0, 1.5, // v1-v6-v7-v2 left-1.5, 0.0, -1.5, 1.5, 0.0, -1.5, 1.5, 0.0, 1.5, -1.5, 0.0, 1.5, // v7-v4-v3-v2 down1.5, 0.0, -1.5, -1.5, 0.0, -1.5, -1.5, 10.0, -1.5, 1.5, 10.0, -1.5 // v4-v7-v6-v5 back]);// Normalvar 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, // v0-v1-v2-v3 front1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, // v0-v3-v4-v5 right0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, // v0-v5-v6-v1 up-1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, // v1-v6-v7-v2 left0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, // v7-v4-v3-v2 down0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0 // v4-v7-v6-v5 back]);// Indices of the verticesindices = new Uint8Array([0, 1, 2, 0, 2, 3, // front4, 5, 6, 4, 6, 7, // right8, 9, 10, 8, 10, 11, // up12, 13, 14, 12, 14, 15, // left16, 17, 18, 16, 18, 19, // down20, 21, 22, 20, 22, 23 // back]);let pointPosition = new Float32Array(vertices);let aPsotion = webgl.getAttribLocation(webgl.program, 'a_position');let triangleBuffer = webgl.createBuffer();webgl.bindBuffer(webgl.ARRAY_BUFFER, triangleBuffer);webgl.bufferData(webgl.ARRAY_BUFFER, pointPosition, webgl.STATIC_DRAW);webgl.enableVertexAttribArray(aPsotion);webgl.vertexAttribPointer(aPsotion, 3, webgl.FLOAT, false, 0, 0);let aNormal = webgl.getAttribLocation(webgl.program, 'a_Normal');let normalsBuffer = webgl.createBuffer();let normalsArr = new Float32Array(normals);webgl.bindBuffer(webgl.ARRAY_BUFFER, normalsBuffer);webgl.bufferData(webgl.ARRAY_BUFFER, normalsArr, webgl.STATIC_DRAW);webgl.enableVertexAttribArray(aNormal);webgl.vertexAttribPointer(aNormal, 3, webgl.FLOAT, false, 0, 0);let indexBuffer = webgl.createBuffer();let indices1 = new Uint8Array(indices);webgl.bindBuffer(webgl.ELEMENT_ARRAY_BUFFER, indexBuffer);webgl.bufferData(webgl.ELEMENT_ARRAY_BUFFER, indices1, webgl.STATIC_DRAW);
}
添加光照
直接添加光照的代码是放在initBuffer当中,现在将其抽离成一个单独的函数,数据都是传递给着色器的,不影响绘制。
function initLight() {let u_DiffuseLight = webGL.getUniformLocation(program, 'u_DiffuseLight');webGL.uniform3f(u_DiffuseLight, 1.0, 1.0, 1.0);let u_LightDirection = webGL.getUniformLocation(program, 'u_PointLightPosition');webGL.uniform3fv(u_LightDirection, [3.0, 3.0, 4.0]);let u_AmbientLight = webGL.getUniformLocation(program, 'u_AmbientLight');webGL.uniform3f(u_AmbientLight, 0.8, 0.8, 0.8);
}
设置矩阵
现在已经准备好了绘制的数据,之后就是通过设置透视投影矩阵和模型矩阵来绘制了。也单独抽离成一个方法。
那么在这里返回了一个模型矩阵的目的是,第一次绘制长方体时是上臂,这个时候调用initTransformation会拿到上臂的模型矩阵,那么通过上臂再去绘制小臂的时候用大臂的模型矩阵再作为小臂变换的顶点矩阵,也就完成了大臂和小臂的联动
function initTransformation(angele, rotateArr, ModelMatrix = mat4.create()) {let ProjMatrix = mat4.create();mat4.identity(ProjMatrix);mat4.perspective(ProjMatrix, angle * Math.PI / 180, webGLdiv.clientWidth / webGLdiv.clientHeight, 1, 1000); //修改可视域范围let uniformMatrix1 = webGL.getUniformLocation(program, 'u_formMatrix');mat4.rotate(ModelMatrix, ModelMatrix, (angele * Math.PI) / 180.0, rotateArr);let ViewMatrix = mat4.create();mat4.identity(ViewMatrix);mat4.lookAt(ViewMatrix, [50, 50, 50], [0, 0, 0], [0, 1, 0]);let mvMatrix = mat4.create();mat4.identity(mvMatrix);mat4.multiply(mvMatrix, ViewMatrix, ModelMatrix);let mvpMatrix = mat4.create();mat4.identity(mvpMatrix);mat4.multiply(mvpMatrix, ProjMatrix, mvMatrix);webGL.uniformMatrix4fv(uniformMatrix1, false, mvpMatrix);return ModelMatrix;
}
绘制
这里就是上一步所说的联动,先绘制上臂,再绘制小臂,小臂的模型矩阵是上臂的模型矩阵。
function draw() {let modelArr = initTransformation(jointAngle, [0, 1, 0]);webGL.drawElements(webGL.TRIANGLES, indices.length, webGL.UNSIGNED_BYTE, 0);initTransformation(armAngle, [0, 0, 1], modelArr);webGL.drawElements(webGL.TRIANGLES, indices.length, webGL.UNSIGNED_BYTE, 0);
}function clear() {webGL.clearColor(0, 0, 0, 1);webGL.clear(webGL.COLOR_BUFFER_BIT | webGL.DEPTH_BUFFER_BIT);webGL.enable(webGL.DEPTH_TEST);
}
添加键盘控制事件
添加键盘事件控制jointAngle、armAngle来控制大臂和小臂的旋转角度。
function initEvent() {document.onkeydown = keydown;
}function keydown(ev) {switch (ev.keyCode) {case 38:if (jointAngle < 135.0) jointAngle += ANGLE_STEP;break;case 40:if (jointAngle > -135.0) jointAngle -= ANGLE_STEP;break;case 39:armAngle += ANGLE_STEP;break;case 37:armAngle -= ANGLE_STEP;break;default:return;}clear();draw();
}
那么最后的效果就是这样啦
多节点模型
那么上一步完成了大臂和小臂的联动,如果现在需要绘制一个简单的有头有手的机器人模型,下面简单的说一下实现步骤:
- 先绘制头部,用头部的模型矩阵来绘制上半身,完成头部、上半身联动。
- 用上半身的模型矩阵绘制左大臂,再通过大臂的模型矩阵来绘制小臂,
- 再通过小臂的模型矩阵来绘制手指1和手指2,这样就完成了大臂、小臂、手指的联动。
不管他有多少个节点,只要有节点的模型矩阵,就可以通过这个模型矩阵来绘制节点,完成联动。
着色器对象 initShader
在前面已经简单解释了一下initShader是用来干啥的,这个后续都没有做过修改。现在来深入探究一下。
initShader函数的作用是:编译GLSLES代码,创建和初始化着色器供WebGL使用。具体地,分为以下7个步骤:
- 创建着色器对象(gl.createShader())
- 向着色器对象中填充着色器程序的源代码(gl.shaderSource())
- 编译着色器(gl.compileShader())
- 创建程序对象(gl.createProgram())
- 为程序对象分配着色器(gl.attachShader())
- 连接程序对象(gl.linkProgram())
- 使用程序对象(gl.useProgram())
这里出现了两个对象:着色器对象、程序对象
- 着色器对象:着色器对象管理一个顶点着色器或一个片元着色器。每一个着色器都有一个着色器对象
- 程序对象:程序对象是管理着色器对象的容器。WebGL中,一个程序对象必须包含一个顶点着色器和一个片元着色器
创建着色器对象
所有的着色器对象都是以gl.createShader()创建的,这个函数接收一个参数,这个参数是gl.VERTEX_SHADER或gl.FRAGMENT_SHADER,分别表示顶点着色器和片元着色器。
如果不需要这个着色器,可以通过gl.deleteShader()删除这个着色器对象。
指定着色器代码
通过gl.shaderSource()指定着色器的源代码,这个函数接收两个参数,第一个参数是着色器对象,第二个参数是着色器的源代码。
编译着色器
GLSL
ES语言和JavaScript不同而更接近C或C++,在使用之前需要编译成二进制的可执行格式,WebGL系统真正使用的是这种可执行格式。使用gl.compileShader()
函数进行编译。
当对着色器编译之后,如果编译失败,可以通过gl.getShaderParameter()
函数获取着色器的编译状态,如果编译失败,可以通过gl.getShaderInfoLog()函数获取着色器的编译信息。
if (!webGL.getShaderParameter(vsShader, webGL.COMPILE_STATUS)) {console.log('vsShader error =====', webGL.getShaderInfoLog(vsShader));return;
}
if (!webGL.getShaderParameter(fsShader, webGL.COMPILE_STATUS)) {console.log('fsShader error =====', webGL.getShaderInfoLog(fsShader));return;
}
创建程序对象
调用gl.createProgram()创建程序对象,这个函数返回一个程序对象。类似的,可以通过gl.deleteProgram()
删除程序对象。一旦程序对象被创建之后,需要向程序附上两个着色器
为程序对象分配着色器
WebGL系统要运行起来,必须要有两个着色器:一个顶点着色器和一个片元着色器。可以使用gl.attachShader()函数为程序对象分配这两个着色器。
着色器在附给程序对象前,并不一定要为其指定代码或进行编译(也就是说,把空的着色器附给程序对象也是可以的)。类似地,可以使用gl.detachShader()
函数来解除分配给程序对象的着色器。
连接程序对象
在为程序对象分配了两个着色器对象后,还需要将(顶点着色器和片元)着色器连接起来。使用gl.1inkProgram()函数来进行这一步操作。
程序对象进行着色器连接操作,目的是保证:
- 顶点着色器和片元着色器的varying变量同名同类型,且一一对应
- 顶点着色器对每个varying变量赋了值
- 顶点着色器和片元着色器中的同名uniform变量也是同类型的(无需一一对应,即某些uniform变量可以出现在一个着色器中而不出现在另一个中)
- 着色器中的attribute变量、uniform变量和varying变量的个数没有超过着色器的上限
使用程序对象
通过调用gl.useProgram()告知WebGL系统绘制时使用哪个程序对象
相关文章:
WebGL图形编程实战【5】:层次构建 × Shader初始化深度剖析
层次结构模型 三维模型和现实中的人类或机器人不一样,它的部件并没有真正连接在一起。如果直接转动上臂,那么肘部以下的部分,包括前臂、手掌和手指,只会留在原地,这样手臂就断开了。 所以,当上臂绕肩关节转…...
126. 单词接龙 II
题目 按字典 wordList 完成从单词 beginWord 到单词 endWord 转化,一个表示此过程的 转换序列 是形式上像 beginWord -> s1 -> s2 -> ... -> sk 这样的单词序列,并满足: 每对相邻的单词之间仅有单个字母不同。转换过程中的每个…...
【LeetCode Hot100】二叉树篇
前言 本文用于整理LeetCode Hot100中题目解答,因题目比较简单且更多是为了面试快速写出正确思路,只做简单题意解读和一句话题解方便记忆。但代码会全部给出,方便大家整理代码思路。 94. 二叉树的中序遍历 一句话题意 返回二叉树中序遍历的数…...
MySQL基础关键_002_DQL
目 录 一、初始化 二、简单查询 1.部分语法规则 2.查询一个字段 (1)查询员工编号 (2)查询员工姓名 3.查询多个字段 (1)查询员工编号、姓名 (2)查询部门编号、名称、位置 …...
游戏引擎学习第249天:清理调试宏
欢迎大家,让我们直接进入调试代码的改进工作 接下来,我们来看一下上次停留的位置。如果我没记错的话,上一场直播的结尾我有提到一些我想做的事情,并且在代码中留下了一个待办事项。所以也许我们今天首先做的就是解决这个问题。但…...
TwinCAT数据类型,%MX,%MD这些特殊符号
在 TwinCAT(Beckhoff PLC 编程环境)中,%MX、%MD 等符号是 IEC 61131-3 标准的地址表示法,用于直接访问 PLC 的物理 I/O 或内存区域。这些符号通常用于 变量声明 或 直接寻址,特别是在 TwinCAT 2 和 传统 PLC 编程 中较…...
力扣——20有效的括号
目录 1.题目描述: 2.算法思路: 3.代码展示: 1.题目描述: 给定一个只包括 (,),{,},[,] 的字符串 s ,判断字符串是否有效。 有效字符串需满足: 左括号必须…...
正点原子STM32H743单片机实现ADC多通道检测
目标 使用STM32CubeMX工具,配置ADC相关参数,实现在STM32H743单片机上获取ADC多通道电压值。共14个ADC引脚,ADC2有5个,ADC3有9个,全部设置单通道 ADC引脚 PF3PF4PF5PF10PC0PC2PC3PH2PH3PA3PB0PB1PA4PA5PA6 STM32cube…...
前端封装WebSocket工具n
Web API 提供的 WebSocket 类,封装一个 Socket 类 // socket.js import modal from /plugins/modal const baseURL import.meta.env.VITE_APP_BASE_WS; const EventTypes [open, close, message, error, reconnect]; const DEFAULT_CHECK_TIME 55 * 1000; // 心…...
Docker进入MySQL之后如何用sql文件初始化数据
关闭Docker-compose.yml里面所有容器 docker compose -f docker_compose.yml down后台形式开启Docker-compose.yml所有容器 docker compose -f docker_compose.yml up -d罗列出所有启动过的(包括退出过的)容器 docker ps -a进入指定容器ID内部 docke…...
Docker搜索镜像报错
科学上网最方便。。。。 尝试一: 报错处理 Error response from daemon: Get https://index.docker.io/v1/search?qmysql&n25: dial tcp 31.13.84.2:443: i/o timeout 国内从 DockerHub 拉取镜像有时会遇到困难,此时可以配置镜像加速器。Docke…...
【Unity笔记】基于距离驱动的参数映射器 InverseDistanceMapper 设计与实现
需求: 当用户距离目标位置越近,参数值越大。 可用于控制场景亮度、动画进度、交互强度等多种效果。 一、需求背景:如何让“距离”成为设计的一部分? 在虚拟现实(VR)、增强现实(AR)乃…...
【Spring AI】Java结合ollama实现大模型调用
在较新的Java版本中,编译器已经支持了接入各种AI模型工具进行开发,这篇文章我会介绍如何利用Spring AI进行大模型的调用的基础方法。 环境准备 由于这篇文章是结合ollama进行演示,所以在开始前需要先安装ollama服务,这个的具体步…...
docker制作python大模型镜像(miniconda环境),工程改造记录
**环境说明:**从系统镜像开始打造python大模型镜像,之前是人工手动装的方式,并且模型和依赖在公网中,对于离线交付环境不太友好,所以打造的离线化交付版本 Dockerfile: FROM centos:7.9 ENV PYTHONIOENCODINGutf-8 E…...
在油气地震资料积分法偏移成像中,起伏地表处理
在油气地震资料积分法偏移成像中,起伏地表情况会带来波场传播路径畸变、静校正问题以及成像精度下降等挑战。以下是处理起伏地表的常用方法和技术要点: 1. 静校正预处理 高程静校正:将地表各接收点校正到统一基准面(浮动基准面或…...
经典算法 独立任务最优调度问题
独立任务最优调度问题 题目描述 用2 台处理机A 和B 处理n 个作业。设第i 个作业交给机器A 处理时需要时间ai ,若由机器B 来处理,则需要时间bi 。由于各作业的特点和机器的性能关系,很可能对于某些i,有ai >bi,而对…...
在TensorFlow中,`Dense`和`Activation`是深度学习模型构建里常用的层
在TensorFlow中,Dense和Activation是深度学习模型构建里常用的层,下面就详细解释它们的使用语法和含义。 1. Dense层 含义 Dense层也就是全连接层,这是神经网络里最基础的层。在全连接层中,每一个输入神经元都和输出神经元相连…...
基于 Rancher 部署 Kubernetes 集群的工程实践指南
一、现状分析 在当今的云计算和容器化领域,Kubernetes(K8S)已经成为了容器编排和管理的事实标准。根据 Gartner 的数据,超过 70% 的企业在生产环境中使用 K8S 来管理容器化应用。然而,K8S 的安装和管理对于许多企业来…...
Seaborn
1. Seaborn概述:Seaborn是基于Matplotlib的Python数据可视化库,专注绘制统计图形。它简化可视化流程,提供高级接口与美观默认主题,能以少量代码实现复杂图形绘制。 2. 安装与导入:安装Seaborn可使用 pip install seabo…...
0基础FWT详解2(巩固)
FWT巩固1 FWT巩固1卡常技巧巩固习题luogu6097CF662Cluogu4221FWT巩固1 在 上篇文章 中,我们学习了 F W T FWT FWT,本文将带读者一起做几道题,巩固对 F W T FWT FWT 的使用 卡常技巧 一个常数大的 F W T FWT FWT 是非常不利于做题的,所以我们需要卡常。 作者简单总结…...
阿里云 ECS 服务器进阶指南:存储扩展、成本优化与架构设计
一、弹性存储架构:块存储深度解析与挂载实践 (一)块存储类型与技术特性 阿里云块存储作为 ECS 核心存储方案,提供三种主流类型: ESSD 云盘 性能等级:PL0/PL1/PL2/PL3,最高支持 100 万 IOPS …...
运维打铁: 存储方案全解析
文章目录 一、引言二、思维导图三、常见存储方案介绍3.1 直接附加存储(DAS,Direct Attached Storage)1. 原理2. 优缺点3. 适用场景 3.2 网络附加存储(NAS,Network Attached Storage)1. 原理2. 优缺点3. 适用…...
Semtech公司简介以及主流产品
Semtech 公司是一家美国的半导体公司,总部位于加利福尼亚州卡马里洛。以下是其简介和主流产品介绍: 公司简介 成立时间与地点:1960 年成立于加利福尼亚州纽伯里帕克。发展历程:最初为军事和航空航天公司提供零部件,1…...
flutter 专题 五十六 Google 2020开发者大会Flutter专题
由于疫情的原因,今年的Google 开发者大会 (Google Developer Summit) 在线上举行,本次大会以“代码不止”为主题,全面介绍了产品更新以及一系列面向本地开发者的技术支持内容。我比较关注的是移动开发,在本次大会上,关…...
93. 后台线程与主线程更新UI Maui例子 C#例子
在.NET MAUI开发中,多线程是常见的需求,但UI更新必须在主线程上执行。今天,我们来探讨一个简单而优雅的解决方案:MainThread.InvokeOnMainThreadAsync。 一、背景 在跨平台应用开发中,后台线程常用于执行耗时操作&am…...
5.运输层
5. 运输层 1. 概述 第2~4章依次介绍了计算机网络体系结构中的物理层、数据链路层和网络层,它们共同解决了将主机通过异构网络互联起来所面临的问题,实现了主机到主机的通信然而在计算机网络中实际进行通信的真正实体,是位于通信两端主机中的…...
ActiveMQ 可靠性保障:消息确认与重发机制(二)
ActiveMQ 重发机制 重发机制的原理与触发条件 ActiveMQ 的重发机制是确保消息可靠传输的重要手段。当消息发送到 ActiveMQ 服务器后,如果消费者由于某些原因未能成功处理消息,ActiveMQ 会依据配置的重发策略,将消息重新放入队列或主题中&am…...
Vue+tdesign t-input-number 设置长度和显示X号
一、需求 Vuetdesign t-input-number 想要设置input的maxlen和显示X号 二、实现 t-input,可以直接使用maxlength和clearable属性 <t-input v-model"value" clearable maxlength10 placeholder"请输入" clear"onClear" blur&q…...
机器学习|通过线性回归了解算法流程
1.线性回归引入 2.决策函数 3. 损失函数 4.目标函数 5.目标函数优化问题 6.过拟合 7.正则化...
两向量平行公式、向量与平面平行公式、两平面平行公式;两向量垂直公式、向量与平面垂直公式、两平面垂直公式
目录 一、两向量平行公式 二、向量与平面平行公式 三、两平面平行公式 四、两向量垂直公式 五、向量与平面垂直公式 六、两平面垂直公式 观察与总结 一、两向量平行公式 二、向量与平面平行公式 三、两平面平行公式 四、两向量垂直公式 五、向量与平…...
vscode 个性化
vscode 个性化 设置 吸顶效果 使用前使用后 设置方法 VS Code 的粘性滚动预览 - 类似于 Excel 的冻结首行 插件 代码片段分享 - CodeSnap 使用方式 CtrlShiftP输入CodeSnap 唤起插件选择代码 行内报错提示 - Error Lens 使用前使用后 VSCode Error Lens插件介绍&…...
OpenHarmony-简单的HDF驱动
学习于:https://docs.openharmony.cn/pages/v5.0/zh-cn/device-dev/driver/driver-hdf-manage.md 首先,OpenHarmony系统里的HDF(Hardware Driver Foundation)驱动框架,已经规范设备驱动的模型、设备节点的配置与统一的…...
Copilot重磅更新:引用文件夹创建Word文档
大家好,AI技术笔记为您带来一则好消息: 根据广大用户的反馈,Microsoft 365 Copilot在Word中的引用能力全面升级啦! 不管是撰写、审阅还是定稿文档,现在你可以更快、更高效地引用更多资料! ✨三大重磅改进…...
SQL Server数据库提权的几种方法——提权教程
SQL Server数据库提权的几种方法——提权教程 一、简介 在利用系统溢出漏洞没有效果的情况下,可以采用数据库进行提权。 数据库提权的前提条件: 1、服务器开启数据库服务 2、获取到最高权限用户密码 (除Access数据库外,其他数据库基本都存在数据库提权的可能) 二、使用x…...
解决在Mac上无法使用“ll”命令
在 macOS 上,ll 命令是一个常见的别名,它通常是指向 ls -l 的。但是,如果你看到 zsh: command not found: ll,这意味着你当前的 zsh 配置中没有设置 ll 作为别名。 解决方法: 1. 使用 ls -l 命令 如果只是想查看目录…...
Dockerfile最佳实践:构建高效、安全的容器镜像
一、前言 Dockerfile是一个文本文档,它包含用户可以在命令行上调用的所有指令,每一条指令构建一层镜像。在日常开发中我们常常需要自己编写Dockerfile来构建镜像,而构建一个精巧、实用且高品质的镜像对运行环境来说尤为重要。下面我们来排一排如何构建这样的镜像。 二、目…...
mac电脑pytest生成测试报告
时隔了好久再写代码,感觉我之前的积累都白费了,全部忘记了,看来每一步都有记录对于我来说才是最好的。 最近又要重新搞接口自动化,然而是在mac电脑,对于我长期使用windows的人来说真的是个考验,对此次过程…...
鸿蒙 应用开发 项目资源结构及资源访问
三层工程结构 模块分类 使用...
C#学习第20天:垃圾回收
什么是垃圾回收? 定义:垃圾回收是一种自动内存管理机制,负责回收不再使用的对象所占用的内存。目的:通过自动化内存回收,减少内存泄漏的风险,并简化开发者的工作。 垃圾回收的核心概念 1. 垃圾回收器的工…...
C#学习笔记 项目引用添加异常
这个问题出现多次了 我觉得有必要记录一下 场景 同一个解决方案下添加了多个项目 我想在单元测试项目中引用一下项目1,按照步骤:添加引用- 项目- 浏览- 在指定目录下找到项目的工程文件XXXSystem.csproj- 确定 然后就触发了异常 解决方案 首先 清理解决…...
使用模块中的`XPath`语法提取非结构化数据
想要在代码中使用Xpath进行处理,就需要模块lxml 模块安装 pip install lxml -i https://pypi.tuna.tsinghua.edu.cn/simplelxml的使用 使用lxml转化为Element对象 from lxml import etreetext <div> <ul> <li class"item-1"><a …...
复杂度和顺序表(双指针方法)
目录 目录 目录 前言: 一、时间复杂度和空间复杂度 1.1概念 1.2规则 二、顺序表 2.1静态顺序表 2.2动态顺序表 三、双指针法 四、总结 前言: 时间复杂度和空间复杂度是用于判断算法好坏的指标,程序性能的核心指标。时间复杂度主要衡…...
day006-实战练习题-参考答案
老男孩教育-99期-实战练习题 1. 你作为"老男孩教育99期云计算"新晋运维工程师,在入职首日遭遇紧急事件: "生产环境3台Web服务器突发性能告警,技术总监要求你立即完成: 快速建立故障诊断工作区收集关键系统指标分…...
批量删除OpenStack实例
在Linux终端实现批量删除OpenStack实例,支持并发删除、安全确认、重试机制、优先清理运行中实例 #!/bin/bash # # 增强版 OpenStack 删除实例脚本 # 功能:支持并发删除、安全确认、重试机制、优先清理运行中实例 # 更新:2025年4月30日 # ##…...
楼宇智能化一、二章【期末复习】
一章、楼宇概述 智能建筑的定义:以建筑物为平台,基于对各类智能化信息的综合应用,集架构、系统、应用、管理及优化组合为一体,具有感知、传输、记忆、推理、判断和决策的综合智慧能力,形成以人、建筑、环境互为协调的整合体,为人们提供安全、高效、便利及可持续发展功能…...
三生原理与西方哲学的具体对比?
AI辅助创作: 一、本体论差异 生成论与构成论的分野 三生原理以《周易》“太极生两仪,两仪生四象,四象生八卦”、《道德经》“道生一,一生二,二生三,三生万物”为基础,构建动态层级生成的宇…...
呼叫中心座席管理系统:智能升级,高效服务
在数字化转型加速的今天,客户服务体验已成为企业竞争力的核心要素。传统 呼叫中心系统 依赖硬件设备、人工操作的模式已无法满足高效、智能、灵活的现代企业需求。畅信达呼叫中心 座席管理系统 V5.0应运而生,以WEBRTC软电话接入、智能座席辅助、知识库管…...
PCB设计实战技巧宝典:从库管理到布线优化的全流程解析
知识点1【PCB设计流程】 器件 符号 封装 (3D模型 实物图 ) 流程介绍 1、如果没有需要的的库,先画库:器件,符号,封装 2、新建工程,放置器件在原理图 3、原理图转PCB 4、导出ROM和Gerber…...
微信小程序 XSS 防护知识整理
场景1:用户输入表单(如评论框) 错误做法:直接渲染未过滤的用户输入 // WXML <view>{{ userInput }}</view>// JS(用户输入了恶意内容) Page({data: { userInput: <script>alert("…...
平衡截断(Balanced Truncation)—— MTALAB 和 Python 实现
平衡截断balreal 算法原理平衡截断过程求解 HSV 为什么不使用定义而是使用 Cholesy 和SVD 分解? MATLAB 实践Python 实现 先验知识:可控性 Gramian W c W_c Wc、可观性 Gramian W o W_o Wo 以及 Hankel 奇异值(HSV) σ i \s…...