THREEJS 片元着色器实现更自然的呼吸灯效果



javascript 复制代码
<template>
  <div ref="container" class="three-container"></div>
</template>

<script setup>
import {ref, onMounted, onBeforeUnmount} from 'vue'
import * as THREE from 'three'
import {OrbitControls} from 'three/addons/controls/OrbitControls.js'
import {GUI} from 'three/addons/libs/lil-gui.module.min.js'


// 着色器代码保持原样
const vertexShader = `
varying vec2 vUv;
void main(){
    vUv = vec2(uv.x,uv.y);
    vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
    gl_Position = projectionMatrix * mvPosition;
}
`

const fragmentShader = `
varying vec2 vUv;
uniform float vTime;
uniform float vPow;
uniform vec3 vColor;

void main(){
    float vy = 1.0 - vUv.y;
    // 添加呼吸波动计算
    float breath = ( sin(vTime * 2.0) * 0.5 + sin(vTime * 3.0) * 0.3) * 0.5 + 0.5; // 生成0-1的波动值
    float alpha = pow(vy, vPow) * breath; // 叠加呼吸效果

    // 添加颜色脉冲效果
    vec3 pulseColor = vColor * (0.8 + breath * 0.2);

    gl_FragColor = vec4(pulseColor, alpha);

    // 在颜色计算后添加边缘光晕
    float edgeGlow = smoothstep(0.7, 1.0, vy);
    gl_FragColor.rgb += edgeGlow * breath * 0.5;
}
`

const container = ref(null)
let scene, renderer, camera, orbit, gui
const uniforms = {
  vTime: {value: 0.01},
  vPow: {value: 2.0},
  vColor: {value: new THREE.Color("#ff0000")}
}

// 初始化场景
const initScene = () => {
  scene = new THREE.Scene()
  renderer = new THREE.WebGLRenderer({
    alpha: true,
    antialias: true
  })
  renderer.setSize(window.innerWidth, window.innerHeight)
  container.value.appendChild(renderer.domElement)

  camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 2000)
  camera.add(new THREE.PointLight())
  camera.position.set(10, 10, 10)
  scene.add(camera)

  orbit = new OrbitControls(camera, renderer.domElement)
  orbit.enableDamping = true
  scene.add(new THREE.GridHelper(10, 10))
}

// 创建网格
const createMesh = () => {
  const planeHeight = 5
  const geometry = new THREE.PlaneGeometry(10, planeHeight)
  const material = new THREE.ShaderMaterial({
    uniforms,
    vertexShader,
    fragmentShader,
    transparent: true,
    side: THREE.DoubleSide
  })

  const createWall = (position, rotation) => {
    const mesh = new THREE.Mesh(geometry, material)
    mesh.position.set(...position)
    if (rotation) mesh.rotation.y = rotation
    return mesh
  }

  scene.add(createWall([5, planeHeight / 2, 0], Math.PI / 2))
  scene.add(createWall([-5, planeHeight / 2, 0], Math.PI / 2))
  scene.add(createWall([0, planeHeight / 2, -5]))
  scene.add(createWall([0, planeHeight / 2, 5]))
}

// 初始化GUI
const initGUI = () => {
  gui = new GUI()
  gui.add(uniforms.vPow, 'value', 0, 10).name('光栅栏高度')

  const colors = {vColor: "#ff0000"}
  gui.addColor(colors, 'vColor').name('光栅栏颜色').onChange(v => {
    uniforms.vColor.value = new THREE.Color(v)
  })
}

// 动画循环
const animate = () => {
  requestAnimationFrame(animate)
  renderer.render(scene, camera)
  orbit.update()
  uniforms.vTime.value += 0.01
}

onMounted(() => {
  initScene()
  createMesh()
  initGUI()
  animate()
  window.addEventListener('resize', onWindowResize)
})

onBeforeUnmount(() => {
  // 清理资源
  gui.destroy()
  scene.traverse(child => {
    if (child.material) child.material.dispose()
    if (child.geometry) child.geometry.dispose()
  })
  renderer.dispose()
  window.removeEventListener('resize', onWindowResize)
})

// 响应窗口变化
const onWindowResize = () => {
  camera.aspect = window.innerWidth / window.innerHeight
  camera.updateProjectionMatrix()
  renderer.setSize(window.innerWidth, window.innerHeight)
}
</script>

<style scoped>
.three-container {
  width: 100vw;
  height: 100vh;
  overflow: hidden;
  margin: 0;
  padding: 0;
}
</style>
相关推荐
Fly26 分钟前
我来提需求,你带着 Codex 做项目:AI 全栈课程开始实战了
前端
集智飞行1 小时前
解决mavros2 ros2版本cpu占用高的问题
java·服务器·前端
w2sfot2 小时前
【JS加密在线】jsjiami.online(让JavaScript 更安全!)
开发语言·javascript·安全
HSunR2 小时前
ruoyi 若依 自定义注解 参数校验
java·前端·数据库
拆房老料3 小时前
ONLYOFFICE也能像Microsoft Word和WPS一样分别设置中西文字体
前端·html·word·开源软件·wps
Solis程序员3 小时前
Stripe 幂等表:把「不确定的重试」变成「查表返回」
前端·安全·bootstrap·php·agent
李纲明3 小时前
WordPress 站点变慢:按 TTFB → 缓存 → 查询 → 前端 分层排查(含配置注意)
前端·缓存·性能优化·wordpress·后端开发
程序人生8883 小时前
PDF 转 Word 版式错乱、表格丢失?DocConverter Web 格式互转引擎的保真实践
前端·人工智能·opencv·机器学习·pdf·word
粥里有勺糖4 小时前
安利一下最近用的桌面“Agent” | T3 Code
前端·github·ai编程
xy34534 小时前
Axure 9.0 动态面板基本操作
前端·ui·html·axure·原型·产品设计