首页 > 其他分享 >ThreeJS Shader的效果样例光影墙、扩散面(四)

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

时间:2024-09-13 19:02:39浏览次数:9  
标签:planeMesh ThreeJS uniforms geometry 样例 Shader THREE new position

一、实现一个光影墙

  1. 根据自定义坐标点,输出一个光影墙

  

/**
 * 添加光影墙
 */
function addLightWall() {
  const geometry = new THREE.BufferGeometry();
  const vertices = new Float32Array([
    5, 0, 2,
    3, 0, 5,
    -2, 0, 5,
    -4, 0, 2,
    -4, 5, 2,
    -2, 5, 5,
    3, 5, 5,
    5, 5, 2
  ]);
  const indices = new Uint16Array([
    0, 1, 7,
    1, 6, 7,
    1, 2, 6,
    2, 5, 6,
    2, 3, 5,
    3, 4, 5
  ])

  geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
  geometry.setIndex(new THREE.BufferAttribute(indices, 1));
  geometry.setAttribute('aHeight', new THREE.BufferAttribute(new Float32Array(new Array(geometry.getAttribute('position').count).fill(5.0)), 1));
  
  const uniforms = {
    uTime: { value: 0.01 },
  };
  setShader(geometry, vertex, frag, [0, 2.5, 0], uniforms)
}

function setShader(geometry, vertexShader, fragmentShader, position = [0, 0, 0], uniforms = {}, isLine = false) {
  material = new THREE.ShaderMaterial({
    vertexShader: vertexShader,
    fragmentShader: fragmentShader,
    side: THREE.DoubleSide,
    uniforms: uniforms,
    transparent: true,
    // blending: THREE.AdditiveBlending, // 多个元素的颜色相互叠加,颜色可能会变亮,会叠加setClearColor设置的背景色
  });
  material.depthTest = true;
  material.depthWrite = false;
  let planeMesh = new THREE.Mesh(geometry, material);
  if (isLine) {
    planeMesh = new THREE.Points(geometry, material);
  }
  planeMesh.position.x = position[0];
  planeMesh.position.y = position[1];
  planeMesh.position.z = position[2];
  scene.add(planeMesh);
}
自定义坐标

 

  2. 圆柱体的光影墙

  

/**
 * 添加光影墙
 */
function addLightWall() {
  const geometry = new THREE.CylinderGeometry(3, 3, 5.0, 32, 32, true);
  geometry.setAttribute('aHeight', new THREE.BufferAttribute(new Float32Array(new Array(geometry.getAttribute('position').count).fill(5.0)), 1));
  
  // 生成一个渐变色的光影墙
  const vertex = `
      varying vec3 vPosition;
      varying vec2 vUv;
      varying float vHeight;
      attribute float aHeight;
      void main() {
        vHeight = aHeight;
        vUv = uv;
        vPosition = position;
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
      }
  `;

  const frag = `
      varying vec3 vPosition;
      varying vec2 vUv;
      varying float vHeight;
      void main() {
        float d = (vHeight - distance(vPosition, vec3(vPosition.x, -2.5, vPosition.z))) / vHeight;
        gl_FragColor = vec4(0.0, 1.0, 1.0, d);
      }
  `;

  const uniforms = {
    uTime: { value: 0.01 },
  };
  setShader(geometry, vertex, frag, [0, 2.5, 0], uniforms)
}

function setShader(geometry, vertexShader, fragmentShader, position = [0, 0, 0], uniforms = {}, isLine = false) {
  material = new THREE.ShaderMaterial({
    vertexShader: vertexShader,
    fragmentShader: fragmentShader,
    side: THREE.DoubleSide,
    uniforms: uniforms,
    transparent: true,
    // blending: THREE.AdditiveBlending, // 多个元素的颜色相互叠加,颜色可能会变亮,会叠加setClearColor设置的背景色
  });
  material.depthTest = true;
  material.depthWrite = false;
  let planeMesh = new THREE.Mesh(geometry, material);
  if (isLine) {
    planeMesh = new THREE.Points(geometry, material);
  }
  planeMesh.position.x = position[0];
  planeMesh.position.y = position[1];
  planeMesh.position.z = position[2];
  scene.add(planeMesh);
}
圆柱体光影墙

 

  3. 为圆柱体添加可移动的线圈

  

/**
 * 添加光影墙
 */
function addLightWall() {
  const geometry = new THREE.CylinderGeometry(3, 3, 5.0, 32, 32, true);
  geometry.setAttribute('aHeight', new THREE.BufferAttribute(new Float32Array(new Array(geometry.getAttribute('position').count).fill(5.0)), 1));

  // 生成一个可以向上移动的墙体线
  const vertex = `
      varying vec3 vPosition;
      varying vec2 vUv;
      varying float vHeight;
      attribute float aHeight;
      void main() {
        vHeight = aHeight;
        vUv = uv;
        vPosition = position;
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
      }
  `;

  const frag = `
      uniform float uTime;
      varying vec3 vPosition;
      varying vec2 vUv;
      varying float vHeight;
      void main() {
        float dis = distance(vPosition, vec3(vPosition.x, -2.5, vPosition.z));
        float highlightPos = mod(uTime * 5.0, vHeight) - 2.5;
        float highlightDis = distance(vec3(vPosition.x, highlightPos, vPosition.z), vec3(vPosition.x, -2.5, vPosition.z));
        float highlightOpa = (vHeight - highlightDis) / vHeight;
        float opacity = (vHeight - dis) / vHeight;
        if (abs(dis - highlightDis) < 0.05) {
          gl_FragColor = vec4(0.04, 0.95, 0.95, highlightOpa + 0.2);
        } else {
          gl_FragColor = vec4(0.0, 1.0, 1.0, opacity);
        }
      }
  `;

  const uniforms = {
    uTime: { value: 0.01 },
  };
  setShader(geometry, vertex, frag, [0, 2.5, 0], uniforms)
}

function setShader(geometry, vertexShader, fragmentShader, position = [0, 0, 0], uniforms = {}, isLine = false) {
  material = new THREE.ShaderMaterial({
    vertexShader: vertexShader,
    fragmentShader: fragmentShader,
    side: THREE.DoubleSide,
    uniforms: uniforms,
    transparent: true,
    // blending: THREE.AdditiveBlending, // 多个元素的颜色相互叠加,颜色可能会变亮,会叠加setClearColor设置的背景色
  });
  material.depthTest = true;
  material.depthWrite = false;
  let planeMesh = new THREE.Mesh(geometry, material);
  if (isLine) {
    planeMesh = new THREE.Points(geometry, material);
  }
  planeMesh.position.x = position[0];
  planeMesh.position.y = position[1];
  planeMesh.position.z = position[2];
  scene.add(planeMesh);
}
移动线圈光影墙

 

二、实现一个渐变色的波纹圆圈

  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;

              

  

  

/**
 * 添加一个扩散面
 */
function addDiffuseCircle() {
  const geometry = new THREE.CircleGeometry(3, 48);

  // 绘制一个渐变圈宽度可控的圆弧
  const vertex = `
      varying vec2 vUv;
      void main() {
        vUv = uv;
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
      }
  `;

  const frag = `
      uniform float uTime;
      uniform float uThickness;
      varying vec2 vUv;
      void main() {
        // 使用UV坐标计算各个点到中心点的距离,需要减0.5,将圆心移动到(0.5, 0.5)的位置,半径为0.5,透明度范围为0~1,所以需要乘以2
        float distance = length(vUv - 0.5) * 2.0;
        float opacity = (distance - 1.0) / uThickness + 1.0;
        gl_FragColor = vec4(0.0, 1.0, 1.0, opacity);
      }
  `;

  const uniforms = {
    uThickness: { value: 0.8, range: [0, 1] }, // 渐变色的厚度
    uSpeed: { value: 0.5, range: [0, 5] },
    uTime: { value: 0.01 },
  };
  setGui(uniforms);
  setShader(geometry, vertex, frag, [0,0,0], uniforms);
}

function setShader(geometry, vertexShader, fragmentShader, position = [0, 0, 0], uniforms = {}, isLine = false) {
  material = new THREE.ShaderMaterial({
    vertexShader: vertexShader,
    fragmentShader: fragmentShader,
    side: THREE.DoubleSide,
    uniforms: uniforms,
    transparent: true,
    // blending: THREE.AdditiveBlending, // 多个元素的颜色相互叠加,颜色可能会变亮,会叠加setClearColor设置的背景色
  });
  material.depthTest = true;
  material.depthWrite = false;
  let planeMesh = new THREE.Mesh(geometry, material);
  if (isLine) {
    planeMesh = new THREE.Points(geometry, material);
  }
  planeMesh.position.x = position[0];
  planeMesh.position.y = position[1];
  planeMesh.position.z = position[2];

  planeMesh.rotateX(Math.PI / 2);
  scene.add(planeMesh);
}
厚度可变的渐变圆

 

  2. 半径自动缩放的渐变圆

  

/**
 * 添加一个扩散面
 */
function addDiffuseCircle() {
  const geometry = new THREE.CircleGeometry(3, 48);

  // 创建一个大小可控的渐变圆弧
  const vertex = `
      varying vec2 vUv;
      void main() {
        vUv = uv;
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
      }
  `;

  const frag = `
      uniform float uTime;
      uniform float uThickness;
      uniform float uSpeed;
      varying vec2 vUv;
      void main() {
        // 使用UV坐标计算各个点到中心点的距离,需要减0.5,将圆心移动到(0.5, 0.5)的位置,半径为0.5,透明度范围为0~1,所以需要乘以2
        // 假设从内像外开始扩散,距离和时间关系是 最内部: 距离0,时间0;最外部:距离1,时间1,如果用1-时间的话,
        // 所以此时1-时间+距离和样例1中的透明度相同
        float timeDis = fract(uTime * uSpeed);
        float distance = length(vUv - 0.5) * 2.0;
        if (timeDis < distance) {
          gl_FragColor = vec4(0.0, 0.0, 1.0, 0.0);
        } else {
          float opacity = (1.0 - timeDis + distance - 1.0) / uThickness + 1.0;
          gl_FragColor = vec4(0.0, 1.0, 1.0, opacity);
        }
      }
  `;

  const uniforms = {
    uThickness: { value: 0.8, range: [0, 1] }, // 渐变色的厚度
    uSpeed: { value: 0.5, range: [0, 5] },
    uTime: { value: 0.01 },
  };
 
  setShader(geometry, vertex, frag, [0,0,0], uniforms);
}

function setShader(geometry, vertexShader, fragmentShader, position = [0, 0, 0], uniforms = {}, isLine = false) {
  material = new THREE.ShaderMaterial({
    vertexShader: vertexShader,
    fragmentShader: fragmentShader,
    side: THREE.DoubleSide,
    uniforms: uniforms,
    transparent: true,
    // blending: THREE.AdditiveBlending, // 多个元素的颜色相互叠加,颜色可能会变亮,会叠加setClearColor设置的背景色
  });
  material.depthTest = true;
  material.depthWrite = false;
  let planeMesh = new THREE.Mesh(geometry, material);
  if (isLine) {
    planeMesh = new THREE.Points(geometry, material);
  }
  planeMesh.position.x = position[0];
  planeMesh.position.y = position[1];
  planeMesh.position.z = position[2];

  planeMesh.rotateX(Math.PI / 2);
  scene.add(planeMesh);
}
自动缩放的渐变圆

 

标签:planeMesh,ThreeJS,uniforms,geometry,样例,Shader,THREE,new,position
From: https://www.cnblogs.com/codeOnMar/p/18406443

相关文章

  • vue3+ts+threejs全景家居VR看房系统v3.0
    一、系统效果图vue3+ts+threejs全景家居VR看房系统v3.0二、系统功能:1.**360°全景自由视角**:用户可以拖拽观看房内全景和自由旋转视角,查看房间的每个角落。2.**场景切换**:用户可以通过点击房间名称热点标注,实现不同房间之间的切换,体验整个房屋的布局。3.**热点标......
  • Threejs之光线投射Raycaster
    本文目录前言一、简要介绍1.1定义与原理1.2构造器1.3常用属性1.4常用方法二、代码准备及效果2.1演示代码准备2.2效果三、创建射线Raycaster及效果3.1代码3.2效果四、完整代码前言Three.js中的光线投射(Raycaster)是一个功能强大的类,用于在三维场景中执行射......
  • Threejs之光线投射Raycaster交互
    这里写目录标题前言一、前置准备1.1代码1.2效果二、添加交互事件2.1代码2.2效果三、完整代码前言基于上篇文章Threejs之光线投射Raycaster我们知道了光线投射的基础用法,在本届我们将使用光线投射进行鼠标交互事件一、前置准备1.1代码<!DOCTYPEhtml><ht......
  • shader 案例学习笔记之绘制圆
    环境搭建:参考glslvscode环境搭建先上代码#ifdefGL_ESprecisionmediumpfloat;#endifuniformvec2u_resolution;voidmain(){vec2st=gl_FragCoord.xy/u_resolution.xy;st-=0.5;st.x*=u_resolution.x/u_resolution.y;floatr=length(st);......
  • PostgreSQL分区功能深度解析及代码样例
    PostgreSQL分区功能深度解析及代码样例引言PostgreSQL(简称PG)是一款功能强大的开源关系型数据库管理系统,广泛应用于各种企业级应用中。随着数据量的不断增长,数据库的性能和可管理性成为开发者关注的焦点。PostgreSQL的分区功能正是为了解决这些问题而设计的,它允许将一个大表分割成......
  • 用Threejs搭建一个Web3D汽车展厅!
    在网页里360度展示它家新款汽车的3d模型,还要可以让用户DIY汽车部件的颜色。先看最终效果3D引擎的基本知识本文的目标是让大家看完之后可以立刻上手用起来,既然要用3d引擎,那我们理解了一些3d的基本知识后,再看threejs的API文档效率就会很高。无论什么3d引擎,都不外乎由以下几种......
  • Amplify Shader Editor学习
    半透明边缘光效果原理整个效果分为两部分,一个是半透明效果另一个是边缘发光,对于第一个效果来说我们只需要使用透明度混合的方法就可以办到,第二个效果的关键在于怎么辨别边缘?我们可以用法线向量点乘视线向量来辨别.\[\vec{a}*\vec{b}=|a|*|b|*cos\theta,所以可以通过......
  • ThreeJS 综合教程100+【目录】
    ThreeJS综合教程100+旨在为开发者提供两大方面的知识信息:(1)提供详细的每个api知识点的详解(2)提供实战的示例,提供源代码。在这量大系统性的知识下,给用户提供清晰的思路和示例参考,更好的服务于自己的threeJS开发项目。文章正在建设中,下面的是cesium的示例教程(暂时撑门面),随......
  • vue+ThreeJS:从0 到1 搭建开发环境
    文章目录一、下载安装(懒人版)二、顺序安装1,下载安装nodejs2,安装vue-cli3,创建vue-three项目。4,安装threeJS5,安装elementUI(选装)最终package.json文件如下:本系列教程是在vue2.X的基础上加载threeJS程序,来开发各种示例程序。一、下载安装(懒人版)下载vue-three系统包,n......
  • 图形学学习(二):Shader输入输出及自制Shader类
    在LearnOpengl学了Shader的输入输出和自制Shader类,输入输出还是好理解的,自制Shader类的讲解我感觉还是用代码更直观一些(个人感觉),这两天看了一下秋招的面试面经,想了想明年找工作的问题,刺激,十分感慨,优秀的人还是太多了,不过最重要的还是得做好自己!!!Shader的输入输出总结有两种......