翼度科技»论坛 编程开发 JavaScript 查看内容

ThreeJS Shader的效果样例光影墙、扩散面(四)

10

主题

10

帖子

30

积分

新手上路

Rank: 1

积分
30
一、实现一个光影墙
  1. 根据自定义坐标点,输出一个光影墙
  

  1. /**
  2. * 添加光影墙
  3. */
  4. function addLightWall() {
  5.   const geometry = new THREE.BufferGeometry();
  6.   const vertices = new Float32Array([
  7.     5, 0, 2,
  8.     3, 0, 5,
  9.     -2, 0, 5,
  10.     -4, 0, 2,
  11.     -4, 5, 2,
  12.     -2, 5, 5,
  13.     3, 5, 5,
  14.     5, 5, 2
  15.   ]);
  16.   const indices = new Uint16Array([
  17.     0, 1, 7,
  18.     1, 6, 7,
  19.     1, 2, 6,
  20.     2, 5, 6,
  21.     2, 3, 5,
  22.     3, 4, 5
  23.   ])
  24.   geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
  25.   geometry.setIndex(new THREE.BufferAttribute(indices, 1));
  26.   geometry.setAttribute('aHeight', new THREE.BufferAttribute(new Float32Array(new Array(geometry.getAttribute('position').count).fill(5.0)), 1));
  27.   
  28.   const uniforms = {
  29.     uTime: { value: 0.01 },
  30.   };
  31.   setShader(geometry, vertex, frag, [0, 2.5, 0], uniforms)
  32. }
  33. function setShader(geometry, vertexShader, fragmentShader, position = [0, 0, 0], uniforms = {}, isLine = false) {
  34.   material = new THREE.ShaderMaterial({
  35.     vertexShader: vertexShader,
  36.     fragmentShader: fragmentShader,
  37.     side: THREE.DoubleSide,
  38.     uniforms: uniforms,
  39.     transparent: true,
  40.     // blending: THREE.AdditiveBlending, // 多个元素的颜色相互叠加,颜色可能会变亮,会叠加setClearColor设置的背景色
  41.   });
  42.   material.depthTest = true;
  43.   material.depthWrite = false;
  44.   let planeMesh = new THREE.Mesh(geometry, material);
  45.   if (isLine) {
  46.     planeMesh = new THREE.Points(geometry, material);
  47.   }
  48.   planeMesh.position.x = position[0];
  49.   planeMesh.position.y = position[1];
  50.   planeMesh.position.z = position[2];
  51.   scene.add(planeMesh);
  52. }
复制代码
自定义坐标 
  2. 圆柱体的光影墙
  

  1. /**
  2. * 添加光影墙
  3. */
  4. function addLightWall() {
  5.   const geometry = new THREE.CylinderGeometry(3, 3, 5.0, 32, 32, true);
  6.   geometry.setAttribute('aHeight', new THREE.BufferAttribute(new Float32Array(new Array(geometry.getAttribute('position').count).fill(5.0)), 1));
  7.   
  8.   // 生成一个渐变色的光影墙
  9.   const vertex = `
  10.       varying vec3 vPosition;
  11.       varying vec2 vUv;
  12.       varying float vHeight;
  13.       attribute float aHeight;
  14.       void main() {
  15.         vHeight = aHeight;
  16.         vUv = uv;
  17.         vPosition = position;
  18.         gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  19.       }
  20.   `;
  21.   const frag = `
  22.       varying vec3 vPosition;
  23.       varying vec2 vUv;
  24.       varying float vHeight;
  25.       void main() {
  26.         float d = (vHeight - distance(vPosition, vec3(vPosition.x, -2.5, vPosition.z))) / vHeight;
  27.         gl_FragColor = vec4(0.0, 1.0, 1.0, d);
  28.       }
  29.   `;
  30.   const uniforms = {
  31.     uTime: { value: 0.01 },
  32.   };
  33.   setShader(geometry, vertex, frag, [0, 2.5, 0], uniforms)
  34. }
  35. function setShader(geometry, vertexShader, fragmentShader, position = [0, 0, 0], uniforms = {}, isLine = false) {
  36.   material = new THREE.ShaderMaterial({
  37.     vertexShader: vertexShader,
  38.     fragmentShader: fragmentShader,
  39.     side: THREE.DoubleSide,
  40.     uniforms: uniforms,
  41.     transparent: true,
  42.     // blending: THREE.AdditiveBlending, // 多个元素的颜色相互叠加,颜色可能会变亮,会叠加setClearColor设置的背景色
  43.   });
  44.   material.depthTest = true;
  45.   material.depthWrite = false;
  46.   let planeMesh = new THREE.Mesh(geometry, material);
  47.   if (isLine) {
  48.     planeMesh = new THREE.Points(geometry, material);
  49.   }
  50.   planeMesh.position.x = position[0];
  51.   planeMesh.position.y = position[1];
  52.   planeMesh.position.z = position[2];
  53.   scene.add(planeMesh);
  54. }
复制代码
圆柱体光影墙 
  3. 为圆柱体添加可移动的线圈
  

  1. /**
  2. * 添加光影墙
  3. */
  4. function addLightWall() {
  5.   const geometry = new THREE.CylinderGeometry(3, 3, 5.0, 32, 32, true);
  6.   geometry.setAttribute('aHeight', new THREE.BufferAttribute(new Float32Array(new Array(geometry.getAttribute('position').count).fill(5.0)), 1));
  7.   // 生成一个可以向上移动的墙体线
  8.   const vertex = `
  9.       varying vec3 vPosition;
  10.       varying vec2 vUv;
  11.       varying float vHeight;
  12.       attribute float aHeight;
  13.       void main() {
  14.         vHeight = aHeight;
  15.         vUv = uv;
  16.         vPosition = position;
  17.         gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  18.       }
  19.   `;
  20.   const frag = `
  21.       uniform float uTime;
  22.       varying vec3 vPosition;
  23.       varying vec2 vUv;
  24.       varying float vHeight;
  25.       void main() {
  26.         float dis = distance(vPosition, vec3(vPosition.x, -2.5, vPosition.z));
  27.         float highlightPos = mod(uTime * 5.0, vHeight) - 2.5;
  28.         float highlightDis = distance(vec3(vPosition.x, highlightPos, vPosition.z), vec3(vPosition.x, -2.5, vPosition.z));
  29.         float highlightOpa = (vHeight - highlightDis) / vHeight;
  30.         float opacity = (vHeight - dis) / vHeight;
  31.         if (abs(dis - highlightDis) < 0.05) {
  32.           gl_FragColor = vec4(0.04, 0.95, 0.95, highlightOpa + 0.2);
  33.         } else {
  34.           gl_FragColor = vec4(0.0, 1.0, 1.0, opacity);
  35.         }
  36.       }
  37.   `;
  38.   const uniforms = {
  39.     uTime: { value: 0.01 },
  40.   };
  41.   setShader(geometry, vertex, frag, [0, 2.5, 0], uniforms)
  42. }
  43. function setShader(geometry, vertexShader, fragmentShader, position = [0, 0, 0], uniforms = {}, isLine = false) {
  44.   material = new THREE.ShaderMaterial({
  45.     vertexShader: vertexShader,
  46.     fragmentShader: fragmentShader,
  47.     side: THREE.DoubleSide,
  48.     uniforms: uniforms,
  49.     transparent: true,
  50.     // blending: THREE.AdditiveBlending, // 多个元素的颜色相互叠加,颜色可能会变亮,会叠加setClearColor设置的背景色
  51.   });
  52.   material.depthTest = true;
  53.   material.depthWrite = false;
  54.   let planeMesh = new THREE.Mesh(geometry, material);
  55.   if (isLine) {
  56.     planeMesh = new THREE.Points(geometry, material);
  57.   }
  58.   planeMesh.position.x = position[0];
  59.   planeMesh.position.y = position[1];
  60.   planeMesh.position.z = position[2];
  61.   scene.add(planeMesh);
  62. }
复制代码
移动线圈光影墙 
二、实现一个渐变色的波纹圆圈
  1. 实现一个固定的渐变色圆圈
  原理:
    1) UV点的范围是[0, 1],所以各个像素点距离圆心的距离范围是0~0.5,如果乘以2刚好是透明度的范围(0~1),这样就可以实现一个简单的渐变圆
    2) 假设厚度为t,那么颜色的透明度的范围是[1, 1-t],而我们实际需要的是[1, 0],可以用图二来表示两个线性关系,可以得到两个方程式
      方程式1:y = -x + 1; 
      方程式2:y = -t + 1;  
      现在我们知道方程式二中的y的值(像素点到中心的距离distance),通过解方程式就可以得到方程式1中所对应的透明度的值为 (distance - 1) / t + 1;
    
          

  

  
  1. /**
  2. * 添加一个扩散面
  3. */
  4. function addDiffuseCircle() {
  5.   const geometry = new THREE.CircleGeometry(3, 48);
  6.   // 绘制一个渐变圈宽度可控的圆弧
  7.   const vertex = `
  8.       varying vec2 vUv;
  9.       void main() {
  10.         vUv = uv;
  11.         gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  12.       }
  13.   `;
  14.   const frag = `
  15.       uniform float uTime;
  16.       uniform float uThickness;
  17.       varying vec2 vUv;
  18.       void main() {
  19.         // 使用UV坐标计算各个点到中心点的距离,需要减0.5,将圆心移动到(0.5, 0.5)的位置,半径为0.5,透明度范围为0~1,所以需要乘以2
  20.         float distance = length(vUv - 0.5) * 2.0;
  21.         float opacity = (distance - 1.0) / uThickness + 1.0;
  22.         gl_FragColor = vec4(0.0, 1.0, 1.0, opacity);
  23.       }
  24.   `;
  25.   const uniforms = {
  26.     uThickness: { value: 0.8, range: [0, 1] }, // 渐变色的厚度
  27.     uSpeed: { value: 0.5, range: [0, 5] },
  28.     uTime: { value: 0.01 },
  29.   };
  30.   setGui(uniforms);
  31.   setShader(geometry, vertex, frag, [0,0,0], uniforms);
  32. }
  33. function setShader(geometry, vertexShader, fragmentShader, position = [0, 0, 0], uniforms = {}, isLine = false) {
  34.   material = new THREE.ShaderMaterial({
  35.     vertexShader: vertexShader,
  36.     fragmentShader: fragmentShader,
  37.     side: THREE.DoubleSide,
  38.     uniforms: uniforms,
  39.     transparent: true,
  40.     // blending: THREE.AdditiveBlending, // 多个元素的颜色相互叠加,颜色可能会变亮,会叠加setClearColor设置的背景色
  41.   });
  42.   material.depthTest = true;
  43.   material.depthWrite = false;
  44.   let planeMesh = new THREE.Mesh(geometry, material);
  45.   if (isLine) {
  46.     planeMesh = new THREE.Points(geometry, material);
  47.   }
  48.   planeMesh.position.x = position[0];
  49.   planeMesh.position.y = position[1];
  50.   planeMesh.position.z = position[2];
  51.   planeMesh.rotateX(Math.PI / 2);
  52.   scene.add(planeMesh);
  53. }
复制代码
厚度可变的渐变圆 
  2. 半径自动缩放的渐变圆
  

  1. /**
  2. * 添加一个扩散面
  3. */
  4. function addDiffuseCircle() {
  5.   const geometry = new THREE.CircleGeometry(3, 48);
  6.   // 创建一个大小可控的渐变圆弧
  7.   const vertex = `
  8.       varying vec2 vUv;
  9.       void main() {
  10.         vUv = uv;
  11.         gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
  12.       }
  13.   `;
  14.   const frag = `
  15.       uniform float uTime;
  16.       uniform float uThickness;
  17.       uniform float uSpeed;
  18.       varying vec2 vUv;
  19.       void main() {
  20.         // 使用UV坐标计算各个点到中心点的距离,需要减0.5,将圆心移动到(0.5, 0.5)的位置,半径为0.5,透明度范围为0~1,所以需要乘以2
  21.         // 假设从内像外开始扩散,距离和时间关系是 最内部: 距离0,时间0;最外部:距离1,时间1,如果用1-时间的话,
  22.         // 所以此时1-时间+距离和样例1中的透明度相同
  23.         float timeDis = fract(uTime * uSpeed);
  24.         float distance = length(vUv - 0.5) * 2.0;
  25.         if (timeDis < distance) {
  26.           gl_FragColor = vec4(0.0, 0.0, 1.0, 0.0);
  27.         } else {
  28.           float opacity = (1.0 - timeDis + distance - 1.0) / uThickness + 1.0;
  29.           gl_FragColor = vec4(0.0, 1.0, 1.0, opacity);
  30.         }
  31.       }
  32.   `;
  33.   const uniforms = {
  34.     uThickness: { value: 0.8, range: [0, 1] }, // 渐变色的厚度
  35.     uSpeed: { value: 0.5, range: [0, 5] },
  36.     uTime: { value: 0.01 },
  37.   };
  38.   setShader(geometry, vertex, frag, [0,0,0], uniforms);
  39. }
  40. function setShader(geometry, vertexShader, fragmentShader, position = [0, 0, 0], uniforms = {}, isLine = false) {
  41.   material = new THREE.ShaderMaterial({
  42.     vertexShader: vertexShader,
  43.     fragmentShader: fragmentShader,
  44.     side: THREE.DoubleSide,
  45.     uniforms: uniforms,
  46.     transparent: true,
  47.     // blending: THREE.AdditiveBlending, // 多个元素的颜色相互叠加,颜色可能会变亮,会叠加setClearColor设置的背景色
  48.   });
  49.   material.depthTest = true;
  50.   material.depthWrite = false;
  51.   let planeMesh = new THREE.Mesh(geometry, material);
  52.   if (isLine) {
  53.     planeMesh = new THREE.Points(geometry, material);
  54.   }
  55.   planeMesh.position.x = position[0];
  56.   planeMesh.position.y = position[1];
  57.   planeMesh.position.z = position[2];
  58.   planeMesh.rotateX(Math.PI / 2);
  59.   scene.add(planeMesh);
  60. }
复制代码
自动缩放的渐变圆 

来源:https://www.cnblogs.com/codeOnMar/p/18406443
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具