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);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值