WebGL之创建 3D 对象

现在让我们给之前的正方形添加五个面从而可以创建一个三维的立方体。最简单的方式就是通过调用方法 gl.drawElements() 使用顶点数组列表来替换之前的通过方法gl.drawArrays() 直接使用顶点数组。而顶点数组列表里保存着将会被引用到一个个独立的顶点。

其实现在会存在这样一个问题:每个面需要 4 个顶点,而每个顶点会被 3 个面共享。我们会创建一个包含 24 个顶点的数组列表,通过使用数组下标来索引顶点,然后把这些用于索引的下标传递给渲染程序而不是直接把整个顶点数据传递过去,这样来减少数据传递。那么也许你就会问:那么使用 8 个顶点就好了,为什么要使用 24 个顶点呢?这是因为每个顶点虽然被 3 个面共享但是它在每个面上需要使用不同的颜色信息。24 个顶点中的每一个都会有独立的颜色信息,这就会造成每个顶点位置都会有 3 份副本。

定义立方体顶点位置

首先,更新 initBuffers() 函数中代码来创建立方体的顶点位置缓存区。现在的代码看起来和渲染正方形时的代码很相似,只是比之前的代码更长因为现在有了 24 个顶点(每个面使用 4 个顶点)。
在“init-buffers.js”文件 initPositionBuffer() 函数中,用下面代码替换 positions:

const positions = [// Front face-1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0,// Back face-1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0,// Top face-1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0,// Bottom face-1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0,// Right face1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0,// Left face-1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0,
];

由于我们给顶点添加了 Z 分量,因此我们需要将 vertexPosition 属性的 numComponents 更新为 3。

定义顶点颜色

然后我们还要为每个顶点定义颜色。下面的代码首先为每个面定义颜色,然后用一个循环语句为每个顶点定义颜色信息。
在“init-buffers.js”文件 initColorBuffer() 函数中,用下面代码替换 colors 定义:

const faceColors = [[1.0, 1.0, 1.0, 1.0], // Front face: white[1.0, 0.0, 0.0, 1.0], // Back face: red[0.0, 1.0, 0.0, 1.0], // Top face: green[0.0, 0.0, 1.0, 1.0], // Bottom face: blue[1.0, 1.0, 0.0, 1.0], // Right face: yellow[1.0, 0.0, 1.0, 1.0], // Left face: purple
];// Convert the array of colors into a table for all the vertices.var colors = [];for (var j = 0; j < faceColors.length; ++j) {const c = faceColors[j];// Repeat each color four times for the four vertices of the facecolors = colors.concat(c, c, c, c);
}

定义元素(三角形)数组

既然已经创建好了顶点数组,接下来就要创建元素(三角形)数组了。

function initIndexBuffer(gl) {const indexBuffer = gl.createBuffer();gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);// This array defines each face as two triangles, using the// indices into the vertex array to specify each triangle's// position.const indices = [0,1,2,0,2,3, // front4,5,6,4,6,7, // back8,9,10,8,10,11, // top12,13,14,12,14,15, // bottom16,17,18,16,18,19, // right20,21,22,20,22,23, // left];// 将索引数据传递给缓冲区对象gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,new Uint16Array(indices),gl.STATIC_DRAW,);return indexBuffer;
}

indices 数组声明每一个面都使用两个三角形来渲染。通过立方体顶点数组的索引指定每个三角形的顶点。那么这个立方体就是由 12 个三角形组成的了。

渲染立方体

接下来就需要在 drawScene() 函数里添加代码使用立方体顶点索引数据来渲染这个立方体了。代码里添加了对 gl.bindBuffer()gl.drawElements()的调用:

{const vertexCount = 36;const type = gl.UNSIGNED_SHORT;const offset = 0;gl.drawElements(gl.TRIANGLES, vertexCount, type, offset);
}

立方体的每个面都由 2 个三角形组成,那就是每个面需要 6 个顶点,或者说总共 36 个顶点,尽管有许多重复的。然而,因为索引数组的每个元素都是简单的整数类型,所以每一帧动画需要传递给渲染程序的数据也不是很多。
最后,让我们把变量 squareRotation 替换成 cubeRotation 并添加 X 轴的第二个旋转。
在“webgl-demo.js”文件的头部,把变量 squareRotation 替换成 cubeRotation

let cubeRotation = 0.0;

在 drawScene() 函数中,用下面代码替换之前的 mat4.rotate 函数:

mat4.rotate(modelViewMatrix, // destination matrixmodelViewMatrix, // matrix to rotatecubeRotation, // amount to rotate in radians[0, 0, 1],
); // axis to rotate around (Z)
mat4.rotate(modelViewMatrix, // destination matrixmodelViewMatrix, // matrix to rotatecubeRotation * 0.7, // amount to rotate in radians[0, 1, 0],
); // axis to rotate around (Y)
mat4.rotate(modelViewMatrix, // destination matrixmodelViewMatrix, // matrix to rotatecubeRotation * 0.3, // amount to rotate in radians[1, 0, 0],
); // axis to rotate around (X)

main() 函数中,替换 drawScene() 函数调用参数中的 squareRotationcubeRotation

drawScene(gl, programInfo, buffers, cubeRotation);
cubeRotation += deltaTime;

完整源码如下:

<!DOCTYPE html>
<html lang="en"><head><meta charset="utf-8" /><title>WebGL Demo</title><scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.8.1/gl-matrix-min.js"integrity="sha512-zhHQR0/H5SEBL3Wn6yYSaTTZej12z0hVZKOv3TwCUXT1z5qeqGcXJLLrbERYRScEDDpYIJhPC1fk31gqR783iQ=="crossorigin="anonymous"defer></script><script src="webgl-demo.js" type="module"></script></head><body><canvas id="glcanvas" width="640" height="480"></canvas></body>
</html>
// webgl-demo.js
import { initBuffers } from "./init-buffers.js";
import { drawScene } from "./draw-scene.js";let cubeRotation = 0.0;
let deltaTime = 0;main();function main() {const canvas = document.querySelector("#glcanvas");// Initialize the GL contextconst gl = canvas.getContext("webgl");// Only continue if WebGL is available and workingif (gl === null) {alert("Unable to initialize WebGL. Your browser or machine may not support it.");return;}// Set clear color to black, fully opaquegl.clearColor(0.0, 0.0, 0.0, 1.0);// Clear the color buffer with specified clear colorgl.clear(gl.COLOR_BUFFER_BIT);// Vertex shader programconst vsSource = `attribute vec4 aVertexPosition;attribute vec4 aVertexColor;uniform mat4 uModelViewMatrix;uniform mat4 uProjectionMatrix;varying lowp vec4 vColor;void main(void) {gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition;vColor = aVertexColor;}`;// Fragment shader programconst fsSource = `varying lowp vec4 vColor;void main(void) {gl_FragColor = vColor;}`;// Initialize a shader program; this is where all the lighting// for the vertices and so forth is established.const shaderProgram = initShaderProgram(gl, vsSource, fsSource);// Collect all the info needed to use the shader program.// Look up which attributes our shader program is using// for aVertexPosition, aVertexColor and also// look up uniform locations.const programInfo = {program: shaderProgram,attribLocations: {vertexPosition: gl.getAttribLocation(shaderProgram, "aVertexPosition"),vertexColor: gl.getAttribLocation(shaderProgram, "aVertexColor"),},uniformLocations: {projectionMatrix: gl.getUniformLocation(shaderProgram,"uProjectionMatrix"),modelViewMatrix: gl.getUniformLocation(shaderProgram, "uModelViewMatrix"),},};// Here's where we call the routine that builds all the// objects we'll be drawing.const buffers = initBuffers(gl);let then = 0;// 添加时间function render(now) {now *= 0.001; // convert to secondsdeltaTime = now - then;then = now;drawScene(gl, programInfo, buffers, cubeRotation);cubeRotation += deltaTime;requestAnimationFrame(render);}requestAnimationFrame(render);
}//
// Initialize a shader program, so WebGL knows how to draw our data
//
function initShaderProgram(gl, vsSource, fsSource) {const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);// Create the shader programconst shaderProgram = gl.createProgram();gl.attachShader(shaderProgram, vertexShader);gl.attachShader(shaderProgram, fragmentShader);gl.linkProgram(shaderProgram);// If creating the shader program failed, alertif (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {alert(`Unable to initialize the shader program: ${gl.getProgramInfoLog(shaderProgram)}`);return null;}return shaderProgram;
}//
// creates a shader of the given type, uploads the source and
// compiles it.
//
function loadShader(gl, type, source) {const shader = gl.createShader(type);// Send the source to the shader objectgl.shaderSource(shader, source);// Compile the shader programgl.compileShader(shader);// See if it compiled successfullyif (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {alert(`An error occurred compiling the shaders: ${gl.getShaderInfoLog(shader)}`);gl.deleteShader(shader);return null;}return shader;
}
// init-buffers.js
function initBuffers(gl) {const positionBuffer = initPositionBuffer(gl);const colorBuffer = initColorBuffer(gl);// 新增立方体所有顶点索引const indexBuffer = initIndexBuffer(gl);return {position: positionBuffer,color: colorBuffer,indices: indexBuffer,};
}
// 设置立方体的点位置
function initPositionBuffer(gl) {// Create a buffer for the square's positions.const positionBuffer = gl.createBuffer();// Select the positionBuffer as the one to apply buffer// operations to from here out.gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);// 定义了一个包含顶点位置信息的 JavaScript 数组。每组三个数值表示一个顶点的 x、y、z 坐标。这里包含了立方体的各个面的顶点坐标// 想要每个面有不同的颜色,那么你需要为每个面定义独立的顶点,因为颜色是顶点属性。这意味着你不能让顶点被多个面共享,因为一个顶点只能有一个颜色const positions = [// Front face-1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0,// Back face-1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0,// Top face-1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0,// Bottom face-1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0,// Right face1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0,// Left face-1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0,];// Now pass the list of positions into WebGL to build the// shape. We do this by creating a Float32Array from the// JavaScript array, then use it to fill the current buffer.gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);return positionBuffer;
}
// 初始化每个顶点颜色并设置缓冲区
function initColorBuffer(gl) {// 定义了一个包含各个面颜色的数组。每个元素是一个包含 RGBA 值的数组,表示一个面的颜色。这里列出了立方体的各个面的颜色const faceColors = [[1.0, 1.0, 1.0, 1.0], // Front face: white[1.0, 0.0, 0.0, 1.0], // Back face: red[0.0, 1.0, 0.0, 1.0], // Top face: green[0.0, 0.0, 1.0, 1.0], // Bottom face: blue[1.0, 1.0, 0.0, 1.0], // Right face: yellow[1.0, 0.0, 1.0, 1.0], // Left face: purple];// Convert the array of colors into a table for all the vertices.var colors = [];// 将当前面的颜色值重复四次,因为每个面有四个顶点,所以需要将颜色值复制四次,以便为每个顶点指定颜色for (var j = 0; j < faceColors.length; ++j) {const c = faceColors[j];// Repeat each color four times for the four vertices of the facecolors = colors.concat(c, c, c, c);}const colorBuffer = gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);return colorBuffer;
}
// 初始化索引缓冲区
function initIndexBuffer(gl) {const indexBuffer = gl.createBuffer();gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);// 定义了一个包含每个面两个三角形的索引数据数组。每六个索引值定义了两个三角形,这些索引值指定了顶点数组中哪些顶点组成了一个面的两个三角形// 为每个面定义独立的颜色,因为每个面的顶点是独立的,所以可以为每个顶点定义不同的颜色const indices = [0,1,2,0,2,3, // front4,5,6,4,6,7, // back8,9,10,8,10,11, // top12,13,14,12,14,15, // bottom16,17,18,16,18,19, // right20,21,22,20,22,23, // left];// Now send the element array to GLgl.bufferData(gl.ELEMENT_ARRAY_BUFFER,new Uint16Array(indices),gl.STATIC_DRAW);return indexBuffer;
}export { initBuffers };
// draw-scene.js
function drawScene(gl, programInfo, buffers, cubeRotation) {gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaquegl.clearDepth(1.0); // Clear everythinggl.enable(gl.DEPTH_TEST); // Enable depth testinggl.depthFunc(gl.LEQUAL); // Near things obscure far things// Clear the canvas before we start drawing on it.gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);const fieldOfView = (45 * Math.PI) / 180; // in radiansconst aspect = gl.canvas.clientWidth / gl.canvas.clientHeight;const zNear = 0.1;const zFar = 100.0;const projectionMatrix = mat4.create();// note: glmatrix.js always has the first argument// as the destination to receive the result.mat4.perspective(projectionMatrix, fieldOfView, aspect, zNear, zFar);// Set the drawing position to the "identity" point, which is// the center of the scene.const modelViewMatrix = mat4.create();// Now move the drawing position a bit to where we want to// start drawing the square.mat4.translate(modelViewMatrix, // destination matrixmodelViewMatrix, // matrix to translate[-0.0, 0.0, -6.0]); // amount to translatemat4.rotate(modelViewMatrix, // destination matrixmodelViewMatrix, // matrix to rotatecubeRotation, // amount to rotate in radians[0, 0, 1]);// 旋转y轴mat4.rotate(modelViewMatrix, // destination matrixmodelViewMatrix, // matrix to rotatecubeRotation * 0.7, // amount to rotate in radians[0, 1, 0]); // 旋转x轴mat4.rotate(modelViewMatrix, // destination matrixmodelViewMatrix, // matrix to rotatecubeRotation * 0.3, // amount to rotate in radians[1, 0, 0]); // Tell WebGL how to pull out the positions from the position// buffer into the vertexPosition attribute.setPositionAttribute(gl, buffers, programInfo);setColorAttribute(gl, buffers, programInfo);// buffers.indices 的索引缓冲区对象绑定到 WebGL 的 ELEMENT_ARRAY_BUFFER 目标上,以便在渲染时使用这个索引缓冲区对象gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffers.indices);// Tell WebGL to use our program when drawinggl.useProgram(programInfo.program);// Set the shader uniformsgl.uniformMatrix4fv(programInfo.uniformLocations.projectionMatrix,false,projectionMatrix);gl.uniformMatrix4fv(programInfo.uniformLocations.modelViewMatrix,false,modelViewMatrix);{// 定义了要绘制的顶点数量const vertexCount = 36;const type = gl.UNSIGNED_SHORT;// 从索引缓冲区中的哪个位置开始绘制。在这个例子中,从索引缓冲区的第一个索引开始绘制const offset = 0;gl.drawElements(gl.TRIANGLES, vertexCount, type, offset);}
}// Tell WebGL how to pull out the positions from the position
// buffer into the vertexPosition attribute.
function setPositionAttribute(gl, buffers, programInfo) {const numComponents = 3;const type = gl.FLOAT; // the data in the buffer is 32bit floatsconst normalize = false; // don't normalizeconst stride = 0; // how many bytes to get from one set of values to the next// 0 = use type and numComponents aboveconst offset = 0; // how many bytes inside the buffer to start fromgl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);gl.vertexAttribPointer(programInfo.attribLocations.vertexPosition,numComponents,type,normalize,stride,offset);gl.enableVertexAttribArray(programInfo.attribLocations.vertexPosition);
}// Tell WebGL how to pull out the colors from the color buffer
// into the vertexColor attribute.
function setColorAttribute(gl, buffers, programInfo) {const numComponents = 4;const type = gl.FLOAT;const normalize = false;const stride = 0;const offset = 0;gl.bindBuffer(gl.ARRAY_BUFFER, buffers.color);gl.vertexAttribPointer(programInfo.attribLocations.vertexColor,numComponents,type,normalize,stride,offset);gl.enableVertexAttribArray(programInfo.attribLocations.vertexColor);
}export { drawScene };

所以要想画立方体首先确定有多少个面,每个面由两个三角形构成,所以一个面需要四个顶点。由于每个面有四个顶点,并且每个面颜色不同,所以顶点也不能共享,同一个面的顶点颜色是一样的。索引值也因为每个面的颜色不一样导致不同面的索引值不能共享,同一个面的可以共享,共4*6个。

索引缓冲区(Index Buffer)

索引缓冲区是一种优化图形渲染的方式,它允许我们重复使用顶点数据来绘制多个面。如果不使用索引缓冲区,我们需要为每个面的每个顶点都提供完整的顶点数据,包括位置、颜色、纹理坐标等。这在有大量重复顶点的情况下,比如在绘制一个立方体时,可能会导致大量的数据冗余。

如果不使用索引,你将需要为每个三角形定义所有的顶点数据。例如,一个立方体由12个三角形组成,每个三角形有3个顶点,所以你需要定义36个顶点。这就需要更多的内存,因为你需要为每个顶点定义所有的属性(比如位置、颜色、纹理坐标等)。而且,GPU需要处理更多的数据,这可能会降低性能。

使用索引,你可以定义立方体的8个顶点,然后通过索引来定义立方体的12个三角形。这样,你只需要定义8个顶点的属性,然后使用索引来重复使用这些顶点。这可以减少内存使用,并提高性能,因为GPU需要处理的数据更少。

然而,使用索引也有一些限制。比如,如果你想让立方体的每个面有不同的颜色,你可能需要为每个面定义独立的顶点,因为颜色是顶点属性。这就减少了使用索引的优势,因为你不能重复使用顶点。

总的来说,是否使用索引取决于你的具体需求。在一些情况下,使用索引可以提高性能和减少内存使用。在其他情况下,可能需要为每个面定义独立的顶点。

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

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

相关文章

设计模式学习系列 -- 随记

文章目录 前言 一、设计模式是什么&#xff1f; 二、设计模式的历史 三、为什么以及如何学习设计模式&#xff1f; 四、关于模式的争议 一种针对不完善编程语言的蹩脚解决方案 低效的解决方案 不当使用 五、设计模式分类 总结 前言 最近可能工作生活上的稳定慢慢感觉自己丢失…

【轮式平衡机器人】——TMS320F28069片内外设之ePWM

声明&#xff1a;本系列博客参考有关专业书籍&#xff0c;截图均为自己实操&#xff0c;仅供交流学习&#xff01; 引入 脉冲宽度调制&#xff08;PWM&#xff09;是一种对模拟信号进行数字编码的方法&#xff0c;硬件原理是根据相应载荷的变化来调制晶体管栅极或基极的偏置&…

【c++】string模拟实现

string类的接口 namespace zjw {class string{public:typedef char* iterator;typedef const char* const_iterator;private:char* _str;int _size;int _capacity;};这里的迭代器直接使用原生指针来封装。 _str为指向string数组的首地址的指针。 _size为string数组的大小。 …

测试工具使用技巧01-->jmeter链接mysql

前言 在做接口或者性能测试的时候&#xff0c;有时需要jmeter连接数据库做操作&#xff0c;可以看看如下实例。操作实例 在mysql数据库中有如下数据表 在jmeter导入jdbc驱动插件&#xff08;需要的留言找我拿&#xff09; 在jmeter测试计划元件最下面&#xff0c;导入jdbc.…

Android平台实现无纸化同屏并推送RTMP或轻量级RTSP服务(毫秒级延迟)

技术背景 在写这篇文章之前&#xff0c;实际上几年之前&#xff0c;我们就有非常稳定的无纸化同屏的模块&#xff0c;本文借demo更新&#xff0c;算是做个新的总结&#xff0c;废话不多说&#xff0c;先看图&#xff0c;本文以Android平台屏幕实时采集推送&#xff0c;Windows…

ActiveRAG—主动学习

原文地址&#xff1a;ActiveRAG — Active Learning 2024 年 2 月 26 日 大型语言模型&#xff08;LLM&#xff09;的出现开创了对话式人工智能的新时代。这些模型可以生成非常类似人类的文本&#xff0c;并且比以往更好地进行对话。然而&#xff0c;他们仍然面临着仅仅依靠预先…

面试宝典-【redis】

目录 1.什么是缓存穿透 ? 怎么解决 ? 2.什么是布隆过滤器 3.什么是缓存击穿 ? 怎么解决 ? 4.什么是缓存雪崩 ? 怎么解决 ? 5.redis做为缓存&#xff0c;mysql数据如何与redis进行同步?(双写) 6.排他锁是如何保证读写、读读互斥的呢&#xff1f; 7.你听说过延…

【万题详解】洛谷P1616 疯狂的采药

题目背景 此题为纪念 LiYuxiang 而生。 题目描述 LiYuxiang 是个天资聪颖的孩子&#xff0c;他的梦想是成为世界上最伟大的医师。为此&#xff0c;他想拜附近最有威望的医师为师。医师为了判断他的资质&#xff0c;给他出了一个难题。医师把他带到一个到处都是草药的山洞里对…

什么是yocto基本组件(bitbake,recipes,classes,configuration,layer)

文章目录 1基本组件1.1 bitbake1.2 Recipes1.3 Classes1.4 Configurations2 层的理解2.1 层结构2.2 nxp yocto示例2.3 ti yocto示例1基本组件 1.1 bitbake bitbake,是OpenEmbedded构建系统的核心工具,负责解析元数据,从中生成任务列表,然后执行这些任务。bitbake是一个通…

C# LINQ运算符

LINQ运算符 1. 概述1.1 集合->集合1.1.1 筛选运算符1.1.2 映射运算符1.1.3 连接运算符1.1.4 排序运算符1.1.5 分组运算符1.1.6 集合运算符1.1.7 转换方法:Import1.1.8 转换方法:Export 1.2 集合->单个元素或标量值1.2.1 元素运算符1.2.2 聚合方法1.2.3 数量词 1.3 空->…

【MySQL 系列】MySQL 语句篇_DQL 语句

DQL&#xff08;Data Query Language&#xff09;&#xff0c;即数据查询语言&#xff0c;用来查询数据记录。DQL 基本结构由 SELECT FROM、WHERE、JOIN 等子句构成。 DQL 语句并不会改变数据库&#xff0c;而是让数据库将查询结果发送结果集给客户端&#xff0c;返回的结果是一…

软考72-上午题-【面向对象技术2-UML】-UML中的图3

一、状态图 1-1、状态图的定义 状态图&#xff0c;展现了一个状态机&#xff0c;由&#xff1a;状态、转换、事件和活动组成&#xff0c;是系统的动态视图。 活动(动作) 可以在状态内执行也可以在状态转换(迁移) 时执行。 状态图强调&#xff1a;行为的事件顺序。 1-2、状态图…

SpringBoot项目如何部署到服务器

文章目录 准备&#xff1a;方式一&#xff1a;Jar包方式&#xff08;推荐&#xff09;部署步骤&#xff1a; 方式二&#xff1a;War包方式部署步骤&#xff1a; 总结 准备&#xff1a; 云服务器&#xff08;阿里云、腾讯云等&#xff09;Linux系统以及运行所需的环境 方式一&a…

力扣--深度优先算法/回溯算法216.组合总和 Ⅲ

思路分析&#xff1a; 深度优先搜索 (DFS)&#xff1a; 通过递归实现&#xff0c;尝试从数字 1 到 9 中选择可能的数字&#xff0c;构建和为 n&#xff0c;长度为 k 的组合。递归函数 dfs&#xff1a; 接收参数&#xff1a;result 为最终结果集&#xff0c;path 为当前正在生成…

AWS认证:云计算领域的卓越里程碑

本文由云计算狂魔公众号提供 随着科技的飞速发展&#xff0c;云计算已成为企业与个人必备的技能之一。亚马逊网络服务&#xff08;Amazon Web Services&#xff0c;简称AWS&#xff09;作为全球领先的云计算服务提供商&#xff0c;其认证体系无疑是云计算领域的卓越里程碑。本…

【C++】二叉树进阶之二叉搜索树

> 作者简介&#xff1a;დ旧言~&#xff0c;目前大二&#xff0c;现在学习Java&#xff0c;c&#xff0c;c&#xff0c;Python等 > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;熟练掌握二叉搜索树&#xff0c;能自己模拟实现二…

Spring Boot的单元测试及示例代码

目录 1、单元测试&#xff08;非 Web 上下文&#xff09; 1.1、引入依赖 1.2 编写单元测试类(示例代码) 2、Spring MVC 控制器测试 2.1、创建控制器及映射方法 2.2 编写控制器测试类 Spring Boot 提供了强大的单元测试和集成测试支持&#xff0c;以简化基于 Spring 的应用…

类和对象-继承

师从黑马程序员 基本语法 有些类与类之间存在特殊的关系&#xff0c;例如&#xff1a; 定义这些类时&#xff0c;下一级别的成员除了拥有上一级的共性&#xff0c;还有自己的特性。 这时候我们就可以考虑继承技术&#xff0c;减少重复代码 语法&#xff1a;class 子类&…

RAG模型的挑战与解决方案概览

RAG模型的挑战与解决方案概览 背景: 提取增强生成(RAG)模型通过利用存储在文档中的外部知识来提高生成文本的准确性和相关性&#xff0c;显示出巨大潜力。但这些模型面临着多个挑战&#xff0c;如低质量检索、覆盖率不足、上下文条件化困难、幻觉和制造问题、解释和可解释性缺…

加密流量分类torch实践4:TrafficClassificationPandemonium项目更新

加密流量分类torch实践4&#xff1a;TrafficClassificationPandemonium项目更新 更新日志 代码已经推送开源至露露云的github&#xff0c;如果能帮助你&#xff0c;就给鼠鼠点一个star吧&#xff01;&#xff01;&#xff01; 3/10号更新 流量预处理更新 增加了基于splitCa…