一切皆有因果 发表于 2024-9-14 04:15:29

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

一、实现一个光影墙
  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, , uniforms)
}

function setShader(geometry, vertexShader, fragmentShader, position = , 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;
planeMesh.position.y = position;
planeMesh.position.z = position;
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, , uniforms)
}

function setShader(geometry, vertexShader, fragmentShader, position = , 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;
planeMesh.position.y = position;
planeMesh.position.z = position;
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, , uniforms)
}

function setShader(geometry, vertexShader, fragmentShader, position = , 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;
planeMesh.position.y = position;
planeMesh.position.z = position;
scene.add(planeMesh);
}移动线圈光影墙 
二、实现一个渐变色的波纹圆圈
  1. 实现一个固定的渐变色圆圈
  原理:
    1) UV点的范围是,所以各个像素点距离圆心的距离范围是0~0.5,如果乘以2刚好是透明度的范围(0~1),这样就可以实现一个简单的渐变圆
    2) 假设厚度为t,那么颜色的透明度的范围是,而我们实际需要的是,可以用图二来表示两个线性关系,可以得到两个方程式
      方程式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: }, // 渐变色的厚度
    uSpeed: { value: 0.5, range: },
    uTime: { value: 0.01 },
};
setGui(uniforms);
setShader(geometry, vertex, frag, , uniforms);
}

function setShader(geometry, vertexShader, fragmentShader, position = , 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;
planeMesh.position.y = position;
planeMesh.position.z = position;

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: }, // 渐变色的厚度
    uSpeed: { value: 0.5, range: },
    uTime: { value: 0.01 },
};

setShader(geometry, vertex, frag, , uniforms);
}

function setShader(geometry, vertexShader, fragmentShader, position = , 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;
planeMesh.position.y = position;
planeMesh.position.z = position;

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

来源:https://www.cnblogs.com/codeOnMar/p/18406443
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: ThreeJS Shader的效果样例光影墙、扩散面(四)