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

一、初识着色器语言

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);

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

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

相关文章

百度上线“文心一言”付费版本,AI聊天机器人市场竞争加剧

原创 | 文 BFT机器人 百度不愧是我国AI技术领域的先行者&#xff0c;每年致力于人工智能领域取得技术产品的突破和创新。据爆料称&#xff0c;百度的文心一言有突破了新境界&#xff0c;开创了文心大模型4.0会员版本。从线上的to C产品到试水商业化&#xff0c;百度都是争先走…

JavaEE平台技术——MyBatis

JavaEE平台技术——MyBatis 1. 对象关系映射框架——Hibernate、MyBatis2. 对象关系模型映射3. MyBatis的实现机制4. MyBatis的XML定义5. Spring事务 在观看这个之前&#xff0c;大家请查阅前序内容。 &#x1f600;JavaEE的渊源 &#x1f600;&#x1f600;JavaEE平台技术——…

互联网金融P2P主业务场景自动化测试

互联网金融P2P行业&#xff0c;近三年来发展迅速&#xff0c;如火如荼。 据不完全统计&#xff0c;全国有3000的企业。 “互联网”企业&#xff0c;几乎每天都会碰到一些奇奇怪怪的bug&#xff0c;作为在互联网企业工作的测试人员&#xff0c;风险和压力都巨大。那么我们如何降…

数据的读取和保存-MATLAB

1 序言 在进行数据处理时&#xff0c;经常需要写代码对保存在文件中的数据进行读取→处理→保存的操作&#xff0c;流程图如下&#xff1a; 笔者每次在进行上述操作时&#xff0c;都需要百度如何“选中目标文件”以及如何“将处理好的数据保存到目标文件中”&#xff0c;对这一…

渗透测试学习day3

文章目录 靶机&#xff1a;DancingTask 1Task 2Task 3Task 4Task 5Task 6Task 7Task 8 靶机&#xff1a;RedeemerTask 1Task 2Task 3Task 4Task 5Task 6Task 7Task 8Task 9Task 10Task 11 靶机&#xff1a;AppointmentTask 1Task 2Task 3Task 4Task 5Task 6Task 7Task 8Task 9T…

AI:62-基于深度学习的人体CT影像肺癌的识别与分类

🚀 本文选自专栏:AI领域专栏 从基础到实践,深入了解算法、案例和最新趋势。无论你是初学者还是经验丰富的数据科学家,通过案例和项目实践,掌握核心概念和实用技能。每篇案例都包含代码实例,详细讲解供大家学习。 📌📌📌在这个漫长的过程,中途遇到了不少问题,但是…

java--String

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

[Vue warn]: Missing required prop: “action“

控制台显示错误信息 vue.runtime.esm.js:4605 [Vue warn]: Missing required prop: "action" found in ---> <ElUpload> at packages/upload/src/index.vue <ElTableRow> <ElTableBody> <ElTable> at pack…

maven中的install 和 clean命令,以及compile、、package、test等操作介绍

maven中的install命令 主要就是谁要被其他模块依赖就install谁 Maven工具可以进行clean、compile、install、package、test等操作&#xff0c;但是这些操作有什么用呢&#xff0c;以下面的p2p-exterface为例说明一下&#xff0c;pwp-exterface工程目录如下&#xff1a; com…

缓存-基础理论和Guava Cache介绍

缓存-基础理论和Guava Cache介绍 缓存基础理论 缓存的容量和扩容 缓存初始容量、最大容量&#xff0c;扩容阈值以及相应的扩容实现。 缓存分类 本地缓存&#xff1a;运行于本进程中的缓存&#xff0c; 如Java的 concurrentHashMap, Ehcache&#xff0c;Guava Cache。 分布式缓…

12 tcp协议详解

1、tcp的本性 tcp是一个悲观者&#xff0c;生下来就不信任网络&#xff0c;任务会发生丢包等&#xff0c;所以要从算法层面来保证可靠性。 2、TCP 包头格式 tcp的包头格式比UDP要复杂的多。 1.源端口号和目标端口号是不可少的&#xff0c;这一点和 UDP 是一样的。如果没有…

星岛专栏|从Web3发展看金融与科技的融合之道

11月起&#xff0c;欧科云链与香港主流媒体星岛集团开设Web3.0安全技术专栏&#xff0c;该专栏主要面向香港从业者、交易机构、监管机构输出专业性的安全合规建议&#xff0c;旨在促进香港Web3.0行业向安全与合规发展。 出品&#xff5c;欧科云链研究院 自2016年首届香港金融…

轻松与任何 SQL 数据库集成:Directus 助你无代码开发 | 开源日报 No.69

Ebazhanov/linkedin-skill-assessments-quizzes Stars: 26.5k License: AGPL-3.0 这个项目是一个 LinkedIn 技能评估答案的存储库。它提供了各种领域和主题的问题和答案&#xff0c;以帮助用户更好地学习新概念并准备相关考试。该项目具有以下核心优势&#xff1a; 提供多语…

计算机毕业设计 基于SpringBoot的养老院管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

作为一名软件测试工程师,需要具备哪些能力?

我是如何走上测试之路的 我是统招本&#xff0c;专业是计算机信息系统和信息管理&#xff0c;大四在一家事业单位&#xff08;就不说名字了&#xff09;实习做Android开发的&#xff0c;等我快毕业的时候&#xff0c;单位明确告诉我不会转正。当然了&#xff0c;我是很清楚的&…

(五)Spring源码解析:ApplicationContext解析

一、概述 1.1> 整体概览 在前面的内容中&#xff0c;我们针对BeanFactory进行了深度的分析。那么&#xff0c;下面我们将针对BeanFactory的功能扩展类ApplicationContext进行深度的分析。ApplicationConext与BeanFactory的功能相似&#xff0c;都是用于向IOC中加载Bean的。…

Python tkinter用iconphoto方法修改窗口标题的图片

修改Python Tkinter窗口的标题图片&#xff0c;可以使用PhotoImage、iconphoto方法。这个方法允许你设置窗口的图标。 运行结果 代码示例如下&#xff1a; import tkinter as tkroot Tk()# 加载图片&#xff0c;记住一定是要PNG图片 icon tk.PhotoImage(filephoto\\图片.pn…

为什么HTTP用得很好的,开始普及HTTPS呢?

显而易见&#xff0c;现在的HTTP早已不安全&#xff0c;当我们在浏览各个网站时会发现HTTP前面都会显示不安全&#xff0c;因为HTTP是明文传输&#xff0c;一旦电脑被植入了木马&#xff0c;木马程序就会主动周期性发消息给Internet的控制终端&#xff0c;这样NAT小洞会一直敞开…

科技创意赋能乡村文旅振兴

近日&#xff0c;由北京大学创意产业研究中心联合中国国际科技促进会新基建专委会共同主办的“科技创意赋能乡村振兴研讨会”在京举行&#xff0c;与会专家学者围绕“和美乡村共同富裕智慧文旅”主题进行深入探讨。北京大学创意产业研究中心副主任吕艺、国家文化和旅游公共服务…

Pytorch R-CNN目标检测-汽车car

概述 目标检测(Object Detection)就是一种基于目标几何和统计特征的图像分割,它将目标的分割和识别合二为一,通俗点说就是给定一张图片要精确的定位到物体所在位置,并完成对物体类别的识别。其准确性和实时性是整个系统的一项重要能力。 R-CNN的全称是Region-CNN(区域卷积神经…