分享WebGL物体三维建模

界面效果

代码结构

模型素材类似CT (Computed Tomography),即电子计算机断层扫描,它是利用精确准直的X线束、γ射线、超声波等,与灵敏度极高的探测器一同围绕物体的某一部位作一个接一个的断面扫描。

坐标系统

渲染流程

渲染流程是个将之前准备好的模型输出到屏幕的过程。3D 渲染流程会接受使用顶点描述 3D 物体的原始数据作为输入用于处理,并计算其片段 (fragment), 然后渲染为像素 (pixels) 输出到屏幕。

着色器

使用 GLSL 的着色器(shader),GLSL 是一门特殊的有着类似于 C 语言的语法,在图形管道 (graphic pipeline) 中直接可执行的 OpenGL 着色语言。着色器有两种类型——顶点着色器 (Vertex Shader) 和片段着色器(Fragment Shader)。前者是将形状转换到真实的 3D 绘制坐标中,后者是计算最终渲染的颜色和其他属性用的。

GLSL 不同于 JavaScript, 它是强类型语言,并且内置很多数学公式用于计算向量和矩阵。快速编写着色器非常复杂,但创建一个简单的着色器并不难。

一个着色器实际上就是一个绘制东西到屏幕上的函数。着色器运行在 GPU 中,它对这些操作进行了很多的优化,这样你就可以卸载很多不必要的 CPU, 然后集中处理能力去执行你自己的代码。

顶点着色器操作 3D 空间的坐标并且每个顶点都会调用一次这个函数。其目的是设置 gl_Position 变量——这是一个特殊的全局内置变量,它是用来存储当前顶点的位置。

片段 (或者纹理) 着色器 在计算时定义了每像素的 RGBA 颜色 — 每个像素只调用一次片段着色器。这个着色器的作用是设置 gl_FragColor 变量,也是一个 GLSL 内置变量。

        <script id="fragmentShaderFirstPass" type="x-shader/x-fragment">varying vec3 worldSpaceCoords;void main(){//The fragment's world space coordinates as fragment output.gl_FragColor = vec4( worldSpaceCoords.x , worldSpaceCoords.y, worldSpaceCoords.z, 1 );}</script><script id="vertexShaderFirstPass" type="x-shader/x-vertex">varying vec3 worldSpaceCoords;void main(){//Set the world space coordinates of the back faces vertices as output.worldSpaceCoords = position + vec3(0.5, 0.5, 0.5); //move it from [-0.5;0.5] to [0,1]gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );}</script><script id="fragmentShaderSecondPass" type="x-shader/x-fragment">varying vec3 worldSpaceCoords;varying vec4 projectedCoords;uniform sampler2D tex, cubeTex, transferTex;uniform float steps;uniform float alphaCorrection;// The maximum distance through our rendering volume is sqrt(3).// The maximum number of steps we take to travel a distance of 1 is 512.// ceil( sqrt(3) * 512 ) = 887// This prevents the back of the image from getting cut off when steps=512 & viewing diagonally.const int MAX_STEPS = 887;//Acts like a texture3D using Z slices and trilinear filtering.vec4 sampleAs3DTexture( vec3 texCoord ){vec4 colorSlice1, colorSlice2;vec2 texCoordSlice1, texCoordSlice2;//The z coordinate determines which Z slice we have to look for.//Z slice number goes from 0 to 255.float zSliceNumber1 = floor(texCoord.z  * 255.0);//As we use trilinear we go the next Z slice.float zSliceNumber2 = min( zSliceNumber1 + 1.0, 255.0); //Clamp to 255//The Z slices are stored in a matrix of 16x16 of Z slices.//The original UV coordinates have to be rescaled by the tile numbers in each row and column.texCoord.xy /= 16.0;texCoordSlice1 = texCoordSlice2 = texCoord.xy;//Add an offset to the original UV coordinates depending on the row and column number.texCoordSlice1.x += (mod(zSliceNumber1, 16.0 ) / 16.0);texCoordSlice1.y += floor((255.0 - zSliceNumber1) / 16.0) / 16.0;texCoordSlice2.x += (mod(zSliceNumber2, 16.0 ) / 16.0);texCoordSlice2.y += floor((255.0 - zSliceNumber2) / 16.0) / 16.0;//Get the opacity value from the 2D texture.//Bilinear filtering is done at each texture2D by default.colorSlice1 = texture2D( cubeTex, texCoordSlice1 );colorSlice2 = texture2D( cubeTex, texCoordSlice2 );//Based on the opacity obtained earlier, get the RGB color in the transfer function texture.colorSlice1.rgb = texture2D( transferTex, vec2( colorSlice1.a, 1.0) ).rgb;colorSlice2.rgb = texture2D( transferTex, vec2( colorSlice2.a, 1.0) ).rgb;//How distant is zSlice1 to ZSlice2. Used to interpolate between one Z slice and the other.float zDifference = mod(texCoord.z * 255.0, 1.0);//Finally interpolate between the two intermediate colors of each Z slice.return mix(colorSlice1, colorSlice2, zDifference) ;}void main( void ) {//Transform the coordinates it from [-1;1] to [0;1]vec2 texc = vec2(((projectedCoords.x / projectedCoords.w) + 1.0 ) / 2.0,((projectedCoords.y / projectedCoords.w) + 1.0 ) / 2.0 );//The back position is the world space position stored in the texture.vec3 backPos = texture2D(tex, texc).xyz;//The front position is the world space position of the second render pass.vec3 frontPos = worldSpaceCoords;//The direction from the front position to back position.vec3 dir = backPos - frontPos;float rayLength = length(dir);//Calculate how long to increment in each step.float delta = 1.0 / steps;//The increment in each direction for each step.vec3 deltaDirection = normalize(dir) * delta;float deltaDirectionLength = length(deltaDirection);//Start the ray casting from the front position.vec3 currentPosition = frontPos;//The color accumulator.vec4 accumulatedColor = vec4(0.0);//The alpha value accumulated so far.float accumulatedAlpha = 0.0;//How long has the ray travelled so far.float accumulatedLength = 0.0;//If we have twice as many samples, we only need ~1/2 the alpha per sample.//Scaling by 256/10 just happens to give a good value for the alphaCorrection slider.float alphaScaleFactor = 25.6 * delta;vec4 colorSample;float alphaSample;//Perform the ray marching iterationsfor(int i = 0; i < MAX_STEPS; i++){//Get the voxel intensity value from the 3D texture.colorSample = sampleAs3DTexture( currentPosition );//Allow the alpha correction customization.alphaSample = colorSample.a * alphaCorrection;//Applying this effect to both the color and alpha accumulation results in more realistic transparency.alphaSample *= (1.0 - accumulatedAlpha);//Scaling alpha by the number of steps makes the final color invariant to the step size.alphaSample *= alphaScaleFactor;//Perform the composition.accumulatedColor += colorSample * alphaSample;//Store the alpha accumulated so far.accumulatedAlpha += alphaSample;//Advance the ray.currentPosition += deltaDirection;accumulatedLength += deltaDirectionLength;//If the length traversed is more than the ray length, or if the alpha accumulated reaches 1.0 then exit.if(accumulatedLength >= rayLength || accumulatedAlpha >= 1.0 )break;}gl_FragColor  = accumulatedColor;}</script><script id="vertexShaderSecondPass" type="x-shader/x-vertex">varying vec3 worldSpaceCoords;varying vec4 projectedCoords;void main(){worldSpaceCoords = (modelMatrix * vec4(position + vec3(0.5, 0.5,0.5), 1.0 )).xyz;gl_Position = projectionMatrix *  modelViewMatrix * vec4( position, 1.0 );projectedCoords =  projectionMatrix * modelViewMatrix * vec4( position, 1.0 );}</script>

三维场景构建

         <script>if ( ! Detector.webgl ) Detector.addGetWebGLMessage();var container, stats;var camera, sceneFirstPass, sceneSecondPass, renderer;var clock = new THREE.Clock();var rtTexture, transferTexture;var cubeTextures = ['bonsai', 'foot', 'teapot'];var histogram = [];var guiControls;var materialSecondPass;init();//animate();function init() {//Parameters that can be modified.guiControls = new function() {this.model = 'bonsai';this.steps = 256.0;this.alphaCorrection = 1.0;this.color1 = "#00FA58";this.stepPos1 = 0.1;this.color2 = "#CC6600";this.stepPos2 = 0.7;this.color3 = "#F2F200";this.stepPos3 = 1.0;};container = document.getElementById( 'container' );camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 0.01, 3000.0 );camera.position.z = 2.0;controls = new THREE.OrbitControls( camera, container );controls.center.set( 0.0, 0.0, 0.0 );//Load the 2D texture containing the Z slices.THREE.ImageUtils.crossOrigin = 'anonymous'; //处理纹理图加载跨域问题cubeTextures['bonsai'] = THREE.ImageUtils.loadTexture('./images/bonsai.raw.png');cubeTextures['teapot'] = THREE.ImageUtils.loadTexture('./images/teapot.raw.png');cubeTextures['foot'] = THREE.ImageUtils.loadTexture('./images/foot.raw.png');//Don't let it generate mipmaps to save memory and apply linear filtering to prevent use of LOD.cubeTextures['bonsai'].generateMipmaps = false;cubeTextures['bonsai'].minFilter = THREE.LinearFilter;cubeTextures['bonsai'].magFilter = THREE.LinearFilter;cubeTextures['teapot'].generateMipmaps = false;cubeTextures['teapot'].minFilter = THREE.LinearFilter;cubeTextures['teapot'].magFilter = THREE.LinearFilter;cubeTextures['foot'].generateMipmaps = false;cubeTextures['foot'].minFilter = THREE.LinearFilter;cubeTextures['foot'].magFilter = THREE.LinearFilter;var transferTexture = updateTransferFunction();var screenSize = new THREE.Vector2( window.innerWidth, window.innerHeight );rtTexture = new THREE.WebGLRenderTarget( screenSize.x, screenSize.y,{ 	minFilter: THREE.LinearFilter,magFilter: THREE.LinearFilter,wrapS:  THREE.ClampToEdgeWrapping,wrapT:  THREE.ClampToEdgeWrapping,format: THREE.RGBFormat,type: THREE.FloatType,generateMipmaps: false} );var materialFirstPass = new THREE.ShaderMaterial( {vertexShader: document.getElementById( 'vertexShaderFirstPass' ).textContent,fragmentShader: document.getElementById( 'fragmentShaderFirstPass' ).textContent,side: THREE.BackSide} );materialSecondPass = new THREE.ShaderMaterial( {vertexShader: document.getElementById( 'vertexShaderSecondPass' ).textContent,fragmentShader: document.getElementById( 'fragmentShaderSecondPass' ).textContent,side: THREE.FrontSide,uniforms: {	tex:  { type: "t", value: rtTexture },cubeTex:  { type: "t", value: cubeTextures['bonsai'] },transferTex:  { type: "t", value: transferTexture },steps : {type: "1f" , value: guiControls.steps },alphaCorrection : {type: "1f" , value: guiControls.alphaCorrection }}});sceneFirstPass = new THREE.Scene();sceneSecondPass = new THREE.Scene();var boxGeometry = new THREE.BoxGeometry(1.0, 1.0, 1.0);boxGeometry.doubleSided = true;var meshFirstPass = new THREE.Mesh( boxGeometry, materialFirstPass );var meshSecondPass = new THREE.Mesh( boxGeometry, materialSecondPass );sceneFirstPass.add( meshFirstPass );sceneSecondPass.add( meshSecondPass );renderer = new THREE.WebGLRenderer();container.appendChild( renderer.domElement );stats = new Stats();stats.domElement.style.position = 'absolute';stats.domElement.style.top = '0px';container.appendChild( stats.domElement );var gui = new dat.GUI();var modelSelected = gui.add(guiControls, 'model', [ 'bonsai', 'foot', 'teapot' ] );gui.add(guiControls, 'steps', 0.0, 512.0);gui.add(guiControls, 'alphaCorrection', 0.01, 5.0).step(0.01);modelSelected.onChange(function(value) { materialSecondPass.uniforms.cubeTex.value =  cubeTextures[value]; } );//Setup transfer function steps.var step1Folder = gui.addFolder('Step 1');var controllerColor1 = step1Folder.addColor(guiControls, 'color1');var controllerStepPos1 = step1Folder.add(guiControls, 'stepPos1', 0.0, 1.0);controllerColor1.onChange(updateTextures);controllerStepPos1.onChange(updateTextures);var step2Folder = gui.addFolder('Step 2');var controllerColor2 = step2Folder.addColor(guiControls, 'color2');var controllerStepPos2 = step2Folder.add(guiControls, 'stepPos2', 0.0, 1.0);controllerColor2.onChange(updateTextures);controllerStepPos2.onChange(updateTextures);var step3Folder = gui.addFolder('Step 3');var controllerColor3 = step3Folder.addColor(guiControls, 'color3');var controllerStepPos3 = step3Folder.add(guiControls, 'stepPos3', 0.0, 1.0);controllerColor3.onChange(updateTextures);controllerStepPos3.onChange(updateTextures);step1Folder.open();step2Folder.open();step3Folder.open();onWindowResize();window.addEventListener( 'resize', onWindowResize, false );}function imageLoad(url){   var image = document.createElement('img');image.crossOrigin = '';image.src = url;var loader = new THREE.TextureLoader();// load a resourceconst textureAssets = nullloader.load(// resource URLimage,// Function when resource is loadedfunction ( texture ) {// do something with the texturetexture.wrapS = THREE.RepeatWrapping;texture.wrapT = THREE.RepeatWrapping;texture.offset.x = 90/(2*Math.PI);textureAssets = texture},// Function called when download progressesfunction ( xhr ) {console.log( (xhr.loaded / xhr.total * 100) + '% loaded' );},// Function called when download errorsfunction ( xhr ) {console.log( 'An error happened' );});return textureAssets; // return the texture}function updateTextures(value){materialSecondPass.uniforms.transferTex.value = updateTransferFunction();}function updateTransferFunction(){var canvas = document.createElement('canvas');canvas.height = 20;canvas.width = 256;var ctx = canvas.getContext('2d');var grd = ctx.createLinearGradient(0, 0, canvas.width -1 , canvas.height - 1);grd.addColorStop(guiControls.stepPos1, guiControls.color1);grd.addColorStop(guiControls.stepPos2, guiControls.color2);grd.addColorStop(guiControls.stepPos3, guiControls.color3);ctx.fillStyle = grd;ctx.fillRect(0,0,canvas.width -1 ,canvas.height -1 );var img = document.getElementById("transferFunctionImg");img.src = canvas.toDataURL();img.style.width = "256 px";img.style.height = "128 px";transferTexture =  new THREE.Texture(canvas);transferTexture.wrapS = transferTexture.wrapT =  THREE.ClampToEdgeWrapping;transferTexture.needsUpdate = true;return transferTexture;}function onWindowResize( event ) {camera.aspect = window.innerWidth / window.innerHeight;camera.updateProjectionMatrix();renderer.setSize( window.innerWidth, window.innerHeight );}function animate() {requestAnimationFrame( animate );render();stats.update();}function render() {var delta = clock.getDelta();//Render first pass and store the world space coords of the back face fragments into the texture.renderer.render( sceneFirstPass, camera, rtTexture, true );//Render the second pass and perform the volume rendering.renderer.render( sceneSecondPass, camera );materialSecondPass.uniforms.steps.value = guiControls.steps;materialSecondPass.uniforms.alphaCorrection.value = guiControls.alphaCorrection;}//Leandro R Barbagallo - 2015 - lebarba at gmail.comconst VSHADER_SOURCE = `attribute vec4 a_Position;attribute vec2 a_uv;varying vec2 v_uv;void main() {gl_Position = a_Position;v_uv = a_uv;}`const FSHADER_SOURCE = `precision mediump float;// 定义一个取样器。sampler2D 是一种数据类型,就像 vec2uniform sampler2D u_Sampler;uniform sampler2D u_Sampler2;varying vec2 v_uv;void main() {// texture2D(sampler2D sampler, vec2 coord) - 着色器语言内置函数,从 sampler 指定的纹理上获取 coord 指定的纹理坐标处的像素vec4 color = texture2D(u_Sampler, v_uv);vec4 color2 = texture2D(u_Sampler2, v_uv);gl_FragColor = color * color2;}`function main() {const canvas = document.getElementById('webgl');const gl = canvas.getContext("webgl");if (!gl) {console.log('Failed to get the rendering context for WebGL');return;}if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {console.log('Failed to intialize shaders.');return;}gl.clearColor(0.0, 0.5, 0.5, 1.0);// 几何图形的4个顶点的坐标const verticesOfPosition = new Float32Array([// 左下角是第一个点,逆时针-0.5, -0.5,0.5, -0.5,0.5, 0.5,-0.5, 0.5,])// 纹理的4个点的坐标const uvs = new Float32Array([// 左下角是第一个点,逆时针,与顶点坐标保持对应0.0, 0.0,1.0, 0.0,1.0, 1.0,0.0, 1.0])initVertexBuffers(gl, verticesOfPosition)initUvBuffers(gl, uvs)initTextures(gl)initMaskTextures(gl)}// 初始化纹理。之所以为复数 s 是因为可以贴多张图片。function initTextures(gl) {// 定义图片const img = new Image();// 请求 CORS 许可。解决图片跨域问题img.crossOrigin = "";// The image element contains cross-origin data, and may not be loaded.img.src = "./images/bonsai.raw.png";img.onload = () => {// 创建纹理const texture = gl.createTexture();// 取得取样器const u_Sampler = gl.getUniformLocation(gl.program, 'u_Sampler');if (!u_Sampler) {console.log('Failed to get the storage location of u_Sampler');return false;}// pixelStorei - 图像预处理:图片上下对称翻转坐标轴 (图片本身不变)gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);// 激活纹理单元gl.activeTexture(gl.TEXTURE0);// 绑定纹理对象gl.bindTexture(gl.TEXTURE_2D, texture);// 配置纹理参数gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.MIRRORED_REPEAT);// 纹理图片分配给纹理对象gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, img);// 将纹理单元传给片元着色器gl.uniform1i(u_Sampler, 0);gl.clear(gl.COLOR_BUFFER_BIT);gl.drawArrays(gl.TRIANGLE_FAN, 0, 4);}}// 初始化纹理。之所以为复数 s 是因为可以贴多张图片。function initMaskTextures(gl) {const img = new Image();img.src = "./images/teapot.raw.png";img.onload = () => {// 创建纹理const texture = gl.createTexture();// 取得取样器const u_Sampler = gl.getUniformLocation(gl.program, 'u_Sampler2');if (!u_Sampler) {console.log('Failed to get the storage location of u_Sampler');return false;}// pixelStorei - 图像预处理:图片上下对称翻转坐标轴 (图片本身不变)gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);// 激活纹理单元gl.activeTexture(gl.TEXTURE1);// 绑定纹理对象gl.bindTexture(gl.TEXTURE_2D, texture);// 配置纹理参数gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);// 纹理图片分配给纹理对象gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, img);// 将纹理单元传给片元着色器gl.uniform1i(u_Sampler, 1);gl.clear(gl.COLOR_BUFFER_BIT);gl.drawArrays(gl.TRIANGLE_FAN, 0, 4);}}function initVertexBuffers(gl, positions) {const vertexBuffer = gl.createBuffer();if (!vertexBuffer) {console.log('创建缓冲区对象失败');return -1;}gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);const a_Position = gl.getAttribLocation(gl.program, 'a_Position');if (a_Position < 0) {console.log('Failed to get the storage location of a_Position');return -1;}gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);gl.enableVertexAttribArray(a_Position);}function initUvBuffers(gl, uvs) {const uvsBuffer = gl.createBuffer();if (!uvsBuffer) {console.log('创建 uvs 缓冲区对象失败');return -1;}gl.bindBuffer(gl.ARRAY_BUFFER, uvsBuffer);gl.bufferData(gl.ARRAY_BUFFER, uvs, gl.STATIC_DRAW);const a_uv = gl.getAttribLocation(gl.program, 'a_uv');if (a_uv < 0) {console.log('Failed to get the storage location of a_uv');return -1;}gl.vertexAttribPointer(a_uv, 2, gl.FLOAT, false, 0, 0);gl.enableVertexAttribArray(a_uv);}</script>

环境设置


你只需关注着色器代码。Three.js 和其他 3D 库给你抽象了很多东西出来——如果你想要用纯 WebGL 创建这个例子,你得写很多其他的代码才能运行。要开始编写 WebGL 着色器你不需要做太多,只需如下三步:

1、确保你在使用对 WebGL 有良好支持的现代浏览器,比如最新版的 Firefox 或 Chrome.
2、创建一个目录保存你的实验。
3、拷贝一份的 压缩版的 Three.js 库 到你的目录。

参见:

LearnOpenGL - Coordinate Systems

WebGL model view projection - Web API 接口参考 | MDN

GLSL 着色器 - 游戏开发 | MDN

解释基本的 3D 原理 - 游戏开发 | MDN

Lebarba - WebGL Volume Rendering made easy

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

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

相关文章

Sora:OpenAI引领AI视频新时代

Sora - 探索AI视频模型的无限可能 随着人工智能技术的飞速发展&#xff0c;AI视频模型已成为科技领域的新热点。而在这个浪潮中&#xff0c;OpenAI推出的首个AI视频模型Sora&#xff0c;以其卓越的性能和前瞻性的技术&#xff0c;引领着AI视频领域的创新发展。让我们将一起探讨…

【SpringCloud】使用 Spring Cloud Alibaba 之 Sentinel 实现微服务的限流、降级、熔断

目录 一、Sentinel 介绍1.1 什么是 Sentinel1.2 Sentinel 特性1.3 限流、降级与熔断的区别 二、实战演示2.1 下载启动 Sentinel 控制台2.2 后端微服务接入 Sentinel 控制台2.2.1 引入 Sentinel 依赖2.2.2 添加 Sentinel 连接配置 2.3 使用 Sentinel 进行流控&#xff08;含限流…

如何将cocos2d-x js打包部署到ios上 Mac M1系统

项目环境 cocos2d-x 3.13 xcode 12 mac m1 big sur 先找到你的项目 使用xcode软件打开上面这个文件 打开后应该是这个样子 执行编译运行就好了 可能会碰到的错误 在xcode11版本以上都会有这个错误&#xff0c;这是因为iOS11废弃了system。 将上面代码修改为 #if (CC_TARGE…

Java 面向对象进阶 16 接口的细节:成员特点和接口的各种关系(黑马)

成员变量默认修饰符是public static final的原因是&#xff1a; Java中接口中成员变量默认修饰符是public static final的原因是为了确保接口的成员变量都是公共的、静态的和不可修改的。 - public修饰符确保了接口的成员变量可以在任何地方被访问到。 - static修饰符使得接口…

vue-利用属性(v-if)控制表单(el-form-item)显示/隐藏

表单控制属性 v-if 示例&#xff1a; 通过switch组件作为开关&#xff0c;控制表单的显示与隐藏 <el-form-item label"创建数据集"><el-switch v-model"selectFormVisible"></el-switch></el-form-item><el-form-item label&…

Redis篇----第七篇

系列文章目录 文章目录 系列文章目录前言一、Redis 的回收策略(淘汰策略)?二、为什么 edis 需要把所有数据放到内存中?三、Redis 的同步机制了解么?四、Pipeline 有什么好处,为什么要用 pipeline?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍…

crontab history查看命令的执行时间

crontab crontab学习网站&#xff08;19. crontab 定时任务 — Linux Tools Quick Tutorial&#xff09; 例子 今天实际工作里用到的&#xff08;已经进行了防信息泄露处理 比如我现在希望每周三上午10:00之行一个php脚本 --gpt生成 00 10 * * 3 cd /home/user/project/r…

阿里云SSL免费证书到期自动申请部署程序

阿里云的免费证书只有3个月的有效期&#xff0c;不注意就过期了&#xff0c;还要手动申请然后部署&#xff0c;很是麻烦&#xff0c;于是写了这个小工具。上班期间抽空写的&#xff0c;没有仔细测试&#xff0c;可能存在一些问题&#xff0c;大家可以自己clone代码改改&#xf…

【大模型 数据增强】LLMAAA:使用 LLMs 作为数据标注器

【大模型 数据增强】LLMAAA&#xff1a;使用 LLMs 作为数据标注器 提出背景算法步骤1. LLM作为活跃标注者&#xff08;LLMAAA&#xff09;2. k-NN示例检索与标签表述化3. 活跃学习策略4. 自动重权技术 LLMAAA 框架1. LLM Annotator2. Active Acquisition3. Robust Training 总结…

SkyWalking之APM无侵入可观测原理分析

一、 简介&#xff08;为什么需要用到可观测能力&#xff09; 随着微服务的开发模式的兴起&#xff0c;早期的单体架构系统已拆分为很多的子系统&#xff0c;各个子系统封装为微服务&#xff0c;各服务间通过HTTP协议RESET API或者RPC协议进行调用。 在单体服务或者微服务较少的…

8:00面试,8:05就出来了 ,问的实在是....

从外包出来&#xff0c;没想到竟然死在了另一家厂子 自从加入这家公司&#xff0c;每天都在加班&#xff0c;钱倒是给的不少&#xff0c;所以我也就忍了。没想到12月一纸通知&#xff0c;所有人都不许加班&#xff0c;薪资直降30%&#xff0c;顿时有吃不起饭的赶脚。 好在有个…

ESP8266智能家居(2)——8266发布数据到mqtt服务器

1.公共服务器 学习物联网就离不开服务器&#xff0c;如果你资金充足的话&#xff0c;可以自己购买或者租用一个服务器。本次我选择&#xff0c;使用免费的公共MQTT服务器。它的端口及Broker信息如下&#xff1a; 网址为&#xff1a; 免费的公共 MQTT 服务器 | EMQ (emqx.com)h…

LLMChain使用 | RouterChain的使用 - 用本地大模型搭建多Agents

单个本地大模型搭建参考博客 单个Chain&#xff1a;面对一个需求&#xff0c;我们需要创建一个llmchain&#xff0c;设置一个prompt模板&#xff0c;这个chain能够接收一个用户input&#xff0c;并输出一个结果&#xff1b;多个Chain&#xff1a;考虑到同时面对多个需求&#x…

第三百六十回

文章目录 1. 概念介绍2. 实现方法2.1 环绕效果2.2 立体效果 3. 示例代码4. 内容总结 我们在上一章回中介绍了"自定义SlideImageSwitch组件"相关的内容&#xff0c;本章回中将介绍两种阴影效果.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在本…

设计模式-创建型模式-原型模式

原型模式&#xff08;Prototype Pattern&#xff09;&#xff1a;使用原型实例指定创建对象的种类&#xff0c;并且通过克隆这些原型创建新的对象。原型模式是一种对象创建型模式。原型模式其实就是从一个对象再创建另外一个可定制的对象&#xff0c;而且不需知道任何创建的细节…

微信小程序开发学习笔记——2.8媒体组件image的src三种引入方式

>>跟着b站up主“咸虾米_”学习微信小程序开发中&#xff0c;把学习记录存到这方便后续查找。 课程连接&#xff1a; https://www.bilibili.com/video/BV19G4y1K74d?p11 image&#xff1a;https://developers.weixin.qq.com/miniprogram/dev/component/image.html 一…

Redis-内存管理

Redis是基于内存存储的&#xff0c;非关系型&#xff0c;键值对数据库。因此&#xff0c;对Redis来说&#xff0c;内存空间的管理至关重要。那Redis是如何内存管理的呢&#xff1f; 一、最大内存限制 Redis 提供了 maxmemory 参数允许用户设置 Redis 可以使用的最大内存大小。…

js设计模式:依赖注入模式

作用: 在对象外部完成两个对象的注入绑定等操作 这样可以将代码解耦,方便维护和扩展 vue中使用use注册其他插件就是在外部创建依赖关系的 示例: class App{constructor(appName,appFun){this.appName appNamethis.appFun appFun}}class Phone{constructor(app) {this.nam…

Elastic Search:构建语义搜索体验

当你逐步熟悉 Elastic 时&#xff0c;你将使用 Elasticsearch Relevance Engine™ (ESRE)&#xff0c;该引擎旨在为 AI 搜索应用程序提供支持。 借助 ESRE&#xff0c;你可以利用一套开发人员工具&#xff0c;包括 Elastic 的文本搜索、向量数据库和我们用于语义搜索的专有转换…

ngnix网站服务详解

一 Nginx的简介 1 Nginx&#xff1a; ①Nginx 是开源、高性能、高可靠的 Web 和反向代理服务器&#xff0c;而且支持热部署&#xff0c;几乎可以做到 7 * 24 小时不间断运行&#xff0c;即使运行几个月也不需要重新启动&#xff0c;还能在不间断服务的情况下对软件版本进行热…