webgl入门-矩阵变换

矩阵变换

前言

变换有三种状态:平移、旋转、缩放。

当我们变换一个图形时,实际上就是在移动这个图形的所有顶点。

课堂目标

  1. 掌握图形变换的三种方式。
  2. 可以对图像进行复合变换。

知识点

  1. 平移
  2. 旋转
  3. 缩放

第一章 平移

对图形的平移就是对图形所有顶点的平移。

1-举个例子

image-20210315105508042

已知:

  • 顶点p(x,y,z)
  • 在x、y、z 三个方向上,分别将点p 移动tx、ty、tz

求:点p 移动后的位置p’(x’,y’,z’)

解:

x'=x+tx
y'=y+ty
z'=z+tz

如果这个图形中并非只有一个顶点,而是有三个,或者更多,那么所有的顶点也是按照同样原理进行位移。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2-向量加法

在实际代码中,我们要有一个向量的概念。

比如 (x,y,z) ,我们既可以说它是一个顶点位置,也可以说它是一个向量。

至于 (x,y,z) 到底是什么,要看我们拿它做什么。

比如,把点p(x,y,z) 作为点位时,那它就是点p(x,y,z)

我们把p 的移动距离tx、ty、tz 封装成一个对象pt(tx,ty,tz),那么pt 就是一个向量,一个为点p 指明移动方向和距离的向量。

因此:点p 的移动结果 p’ 就可以这么写:

p'=p+pt

由上可知,顶点的位移就是向量的加法。

3-代码实现

3-1-GLSL ES 语言里的向量运算

在GLSL ES 语言里,是可以直接进行向量运算。

下面的顶点着色器里的代码:

attribute vec4 a_Position;
vec4 translation=vec4(0,0.2,0,0);
void main(){
    gl_Position = a_Position+translation;
}
  • a_Position 是原始点位,属于attribute 变量
  • translation 是顶点着色器里的私有变量,没有向外部暴露,属于4维向量
  • a_Position+translation 便是着色器内的向量加法,这里是对原始点位进行位移

之后,我们也可以把translation 变量暴露出去,让js可以修改图形位置:

<script id="vertexShader" type="x-shader/x-vertex">
    attribute vec4 a_Position;
    uniform vec4 u_Translation;
    void main(){
        gl_Position = a_Position+u_Translation;
    }
</script>

在js 中修改uniform 变量的方法,我们之前已经说过:

const u_Translation=gl.getUniformLocation(gl.program,'u_Translation');
gl.uniform4f(u_Translation,0,0.5,0,0);

整体代码:

<canvas id="canvas"></canvas>
<script id="vertexShader" type="x-shader/x-vertex">
    attribute vec4 a_Position;
    uniform vec4 u_Translation;
    void main(){
        gl_Position = a_Position+u_Translation;
    }
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
    void main(){
        gl_FragColor=vec4(1,1,0,1);
    }
</script>
<script type="module">
    import {initShaders} from '../jsm/Utils.js';

    const canvas = document.getElementById('canvas');
    canvas.width=window.innerWidth;
    canvas.height=window.innerHeight;
    const gl = canvas.getContext('webgl');

    const vsSource = document.getElementById('vertexShader').innerText;
    const fsSource = document.getElementById('fragmentShader').innerText;
    initShaders(gl, vsSource, fsSource);

    const vertices=new Float32Array([
        0,  0.1,
        -0.1,-0.1,
        0.1, -0.1
    ])

    const vertexBuffer=gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER,vertexBuffer);
    gl.bufferData(gl.ARRAY_BUFFER,vertices,gl.STATIC_DRAW);
    const a_Position=gl.getAttribLocation(gl.program,'a_Position');
    gl.vertexAttribPointer(a_Position,2,gl.FLOAT,false,0,0);
    gl.enableVertexAttribArray(a_Position);

    const u_Translation=gl.getUniformLocation(gl.program,'u_Translation');
    gl.uniform4f(u_Translation,0,0.5,0,0);

    gl.clearColor(0, 0, 0, 1);
    gl.clear(gl.COLOR_BUFFER_BIT);

    // gl.drawArrays(gl.POINTS, 0, 3);
    gl.drawArrays(gl.TRIANGLES, 0, 3);
    
</script>

image-20201019140550020

在最后面我们还可以加一段逐帧动画:

let y=0;
!(function ani(){
    y+=0.02
    if(y>1){
        y=-1
    }
    gl.uniform4f(u_Translation,0,y,0,0);
    gl.clear(gl.COLOR_BUFFER_BIT);
    gl.drawArrays(gl.TRIANGLES, 0, 3);
    requestAnimationFrame(ani)
})()

效果如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

接下来咱们说旋转。

第二章 旋转

1-旋转的概念

三维物体的旋转要比位移复杂一点,因为三维物体的旋转需要知道以下条件:

  • 旋转轴
  • 旋转方向
  • 旋转角度

我们可以想象一个场景:

一个小人站在旋转轴的起点进行旋转。

小人要往左转还是往右转,就是旋转的方向。

小人旋转的大小就是旋转角度。

1

2-旋转方向的正负

物体的旋转方向是有正负之分的。

那何时为正,何时为负呢?

在webgl 中,除裁剪空间之外的大部分功能都使用了右手坐标系。

所以,在我们初学webgl 的时候,可以暂且将其当成右手坐标系,等讲到裁剪空间的时候,我再跟大家说左手坐标系。

下图就是右手坐标系:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

以上图为例:

  • 当物体绕z 轴,从x轴正半轴向y轴正半轴逆时针旋转时,是正向旋转,反之为负。
  • 当物体绕x 轴,从y轴正半轴向z轴正半轴逆时针旋转时,是正向旋转,反之为负。
  • 当物体绕y 轴,从z轴正半轴向x轴正半轴逆时针旋转时,是正向旋转,反之为负。

如下图就是正向旋转:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3-旋转公式

先举一个让顶点围绕z 轴旋转的例子。

image-20210106142031447

已知:

  • 点A的位置是(ax,ay,az)
  • 点A要围绕z轴旋转β度,转到点B的位置

求:点A旋转后的bx、by位置

解:

我们由结果逆推一下解题思路。

因为∠β是已知的,∠α 可以通过点A 得出。

所以我们可以得出:

∠xOB=α+β

那我们通过三角函数就可以推出bx、by

设∠xOB=θ,则:

bx=cosθ*|OA|
by=sinθ*|OA|

上面的|OA|是点O到点A的距离,可以直接用点A求出:

|OA|=Math.sqrt(ax*ax+ay*ay)

那我们接下来只需要知道cosθ和sinθ的值即可

因为:θ=α+β

所以,我们可以利用和角公式求cosθ和sinθ的值:

cosθ=cos(α+β)
cosθ=cosα*cosβ-sinα*sinβ
sinθ=sin(α+β)
sinθ=cosβ*sinα+sinβ*cosα

所以:

bx=cosθ*|OA|
bx=(cosα*cosβ-sinα*sinβ)*|OA|
bx=cosα*cosβ*|OA|-sinα*sinβ*|OA|
by=sinθ*|OA|
by=(cosβ*sinα+sinβ*cosα)*|OA|
by=cosβ*sinα*|OA|+sinβ*cosα*|OA|

因为:

cosα*|OA|=ax
sinα*|OA|=ay

所以我们可以简化bx、by的公式

bx=ax*cosβ-ay*sinβ
by=ay*cosβ+ax*sinβ

上面的bx、by就是我们要求的答案。

那接下来咱们可以测试一下,如何让一个三角形绕z轴转起来

4-在着色器中旋转

我们可以直接在着色器里写旋转公式:

<script id="vertexShader" type="x-shader/x-vertex">
    attribute vec4 a_Position;
    float angle=radians(80.0);
    float sinB=sin(angle);
    float cosB=cos(angle);
    void main(){
        gl_Position.x=a_Position.x*cosB-a_Position.y*sinB;
        gl_Position.y=a_Position.y*cosB+a_Position.x*sinB;
        gl_Position.z=a_Position.z;
        gl_Position.w=1.0;
    }
</script>
  • radians(float degree) 将角度转弧度
  • sin(float angle) 正弦
  • cos(float angle) 余弦

我们也可以用js控制图形的旋转。

5-用js旋转图形

我们将顶点着色器里的正弦值和余弦值暴露给js,便可以用js旋转图形了。

<script id="vertexShader" type="x-shader/x-vertex">
    attribute vec4 a_Position;
    uniform float u_SinB;
    uniform float u_CosB;
    void main(){
        gl_Position.x=a_Position.x*u_CosB-a_Position.y*u_SinB;
        gl_Position.y=a_Position.y*u_CosB+a_Position.x*u_SinB;
        gl_Position.z=a_Position.z;
        gl_Position.w=1.0;
    }
</script>

在js 中修改uniform 变量

const u_SinB = gl.getUniformLocation(gl.program, 'u_SinB')
const u_CosB = gl.getUniformLocation(gl.program, 'u_CosB')
let angle = 0.3
gl.uniform1f(u_SinB, Math.sin(angle))
gl.uniform1f(u_CosB, Math.cos(angle))

之后也可以让图形转起来:

!(function ani() {
    angle += 0.01
    gl.uniform1f(u_SinB, Math.sin(angle))
    gl.uniform1f(u_CosB, Math.cos(angle))
    gl.clear(gl.COLOR_BUFFER_BIT);
    gl.drawArrays(gl.TRIANGLES, 0, 3);
    requestAnimationFrame(ani)
})()

第三章 缩放

1-缩放的基本概念

缩放可以理解为对向量长度的改变,或者对向量坐标分量的同步缩放

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

已知:

  • 点A的位置是(ax,ay,az)
  • 点A基于原点內缩了一半

求:点A內缩了一半后的bx、by、bz位置

解:

bx=ax*0.5
by=ay*0.5
bz=az*0.5

2-在着色器中缩放

我可以对gl_Position 的x、y、z依次缩放。

<script id="vertexShader" type="x-shader/x-vertex">
attribute vec4 a_Position;
float scale=1.2;
void main(){
    gl_Position.x= a_Position.x*scale;
    gl_Position.y= a_Position.y*scale;
    gl_Position.z= a_Position.z*scale;
    gl_Position.w=1.0;
}
</script>

也可以从a_Position中抽离出由x、y、z组成的三维向量,对其进行一次性缩放。

<script id="vertexShader" type="x-shader/x-vertex">
attribute vec4 a_Position;
float scale=1.2;
void main(){
    gl_Position=vec4(vec3(a_Position)*scale,1.0);
}
</script>

3-用js缩放图形

同样的我们也可以把缩放系数暴露给js,通过js 缩放图形。

1.建立uniform变量

<script id="vertexShader" type="x-shader/x-vertex">
    attribute vec4 a_Position;
    uniform float u_Scale;
    void main(){
        gl_Position=vec4(vec3(a_Position)*u_Scale,1.0);
    }
</script>

2.使用js获取并修改uniform 变量

const u_Scale = gl.getUniformLocation(gl.program, 'u_Scale')
gl.uniform1f(u_Scale, 1.0)

3.继续来点动画

let angle = 0
!(function ani() {
    angle += 0.05
    const scale = Math.sin(n) + 1
    gl.uniform1f(u_Scale, scale)
    gl.clear(gl.COLOR_BUFFER_BIT);
    gl.drawArrays(gl.TRIANGLES, 0, 3);
    requestAnimationFrame(ani)
})()

第四章 矩阵

矩阵(Matrix)是一个按照矩形纵横排列的复数集合。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

矩阵就像一个矩形的阵盘,通过其中纵横排列的元素,我们可以摆出不同功能的阵法,比如位移矩阵、旋转矩阵、缩放矩阵……

image-20210326165809914

在矩阵中的每一行,或者每一列数字构成的集合,可以视之为向量。

所以咱们接下来要先从向量说起。

1-向量

向量,又叫矢量,它是一个用于表示方向和量的对象。

我另写了几篇可以从零基础认识向量的文章,大家可看一下,以便对向量有一个透彻的认知:

  • 漫谈直线之向量
  • 漫谈向量之坐标运算
  • 向量之点积
  • 向量之叉乘

在webgl 里的向量有1维向量、2维向量、3维向量和4维向量。

  • 1维向量中有1个数字,对应的是单轴坐标系里的点位。
  • 2维向量中有2个数字,对应的是2维坐标系里的点位。
  • 3维向量中有3个数字,对应的是3维坐标系里的点位。
  • 4维向量中有4个数字,对应的是3维坐标系里的点位,外加一个附加数据,至于这个数据是什么,要看我们的项目需求。

向量咱们就说到这,接下来咱们再说一下矩阵和向量的乘法。

2-矩阵和向量的乘法

首先,咱先看一个矩阵和向量的乘法图:

image-20210107184337749

矩阵乘以向量时,向量是几维的,那矩阵中就应该有几个向量。

如上图向量v 是2维的,那么矩阵中就有2组向量,这两组向量可以是横着的两组向量,也可以是竖着的两组向量。

  • 横着的两组向量是:向量(a,b)、向量(e,f)
  • 竖着的两组向量是:向量(a,e)、向量(b,f)

用专业术语来说:

  • 横着的两组遵循的规则是行主序,即将矩阵中的一行数据视之为一个向量。
  • 竖着的两组遵循的规则是列主序,即将矩阵中的一列数据视之为一个向量。

至于我们是使用行主序,还是列主序,这就得看规则的定制者了。

在webgl 里,矩阵元素的排列规则是列主序。

数学中常用的写法是行主序,所以我们接下来就用行主序举例子了。

矩阵和向量相乘的规则就是让矩阵中的每个向量和向量v相乘。

向量和向量相乘,就是在求向量的点积,其结果是一个实数,而不再是向量。

比如上图中,向量(a,b)乘以向量v(x,y)的结果是:

a*x+b*y

因为a、b、x、y都是实数,所以其结果也是实数。

上图中,矩阵m乘以向量v 会得到两个结果,即ax+by和ex+fy。

这两个结果会构成一个新的向量v’(x’,y’)

x'=a*x+b*y
y'=e*x+f*y

这时我们可以将其和数学里的旋转公式做一下比较。

点A(ax,ay)围绕z轴旋β度,其旋转后的位置是点B(bx,by),则:

bx=cosβ*ax-sinβ*ay
by=sinβ*ax+cosβ*ay

对比上面的两组公式,试想一下:

向量v是不是可以当成一个点位呢?

答案是可以的。

那我现在就让向量v代表的位置,就是点A的位置。

那么矩阵m乘以向量v,是不是可以让向量v代表的这个点位旋转β度呢?

如果可以,那么矩阵里的元素应该满足什么条件呢?

满足以下条件即可:

a=cosβ
b=-sinβ
e=sinβ
f=cosβ

这样,用矩阵乘以向量的方法得到的旋转结果和用数学公式得到的结果就是一样的,即;

a*x+b*y=cosβ*ax-sinβ*ay
e*x+f*y=sinβ*ax+cosβ*ay

最终我们就可以用矩阵乘以向量的方式让点p旋转β度

image-20210108120112541

那我们知道了上面的这种关系之后,要干什么,能干什么呢?接下来就是重点啦!

3-在着色器中写矩阵

我们是可以直接在着色器中建立矩阵对象的。

<script id="vertexShader" type="x-shader/x-vertex">
    attribute vec4 a_Position;
    float angle=radians(40.0);
    float sinB=sin(angle);
    float cosB=cos(angle);
    mat2 m2=mat2(
      cosB, sinB,
      -sinB,cosB
    );
    void main(){
      gl_Position = vec4(
        m2*vec2(a_Position),
        a_Position.z,a_Position.w
      );
    }
</script>
  • mat2 是二维矩阵对象

4-用js建立矩阵对象并传递给着色器

1.在顶点着色器中建立uniform变量

<script id="vertexShader" type="x-shader/x-vertex">
    attribute vec4 a_Position;
    uniform mat2 u_Matrix;
    void main(){
      gl_Position = vec4(
        u_Matrix*vec2(a_Position),
        a_Position.z,a_Position.w
      );
    }
</script>

2.获取并修改uniform 变量

const u_Matrix = gl.getUniformLocation(gl.program, 'u_Matrix')
let angle = 0.2
const [sinB, cosB] = [Math.sin(angle), Math.cos(angle)]
const matrix = [
    cosB, sinB,
    -sinB, cosB
]
gl.uniformMatrix2fv(u_Matrix, false, matrix)

3.后面我们也可以在其中添加动画

const u_Matrix = gl.getUniformLocation(gl.program, 'u_Matrix')
let angle = 0.2

!(function ani() {
    angle += 0.02
    const [sinB, cosB] = [Math.sin(angle), Math.cos(angle)]
    const matrix = [
        cosB, sinB,
        -sinB, cosB
    ]
    gl.uniformMatrix2fv(u_Matrix, false, matrix)

    gl.clear(gl.COLOR_BUFFER_BIT);
    gl.drawArrays(gl.TRIANGLES, 0, 3);
    requestAnimationFrame(ani)
})()

目前我们说的只是最简单的二维矩阵,我们可以直接给顶点着色器一个四维矩阵。

5-四维矩阵

四维矩阵在着色器里的应用原理和二维矩阵是一样的,只要理解了其运算原理就好。

<script id="vertexShader" type="x-shader/x-vertex">
    attribute vec4 a_Position;
    float angle=radians(10.0);
    float cosB=cos(angle);
    float sinB=sin(angle);
    mat4 m4=mat4(
      cosB, sinB,0.0,0.0,
      -sinB,cosB,0.0,0.0,
      0.0,  0.0, 1.0,0.0,
      0.0,  0.0, 0.0,1.0
    );
    void main(){
      gl_Position = m4*a_Position;
    }
</script>

我们也可以用js向顶点着色器传递四维矩阵。

const u_Matrix = gl.getUniformLocation(gl.program, 'u_Matrix')
let angle = 0.1
const [sinB, cosB] = [Math.sin(angle), Math.cos(angle)]
const matrix = [
    cosB, sinB, 0.0, 0.0,
    -sinB, cosB, 0.0, 0.0,
    0.0, 0.0, 1.0, 0.0,
    0.0, 0.0, 0.0, 1.0
]
gl.uniformMatrix4fv(u_Matrix, false, matrix)

矩阵不仅可以用于旋转,还可以平移和缩放。

6-矩阵平移

比如我要让顶点的x移动0.1,y移动0.2,z移动0.3

顶点着色可以这样写:

<script id="vertexShader" type="x-shader/x-vertex">
    attribute vec4 a_Position;
    //列主序
    mat4 m4=mat4(
      1.0, 0.0, 0.0,0.0,
      0.0, 1.0, 0.0,0.0,
      0.0, 0.0, 1.0,0.0,
      0.1, 0.2, 0.3,1.0
    );
    void main(){
      gl_Position = m4*a_Position;
    }
</script>

对于js 建立矩阵对象,并传递给着色器的方法,我之前已经说过,就不再赘述了。

7-矩阵缩放

以同样的原理,我们也可以写缩放矩阵。

比如我要让顶点在x轴向缩放2,y轴向缩放3,轴向缩放4

顶点着色可以这样写:

<script id="vertexShader" type="x-shader/x-vertex">
    attribute vec4 a_Position;
    //列主序
    mat4 m4=mat4(
      2.0, 0.0, 0.0,0.0,
      0.0, 3.0, 0.0,0.0,
      0.0, 0.0, 4.0,0.0,
      0.0, 0.0, 0.0,1.0
    );
    void main(){
      gl_Position = m4*a_Position;
    }
</script>

第五章 矩阵库

像我们之前那样手写矩阵,其实是很麻烦的,我们可以将其模块化。

现在市面上已经有许多开源的矩阵库了,比如《WebGL 编程指南》里的cuon-matrix.js,three.js 的Matrix3和Matrix4对象。

接下我们就简单说一下three.js的Matrix4对象的用法。

1.引入Matrix4对象

import {Matrix4} from 'https://unpkg.com/three/build/three.module.js';

2.实例化矩阵对象,在其中写入旋转信息

const matrix=new Matrix4()
matrix.makeRotationZ(Math.PI/6)

3.基于matrix 对象的elements 属性,修改uniform 变量

const u_Matrix=gl.getUniformLocation(gl.program,'u_Matrix')
gl.uniformMatrix4fv(u_Matrix,false,matrix.elements)

总结

这一篇主要讲解了如何使用矩阵统一变换一个物体的多个顶点,下一篇我们会让矩阵包含多种变换信息,比如移动加旋转,旋转加缩放。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

双向链表C++,C#,Java版,这些程序大多已经过测试,一直在用。

先C版吧&#xff0c;我最先用的是C#,后来是Java&#xff0c;后来改用C版的&#xff0c;因为现在一直在用C&#xff0c;单链 表一直没写上去&#xff0c;因为我很少用&#xff0c;用的是双链表。 执行代码例子1&#xff1a; int main() { _DList<_string> s…

手机相册怎么恢复?如何挽救误删的照片?

手机相册成为我们存储和分享照片的主要途径&#xff0c;这些照片可能代表着我们的美好回忆、重要时刻或珍贵的瞬间。然而&#xff0c;有时候我们会因为误操作或一时冲动&#xff0c;将一些珍贵的照片误删&#xff0c;并且很难找回来。手机相册怎么恢复呢&#xff1f;本文将为你…

有效的变位词

如果哈希表的键的取值范围是固定的&#xff0c;并且范围不是很大&#xff0c;则可以用数组来模拟哈希表。数组的下标和哈希表的键相对应&#xff0c;而数组的值和哈希表的值相对应。 英文小写字母只有26个&#xff0c;因此可以用一个数组来模拟哈希表。 class Solution {publi…

【软考中级 软件设计师】数据结构

数据结构是计算机科学中一个基础且重要的概念&#xff0c;它研究数据的存储结构以及在此结构上执行的各种操作。在准备软考中级-软件设计师考试时&#xff0c;掌握好数据结构部分对于通过考试至关重要。下面是一些核心知识点概览&#xff1a; 基本概念&#xff1a; 数据结构定义…

算法入门----小话算法(1)

下面就首先从一些数学问题入手。 Q1&#xff1a; 如何证明时间复杂度O(logN) < O(N) < O(NlogN) < O(N2) < O(2N) < O(N!) < O(NN)? A&#xff1a; 如果一个以整数为参数的不等式不能很容易看出不等的关系&#xff0c;那么最好用图示或者数学归纳法。 很显…

一文深度剖析 ColBERT

近年来&#xff0c;向量搜索领域经历了爆炸性增长&#xff0c;尤其是在大型语言模型&#xff08;LLMs&#xff09;问世后。学术界开始重点关注如何通过扩展训练数据、采用先进的训练方法和新的架构等方法来增强 embedding 向量模型。 在之前的文章中&#xff0c;我们已经深入探…

python文件名通常以什么结尾

python文件后缀一般有两个&#xff0c;分别是.py和.pyw。视窗用 python.exe 运行 .py&#xff0c;用 pythonw.exe 运行 .pyw 。 这纯粹是因为安装视窗版Python时&#xff0c;扩展名 .py 自动被登记为用 python.exe 运行的文件&#xff0c;而 .pyw 则被登记为用 pythonw.exe 运…

Stanford-Coursera 算法Week1 笔记

题外话&#xff1a;全文免费放心食用&#xff0c;作者在此求个 三连关注 1. Integer Multiplication&#xff08;引入&#xff09; &#xff08;很小的时候我们就学过&#xff1a;两个数字相乘的算法——将输入(两个数字)转换为输出(它们的乘积)的一组定义良好的规则&#xf…

5.23.9 TransUNet:Transformers 为医学图像分割提供强大的编码器

TransUNet&#xff0c;它兼具 Transformers 和 U-Net 的优点&#xff0c;作为医学图像分割的强大替代方案。一方面&#xff0c;Transformer 对来自卷积神经网络 (CNN) 特征图的标记化图像块进行编码&#xff0c;作为用于提取全局上下文的输入序列。另一方面&#xff0c;解码器对…

Nginx-负载均衡

Nginx 简介 Nginx概述 Nginx ("engine x")是一个高性能的HTTP和反向代理服务器特点是占有内存少&#xff0c;并发能力强&#xff0c;事实上nginx 的并发能力确实在同类型的网页服务器中表现较好&#xff0c;中国大陆使用nginx网站用户有&#xff1a;百度、京东、新浪…

若依微服务整合knife4j

在Spring Cloud的微服务架构下&#xff0c;每个微服务并不需要引入前端的ui资源&#xff0c;因此在每个微服务的Spring Boot项目下&#xff0c;引入ruoyi-common-swagger提供的starter即可。 1、在ruoyi-gateway网关模块下&#xff0c;把knife4j依赖资源引入 <!-- knife4j…

Html基础笔记

Html超文本标记语言 (HyperText Markup Language) 超文本 指的是网页中可以显示的内容(图片,超链接,视频,) 标记语言 标记–>标签(标注) 例如:买东西的时候—>商品具有标签,看到标签就知道商品的属性(价格,材质,型号等,) 标记语言就是提供了很多的标签,不同的标签…

CSS基础(第二天)

Emmet语法 快速生成HTML结构语法 1. 生成标签 直接输入标签名 按tab键即可 比如 div 然后tab 键&#xff0c; 就可以生成 <div></div> 2. 如果想要生成多个相同标签 加上 * 就可以了 比如 div*3 就可以快速生成3个div 3. 如果有父子级关系的标签&#xff0c;可以…

CGAN|生成手势图像|可控制生成

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f366; 参考文章&#xff1a;TensorFlow入门实战&#xff5c;第3周&#xff1a;天气识别&#x1f356; 原作者&#xff1a;K同学啊|接辅导、项目定制 CGAN&#xff08;条件生成对抗网络&#xf…

影视解说5.0版零基础视频课程

课程简介 现在还能做解说吗、不会写解说文案怎么解决、不会配音怎么解决、如何找到合适的素材资源、如何变现…这是很多想做解说的伙伴最关心的几大问题。比如文案&#xff0c;我们推荐一个网站&#xff0c;10分钟搞定一篇文案&#xff0c;配音可以真人配音也可以软件配音。5.…

代码随想录算法训练营第三天| 203.移除链表元素、 707.设计链表、 206.反转链表

203.移除链表元素 题目链接&#xff1a; 203.移除链表元素 文档讲解&#xff1a;代码随想录 状态&#xff1a;没做出来&#xff0c;做题的时候定义了一个cur指针跳过了目标val遍历了一遍链表&#xff0c;实际上并没有删除该删的节点。 错误代码&#xff1a; public ListNode re…

Leecode热题100---45:跳跃游戏②

题目&#xff1a; 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。 返回到达 nums[n - 1] 的最小跳跃次数。 思路&#xff1a; 如果某一个作为 起跳点 的格子可以跳跃的距离是 3&#xff0c;那么表示后面…

127.数据异构方案

文章目录 前言一、数据异构的常用方法1. 完整克隆2. MQ方式3. binlog方式 二、MQ与Binlog方案实现MQ方式binlog方式注意点 三、总结 前言 何谓数据异构&#xff1a;把数据按需&#xff08;数据结构、存取方式、存取形式&#xff09;异地构建存储。比如我们将DB里面的数据持久化…

【源码分享】简单的404 HTML页面示例,该页面在加载时会等待2秒钟,然后自动重定向到首页

展示效果 源码 html <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><title>404 页面未找到</title><meta http-equiv"refresh" content"2;url/"> <!-- 设置2秒后跳转到首…

适合小白入门的AI扩图(创成式填充)工具

近期&#xff0c;发现许多人对AI扩图工具的需求比较大&#xff0c;为了满足大家的需求&#xff0c;本期天祺为大家整理了一些好用的AI扩图工具&#xff0c;各个设配的扩图工具都有介绍哦&#xff0c;电脑&#xff0c;手机端都能用&#xff0c;大家可以根据自己的喜好和需求进行…