WebGL 切换着色器

目录

前言 

如何实现切换着色器 

1. 准备用来绘制单色立方体的着色器

2. 准备用来绘制纹理立方体的着色器

3. 调用createProgram()函数,利用第1步创建出的着色器,创建着色器程序对象

4. 调用createProgram()函数,利用第2步创建出的着色器,创建着色器程序对象

5. 调用gl.useProgram()函数,指定使用第3步创建出的着色器程序对象。

6. 通过缓冲区对象向着色器中传入attribute变量并开启之。

7. 绘制单色立方体

8. 调用gl.useProgram()函数,指定使用第4步创建出的着色器程序对象。

9. 通过缓冲区对象向着色器传入attribute变量并开启之。

10. 绘制纹理立方体

示例程序(ProgramObject.js)

示例效果

示例代码

代码详解 


前言 

WebGL中,如果一个着色器就能绘制出场景中所有的物体,那就没有问题。然而事实是,对不同的物体经常需要使用不同的着色器来绘制,每个着色器中可能有非常复杂的逻辑以实现各种不同的效果。我们可以准备多个着色器,然后根据需要来切换使用它们。本文的示例程序ProgramObject就使用了两个着色器绘制了两个立方体,一个是纯色的,另一个贴有纹理。下图显示了程序的运行效果。

该程序也可以帮你复习一下如何在物体表面贴上纹理。 

如何实现切换着色器 

 为了切换着色器,需要先创建多个着色器程序对象,然后在进行绘制前选择使用的程序对象。我们使用gl.useProgram()函数来进行切换。由于现在需要显式地操作着色器和程序对象,所以不能再使用initShaders()函数了。但是,可以使用定义在cuon-utils.js中的createProgram()函数,实际上initShaders()函数内部也是调用该函数来创建着色器对象的。

下面是示例程序的流程步骤,由于它创建了两个程序对象,做了两轮相同的操作,所以看上去有点长。关键的代码实际上很简单。

1. 准备用来绘制单色立方体的着色器

2. 准备用来绘制纹理立方体的着色器

3. 调用createProgram()函数,利用第1步创建出的着色器,创建着色器程序对象

4. 调用createProgram()函数,利用第2步创建出的着色器,创建着色器程序对象

5. 调用gl.useProgram()函数,指定使用第3步创建出的着色器程序对象。

6. 通过缓冲区对象向着色器中传入attribute变量并开启之。

7. 绘制单色立方体

8. 调用gl.useProgram()函数,指定使用第4步创建出的着色器程序对象。

9. 通过缓冲区对象向着色器传入attribute变量并开启之。

10. 绘制纹理立方体

下面看一下示例程序 

示例程序(ProgramObject.js)

如下显示了示例程序中的上述第1步到第4步。我们准备了顶点着色器和片元着色器各两种:SOLID_VSHADER_SOURCE(第1行),SOLID_FSHADER_SOURCE(第15行),TEXTURE_VSHADER_SOURCE(第24行),TEXTURE_FSHADER_SOURCE(第39行)。前两者用来绘制单色的立方体,而后两者绘制贴有纹理的立方体。由于本文的重点是如何切换着色器程序对象,所以着色器的具体内容被省略了。

示例效果

示例代码

var SOLID_VSHADER_SOURCE = // 单色立方体 顶点着色器'attribute vec4 a_Position;\n' +'attribute vec4 a_Normal;\n' +'uniform mat4 u_MvpMatrix;\n' +'uniform mat4 u_NormalMatrix;\n' +'varying vec4 v_Color;\n' +'void main() {\n' +'  vec3 lightDirection = vec3(0.0, 0.0, 1.0);\n' + // 光线方向'  vec4 color = vec4(0.0, 1.0, 1.0, 1.0);\n' +     // 表面颜色'  gl_Position = u_MvpMatrix * a_Position;\n' +'  vec3 normal = normalize(vec3(u_NormalMatrix * a_Normal));\n' + // 归一化模型矩阵变换后的法向量'  float nDotL = max(dot(normal, lightDirection), 0.0);\n' + // 点积 (光线/法向量 -> cosΘ)'  v_Color = vec4(color.rgb * nDotL, color.a);\n' +'}\n';
var SOLID_FSHADER_SOURCE = // 单色立方体 片元着色器'#ifdef GL_ES\n' +'precision mediump float;\n' +'#endif\n' +'varying vec4 v_Color;\n' +'void main() {\n' +'  gl_FragColor = v_Color;\n' +'}\n';var TEXTURE_VSHADER_SOURCE = // 纹理立方体 顶点着色器'attribute vec4 a_Position;\n' +'attribute vec4 a_Normal;\n' +'attribute vec2 a_TexCoord;\n' +'uniform mat4 u_MvpMatrix;\n' +'uniform mat4 u_NormalMatrix;\n' +'varying float v_NdotL;\n' +'varying vec2 v_TexCoord;\n' +'void main() {\n' +'  vec3 lightDirection = vec3(0.0, 0.0, 1.0);\n' + // 光线方向'  gl_Position = u_MvpMatrix * a_Position;\n' +'  vec3 normal = normalize(vec3(u_NormalMatrix * a_Normal));\n' +'  v_NdotL = max(dot(normal, lightDirection), 0.0);\n' +'  v_TexCoord = a_TexCoord;\n' +'}\n';
var TEXTURE_FSHADER_SOURCE = // 纹理立方体 片元着色器'#ifdef GL_ES\n' +'precision mediump float;\n' +'#endif\n' +'uniform sampler2D u_Sampler;\n' +'varying vec2 v_TexCoord;\n' +'varying float v_NdotL;\n' +'void main() {\n' +'  vec4 color = texture2D(u_Sampler, v_TexCoord);\n' +'  gl_FragColor = vec4(color.rgb * v_NdotL, color.a);\n' +'}\n';function main() {var canvas = document.getElementById('webgl');var gl = getWebGLContext(canvas);var solidProgram = createProgram(gl, SOLID_VSHADER_SOURCE, SOLID_FSHADER_SOURCE);var texProgram = createProgram(gl, TEXTURE_VSHADER_SOURCE, TEXTURE_FSHADER_SOURCE);// 获取单色绘图程序对象中属性和统一变量的存储位置solidProgram.a_Position = gl.getAttribLocation(solidProgram, 'a_Position');solidProgram.a_Normal = gl.getAttribLocation(solidProgram, 'a_Normal');solidProgram.u_MvpMatrix = gl.getUniformLocation(solidProgram, 'u_MvpMatrix');solidProgram.u_NormalMatrix = gl.getUniformLocation(solidProgram, 'u_NormalMatrix');// 获取纹理绘制程序对象中属性和统一变量的存储位置texProgram.a_Position = gl.getAttribLocation(texProgram, 'a_Position');texProgram.a_Normal = gl.getAttribLocation(texProgram, 'a_Normal');texProgram.a_TexCoord = gl.getAttribLocation(texProgram, 'a_TexCoord');texProgram.u_MvpMatrix = gl.getUniformLocation(texProgram, 'u_MvpMatrix');texProgram.u_NormalMatrix = gl.getUniformLocation(texProgram, 'u_NormalMatrix');texProgram.u_Sampler = gl.getUniformLocation(texProgram, 'u_Sampler');// 设置顶点信息var cube = initVertexBuffers(gl);// 设置纹理var texture = initTextures(gl, texProgram);// 设置透明颜色并启用深度测试gl.enable(gl.DEPTH_TEST);gl.clearColor(0.0, 0.0, 0.0, 1.0);var viewProjMatrix = new Matrix4();viewProjMatrix.setPerspective(30.0, canvas.width / canvas.height, 1.0, 100.0);viewProjMatrix.lookAt(0.0, 0.0, 15.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);// 开始绘制var currentAngle = 0.0; // 当前旋转角度(度)var tick = function () {currentAngle = animate(currentAngle);  // 更新当前旋转角度gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);// 用单色绘制立方体drawSolidCube(gl, solidProgram, cube, -2.0, currentAngle, viewProjMatrix);// 绘制具有纹理的立方体drawTexCube(gl, texProgram, cube, texture, 2.0, currentAngle, viewProjMatrix);window.requestAnimationFrame(tick, canvas);};tick();
}function initVertexBuffers(gl) {//    v6----- v5//   /|      /|//  v1------v0|//  | |     | |//  | |v7---|-|v4//  |/      |///  v2------v3var vertices = new Float32Array([   // 顶点坐标1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0,    // v0-v1-v2-v3 front1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0,    // v0-v3-v4-v5 right1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0,    // v0-v5-v6-v1 up-1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0,    // v1-v6-v7-v2 left-1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0,    // v7-v4-v3-v2 down1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0     // v4-v7-v6-v5 back]);var 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]);var texCoords = new Float32Array([   // 纹理坐标1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0,    // v0-v1-v2-v3 front0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0,    // v0-v3-v4-v5 right1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0,    // v0-v5-v6-v1 up1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0,    // v1-v6-v7-v2 left0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0,    // v7-v4-v3-v2 down0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0     // v4-v7-v6-v5 back]);var indices = 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]);var o = new Object(); // 使用该对象返回多个缓冲区对象// 将顶点信息写入缓冲区对象o.vertexBuffer = initArrayBufferForLaterUse(gl, vertices, 3, gl.FLOAT);o.normalBuffer = initArrayBufferForLaterUse(gl, normals, 3, gl.FLOAT);o.texCoordBuffer = initArrayBufferForLaterUse(gl, texCoords, 2, gl.FLOAT);o.indexBuffer = initElementArrayBufferForLaterUse(gl, indices, gl.UNSIGNED_BYTE);o.numIndices = indices.length;return o;
}function initTextures(gl, program) {var texture = gl.createTexture();   // 创建一个纹理对象var image = new Image();image.onload = function () {/* 将图像数据写入纹理对象 */gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);  // 翻转图像Y坐标gl.activeTexture(gl.TEXTURE0); // 激活0号纹理单元gl.bindTexture(gl.TEXTURE_2D, texture); // 将纹理对象绑定至0号纹理单元并指定2d纹理类型gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); // 配置纹理参数gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); // 配置图像参数/* 将纹理单元0传递到uSampler */gl.useProgram(program);gl.uniform1i(program.u_Sampler, 0);};image.src = '../resources/orange.jpg';return texture;
}function drawSolidCube(gl, program, o, x, angle, viewProjMatrix) {gl.useProgram(program);   // 告诉WebGL使用这个程序对象/* 分配缓冲区对象并启用分配(非索引) */initAttributeVariable(gl, program.a_Position, o.vertexBuffer); // 顶点坐标initAttributeVariable(gl, program.a_Normal, o.normalBuffer);   // 法向量drawCube(gl, program, o, x, angle, viewProjMatrix);   // Draw
}function drawTexCube(gl, program, o, texture, x, angle, viewProjMatrix) {gl.useProgram(program);   // 告诉WebGL使用这个程序对象/* 分配缓冲区对象并启用分配(非索引) */initAttributeVariable(gl, program.a_Position, o.vertexBuffer);  // 顶点坐标initAttributeVariable(gl, program.a_Normal, o.normalBuffer);    // 法向量initAttributeVariable(gl, program.a_TexCoord, o.texCoordBuffer);// 纹理坐标/* 将纹理对象绑定到纹理单元0 */gl.activeTexture(gl.TEXTURE0);gl.bindTexture(gl.TEXTURE_2D, texture);drawCube(gl, program, o, x, angle, viewProjMatrix); // Draw
}function initAttributeVariable(gl, a_attribute, buffer) { // 分配缓冲区对象并启用分配gl.bindBuffer(gl.ARRAY_BUFFER, buffer);gl.vertexAttribPointer(a_attribute, buffer.num, buffer.type, false, 0, 0);gl.enableVertexAttribArray(a_attribute);
}var g_modelMatrix = new Matrix4();
var g_mvpMatrix = new Matrix4();
var g_normalMatrix = new Matrix4();
function drawCube(gl, program, o, x, angle, viewProjMatrix) { // 最终画/* 计算模型矩阵 */g_modelMatrix.setTranslate(x, 0.0, 0.0);g_modelMatrix.rotate(20.0, 1.0, 0.0, 0.0);g_modelMatrix.rotate(angle, 0.0, 1.0, 0.0);/* 计算法线变换矩阵 */g_normalMatrix.setInverseOf(g_modelMatrix);g_normalMatrix.transpose();gl.uniformMatrix4fv(program.u_NormalMatrix, false, g_normalMatrix.elements);/* 计算模型视图投影矩阵 */g_mvpMatrix.set(viewProjMatrix); // g_mvpMatrix -> viewProjMatrixg_mvpMatrix.multiply(g_modelMatrix); // viewProjMatrix * g_modelMatrixgl.uniformMatrix4fv(program.u_MvpMatrix, false, g_mvpMatrix.elements);gl.drawElements(gl.TRIANGLES, o.numIndices, o.indexBuffer.type, 0);   // Draw
}function initArrayBufferForLaterUse(gl, data, num, type) { // 坐标、法线、纹理坐标专用var buffer = gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER, buffer);gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);// 保留以后分配给属性变量所需的信息buffer.num = num;buffer.type = type;return buffer;
}function initElementArrayBufferForLaterUse(gl, data, type) { // 索引数据专用var buffer = gl.createBuffer();gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer);gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, data, gl.STATIC_DRAW);buffer.type = type;return buffer;
}var ANGLE_STEP = 30;   // 旋转角度的增量(度)
var last = Date.now(); // 上次调用此函数的时间
function animate(angle) {var now = Date.now();var elapsed = now - last;last = now;var newAngle = angle + (ANGLE_STEP * elapsed) / 1000.0; // 更新当前旋转角度(根据经过的时间进行调整)return newAngle % 360;
}

代码详解 

main()函数首先调用gl.createProgram()创建了两个着色器程序对象(第54、55行),该函数接收的参数和initShaders()一样,即字符串形式的顶点着色器和片元着色器代码,返回值就是着色器程序对象。两个着色器程序对象分别命名为solidProgram和texProgram。然后,获取每个着色器中各attribute变量的存储地址,保存在相应着色器程序对象的同名属性上。我们又一次用到了JavaScript的“可以随意向对象添加属性”的特性。

接着,将顶点的数据存储在由initVertexBuffers()函数创建的缓冲区对象中。对单色立方体而言,顶点的数据包括(1)顶点的坐标,(2)法线,(3)索引。对贴有纹理的立方体而言,还得加上纹理坐标。这些缓冲区对象将在绘制立方体和切换着色器时分配给着色器中的attribute变量。

具体的,initVertexBuffers()函数首先定义了顶点坐标数组(第102行)、法线数组(第110行)、纹理坐标数组(第118行)和顶点索引数组(第126行),然后定义了一个空的Object类型的对象o,将创建的各个缓冲区对象全部添加为o的属性(第137~141行),最后返回o对象。你也通过向全局变量赋值的方式来传出缓冲区对象,但是全局变量就太多了,程序的可读性也会降低。利用函数返回对象的属性来返回多个缓冲区对象,可以帮助我们更好地管理这些缓冲区对象。 

我们使用initArrayBufferForLaterUse()函数来创建单个缓冲区对象(第137~139行),它将数组中的数据写入缓冲区,但不将缓冲区分配给attribute变量。

回到main()函数,我们接着调用initTextures()函数建立好纹理图像(第72行),然后一切就准备好了,只等绘制两个立方体对象。首先调用drawSolidCube()函数绘制单色的立方体(第86行),然后调用drawTexCube()函数绘制贴有纹理图像的立方体(第88行)。如下图显示了接下来的这第5~10步。

drawSolidCube()函数绘制单色立方体:首先调用gl.useProgram()并将着色器程序solidProgram作为参数传入,即告诉WebGL使用这个程序。然后,调用initAttributeVariable()函数将顶点的坐标、法线分配给相应的attribute变量(第167~168行)。接着,将索引缓冲区对象绑定到gl.ELEMENT_ARRAY_BUFFER上,一切就准备好了。最后,调用gl.drawElements()函数,完成绘制操作。 

drawTexCube()函数与drawSolidCube()函数的流程基本一致。额外的步骤是将纹理坐标的缓冲区分配给attribute变量(第178行),以及将纹理对象绑定到0号纹理单元上(第180~181行)。实际的绘制操作仍是由gl.drawElements()完成的,和drawSolidCube()函数一样。

一旦掌握了切换着色器的基本方法,你就可以在任意多个着色器程序中进行切换,在同一个场景中绘制出各种不同的效果的组合。

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

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

相关文章

Java 设计模式——抽象工厂模式

目录 1.概念2.结构3.实现4.优缺点5.使用场景6.模式扩展7.JDK源码解析——Collection.iterator方法 1.概念 (1)Java 设计模式——工厂方法模式中考虑的是一类产品的生产,如畜牧场只养动物、电视机厂只生产电视机等。这些工厂只生产同种类产品…

【kubernetes】【基础资源使用】kubernetes中的Deployment使用

1 Why need Deployment? K8S中Pod是用户管理工作负载的基本单位,Pod通常通过Service进行暴露,因此,通常需要管理一组Pod,RC和RS主要就实现了一组Pod的管理工作,其中,RC和RS的区别在于,RS提供更…

【每日一题】528. 按权重随机选择

528. 按权重随机选择 - 力扣(LeetCode) 给你一个 下标从 0 开始 的正整数数组 w ,其中 w[i] 代表第 i 个下标的权重。 请你实现一个函数 pickIndex ,它可以 随机地 从范围 [0, w.length - 1] 内(含 0 和 w.length - 1&…

混合IT基础设施的安全挑战与缓解策略

自从“身份是新的边界”这句格言问世以来,公司已经开始扩展他们的能力和运营,超越了基于本地、办公室基础设施的范围。采用云原生技术意味着组织正在寻求扩大传统工作流程,而无需投入时间和资源来建立物理数据中心和其他硬件基础设施。 身份…

JTS:08 JTS图形相交

这里写目录标题 版本JTS disjoint intersects俩个图形不相交俩个图形 边相交俩个图形 内部相交俩个图形 点相交 版本 org.locationtech.jts:jts-core:1.19.0 链接: github JTS disjoint intersects 不相交的 九交模型FF*FF**** 相交的 九交模型 [T********] [*T*******] [**…

服务断路器_Resilience4j信号量隔离实现

POM引入依赖 <dependency><groupId>io.github.resilience4j</groupId><artifactId>resilience4j-bulkhead</artifactId><version>1.7.0</version> </dependency>信号量隔离修改YML文件 resilience4j:#信号量隔离bulkhead:ins…

GIT提示Another git process seems to be running in this repository

解决方法 1、进入项目里面的.git文件里面找到index.lock删除即可。

【算法】递归(高阶题目) -随时补充

文章目录 岛问题汉诺塔问题牛群繁衍数量问题求字符串的全部子序列字符串的全排列数字的全排列I数字的全排列IIN皇后IIN皇后I 岛问题 递归的方法: 遍历岛这个二维数组&#xff0c;如果当前数为1&#xff0c;则进入感染函数并将岛个数1感染函数&#xff1a;其实就是一个递归标注…

创建线程的4种方法

目录 一.前言 1.关于进程调度 (1)为什么要调度? (2)调度的真正对象 (3)调度的资源 2.线程 (1).线程的写法 (2)线程创建的方法 1.继承Thread (1)使用继承Thread,重写run的方式来创建线程 (2)继承Thread,使用匿名内部类 2.实现Runnable (1)使用实现Runnable,重写run…

自定义ElementPlus主题颜色

构建工具采用Vite CSS预处理器采用Sass 一.准备定制化的样式文件 1.安装Sass npm i sass -D 2.创建好文件目录 3.书写样式 ElementPlus默认样式. //index.scss/* 只需要重写你需要的即可 */ forward element-plus/theme-chalk/src/common/var.scss with ($colors: (prim…

pytorch固定随机数中种子

1、添加到yolov7的utils/general.py文件最下面 import pkg_resources as pkg def check_version(current0.0.0, minimum0.0.0, nameversion , pinnedFalse, hardFalse, verboseFalse):# Check version vs. required versioncurrent, minimum (pkg.parse_version(x) for x in …

【Verilog 教程】6.6Verilog 仿真激励

关键词&#xff1a;testbench&#xff0c;仿真&#xff0c;文件读写 Verilog 代码设计完成后&#xff0c;还需要进行重要的步骤&#xff0c;即逻辑功能仿真。仿真激励文件称之为 testbench&#xff0c;放在各设计模块的顶层&#xff0c;以便对模块进行系统性的例化调用进行仿真…

c#用Gnuplot画图源码

直接调用这个类即可&#xff0c;需要下载个GnuPlot安装下。 // Author: Leonardo Tazziniusing System; using System.Diagnostics; using System.Drawing; using System.IO; using System.Windows.Forms;/// <summary> /// Tested with Gnuplot 5.2 /// </summary&g…

云原生微服务治理经典框架之Spring Cloud Alibaba核心技术与实战案例

系列文章目录 送书第一期 《用户画像&#xff1a;平台构建与业务实践》 送书活动之抽奖工具的打造 《获取博客评论用户抽取幸运中奖者》 送书第二期 《Spring Cloud Alibaba核心技术与实战案例》 文章目录 系列文章目录1、云原生如何做微服务治理&#xff1f;2、微服务治理框…

类和对象:运算符重载

本篇文章来介绍一下C中的运算符重载&#xff0c;以及与运算符重载有关的三个默认默认成员函数&#xff1a;赋值运算符重载&#xff0c;普通对象取地址与const对象取地址操作符重载&#xff0c;也就是下面图片中6个默认成员函数的后三个&#xff0c;前三个默认成员函数在之前文章…

【go语言】结构体

结构体 结构体定义 type name struct{value1 type1value2 type2...... }组成结构体的数据称为字段&#xff0c;每一个字段有一个类型和一个名字&#xff0c;每一个字段的名字必须唯一&#xff0c;字段的类型任意。 创建结构体 type myStruct struct{i1 intf1 float32str st…

HDLBits-Edgedetect

刚开始写的代码如下&#xff1a; module top_module (input clk,input [7:0] in,output [7:0] pedge );reg [7:0] in_pre;always (posedge clk)begin in_pre < in;endassign pedge in & ~in_pre; endmodule但是提交结果是错误的。猜想原因如下&#xff1a; assign p…

某音网页端 X-Bogus 参数

逆向目标 目标&#xff1a;某音网页端用户信息接口 X-Bogus 参数 接口&#xff1a;aHR0cHM6Ly93d3cuZG91eWluLmNvbS9hd2VtZS92MS93ZWIvdXNlci9wcm9maWxlL290aGVyLw 什么是 JSVMP&#xff1f; JSVMP 全称 Virtual Machine based code Protection for JavaScript&#xff0c;即 …

【网络八股】TCP八股

网络八股 请简述TCP/IP模型中每层的作用&#xff0c;典型协议和典型设备介绍一下三次握手的过程介绍一下四次挥手的过程必须三次握手吗&#xff0c;两次不行吗&#xff1f;为什么ACK数据包消耗TCP的序号吗三次握手中可以携带应用层数据吗四次挥手时&#xff0c;可以携带应用层数…

crypto:丢失的MD5

题目 得到一个md5.py 运行一下&#xff0c;发现报错&#xff0c;修改一下 运行之后又报错 报错原因是算法之前编码 正确的代码为 import hashlib for i in range(32,127):for j in range(32,127):for k in range(32,127):mhashlib.md5()m.update((TASC chr(i) O3RJMV c…