threejs+shader绘制常用的图形

工作中利用好各种图形,是可以做成好看的动态交互,如下动图就是其中的一部分
在这里插入图片描述
在这里插入图片描述

接下来,将展示常用的图形,以及代码如何实现。后面将附上代码,也可以访问这里查看图形效果

常用图形

新建一个平面 ,设置颜色为黄色,透明度为1,

为了更好的显示取反的效果,平面沿着X轴的宽高都设置为2.
new THREE.PlaneBufferGeometry(2, 2, 20,20)
然后设置着色器的颜色,如下

 gl_FragColor =vec4(1,1,0,1);

在这里插入图片描述
注意: 下面用到的vPosition 是由vertexShader中传入的position,此处代码就不写了

x

x轴渐变 从圆点向右,由0到1,越来越不透明,vPosition.x的-1到0的部分,透明度按0处理。

 gl_FragColor =vec4(1,1,0,vPosition.x);
  gl_FragColor =vec4(1,1,0,vPosition.x + vPosition.x); // x 相加,透明度超过1的,按1处理,所以范围只有x的一半

在这里插入图片描述

x + x

x 相加,透明度超过1的,按1处理,所以范围只有x的一半

  gl_FragColor =vec4(1,1,0,vPosition.x + vPosition.x); 

在这里插入图片描述

x * x

x*x 得到 x 镜像叠加 x * x == -x * -x;
[-1,0]的部分相乘的结果和[0,1]相乘的结果是一样的,会得到对称的从两边到中间越来越透明,

 gl_FragColor =vec4(1,1,0,vPosition.x * vPosition.x);

在这里插入图片描述

1.0 - x * x

对 x * x 取反

 gl_FragColor =vec4(1,1,0,1.0-vPosition.x * vPosition.x);

在这里插入图片描述

y 同 x ,不过透明度是从上到下

gl_FragColor =vec4(1,1,0,vPosition.y); //y    透明度 由0到1
gl_FragColor =vec4(1,1,0,vPosition.y); //y +y  相加,透明度超过1的,按1处理,所以范围只有x的一半
gl_FragColor =vec4(1,1,0,vPosition.y * vPosition.y); // y * y 得到y的镜像叠加,中间透明
gl_FragColor =vec4(1,1,0,1.0-vPosition.y * vPosition.y); // 取反

x + y

gl_FragColor =vec4(1,1,0,(vPosition.x+vPosition.y));

在这里插入图片描述

(x + y) + (x + y)

x+y 的基础上范围缩小, 透明度超过1的,按1处理

gl_FragColor =vec4(1,1,0,(vPosition.x+vPosition.y) + (vPosition.x+vPosition.y)); //  

在这里插入图片描述

(x + y) * (x + y)

相乘, 得到 x + y 的镜像叠加 (x + y)(x + y) = -(x + y)-(x + y)

gl_FragColor =vec4(1,1,0,(vPosition.x+vPosition.y) * (vPosition.x+vPosition.y));   

在这里插入图片描述

1.0 - (x + y) * (x + y)

对(x + y) * (x + y) 取反

gl_FragColor =vec4(1,1,0,1.0-(vPosition.x+vPosition.y) * (vPosition.x+vPosition.y)); 

在这里插入图片描述

x*y

gl_FragColor =vec4(1,1,0,(vPosition.x*vPosition.y));

在这里插入图片描述

x * y + x * y

x*y 的基础上范围缩小, 透明度超过1的,按1处理

gl_FragColor =vec4(1,1,0,(vPosition.x*vPosition.y) + (vPosition.x*vPosition.y));

在这里插入图片描述

xy * xy

叠加

gl_FragColor =vec4(1,1,0,(vPosition.x*vPosition.y) * (vPosition.x*vPosition.y)); 

在这里插入图片描述

1.0 - xy * xy

对 xy * xy 取反

gl_FragColor =vec4(1,1,0,1.0-(vPosition.x*vPosition.y) * (vPosition.x*vPosition.y)); // 取反

在这里插入图片描述
当加大平面的宽高 new THREE.PlaneBufferGeometry(20, 20, 20,20) ,得到的结果:如下

在这里插入图片描述

下面是点到坐标点的距离渐变

radius

[0,1] 透明度由0到1 ,超过1的透明度都按1处理

float distanceToCenter = distance(vPosition.xy,vec2(0.0,0.0)) ; // 半径
gl_FragColor =vec4(1,1,0,distanceToCenter); // 圆圈:[0,1] 透明度由0到1 

在这里插入图片描述

radius + radius

圆圈缩小: ,半径相加,透明度超过1的,按1处理

float distanceToCenter = distance(vPosition.xy,vec2(0.0,0.0)) ; // 半径
gl_FragColor =vec4(1,1,0,distanceToCenter + distanceToCenter); // 圆圈缩小: ,半径相加,透明度超过1的,按1处理 

在这里插入图片描述

radius * radius

小数相乘, radius *radius 相乘会小于radius 的值,所以透明度比radius更接近0,透明区域更深

float distanceToCenter = distance(vPosition.xy,vec2(0.0,0.0)) ; // 半径
gl_FragColor =vec4(1,1,0,distanceToCenter * distanceToCenter); // 圆圈: 

在这里插入图片描述

1.0 - radius * radius

对radius * radius 取反

float distanceToCenter = distance(vPosition.xy,vec2(0.0,0.0)) ; // 半径
gl_FragColor =vec4(1,1,0,1.0-distanceToCenter * distanceToCenter); 

在这里插入图片描述

扇形

float alpha =  1.0 - step(0.5,distance(vUv,vec2(0.5)));
float angle = atan(vUv.x-0.5,vUv.y-0.5); //范围 [-3.14, 3.14]
float strength = (angle+3.14)/6.28;
gl_FragColor =vec4(strength,strength,strength,alpha);

在这里插入图片描述

圆环案例

const size  = 50;
 planeMesh = new THREE.Mesh(
    new THREE.PlaneBufferGeometry(size, size),
    new THREE.ShaderMaterial({
      side: THREE.DoubleSide,
      uniforms: {
        uW: { value: 10 },
        uTime: { value: 0 },
        uTexture1: {
          value: textureLoader.load(
            'http://127.0.0.1:5500/examples/screenshots/webgl_animation_keyframes.jpg'
          ),
        },
      },
      vertexShader: `
      varying vec3 vPosition;
      void main() {
        gl_Position = projectionMatrix * viewMatrix * modelMatrix *  vec4( position,1.0 );
        vPosition = position;
      }
      `,
      fragmentShader: `
      varying vec3 vPosition;
      uniform float uW;
      uniform float uTime;
      void main(){
        float distanceToCenter = distance(vPosition.xy,vec2(0.0,0.0)) ; // distanceToCenter的范围[0,size /2 ]
        float radius = (distanceToCenter-uTime); // s的范围是 [-10,40] 透明度小于0的都按0处理,所以10以内的像素都是透明的
        float rr =  1.0 - radius * radius;  // 两个圆叠加,边缘部分透明渐变,然后取反,就是一条虚的环
        float per =  rr + uW;// 环加点宽度; 

        gl_FragColor = mix(vec4(0,0,1,1), vec4(1,1,1,1), per/ uW); // 颜色混合 
      }`,  
    })
  );
  
  gsap.to(planeMesh.material.uniforms.uTime, {
    value: size / 2,
    duration: 3,
    ease: 'none',
    repeat: -1,
    yoyo: true,
  });
 scene.add(planeMesh);

结果如下
在这里插入图片描述

点有规律的增大

aIndex : 每个点的索引index
uScale: 缩放比例

// vertexShader:
// 当前点的大小减去当前时间,所有点会同时越来越小,当点小于0的时候,立即将该点目前的大小(负值)加上最大的点值
float size = aIndex  - uTime; 
// 例如当前是第0个点,随着时间变大,点(负数+uLength)越来越小, 
// 例如当前是第10个点,随着时间变大点越来越小,当点成负数后(负数+uLength),会忽然变成最大值,然后再次越来越小, 
// 以此类推
if(size < 0.0) {
  size = size + uLength;
}
vSize = size  * uScale;
// vSize = (size - uLength / 2.0) * uScale; // 设置前二分之一的点为不可见
gl_PointSize = vSize;

改变uTime会看到如下效果:
在这里插入图片描述

飞线案例

 const m = new THREE.Mesh(
    new THREE.PlaneBufferGeometry(20, 20),
    new THREE.MeshStandardMaterial({ color: 0xffffff, side: THREE.DoubleSide })
  );
  m.rotation.x = -Math.PI / 2;
  scene.add(m);

  const lineCurve = new THREE.CatmullRomCurve3([
    new THREE.Vector3(5, 0, 0),
    new THREE.Vector3(0, 5, 0),
    new THREE.Vector3(-5, 0, 0),
  ]);

  const points = lineCurve.getPoints(500);
  const geometry = new THREE.BufferGeometry().setFromPoints(points);
  const ver = new Float32Array(points.length);

  for (let i = 0; i < points.length; i++) {
    ver[i] = i;
  }

  geometry.setAttribute('aIndex', new THREE.BufferAttribute(ver, 1));

  const material = new THREE.ShaderMaterial({
    transparent: true,
    uniforms: {
      uTime: { value: 0 },
      uLength: {
        value: points.length,
      },
      uScale: {
        value: 0.025,
      },
    },
    vertexShader: `
    attribute float aIndex;
    uniform float uTime;
    uniform float uLength;
    uniform float uScale;
    varying float vSize;
    void main() {
      vec4 modelPosition = modelMatrix * vec4( position, 1.0 ); // 顶点坐标
      gl_Position =  projectionMatrix * viewMatrix * modelPosition;
	  // 当前点的大小减去当前时间,所有点会同时越来越小,当点小于0的时候,立即将该点目前的大小(负值)加上最大的点值
      float size = aIndex  - uTime; 
      // 例如当前是第0个点,随着时间变大,点(负数+uLength)越来越小, 
      // 例如当前是第10个点,随着时间变大点越来越小,当点成负数后(负数+uLength),会忽然变成最大值,然后再次越来越小, 
      // 以此类推
      if(size < 0.0) {
        size = size + uLength;
      }
      // vSize = (size) * uScale;
      vSize = (size - uLength / 2.0) * uScale; // 设置前二分之一的点为不可见
      gl_PointSize = vSize;
    }
    `,
    fragmentShader: `
    varying float vSize;
    uniform float uTime;
    uniform float uLength;
    uniform float uScale;
    void main(){
      // 小于或者等于0的点设置透明度为0;
      if(vSize <= 0.0){
        gl_FragColor = vec4(1,1,0,0);      
      }else{
        // 根据点的大小设置透明度,点越小越透明
        float opacity = uLength / 2.0 * uScale;
        gl_FragColor = vec4(1,1,0,vSize / opacity);      
      }
    }
    `,
  });

  gsap.to(material.uniforms.uTime, {
    value: points.length,
    duration: 5,
    repeat: -1,
  });

  // 创建飞线物体
  const mesh = new THREE.Points(geometry, material);
  scene.add(mesh);

效果如下:
在这里插入图片描述

更多shader案例

案例地址

案例源码

  • 9
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Three.js is a JavaScript library used for creating 3D graphics in the browser. It provides a set of built-in shaders that can be used to create various visual effects like reflections, refractions, shadows, and more. Three.js shaders are written in GLSL (OpenGL Shading Language), a C-like language used for programming graphics processing units (GPUs). To create a custom shader in Three.js, you need to define a new shader material and pass in the GLSL code as a string. Here is an example of a simple custom shader that applies a color gradient based on the object's Y position: ``` var customShader = new THREE.ShaderMaterial({ uniforms: { color1: { value: new THREE.Color(0xff0000) }, color2: { value: new THREE.Color(0x0000ff) } }, vertexShader: ` varying vec3 vPosition; void main() { vPosition = position; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); } `, fragmentShader: ` uniform vec3 color1; uniform vec3 color2; varying vec3 vPosition; void main() { float t = (vPosition.y + 1.0) / 2.0; gl_FragColor = vec4(mix(color1, color2, t), 1.0); } ` }); var cube = new THREE.Mesh( new THREE.BoxGeometry(1, 1, 1), customShader ); scene.add(cube); ``` This shader defines two uniforms (color1 and color2) that represent the two colors of the gradient. In the vertex shader, we pass the vertex position to the fragment shader via a varying variable. In the fragment shader, we calculate the gradient value (t) based on the Y position of the vertex and use the mix() function to interpolate between the two colors. Finally, we set the output color using gl_FragColor.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值