GLSL-WebGL着色器语言语法详解

news2024/9/28 11:14:20

GLSL语法

GLSL它是强类型语言,每一句都必须有分号。它的语法和 typescript 挺像。
GLSL的注释语法和 JS 一样,变量名规则也和 JS 一样,不能使用关键字,保留字,不能以 gl_、webgl_ 或 webgl 开头。运算符基本也和 JS 一样,++ – += && || 还有三元运算符都支持。
GLSL 中主要有三种数据值类型,浮点数、整数和布尔。注意浮点数必须要带小数点。类型转换可以直接使用 float、int 和 bool 函数。例如下面像下面这样将整数 1 转换成浮点数 1.0。

float f = float(1);

另外 GLSL 中定义变量的语法是 <类型> <变量名>,并且赋给变量的值应该和定义变量的类型是一致的,如果上面代码这样写 float f = 1; 将会直接报错,因为 1 是整数,但是加一个小数点就会变成浮点数,float f = 1.; 这样写则不会报错。
JavaScript、C 等语言通常在 CPU 上执行,而着色器语言通常在 GPU 上执行,执行的环境不同,所以语法设计上自然会有些不同。

基本类型:

类型说明
void空类型,即不返回任何值
bool布尔类型 true,false
int带符号的整数 signed integer
float带符号的浮点数 floating scalar
vec2, vec3, vec4n维浮点数向量 n-component floating point vector
bvec2, bvec3, bvec4n维布尔向量 Boolean vector
ivec2, ivec3, ivec4n维整数向量 signed integer vector
mat2, mat3, mat42x2, 3x3, 4x4 浮点数矩阵 float matrix
sampler2D2D纹理 a 2D texture
samplerCube盒纹理 cube mapped texture

基本结构和数组:

类型说明
结构struct type-name{} 类似c语言中的 结构体
数组float foo[3] glsl只支持1维数组,数组可以是结构体的成员

向量的分量访问:

glsl中的向量(vec2,vec3,vec4)往往有特殊的含义,比如可能代表了一个空间坐标(x,y,z,w),或者代表了一个颜色(r,g,b,a),再或者代表一个纹理坐标(s,t,p,q),所以glsl提供了一些更人性化的分量访问方式.

vector.xyzw 其中xyzw 可以任意组合

vector.rgba 其中rgba 可以任意组合

vector.stpq 其中rgba 可以任意组合

vec4 v = vec4(1.0,2.0,3.0,1.0);
float x = v.x; //1.0
float x1 = v.r; //1.0
float x2 = v[0]; //1.0
vec3 xyz = v.xyz; // vec3(1.0,2.0,3.0)
vec3 xyz1 = vec(v[0],v[1],v[2]); // vec3(1.0,2.0,3.0)
vec3 rgb = v.rgb; // vec3(1.0,2.0,3.0)
vec2 xyzw = v.xyzw; // vec4(1.0,2.0,3.0,1.0);
vec2 rgba = v.rgba; // vec4(1.0,2.0,3.0,1.0);

运算符:

优先级(越小越高)运算符说明
1()聚组:a*(b+c)
2[] () . ++ - -数组下标[],方法参数fun(arg1,arg2,arg3),属性访问a.b,自增/减后缀a++ a- -
3++ – + - !自增/减前缀++a --a,正负号(一般正号不写)a ,-a,取反!false
4* /乘除数学运算
5+ -加减数学运算
6< > <= >=关系运算符
7== !=相等性运算符
8&&逻辑与
9^^逻辑排他或(用处基本等于!=)
10逻辑或。打不出来,符号是双竖杠
11? :三目运算符
12= += -= *= /=赋值与复合赋值
13,顺序分配运算

基础类型间的运算:

glsl中,没有隐式类型转换,原则上glsl要求任何表达式左右两侧(l-value),(r-value)的类型必须一致 也就是说以下表达式都是错误的:

int a = 2.0; // 错误,右侧 value为float 而 左侧 value 为int.
int a = 1.0 + 2;
float a = 2;
float a = 2.0 + 1;
bool a = 0; 
vec3 a = vec3(1.0, 2.0, 3.0) * 2;

其它可能遇到的情况
1、float 与 int:

float与float , int与int之间是可以直接运算的,但float与int不行.它们需要进行一次显示转换.即要么把float转成int: int(1.0)
,要么把int转成float: float(1) ,以下表达式都是正确的:

int a = int(2.0);
float a = float(2);
int a = int(2.0)*2 + 1;
float a = float(2)*6.0+2.3;

2、float 与 vec(向量) mat(矩阵):

vec,mat这些类型其实是由float复合而成的,当它们与float运算时,其实就是在每一个分量上分别与float进行运算,这就是所谓的逐分量运算.glsl里
大部分涉及vec,mat的运算都是逐分量运算,但也并不全是. 下文中就会讲到特例.
逐分量运算是线性的,这就是说 vec 与 float 的运算结果是还是 vec.
int 与 vec,mat之间是不可运算的, 因为vec和mat中的每一个分量都是 float 类型的. 无法与int进行逐分量计算.
下面枚举了几种 float 与 vec,mat 运算的情况

vec3 a = vec3(1.0, 2.0, 3.0);
mat3 m = mat3(1.0);
float s = 10.0;
vec3 b = s * a; // vec3(10.0, 20.0, 30.0)
vec3 c = a * s; // vec3(10.0, 20.0, 30.0)
mat3 m2 = s * m; // = mat3(10.0)
mat3 m3 = m * s; // = mat3(10.0)

3、vec(向量) 与 vec(向量):

两向量间的运算首先要保证操作数的阶数都相同.否则不能计算.例如: vec3*vec2 vec4+vec3 等等都是不行的.
它们的计算方式是两操作数在同位置上的分量分别进行运算,其本质还是逐分量进行的,这和上面所说的float类型的
逐分量运算可能有一点点差异,相同的是 vec 与 vec 运算结果还是 vec, 且阶数不变.

vec3 a = vec3(1.0, 2.0, 3.0);
vec3 b = vec3(0.1, 0.2, 0.3);
vec3 c = a + b; // vec3(1.1, 2.2, 3.3)
vec3 d = a * b; // vec3(0.1, 0.4, 0.9)

在这里插入图片描述
4、vec(向量) 与 mat(矩阵):

要保证操作数的阶数相同,且vec与mat间只存在乘法运算.
它们的计算方式和线性代数中的矩阵乘法相同,不是逐分量运算.

vec2 v = vec2(10., 20.);
mat2 m = mat2(1., 2.,  3., 4.);
vec2 w = m * v;  //  vec2(1. * 10. + 3. * 20., 2. * 10. + 4. * 20.)
vec2 v = vec2(10., 20.);
mat2 m = mat2(1., 2.,  3., 4.);
vec2 w = v * m;  //  vec2(1. * 10. + 2. * 20., 3. * 10. + 4. * 20.)

向量与矩阵的乘法规则如下:
在这里插入图片描述
5、 mat(矩阵) 与 mat(矩阵):

要保证操作数的阶数相同.
在mat与mat的运算中, 除了乘法是线性代数中的矩阵乘法外.其余的运算任为逐分量运算.简单说就是只有乘法是特殊的,其余都和vec与vec运算类似.

mat2 a = mat2(1., 2.,  3., 4.);
mat2 b = mat2(10., 20.,  30., 40.);
mat2 c = a * b;  // mat2(1.*10.+3.*20.,2.*10.+4.*20.,1.* 30.+3.*40.,2.* 30.+4.*40.);
mat2 d = a+b;  // mat2(1.+10.,2.+20.,3.+30.,4.+40);

矩阵乘法规则如下:
在这里插入图片描述

变量限定符:

修饰符说明
none(默认的可省略)本地变量,可读可写,函数的输入参数既是这种类型
const声明变量或函数的参数为只读类型
attribute只能存在于vertex shader中,一般用于保存顶点或法线数据,它可以在数据缓冲区中读取数据
uniform在运行时shader无法改变uniform变量, 一般用来放置程序传递给shader的变换矩阵,材质,光照参数等等
varying主要负责在vertex 和 fragment 之间传递变量

const:

和C语言类似,被const限定符修饰的变量初始化后不可变,除了局部变量,函数参数也可以使用const修饰符.但要注意的是结构变量可以用const修饰,但结构中的字段不行.

const变量必须在声明时就初始化 const vec3 v3 = vec3(0.,0.,0.)
局部变量只能使用const限定符.
函数参数只能使用const限定符.

struct light {
  vec4 color;
  vec3 pos; 
  // const vec3 pos1; // 结构中的字段不可用const修饰会报错.
};
const light lgt = light(vec4(1.0), vec3(0.0)); // 结构变量可以用const修饰

attribute:

attribute变量是全局且只读的,它只能在vertex shader中使用,只能与浮点数、向量或矩阵变量组合,
一般attribute变量用来放置程序传递来的模型顶点,法线,颜色,纹理等数据它可以访问数据缓冲区
(还记得__gl.vertexAttribPointer__这个函数吧)

attribute vec4 a_Position;

uniform:

uniform变量是全局且只读的,在整个shader执行完毕前其值不会改变,他可以和任意基本类型变量组合,
一般我们使用uniform变量来放置外部程序传递来的环境数据(如点光源位置,模型的变换矩阵等等)
这些数据在运行中显然是不需要被改变的.

uniform vec4 lightPosition;

varying:

varying类型变量是 vertex shader 与 fragment shader 之间的信使,一般我们在 vertex shader 中修改它然后在fragment shader使用它,但不能在fragment shader中修改它.

// 顶点着色器
varying vec4 v_Color;
void main(){
  v_Color = vec4(1.,1.,1.,1);
}
// 片元着色器
varying vec4 v_Color;
void main() {
  gl_FragColor = v_Color;
}

glsl的函数:

glsl允许在程序的最外部声明函数.函数不能嵌套,不能递归调用,且必须声明返回值类型(无返回值时声明为void) 在其他方面glsl函数与c函数非常类似.

vec4 getPosition(){ 
  vec4 v4 = vec4(0.,0.,0.,1.);
  return v4;
}

void doubleSize(inout float size){
  size= size*2.0  ;
}
void main() {
  float psize= 10.0;
  doubleSize(psize);
  gl_Position = getPosition();
  gl_PointSize = psize;
}

构造函数:

glsl中变量可以在声明的时候初始化,float pSize = 10.0 也可以先声明然后等需要的时候在进行赋值.
聚合类型对象如(向量,矩阵,数组,结构) 需要使用其构造函数来进行初始化. vec4 color = vec4(0.0, 1.0, 0.0, 1.0);

// 一般类型
float pSize = 10.0;
float pSize1;
pSize1 = 10.0;
// 复合类型
vec4 color = vec4(0.0, 1.0, 0.0, 1.0);
vec4 color1;
color1 = vec4(0.0, 1.0, 0.0, 1.0);
// 结构
struct light {
  float intensity;
  vec3 position;
};
light lightVar = light(3.0, vec3(1.0, 2.0, 3.0)); // 数组
const float c[3] = float[3](5.0, 7.2, 1.1);

类型转换:

glsl可以使用构造函数进行显式类型转换,各值如下:

bool t= true;
bool f = false;
int a = int(t); // true转换为1或1.0
int a1 = int(f);  // false转换为0或0.0 
float b = float(t);
float b1 = float(f);
bool c = bool(0); // 0或0.0转换为false
bool c1 = bool(1); // 非0转换为true
bool d = bool(0.0);
bool d1 = bool(1.0);

精度限定:

glsl在进行光栅化着色的时候,会产生大量的浮点数运算,这些运算可能是当前设备所不能承受的,所以glsl提供了3种浮点数精度,我们可以根据不同的设备来使用合适的精度.
在变量前面加上 highp mediump lowp 即可完成对该变量的精度声明.

lowp float color;
varying mediump vec2 Coord;
lowp ivec2 foo(lowp mat3);
highp mat4 m;

我们一般在片元着色器(fragment shader)最开始的地方加上 precision mediump float; 便设定了默认的精度.这样所有没有显式表明精度的变量都会按照设定好的默认精度来处理.

如何确定精度:

变量的精度首先是由精度限定符决定的,如果没有精度限定符,则要寻找其右侧表达式中,已经确定精度的变量,一旦找到,那么整个表达式都将在该精度下运行.如果找到多个,
则选择精度较高的那种,如果一个都找不到,则使用默认或更大的精度类型.

uniform highp float h1;
highp float h2 = 2.3 * 4.7; //运算过程和结果都 是高精度
mediump float m;
m = 3.7 * h1 * h2; //运算过程 是高精度
h2 = m * h1; //运算过程 是高精度
m = h2 – h1; //运算过程 是高精度
h2 = m + m; //运算过程和结果都 是中等精度
void f(highp float p); // 形参 p 是高精度
f(3.3); //传入的 3.3是高精度

invariant关键字:

由于shader在编译时会进行一些内部优化,可能会导致同样的运算在不同shader里结果不一定精确相等.这会引起一些问题,尤其是vertx shader向fragmeng shader传值的时候.
所以我们需要使用invariant 关键字来显式要求计算结果必须精确一致. 当然我们也可使用 #pragma STDGL invariant(all)来命令所有输出变量必须精确一致,
但这样会限制编译器优化程度,降低性能.

#pragma STDGL invariant(all) //所有输出变量为 invariant
invariant varying texCoord; //varying在传递数据的时候声明为invariant

限定符的顺序:

当需要用到多个限定符的时候要遵循以下顺序:
1.在一般变量中: invariant > storage > precision
2.在参数中: storage > parameter > precision

我们来举例说明:

invariant varying lowp float color; // invariant > storage > precision
void doubleSize(const in lowp float s){ //storage > parameter > precision
    float s1=s;
}

预编译指令:

以 # 开头的是预编译指令,常用的有:
#define #undef #if #ifdef #ifndef #else
#elif #endif #error #pragma #extension #version #line
比如 #version 100 他的意思是规定当前shader使用 GLSL ES 1.00标准进行编译,如果使用这条预编译指令,则他必须出现在程序的最开始位置.

内置的宏:

LINE : 当前源码中的行号.

VERSION : 一个整数,指示当前的glsl版本 比如 100 ps: 100 = v1.00

GL_ES : 如果当前是在 OPGL ES 环境中运行则 GL_ES 被设置成1,一般用来检查当前环境是不是 OPENGL ES.

GL_FRAGMENT_PRECISION_HIGH : 如果当前系统glsl的片元着色器支持高浮点精度,则设置为1.一般用于检查着色器精度.

实例:

1.如何通过判断系统环境,来选择合适的精度:

#ifdef GL_ES //
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
#endif

2.自定义宏:

#define NUM 100
#if NUM==100
#endif

内置的特殊变量

glsl程序使用一些特殊的内置变量与硬件进行沟通.他们大致分成两种
一种是 input类型,他负责向硬件(渲染管线)发送数据.
另一种是output类型,负责向程序回传数据,以便编程时需要.

在 vertex Shader 中:
output 类型的内置变量:

变量说明单位
highp vec4 gl_Position;gl_Position 放置顶点坐标信息vec4
mediump float gl_PointSize;gl_PointSize 需要绘制点的大小,(只在gl.POINTS模式下有效)float

在 fragment Shader 中:
input 类型的内置变量:

变量说明单位
mediump vec4 gl_FragCoord;片元在framebuffer画面的相对位置vec4
bool gl_FrontFacing;标志当前图元是不是正面图元的一部分bool
mediump vec2 gl_PointCoord;经过插值计算后的纹理坐标,点的范围是0.0到1.0vec2

output 类型的内置变量:

变量说明单位
mediump vec4 gl_FragColor;设置当前片点的颜色vec4 RGBA color
mediump vec4 gl_FragData[n]设置当前片点的颜色,使用glDrawBuffers数据数组vec4 RGBA color

流控制

glsl的流控制和c语言非常相似,这里不必再做过多说明,唯一不同的是片段着色器中有一种特殊的控制流discard.使用discard会退出片段着色器,不执行后面的片段着色操作。片段也不会写入帧缓冲区。

void main() {
	vec4 diffuseColor = texture2D( map, vUv );
	gl_FragColor = vec4( diffuseColor.xyz * HSLtoRGB(vec3(vScale/5.0, 1.0, 0.5)), diffuseColor.w );
	if ( diffuseColor.w < 0.5 ) discard;
}

内置函数库

glsl提供了非常丰富的函数库,供我们使用,这些功能都是非常有用且会经常用到的. 这些函数按功能区分大改可以分成7类:

1、通用函数:
下文中的 类型 T可以是 float, vec2, vec3, vec4,且可以逐分量操作.

方法说明
T abs(T x)返回x的绝对值
T sign(T x)比较x与0的值,大于,等于,小于 分别返回 1.0 ,0.0,-1.0
T floor(T x)返回<=x的最大整数
T ceil(T x)返回>=等于x的最小整数
T fract(T x)获取x的小数部分
T mod(T x, T y),T mod(T x, float y)取x,y的余数
T min(T x, T y),T min(T x, float y)取x,y的最小值
T max(T x, T y),T max(T x, float y)取x,y的最大值
T clamp(T x, T minVal, T maxVal),T clamp(T x, float minVal,float maxVal)min(max(x, minVal), maxVal),返回值被限定在 minVal,maxVal之间
T mix(T x, T y, T a),T mix(T x, T y, float a)取x,y的线性混合,x*(1-a)+y*a
T step(T edge, T x),T step(float edge, T x)如果 x<edge 返回 0.0 否则返回1.0
T smoothstep(T edge0, T edge1, T x),T smoothstep(float edge0,float edge1, T x)如果x<edge0 返回 0.0 如果x>edge1返回1.0, 否则返回Hermite插值

2、角度&三角函数:
下文中的 类型 T可以是 float, vec2, vec3, vec4,且可以逐分量操作.

方法说明
T radians(T degrees)角度转弧度
T radians(T degrees)角度转弧度
T degrees(T radians)弧度转角度
T sin(T angle)正弦函数,角度是弧度
T cos(T angle)余弦函数,角度是弧度
T tan(T angle)正切函数,角度是弧度
T asin(T x)反正弦函数,返回值是弧度
T acos(T x)反余弦函数,返回值是弧度
T atan(T y, T x),T atan(T y_over_x)反正切函数,返回值是弧度

3、指数函数:
下文中的 类型 T可以是 float, vec2, vec3, vec4,且可以逐分量操作.

方法说明
T pow(T x, T y)返回x的y次幂 xy
T exp(T x)返回x的自然指数幂 ex
T log(T x)返回x的自然对数 ln
T exp2(T x)返回2的x次幂 2x
T log2(T x)返回2为底的对数 log2
T sqrt(T x)开根号 √x
T inversesqrt(T x)先开根号,在取倒数,就是 1/√x

4、几何函数:
下文中的 类型 T可以是 float, vec2, vec3, vec4,且可以逐分量操作.

方法说明
float length(T x)返回矢量x的长度
float distance(T p0, T p1)返回p0 p1两点的距离
float dot(T x, T y)返回x y的点积
vec3 cross(vec3 x, vec3 y)返回x y的叉积
T normalize(T x)对x进行归一化,保持向量方向不变但长度变为1
T faceforward(T N, T I, T Nref)根据 矢量 N 与Nref 调整法向量
T reflect(T I, T N)返回 I - 2 * dot(N,I) * N, 结果是入射矢量 I 关于法向量N的 镜面反射矢量
T refract(T I, T N, float eta)返回入射矢量I关于法向量N的折射矢量,折射率为eta

5、矩阵函数:
mat可以为任意类型矩阵.

方法说明
mat matrixCompMult(mat x, mat y)将矩阵 x 和 y的元素逐分量相乘

6、向量函数:

下文中的 类型 T可以是 vec2, vec3, vec4, 且可以逐分量操作.

bvec指的是由bool类型组成的一个向量:

vec3 v3= vec3(0.,0.,0.);
vec3 v3_1= vec3(1.,1.,1.);
bvec3 aa= lessThan(v3,v3_1); //bvec3(true,true,true)

方法说明
bvec lessThan(T x, T y)逐分量比较x < y,将结果写入bvec对应位置
bvec lessThanEqual(T x, T y)逐分量比较 x <= y,将结果写入bvec对应位置
bvec greaterThan(T x, T y)逐分量比较 x > y,将结果写入bvec对应位置
bvec greaterThanEqual(T x, T y)逐分量比较 x >= y,将结果写入bvec对应位置
bvec equal(T x, T y),bvec equal(bvec x, bvec y)逐分量比较 x == y,将结果写入bvec对应位置
bvec notEqual(T x, T y),bvec notEqual(bvec x, bvec y)逐分量比较 x!= y,将结果写入bvec对应位置
bool any(bvec x)如果x的任意一个分量是true,则结果为true
bool all(bvec x)如果x的所有分量是true,则结果为true
bvec not(bvec x)bool矢量的逐分量取反

7、纹理查询函数:

图像纹理有两种 一种是平面2d纹理,另一种是盒纹理,针对不同的纹理类型有不同访问方法.

纹理查询的最终目的是从sampler中提取指定坐标的颜色信息. 函数中带有Cube字样的是指 需要传入盒状纹理. 带有Proj字样的是指带投影的版本.

以下函数只在vertex shader中可用:

vec4 texture2DLod(sampler2D sampler, vec2 coord, float lod);
vec4 texture2DProjLod(sampler2D sampler, vec3 coord, float lod);
vec4 texture2DProjLod(sampler2D sampler, vec4 coord, float lod);
vec4 textureCubeLod(samplerCube sampler, vec3 coord, float lod);

以下函数只在fragment shader中可用:

vec4 texture2D(sampler2D sampler, vec2 coord, float bias);
vec4 texture2DProj(sampler2D sampler, vec3 coord, float bias);
vec4 texture2DProj(sampler2D sampler, vec4 coord, float bias);
vec4 textureCube(samplerCube sampler, vec3 coord, float bias);

在 vertex shader 与 fragment shader 中都可用:

vec4 texture2D(sampler2D sampler, vec2 coord);
vec4 texture2DProj(sampler2D sampler, vec3 coord);
vec4 texture2DProj(sampler2D sampler, vec4 coord);
vec4 textureCube(samplerCube sampler, vec3 coord);

官方的shader范例:

下面的shader如果你可以一眼看懂,说明你已经对glsl语言基本掌握了.

Vertex Shader:

uniform mat4 mvp_matrix; //透视矩阵 * 视图矩阵 * 模型变换矩阵
uniform mat3 normal_matrix; //法线变换矩阵(用于物体变换后法线跟着变换)
uniform vec3 ec_light_dir; //光照方向
attribute vec4 a_vertex; // 顶点坐标
attribute vec3 a_normal; //顶点法线
attribute vec2 a_texcoord; //纹理坐标
varying float v_diffuse; //法线与入射光的夹角
varying vec2 v_texcoord; //2d纹理坐标
void main(void) {
	// 归一化法线
	vec3 ec_normal = normalize(normal_matrix * a_normal);
	// v_diffuse 是法线与光照的夹角.根据向量点乘法则,当两向量长度为1是 乘积即cosθ值
	v_diffuse = max(dot(ec_light_dir, ec_normal), 0.0);
	v_texcoord = a_texcoord;
	gl_Position = mvp_matrix * a_vertex;
}

Fragment Shader:

precision mediump float;
uniform sampler2D t_reflectance;
uniform vec4 i_ambient;
varying float v_diffuse;
varying vec2 v_texcoord;
void main (void) {
	vec4 color = texture2D(t_reflectance, v_texcoord);
	// 这里分解开来是 color*vec3(1,1,1)*v_diffuse + color*i_ambient
	// 色*光*夹角cos + 色*环境光
	gl_FragColor = color*(vec4(v_diffuse) + i_ambient);
}

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

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

相关文章

C++之std::holds_alternative、std::get、std::variant应用实例(二百一十九)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

AVLoadingIndicatorView - 一个很好的Android加载动画集合

官网 GitHub - HarlonWang/AVLoadingIndicatorView: DEPRECATED 项目简介 AVLoadingIndicatorView is a collection of nice loading animations for Android. You can also find iOS version of this here. Now AVLoadingIndicatorView was updated version to 2.X , If …

git的使用——结合具体问题记录git的使用 代码提交从入门到熟练

前言 git作为开发人员必备的技能&#xff0c;需要熟练掌握&#xff0c;本篇博客记录一些git使用的场景&#xff0c;结合具体问题进行git使用的记录。以gitee的使用为例。 文章目录 前言引出已有项目推送gitee1.gitee中新建项目仓库2.本地项目的初始化提交3.比较好玩的commit图…

【EI会议征稿】2023年工业设计与环境工程国际学术会议

2023 International Conference on Industrial Design and Environmental Engineering 2023年工业设计与环境工程国际学术会议 2023年工业设计与环境工程国际学术会议&#xff08;IDEE 2023&#xff09;将于2023年11月24-26日于郑州召开。本次会议主要围绕工业设计与环境工程…

Django(18):中间件原理和使用

目录 概述Django自带中间件Django的中间件执行顺序自定义中间件函数使用类 其它中间件钩子函数process_viewprocess_exceptionprocess_template_response如何使用这3个钩子函数&#xff1f; 全局异常处理小结 概述 中间件(middleware)是一个镶嵌到Django的request(请求)/respo…

Zero-Shot、One-shot、Few-Shot 的简介

本文将介绍以下内容&#xff1a; Zero-Shot Learning 的提出ZSL 的通俗理解GPT 之 Zero-ShotZero-Shot、One-shot、Few-Shot 的通俗理解 一、Zero-Shot Learning 的提出 零样本学习 Zero-Shot Learning&#xff0c;简称 ZSL&#xff0c;是由 Lampert 等人在 2009 年提出的。…

Powerbi-矩阵日期表矩阵列数据表头排序

首先做一个DAX日期表&#xff0c;Powerbi中新建表输入如下代码即可 日期表 VAR YearStart 2023 //起始年度 VAR YearEnd 2024 //结束年度VAR WeekNumberType 2 VAR WeekDayType 2RETURN GENERATE (CALENDAR( DATE( YearStart , 1 , 1 ) , DATE( YearEnd , 12 , 31…

什么是内存碎片?

在嵌入式系统中&#xff0c;内存是十分有限而且是十分珍贵的&#xff0c;用一块内存就少了一块内存&#xff0c;而在分配中随着内存不断被分配和释放&#xff0c;整个系统内存区域会产生越来越多的碎片。 因为在使用过程中&#xff0c;申请了一些内存&#xff0c;其中一些释放…

软件定义世界,工程引领未来——中山大学软件工程学院 软件工程导论大作业

目录 软件工程&#xff0c;理解加深 个人困惑 软件与软件工程的定义 学习思路的启发 软件危机的认识及思考 软件测试的初步认识 科技前沿&#xff0c;守正创新 代码有智能&#xff0c;教育有情怀 深入浅出&#xff0c;引人入胜 再接再厉&#xff0c;未来可期 “软件…

AI数字人虚拟主播,跟传统主播相比有哪些优势,究竟谁更胜一筹?

在今年&#xff0c;AI人工智能技术得到了快速发展&#xff0c;AI数字人开始大面积进入我们的生活&#xff0c;我们经常可以在各大直播间刷到AI数字人虚拟主播。 这些主播光从表面上来看&#xff0c;完全跟真人一模一样&#xff0c;一样的容貌、一样的身形、一样的声音&#xf…

2023年8月体育用品行业数据分析(京东数据产品)

当前&#xff0c;亚运会临近&#xff0c;这也带动了国民对体育消费的热情&#xff0c;体育产品内销逐渐旺盛&#xff0c;“亚运经济”红利开始显现。鲸参谋数据显示&#xff0c;今年8月份&#xff0c;京东平台上体育用品行业的销量为185万&#xff0c;同比增长2%&#xff1b;销…

vue 组件公共的方法

我这是取后端数据发现后端给的数据啥样的都有 有带标签的 有带图片的 还有换行的把这些筛选掉 比如去掉标签 去掉空格 1.首先创建一个公共页面 /* 处理数据html标签显示界面 */export function removeHTMLTag(htmlStr) { let html htmlStr .replace(/<img.*?>/g…

硬件系统工程师宝典(41)-----蛇形走线有什么用?

各位同学大家好&#xff0c;欢迎继续做客电子工程学习圈&#xff0c;今天我们继续来讲这本书&#xff0c;硬件系统工程师宝典。 上篇我们说到了Datasheet里的内容不用全文通读&#xff0c;应该有选择的查看&#xff0c;如引脚功能、电气参数、典型电路及封装大小。今天我们来讲…

【Vue】修饰符、表单提交方式、自定义组件的关键步骤

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是Java方文山&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的专栏《Vue快速入门》。&#x1f3af;&#x1f3af; &…

Vue3项目中使用插槽

前言&#xff1a; 此文章仅记录插槽的使用&#xff0c;用于自己后期学习查看。 代码实现过程中&#xff0c;HelloWorld为子组件&#xff0c;HomeView为父组件 <slot></slot>元素&#xff1a; 是一个插槽出口&#xff0c;是写在子组件中的&#xff0c;表示了父组件…

81《乡村振兴战略下传统村落文化旅游设计》许少辉瑞博士生辉少许——2023学生开学季许多少年辉光三农

81《乡村振兴战略下传统村落文化旅游设计》许少辉瑞博士生辉少许——2023学生开学季许多少年辉光三农

【卖出备兑看涨期权策略(Covered_call)】

卖出备兑看涨期权策略&#xff08;Covered_call&#xff09; 卖出备兑看涨期权策略是一种最基本的收入策略&#xff0c;该策略主要操作就是在持有标的资产的同时卖出对应的看涨期权合约&#xff0c;以此来作为从持有的标的资产中获取租金的一种方法。如果标的资产的价格上涨到…

基于STC15单片机电子时钟液晶1602串口显示-proteus仿真-源程序

一、系统方案 1、本设计采用STC15单片机作为主控器。 2、液晶1602显示电子时钟。 3、串口显示电子时钟。 4、按键控制开启暂停清零。 二、硬件设计 原理图如下&#xff1a; 三、单片机软件设计 1、首先是系统初始化 uint count0; uint8 strPhoto[8]; uint wendu0;P3M0 0x…

LeetCode 332. Reconstruct Itinerary【欧拉回路,通路,DFS】困难

本文属于「征服LeetCode」系列文章之一&#xff0c;这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁&#xff0c;本系列将至少持续到刷完所有无锁题之日为止&#xff1b;由于LeetCode还在不断地创建新题&#xff0c;本系列的终止日期可能是永远。在这一系列刷题文章…

怎样获取某个文件的public方法个数

背景&#xff1a;idea 提供的list可以查看所有的构造方法&#xff0c;但是无法直接告诉我准确的数目&#xff0c;于是写了以下一个单独的类 import java.lang.reflect.Method; import java.lang.reflect.Modifier;public class MyPublicMethodCounter {public static void mai…