threejs(11)-精通着色器编程(难点)1

news2024/12/26 10:55:32

一、初识着色器语言

GLSL 代表 openGL Shading Language,它是着色器程序的特定标准,您将在接下来的章节中看到。根据硬件和操作系统,还有其他类型的着色器。在这里,我们将使用由Khronos Group监管的 openGL 规范。了解 OpenGL 的历史有助于理解其大部分奇怪的约定,为此我建议您查看:https://openglbook.com/chapter-0-preface-what-is-opengl.html

在这里插入图片描述

import * as THREE from "three";

import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";

// console.log(THREE);
// 初始化场景
const scene = new THREE.Scene();

// 创建透视相机
const camera = new THREE.PerspectiveCamera(
  90,
  window.innerHeight / window.innerHeight,
  0.1,
  1000
);
// 设置相机位置
// object3d具有position,属性是1个3维的向量
camera.position.set(0, 0, 2);
// 更新摄像头
camera.aspect = window.innerWidth / window.innerHeight;
//   更新摄像机的投影矩阵
camera.updateProjectionMatrix();
scene.add(camera);

// 加入辅助轴,帮助我们查看3维坐标轴
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);

// 加载纹理

// const material = new THREE.MeshBasicMaterial({ color: "#00ff00" });
// 创建着色器材质
// vertexShader顶点着色器
//fragmentShader 片源着色器
const shaderMaterial = new THREE.ShaderMaterial({
  vertexShader: ` // vertexShader顶点着色器
        void main(){  // 投影矩阵(三维投影到二维,因为电脑屏幕是二维)<-视图矩阵<-模型矩阵
            gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4( position, 1.0 ) ; //vec4 四个维度
        }
    `,
  fragmentShader: `//fragmentShader 片源着色器
        void main(){
            gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
        }
  `,
});

// 创建平面
const floor = new THREE.Mesh(
  new THREE.PlaneBufferGeometry(1, 1, 64, 64),
  shaderMaterial
);

console.log(floor);
scene.add(floor);

// 初始化渲染器
const renderer = new THREE.WebGLRenderer({ alpha: true });
// renderer.shadowMap.enabled = true;
// renderer.shadowMap.type = THREE.BasicShadowMap;
// renderer.shadowMap.type = THREE.VSMShadowMap;

// 设置渲染尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);

// 监听屏幕大小改变的变化,设置渲染的尺寸
window.addEventListener("resize", () => {
  //   console.log("resize");
  // 更新摄像头
  camera.aspect = window.innerWidth / window.innerHeight;
  //   更新摄像机的投影矩阵
  camera.updateProjectionMatrix();

  //   更新渲染器
  renderer.setSize(window.innerWidth, window.innerHeight);
  //   设置渲染器的像素比例
  renderer.setPixelRatio(window.devicePixelRatio);
});

// 将渲染器添加到body
document.body.appendChild(renderer.domElement);

// 初始化控制器
const controls = new OrbitControls(camera, renderer.domElement);
// 设置控制器阻尼
controls.enableDamping = true;
// 设置自动旋转
// controls.autoRotate = true;

const clock = new THREE.Clock();
function animate(t) {
  const elapsedTime = clock.getElapsedTime();
  //   console.log(elapsedTime);
  requestAnimationFrame(animate);
  // 使用渲染器渲染相机看这个场景的内容渲染出来
  renderer.render(scene, camera);
}

animate();

二、着色器插件安装与文件导入开发

vscode安装shader插件来写glsl文件就会高亮
在这里插入图片描述
01-shader/src/shader/basic/fragment.glsl
片源着色器

void main(){ //vec4 四个维度
    gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
}

01-shader/src/shader/basic/vertex.glsl
顶点着色器

void main(){ // 投影矩阵(三维投影到二维,因为电脑屏幕是二维)<-视图矩阵<-模型矩阵
    gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4( position, 1.0 ) ;
}
import * as THREE from "three";

import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";

// 顶点着色器
import basicVertexShader from "../shader/basic/vertex.glsl";
// 片元着色器
import basicFragmentShader from "../shader/basic/fragment.glsl";

// 初始化场景
const scene = new THREE.Scene();

// 创建透视相机
const camera = new THREE.PerspectiveCamera(
  90,
  window.innerHeight / window.innerHeight,
  0.1,
  1000
);
// 设置相机位置
// object3d具有position,属性是1个3维的向量
camera.position.set(0, 0, 2);
// 更新摄像头
camera.aspect = window.innerWidth / window.innerHeight;
//   更新摄像机的投影矩阵
camera.updateProjectionMatrix();
scene.add(camera);

// 加入辅助轴,帮助我们查看3维坐标轴
const axesHelper = new THREE.AxesHelper(5);
scene.add(axesHelper);

// const material = new THREE.MeshBasicMaterial({ color: "#00ff00" });
// 创建着色器材质
const shaderMaterial = new THREE.ShaderMaterial({
  vertexShader: basicVertexShader,
  fragmentShader: basicFragmentShader,
});

// 创建平面
const floor = new THREE.Mesh(
  new THREE.PlaneBufferGeometry(1, 1, 64, 64),
  shaderMaterial
);

console.log(floor);
scene.add(floor);

// 初始化渲染器
const renderer = new THREE.WebGLRenderer({ alpha: true });
// renderer.shadowMap.enabled = true;
// renderer.shadowMap.type = THREE.BasicShadowMap;
// renderer.shadowMap.type = THREE.VSMShadowMap;

// 设置渲染尺寸大小
renderer.setSize(window.innerWidth, window.innerHeight);

// 监听屏幕大小改变的变化,设置渲染的尺寸
window.addEventListener("resize", () => {
  //   console.log("resize");
  // 更新摄像头
  camera.aspect = window.innerWidth / window.innerHeight;
  //   更新摄像机的投影矩阵
  camera.updateProjectionMatrix();

  //   更新渲染器
  renderer.setSize(window.innerWidth, window.innerHeight);
  //   设置渲染器的像素比例
  renderer.setPixelRatio(window.devicePixelRatio);
});

// 将渲染器添加到body
document.body.appendChild(renderer.domElement);

// 初始化控制器
const controls = new OrbitControls(camera, renderer.domElement);
// 设置控制器阻尼
controls.enableDamping = true;
// 设置自动旋转
// controls.autoRotate = true;

function animate(t) {
  requestAnimationFrame(animate);
  // 使用渲染器渲染相机看这个场景的内容渲染出来
  renderer.render(scene, camera);
}

animate();

三、认识原始着色器材质rawShaderMaterial与attribute_uniform_varying变量

1. 什么是着色器材质

着色器材质(ShaderMaterial)是一个用GLSL编写的小程序 ,在GPU上运行。它能够提供 materials 之外的效果,也可以将许多对象组合成单个Geometry或BufferGeometry以提高性能。

原始着色器材质(RawShaderMaterial) 此类的工作方式与ShaderMaterial类似,不同之处在于内置的uniforms和attributes的定义不会自动添加到GLSL shader代码中。

2. 着色器材质的变量

每个着色器材质都可以指定两种不同类型的shaders,他们是顶点着色器和片元着色器(Vertex shaders and fragment shaders)。
● 顶点着色器首先运行; 它接收attributes, 计算/操纵每个单独顶点的位置,并将其他数据(varyings)传递给片元着色器。
● 片元(或像素)着色器后运行; 它设置渲染到屏幕的每个单独的“片元”(像素)的颜色。
shader中有三种类型的变量: uniforms, attributes, 和 varyings
Uniforms是所有顶点都具有相同的值的变量。 比如灯光,雾,和阴影贴图就是被储存在uniforms中的数据。 uniforms可以通过顶点着色器和片元着色器来访问。
Attributes 与每个顶点关联的变量。例如,顶点位置,法线和顶点颜色都是存储在attributes中的数据。attributes 只 可以在顶点着色器中访问。
Varyings 是从顶点着色器传递到片元着色器的变量。对于每一个片元,每一个varying的值将是相邻顶点值的平滑插值。
注意:在shader 内部,uniforms和attributes就像常量;你只能使用JavaScript代码通过缓冲区来修改它们的值。

3. 着色器材质的使用

上面说了每个着色器材质都可以指定两种不同类型的shaders,不过如果我们不去指定这两个shaders而直接使用也不会报错,因为ShaderMaterial已经定义了默认的顶点着色器和片元着色器,他们的代码是这样的。

//顶点着色器代码
void main() {
    gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}
//片元着色器代码
void main() {
    gl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );
}

这里的projectionMatrix、modelViewMatrix和position都是three为我们设置好的变量,可以直接拿来用,前两个变量我们之前已经说了,而position就是每一个顶点的坐标值,当着色器代码执行时,会循环执行gl_Position和gl_FragColor设置顶点位置,和颜色插值。并且我们最终要设置的就是gl_Position和gl_FragColor。多的先不说,下面看一个小例子。

var geom = new THREE.SphereGeometry(10, 30, 20);
var mate = new THREE.ShaderMaterial({
    vertexShader: `
    varying vec3 vNormal;
    void main() {
                //将attributes的normal通过varying赋值给了向量vNormal
        vNormal = normal;
                //projectionMatrix是投影变换矩阵 modelViewMatrix是相机坐标系的变换矩阵 最后我们将y值乘以1.4得到了一个形如鸡蛋的几何体
        gl_Position = projectionMatrix * modelViewMatrix * vec4( position.x, position.y * 1.4, position.z, 1.0 );
    }
    `,
    fragmentShader: `
        //片元着色器同样需要定义varying vec3 vNormal;
    varying vec3 vNormal;
    void main() {
                //vNormal是一个已经归一化的三维向量
        float pr = (vNormal.x + 1.0) / 2.0; //pr红色通道值范围为0~1
        float pg = (vNormal.y + 1.0) / 2.0; //pg绿色通道值范围为0~1
        float pb = (vNormal.z + 1.0) / 2.0; //pb蓝色通道值范围为0~1
        gl_FragColor=vec4(pr, pg, pb, 1.0); //最后设置顶点颜色,点与点之间会自动插值
    }
    `
})
var mesh = new THREE.Mesh(geom, mate);
scene.add(mesh)

在这里插入图片描述
这篇我们简单的操作顶点着色器和片元着色器绘制了一个五彩的鸡蛋,但是这还仅仅是一个静态的着色器
在这里插入图片描述
在顶点着色器中,将模型坐标单独提取出来:

vec4 modelPosition = modelMatrix * vec4(position, 1.0);  
gl_Position = projectionMatrix * viewMatrix * modelPosition;

modelPosition就是我们说的模型坐标,即右手坐标系,注意它和空间直角坐标系是不同的。(图片来自网络)

右手坐标系
在这里插入图片描述
空间直角坐标系

在这里插入图片描述
对模型的xyz坐标进行处理,修改顶点着色器,对于每个点顶点:

  • XY坐标整体移动1.0个单位
  • Z坐标随着其X坐标成正弦分布
void main() {
	v_uv = uv; // uv坐标信息
    vec4 modelPosition = modelMatrix * vec4(position, 1.0);
    modelPosition.x += 1.0;
    modelPosition.y += 1.0;
    modelPosition.z += 0.1 * sin(modelPosition.x * 10.0);
    gl_Position = projectionMatrix * viewMatrix * modelPosition;
}

threejs为了提高效率默认只渲染单面,需要把 side:THREE.DoubleSide给设置上

const shaderMaterial = new THREE.RawShaderMaterial({
  // 投影矩阵 * 视图矩阵 * 模型矩阵 * 顶点坐标
  vertexShader: vertexShader,
  fragmentShader: fragmentShader,
  side:THREE.DoubleSide
})

效果也如预计中的一样:
在这里插入图片描述
对模型的片元着色器再进行处理,按照Z坐标的大小为其设置颜色:

  • 顶点着色器中设置varying float f_height, 用来向片元着色器传递模型的Z坐标
  • 片元着色器中声明arying float f_height接收来自顶点着色器的信息,在main函数中接受它,把这个值赋给rgba中的第一位

顶点着色器:

attribute vec3 position;
attribute vec2 uv;

uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;

varying vec2 v_uv;
varying float f_height;// 传递Z

precision lowp float;

void main() {
	// v_uv = uv; // uv坐标信息
    vec4 modelPosition = modelMatrix * vec4(position, 1.0);
    modelPosition.x += 1.0;
    modelPosition.y += 1.0;
    modelPosition.z += 0.1 * sin(modelPosition.x * 10.0); 
  f_height = modelPosition.z // 放入传递的数据
    gl_Position = projectionMatrix * viewMatrix * modelPosition;
}

片元着色器:

// varying vec2 v_uv;
varying float f_height; // 传递来的Z坐标
precision lowp float;

void main() {
  float height = f_height + 1.0;  // 创建变量接收数据
  // gl_FragColor = vec4(v_uv, 0.0, 1.0); 
  gl_FragColor = vec4(height * 1.0, 0.0, 0.0, 1.0);
}

波峰处R值很高,而波谷Z坐标为0,接近纯黑色。
在这里插入图片描述

四、unform传递时间变量打造动画与通过uv采样纹理

const texture = textureLoader.load("./texture/ca.jpeg");
const rawShaderMaterial = new THREE.RawShaderMaterial({
  vertexShader: basicVertexShader,
  fragmentShader: basicFragmentShader,
  //   wireframe: true,
  side: THREE.DoubleSide,
  uniforms: { // 传入时间
    uTime: {
      value: 0,
    },
    uTexture: {
      value: texture,
    },
  },
});
function animate(t) {
  const elapsedTime = clock.getElapsedTime();
  //   console.log(elapsedTime);
  rawShaderMaterial.uniforms.uTime.value = elapsedTime; // 改变时间
  requestAnimationFrame(animate);
  // 使用渲染器渲染相机看这个场景的内容渲染出来
  renderer.render(scene, camera);
}

01-shader/src/shader/raw/vertex.glsl
uTime时间传 进去

precision lowp float;
attribute vec3 position;
attribute vec2 uv;


uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;

// 获取时间
uniform float uTime;


varying vec2 vUv;

// highp  -2^16 - 2^16
// mediump -2^10 - 2^10
// lowp -2^8 - 2^8

varying float vElevation;


void main(){
    vUv = uv;
    vec4 modelPosition = modelMatrix * vec4( position, 1.0 );
    // modelPosition.x += 1.0;
    // modelPosition.z += 1.0;

    // modelPosition.z += modelPosition.x;

    modelPosition.z = sin((modelPosition.x+uTime) * 10.0)*0.05 ;
    modelPosition.z += sin((modelPosition.y+uTime)  * 10.0)*0.05 ;
    vElevation = modelPosition.z;

    gl_Position = projectionMatrix * viewMatrix * modelPosition ;
}

01-shader/src/shader/raw/fragment.glsl

precision lowp float;
varying vec2 vUv;
varying float vElevation;

uniform sampler2D uTexture; 


void main(){
    // gl_FragColor = vec4(vUv, 0.0, 1.0);
    // float height = vElevation + 0.05 * 10.0;
    // gl_FragColor = vec4(1.0*height,0.0, 0.0, 1.0);

    // 根据UV,取出对应的颜色
    float height = vElevation + 0.05 * 20.0;
    vec4 textureColor = texture2D(uTexture,vUv);
    textureColor.rgb*=height;
    gl_FragColor = textureColor;
}

在这里插入图片描述

五、着色器编写各种类型图案1

glsl内置函数

开始学习three.js着色器材质时,我们经常会无从下手,辛苦写下的着色器,也会因莫名的报错而手足无措。原因是着色器材质它涉及到另一种语言–GLSL,只有懂了这个语言,我们才能更好的写出着色器材质,利用好的我们的GPU。这篇说一说glsl内置函数。

1. 和角度相关的函数
函数参数描述
sin(x)弧度正弦函数
cos(x)弧度余弦函数
tan(x)弧度正切函数
asin(x)弧度反正弦函数
acos(x)弧度反余弦函数
atan(x)弧度反正切函数
radians(x)弧度角度转换为弧度
degrees(x)弧度弧度转换为角度
2. 数学函数

这类主要是对指数对数幂函数的操作

函数描述
pow(x,y)x的y次方。如果x小于0,结果是未定义的。同样,如果x=0并且y<=0,结果也是未定义的。
exp(x)e的x次方
log(x)计算满足x等于e的y次方的y的值。如果x的值小于0,结果是未定义的。
exp2(x)计算2的x次方
log2(x)计算满足x等于2的y次方的y的值。如果x的值小于0,结果是未定义的。
sqrt(x)计算x的开方。如果x小于0,结果是未定义的。
inversesqrt(x)计算x的开方之一的值,如果x小于等于0,结果是未定义的。
3. 常用函数

这里是常用函数,和js中的内置函数很像,需要牢记。

函数描述
abs(x)返回x的绝对值
sign(x)如果x>0,返回1.0;如果x=0,返回0,如果x<0,返回-1.0
floor(x)返回小于等于x的最大整数值
ceil(x)返回大于等于x的最小整数值
fract(x)返回x-floor(x),即返回x的小数部分
mod(x)返回x和y的模
min(x)返回x和y的值较小的那个值。
max(x)返回x和y的值较大的那个值。
clamp(x, minVal, maxVal)将x值钳于minVal和maxVal之间,意思就是当x<minVal时返回minVal,当x>maxVal时返回maxVal,当x在minVal和maxVal之间时,返回x
mix(x, y, a)返回线性混合的x和y,如:x*(1−a)+y*a
step(edge, x)如果x < edge,返回0.0,否则返回1.0
smoothstep(edge0, edge1, x)如果x <= edge0,返回0.0 ;如果x >= edge1 返回1.0;如果edge0 < x < edge1,则执行0~1之间的平滑埃尔米特差值。如果edge0 >= edge1,结果是未定义的。
4. 几何函数

这是与长度、距离、向量等相关的函数

函数描述
length(x)返回向量x的长度
distance(p0,p1)计算向量p0,p1之间的距离
dot向量x,y之间的点积
cross(x, y)向量x,y之间的叉积
normalize(x)标准化向量,返回一个方向和x相同但长度为1的向量
faceforward(N, I, Nref)如果Nref和I的点积小于0,返回N;否则,返回-N;
reflect(I, N)返回反射向量
refract(I, N, eta)返回折射向量

经常用的函数差不多就是这些。还需要我们在实践中反复练习,才能使用的得心应手。

随机数
https://thebookofshaders.com/10/?lan=ch

在这里插入图片描述

02-three_shader图形/src/shaders/deep/vertex.glsl
顶点着色器

varying vec2 vUv;
// highp -2^16-2^16
// mediump = -2^10-2^10
// lowp -2^8-2^8
precision lowp float;
void main(){
    vec4 modelPosition = modelMatrix * vec4( position, 1.0 );
    vUv=uv; // uv自动获取,相当于(0,0)、(1,0)、(1,1)、(0,1) 四点坐标
    gl_Position =  projectionMatrix * viewMatrix * modelPosition;
}

// uv自动获取,相当于(0,0)、(1,0)、(1,1)、(0,1) 四点坐标在这里插入图片描述
02-three_shader图形/src/shaders/deep/fragment.glsl

precision lowp float;
varying vec2 vUv;
void main(){
	 // 1通过顶点对应的uv,决定每一个像素在uv图像的位置,通过这个位置x,y决定颜色
	 // rgba(0,0,0,1)、rgba(1,0,0,1)、rgba(1,1,0,1)、rgba(0,1,0,1)
     gl_FragColor =vec4(vUv,0,1) ;
}

在这里插入图片描述

对第一种变形

在这里插入图片描述

02-three_shader图形/src/shaders/deep/fragment.glsl

precision lowp float;
varying vec2 vUv;
void main(){
	 // 1通过顶点对应的uv,决定每一个像素在uv图像的位置,通过这个位置x,y决定颜色
	 // rgba(0,0,1,1)、rgba(1,0,1,1)、rgba(1,1,1,1)、rgba(0,1,1,1)
     gl_FragColor =vec4(vUv,1,1) ;
}

利用uv实现渐变效果,从左到右

在这里插入图片描述

precision lowp float;
varying vec2 vUv;
void main(){
     gl_FragColor =vec4(vUv.x,vUv.x,vUv.x,1) ;
}

利用uv实现渐变效果,从下到上

在这里插入图片描述

precision lowp float;
varying vec2 vUv;
void main(){
	float strength = vUv.y;
    gl_FragColor =vec4(strength,strength,strength,1);
}

利用uv实现渐变效果,从上到下

在这里插入图片描述

precision lowp float;
varying vec2 vUv;
void main(){
	float strength = 1.0 - vUv.y;
    gl_FragColor =vec4(strength,strength,strength,1);
}

利用通过取模达到反复效果

在这里插入图片描述

precision lowp float;
varying vec2 vUv;
void main(){
	float strength = mod(vUv.y * 10.0 , 1.0) ; // 取模 0.1,0.2,0.3....->0.1,0.2,0.3....
    gl_FragColor =vec4(strength,strength,strength,1);
}

利用step(edge, x)如果x < edge,返回0.0,否则返回1.0

在这里插入图片描述

precision lowp float;
varying vec2 vUv;
void main(){
	float strength =  mod(vUv.y * 10.0 , 1.0);
	strength = step(0.5,strength);
    gl_FragColor =vec4(strength,strength,strength,1);
}

条纹相加

在这里插入图片描述

precision lowp float;
varying vec2 vUv;
void main(){
	float strength = step(0.8, mod(vUv.x * 10.0 , 1.0)) ;
	strength += step(0.8, mod(vUv.y * 10.0 , 1.0)) ;
    gl_FragColor =vec4(strength,strength,strength,1);
}

条纹相乘

在这里插入图片描述

precision lowp float;
varying vec2 vUv;
void main(){
	float strength = step(0.8, mod(vUv.x * 10.0 , 1.0)) ;
	strength *= step(0.8, mod(vUv.y * 10.0 , 1.0)) ;
    gl_FragColor =vec4(strength,strength,strength,1);
}

方块图形

在这里插入图片描述

precision lowp float;
varying vec2 vUv;
void main(){
	float strength = step(0.2, mod(vUv.x * 10.0 , 1.0)) ;
	strength *= step(0.2, mod(vUv.y * 10.0 , 1.0)) ;
    gl_FragColor =vec4(strength,strength,strength,1);
}

利用绝对值

在这里插入图片描述

precision lowp float;
varying vec2 vUv;
void main(){
	float strength = abs(vUv.x - 0.5) ;
    gl_FragColor =vec4(strength,strength,strength,1);
}

六、着色器编写各类型图案2

取2个值的最小值

在这里插入图片描述

precision lowp float;
varying vec2 vUv;
void main(){
	float strength =min(abs(vUv.x - 0.5), abs(vUv.y - 0.5))  ;
    gl_FragColor =vec4(strength,strength,strength,1);
}

step

在这里插入图片描述

precision lowp float;
varying vec2 vUv;
void main(){
	float strength =step(0.2,max(abs(vUv.x - 0.5), abs(vUv.y - 0.5)));
    gl_FragColor =vec4(strength,strength,strength,1);
}

利用取整,实现条纹渐变

在这里插入图片描述

precision lowp float;
varying vec2 vUv;
void main(){
	float strength = floor(vUv.y*10.0)/10.0;
    gl_FragColor =vec4(strength,strength,strength,1);
}

条纹相乘,实现渐变格子

在这里插入图片描述

precision lowp float;
varying vec2 vUv;
void main(){
	float strength = floor(vUv.x*10.0)/10.0*floor(vUv.y*10.0)/10.0;
    gl_FragColor =vec4(strength,strength,strength,1);
}

随机效果

在这里插入图片描述

precision lowp float;
varying vec2 vUv;
// 随机函数
float random (vec2 st) {
    return fract(sin(dot(st.xy,vec2(12.9898,78.233)))*43758.5453123);
}
strength = random(vec2(strength,strength));
gl_FragColor =vec4(strength,strength,strength,1);

依据length返回向量长度

在这里插入图片描述

precision lowp float;
varying vec2 vUv;
float strength = length(vUv);
gl_FragColor =vec4(strength,strength,strength,1);

根据distance技术2个向量的距离

在这里插入图片描述

在这里插入图片描述

precision lowp float;
varying vec2 vUv;
float strength =1.0 - distance(vUv,vec2(0.5,0.5));
gl_FragColor =vec4(strength,strength,strength,1);

根据相除,实现星星

在这里插入图片描述

precision lowp float;
varying vec2 vUv;
float strength =0.15 / distance(vUv,vec2(0.5,0.5)) - 1.0;
gl_FragColor =vec4(strength,strength,strength,1);

十字交叉的星星

在这里插入图片描述

precision lowp float;
varying vec2 vUv;
float  strength = 0.15 / distance(vec2(vUv.x,(vUv.y-0.5)*5.0+0.5),vec2(0.5,0.5)) - 1.0;
strength += 0.15 / distance(vec2(vUv.y,(vUv.x-0.5)*5.0+0.5),vec2(0.5,0.5)) - 1.0;
gl_FragColor =vec4(strength,strength,strength,strength);

旋转飞镖,旋转uv

在这里插入图片描述

数学 派->3.14

precision lowp float;
varying vec2 vUv;
// 旋转函数
vec2 rotate(vec2 uv, float rotation, vec2 mid)
{
    return vec2(
      cos(rotation) * (uv.x - mid.x) + sin(rotation) * (uv.y - mid.y) + mid.x,
      cos(rotation) * (uv.y - mid.y) - sin(rotation) * (uv.x - mid.x) + mid.y
    );
}

vec2 rotateUv = rotate(vUv,3.14*0.25,vec2(0.5));
vec2 rotateUv = rotate(vUv,-uTime*5.0,vec2(0.5));
float  strength = 0.15 / distance(vec2(rotateUv.x,(rotateUv.y-0.5)*5.0+0.5),vec2(0.5,0.5)) - 1.0;
strength += 0.15 / distance(vec2(rotateUv.y,(rotateUv.x-0.5)*5.0+0.5),vec2(0.5,0.5)) - 1.0;
gl_FragColor =vec4(strength,strength,strength,strength);

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

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

相关文章

java--String

1.String创建对象封装字符串数据的方式 ①方式一&#xff1a;java程序中的所有字符串文字(例如"abc")都为此类的对象 ②方式二&#xff1a;调用String类的构造器初始化字符串对象。 2.String提供的操作字符串数据的常用方法

table组件隐藏额外内容并使用Toolpit显示(vue3)

找到table组件的APi的一个属性 直接在代码里面添加 效果&#xff1a;

JAVA代码视频转GIF(亲测有效)

1.说明 本次使用的是JAVA代码视频转GIF&#xff0c;maven如下&#xff1a; <dependency><groupId>ws.schild</groupId><artifactId>jave-nativebin-win64</artifactId><version>3.2.0</version></dependency><dependency&…

Spring Gateway网关服务分析

关键原理解析 基本原理 Spring Cloud Route核心可以概括为Gateway过滤器框架和Route定义和解析两块内容。 DefaultFilter、GatewayFilter、GlobalFilter 三种过滤器的区别及执行顺序 SpringCloud Gateway中的提到的过滤器包括三种类型&#xff1a; DefaultFilter&#xff1…

CAN总线协议的理解以及移植stm32代码并使用

什么是CAN总线协议 是一种异步半双工的通讯协议&#xff0c;只有CAN_High与CAN_Low两条信号线。 有两种连接形式&#xff1a;闭环总线&#xff08;高速&#xff09;和开环总线&#xff08;远距离&#xff09; 他使用的是一种差分信号来传输电信号 所谓差分信号就是两条信号线…

软件测试|黑盒测试方法论-判定表

在因果图分析法中最后会得出一个判定表&#xff0c;可以看出因果图和判定表是有联系的&#xff0c;一般需要结合起来使用。 因果图是一种分析工具&#xff0c;通过分析最终得到判定表&#xff0c;再通过判定表编写测试用例。在一定情况下也可以直接书写判定表&#xff0c;省略…

Stable Diffusion webui 源码调试(一)

Stable Diffusion webui 源码调试&#xff08;一&#xff09; 个人模型主页&#xff1a;LibLibai stable-diffusion-webui 版本&#xff1a;v1.4.1 内容更新随机&#xff0c;看心情调试代码~ 调试txt2img的参数和工作流 文件 /work/stable-diffusion-webui/modules/txt2img…

软件测试|selenium执行js脚本

JavaScript是运行在客户端&#xff08;浏览器&#xff09;和服务器端的脚本语言&#xff0c;允许将静态网页转换为交互式网页。可以通过 Python Selenium WebDriver 执行 JavaScript 语句&#xff0c;在Web页面中进行js交互。那么js能做的事&#xff0c;Selenium应该大部分也能…

地铁机电设备健康管理现状及改善方法

轨道交通和我们的生活息息相关&#xff0c;从火车到地铁再到轻轨&#xff0c;给人们的出行带来了很大的便利。因此&#xff0c;保障轨道交通的的正常运行和安全至关重要&#xff0c;需要运维人员及时排查设备的问题&#xff0c;解决故障&#xff0c;保证轨道交通的安全运行。本…

Cygwin工具制作Redis服务端Window版本

文章目录 前言一、cygwin是什么&#xff1f;二、cygwin安装Redis源码编译 前言 在学习到redis&#xff0c;经常需要用到一个redis服务端&#xff0c;如果有买服务器或者本机可以支持经常开虚拟机&#xff0c;也是可以的&#xff0c;如果不具备这些条件&#xff0c;还是本机win…

Leetcode刷题详解——字母大小写全排列

1. 题目链接&#xff1a;784. 字母大小写全排列 2. 题目描述&#xff1a; 给定一个字符串 s &#xff0c;通过将字符串 s 中的每个字母转变大小写&#xff0c;我们可以获得一个新的字符串。 返回 所有可能得到的字符串集合 。以 任意顺序 返回输出。 示例 1&#xff1a; 输入&…

2023年9月少儿编程 中国电子学会图形化编程等级考试Scratch编程二级真题解析(判断题)

2023年9月scratch编程等级考试二级真题 判断题(共10题,每题2分,共20分) 26、下列两个程序运行效果一样 答案:对 考点分析:考查积木综合使用,重点考查重复执行和坐标积木 两个程序都是在x=0,y=100的时候停止,所以正确 27、甲、乙和丙,一位是山东人,一位是河南人,…

死锁问题概述

文章目录 死锁的概念死锁的定义相似概念&#xff1a;饥饿死锁产生的原因死锁产生的必要条件死锁的预防破坏互斥条件破坏不可剥夺/不可抢占条件破坏请求并保持条件破坏循环等待条件 死锁避免安全性算法 死锁的处理策略死锁的检测死锁的解除 死锁的概念 死锁的定义 多个进程由于…

什么是代理IP池?如何判断IP代理商的IP池是否真实优质?

代理池充当多个代理服务器的存储库&#xff0c;提供在线安全和匿名层。代理池允许用户抓取数据、访问受限制的内容以及执行其他在线任务&#xff0c;而无需担心被检测或阻止的风险。代理池为各种在线活动&#xff08;例如网页抓取、安全浏览等&#xff09;提高后勤保障。 读完…

<C++> list模拟实现

目录 前言 一、list的使用 1. list的构造函数 2. list iterator的使用 3. list capacity 4. list modifiers 5. list的算法 1. unique​ 2. sort 3. merge 4. remove 5. splice 二、list模拟实现 1. 设置节点类 && list类 2. push_back 3. 迭代器 重载 * 重载前置 …

统计一个只包含大写字母的字符串中顺序对的数量.其中顺序对的定义为前面的字符小后面的字符大.例如在“ABC“中的顺序对为3,因为有AB,AC,BC

哈希法&#xff1a;扫描字符串&#xff0c;将出现的字符次数加1&#xff0c;统计比当前字符字典序小的字母出现的次数&#xff0c;即为顺序串的个数。 int CounSq(const char* arr)//时间复杂度O&#xff08;n&#xff09; {int sig[26] { 0 };int index 0;int sum 0;for (…

【TiDB】TiDB CLuster部署

目录 0 大纲 一 集群部署工具TiUP简介 1 TiUP 简介 2 TiUP使用 3 TiUP使用举例 二 TiDB Cluster安装配置需求 1 生产环境硬件需求 2 操作系统需求 三 TIDB部署 1 软硬件需求以及前置检查​编辑 2 安装TiUP 组件 ​3 集群拓扑文件 4 执行部署命令 &#xff08;1&…

如何使用 NFTScan NFT API 在 zkSync 网络上开发 Web3 应用

zkSync 是由 Matter Labs 创建的&#xff0c;是一个以用户为中心的 zk rollup 平台&#xff0c;它是以太坊的第 2 层扩展解决方案&#xff0c;使用 zk-rollups 作为扩展技术&#xff0c;与 optimistic rollups 一样&#xff0c;zk-rollups 将会汇总以太坊主网上的交易并将交易证…

SSM图书管理系统开发mysql数据库web结构java编程计算机网页源码eclipse项目

一、源码特点 SSM 图书管理系统是一套完善的信息系统&#xff0c;结合springboot框架和bootstrap完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码和 数据库&#xff0c;系统主要…

模拟ASP.NET Core MVC设计与实现

前几天有人在我的《ASP.NET Core框架揭秘》读者群跟我留言说&#xff1a;“我最近在看ASP.NET Core MVC的源代码&#xff0c;发现整个系统太复杂&#xff0c;涉及的东西太多&#xff0c;完全找不到方向&#xff0c;你能不能按照《200行代码&#xff0c;7个对象——让你了解ASP.…