Three.js 催眠粒子漩涡与鼠标反应性运动(源码)

2025-04-24 0 632

使用 Three.js 的 WebGL 小实验。催眠粒子漩涡与鼠标反应性运动。

Three.js 催眠粒子漩涡与鼠标反应性运动(源码)
实现代码
<style>* {    margin0;    padding0;    box-sizing: border-box;}
#container {    position: fixed;    width100%;    height100%;    backgroundlinear-gradient(180deg,        #0a0001 0%,        #220002 50%,        #430100 100%    );    overflow: hidden;}
.glow {    position: fixed;    top0;    left0;    width100%;    height100%;    pointer-events: none;    backgroundradial-gradient(circle at 50% 50%,        rgba(25514000.080%,        rgba(2550760.145%,        transparent 70%    );    mix-blend-mode: screen;    opacity0.85;}</style>
<script type="importmap">{  "imports": {    "three""https://unpkg.com/three@0.162.0/build/three.module.js"  }}</script>
<div id="container"></div><div class="glow"></div>
<script type="module">import * as THREE from 'three';
let scene, camera, renderer, particles;let time = 0;const screenMouse = new THREE.Vector2(1000010000);const worldMouse = new THREE.Vector3();const lastWorldMouse = new THREE.Vector3();const mouseVelocity = new THREE.Vector3();const smoothedMouseVelocity = new THREE.Vector3();
function generateShape(t, angle, phase) {    const baseRadius = 26;    const spiralTwist = 6;    const pulse = Math.sin(t * Math.PI * 2 + phase);    const radius = baseRadius * Math.sqrt(t) * (1 + 0.3 * pulse);    let x = radius * Math.cos(angle + t * spiralTwist);    let y = radius * Math.sin(angle + t * spiralTwist);    let z = radius * Math.sin(t * 8 + phase) * 0.4;    return { x, y, z };}
const particleCount = 100000;
function createParticleSystem() {    const geometry = new THREE.BufferGeometry();    const positions = new Float32Array(particleCount * 3);    const colors = new Float32Array(particleCount * 3);    const sizes = new Float32Array(particleCount);    const angles = new Float32Array(particleCount);    const originalPos = new Float32Array(particleCount * 3);    const randomFactors = new Float32Array(particleCount);
    const colorPalette = [        new THREE.Color('#ff9a00'),        new THREE.Color('#ff004d'),        new THREE.Color('#ffec00'),        new THREE.Color('#ffffff'),        new THREE.Color('#ff5500')    ];
    const goldenAngle = Math.PI * (3 - Math.sqrt(5));
    for(let i = 0; i < particleCount; i++) {        const i3 = i * 3;        const t = i / particleCount;        const angle = i * goldenAngle;        const pos = generateShape(t, angle, 0.8);
        positions[i3] = pos.x;        positions[i3 + 1] = pos.y;        positions[i3 + 2] = pos.z;        originalPos[i3] = pos.x;        originalPos[i3 + 1] = pos.y;        originalPos[i3 + 2] = pos.z;        angles[i] = angle;
        const colorT = t * (colorPalette.length - 1);        const idx = Math.floor(colorT);        const mix = colorT - idx;        const c1 = colorPalette[idx];        const c2 = colorPalette[Math.min(idx + 1, colorPalette.length - 1)];        const color = new THREE.Color().lerpColors(c1, c2, mix);        color.multiplyScalar(0.9 + Math.random() * 0.5);
        colors[i3] = color.r;        colors[i3 + 1] = color.g;        colors[i3 + 2] = color.b;
        sizes[i] = 0.7 * (1.1 - t * 0.3) * (0.6 + Math.random() * 0.7);        randomFactors[i] = Math.random();    }
    geometry.setAttribute('position'new THREE.BufferAttribute(positions, 3));    geometry.setAttribute('color'new THREE.BufferAttribute(colors, 3));    geometry.setAttribute('size'new THREE.BufferAttribute(sizes, 1));    geometry.setAttribute('angle'new THREE.BufferAttribute(angles, 1));    geometry.setAttribute('originalPos'new THREE.BufferAttribute(originalPos, 3));    geometry.setAttribute('randomFactor'new THREE.BufferAttribute(randomFactors, 1));
    const material = new THREE.ShaderMaterial({        uniforms: {            time: { value0 },            mousePos: { valuenew THREE.Vector3(10000100000) },            mouseVel: { valuenew THREE.Vector3() }        },        vertexShader`            uniform float time;            uniform vec3 mousePos;            uniform vec3 mouseVel;            attribute vec3 originalPos;            attribute float size;            attribute float angle;            attribute float randomFactor;            varying vec3 vColor;            varying float vIntensity;            varying float vRandomFactor;
            void main() {                vColor = color;                vRandomFactor = randomFactor;                vec3 basePos = originalPos;
                float morphTime = time * 0.7;                float pattern1 = sin(angle * 5.0 + morphTime) * cos(angle * 2.0);                float pattern2 = cos(angle * 4.0 - morphTime) * sin(angle * 3.0);                float blend = sin(morphTime * 0.6) * 0.5 + 0.5;                float displacement = mix(pattern1, pattern2, blend);                vec3 normOrig = normalize(originalPos + vec3(0.001));                vec3 animatedPos = originalPos + normOrig * displacement * 3.5;
                vec3 pos = animatedPos;                vec3 toMouse = mousePos - pos;                float dist = length(toMouse);                float influence = pow(smoothstep(35.0, 8.0, dist), 2.0);                vIntensity = 0.0;
                if (influence > 0.001) {                    float velMag = length(mouseVel);                    float velInfluence = smoothstep(0.1, 2.0, velMag) * influence;                    vec3 forceDir = normalize(mouseVel + vec3(0.001));                    vec3 pushDir = normalize(pos - mousePos);                    vec3 dir = normalize(mix(forceDir, pushDir, 0.3));                    float dispMag = velInfluence * (3.5 + randomFactor * 4.0);                    pos += dir * dispMag;                    vIntensity = clamp(influence * 0.6 + velInfluence * 0.9, 0.0, 1.0);                }
                pos += (animatedPos - pos) * 0.01;
                float breath = sin(time * 1.3 + angle) * 0.08;                pos *= 1.0 + breath * (1.0 - influence * 0.7) * (0.6 + vRandomFactor * 0.7);
                vec4 mvPos = modelViewMatrix * vec4(pos, 1.0);                gl_Position = projectionMatrix * mvPos;
                float sizeFactor = 1.0 + vIntensity * 0.3;                float perspective = 400.0 / -mvPos.z;                gl_PointSize = size * sizeFactor * perspective * (0.6 + vRandomFactor * 0.7);            }        `,        fragmentShader`            uniform float time;            varying vec3 vColor;            varying float vIntensity;            varying float vRandomFactor;
            void main() {                vec2 pc = gl_PointCoord * 2.0 - 1.0;                float dist = length(pc);                if (dist > 1.0) discard;
                float core = smoothstep(0.2, 0.0, dist) * 0.6;                float glow = exp(-dist * 2.4) * 0.7;
                vec3 highlight = vec3(1.0, 0.9, 0.6);                vec3 finalColor = mix(vColor, highlight, vIntensity * 0.75);
                float shimmer = 1.0 + sin((time * 60.0 + vRandomFactor * 150.0) * (0.7 + vIntensity * 0.3)) * 0.15 * (1.0 - dist * 0.5);                float baseAlpha = (core + glow) * clamp(0.4 + vIntensity * 0.6, 0.0, 1.0);                float finalAlpha = baseAlpha * shimmer;
                gl_FragColor = vec4(finalColor, finalAlpha);            }        `,        transparenttrue,        depthWritefalse,        blendingTHREE.AdditiveBlending,        vertexColorstrue    });
    material.uniforms.time = { value0 };    return new THREE.Points(geometry, material);}
function init() {    scene = new THREE.Scene();    camera = new THREE.PerspectiveCamera(60window.innerWidth / window.innerHeight11000);    camera.position.z = 100;
    renderer = new THREE.WebGLRenderer({ antialiastruepowerPreference"high-performance" });    renderer.setSize(window.innerWidthwindow.innerHeight);    renderer.setClearColor(0x0000000);    renderer.setPixelRatio(Math.min(window.devicePixelRatio1.5));    document.getElementById('container').appendChild(renderer.domElement);
    particles = createParticleSystem();    scene.add(particles);
    document.addEventListener('mousemove'e => {        screenMouse.x = (e.clientX / window.innerWidth) * 2 - 1;        screenMouse.y = -(e.clientY / window.innerHeight) * 2 + 1;    }, { passivetrue });    document.addEventListener('mouseleave'() => {        screenMouse.x = 10000;        screenMouse.y = 10000;    });    window.addEventListener('resize', onWindowResize);}
const raycaster = new THREE.Raycaster();const plane = new THREE.Plane(new THREE.Vector3(001), 0);function updateMouseAndUniforms() {    lastWorldMouse.copy(worldMouse);    raycaster.setFromCamera(screenMouse, camera);    const intersect = new THREE.Vector3();    if (screenMouse.x < 9999 && raycaster.ray.intersectPlane(plane, intersect)) {        worldMouse.copy(intersect);        if (lastWorldMouse.x < 9000) {            mouseVelocity.subVectors(worldMouse, lastWorldMouse);        } else {            mouseVelocity.set(000);        }    } else {        worldMouse.set(10000100000);        mouseVelocity.set(000);    }    smoothedMouseVelocity.lerp(mouseVelocity, 0.15);    mouseVelocity.multiplyScalar(0.92);
    if (particles) {        particles.material.uniforms.mousePos.value.copy(worldMouse);        particles.material.uniforms.mouseVel.value.copy(smoothedMouseVelocity);        particles.material.uniforms.time.value = time;    }}
function animate() {    requestAnimationFrame(animate);    time = performance.now() * 0.0007;
    updateMouseAndUniforms();
    camera.position.x = Math.sin(time * 0.3) * 12;    camera.position.y = Math.cos(time * 0.4) * 12;    camera.lookAt(000);
    renderer.render(scene, camera);}
function onWindowResize() {    camera.aspect = window.innerWidth / window.innerHeight;    camera.updateProjectionMatrix();    renderer.setSize(window.innerWidthwindow.innerHeight);    renderer.setPixelRatio(Math.min(window.devicePixelRatio1.5));}
init();animate();</script>

源码:

https://codepen.io/VoXelo/pen/qEBQqBR

体验:

https://codepen.io/VoXelo/ben/qEBQqBR

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

免责声明 1、百创网作为第三方中介平台,依据交易合同(商品描述、交易前商定的内容)来保障交易的安全及买卖双方的权益; 2、非平台线上交易的项目,出现任何后果均与百创网无关;无论卖家以何理由要求线下交易的,请联系管理举报。 3. 百创网网站的资源均由店家上传出售,本站无法判断和识别资源的版权等合法性属性。如果您对本网站上传的信息资源的版权存有异议,请您及时联系 我们。如果需要删除链接,请下载下面的附件,正确填写信息后并发给我们,本站核实信息真实性后,在24小时内对商品进行删除处理。 联系邮箱:baicxx@baicxx.com (相关事务请发函至该邮箱)

百创网-源码交易平台_网站源码_商城源码_小程序源码 行业资讯 Three.js 催眠粒子漩涡与鼠标反应性运动(源码) https://www.baicxx.com/30426.html

常见问题
  • 1、自动:拍下后,点击(下载)链接即可下载;2、手动:拍下后,联系卖家发放即可或者联系官方找开发者发货。
查看详情
  • 1、源码默认交易周期:手动发货商品为1-3天,并且用户付款金额将会进入平台担保直到交易完成或者3-7天即可发放,如遇纠纷无限期延长收款金额直至纠纷解决或者退款!;
查看详情
  • 1、百创会对双方交易的过程及交易商品的快照进行永久存档,以确保交易的真实、有效、安全! 2、百创无法对如“永久包更新”、“永久技术支持”等类似交易之后的商家承诺做担保,请买家自行鉴别; 3、在源码同时有网站演示与图片演示,且站演与图演不一致时,默认按图演作为纠纷评判依据(特别声明或有商定除外); 4、在没有”无任何正当退款依据”的前提下,商品写有”一旦售出,概不支持退款”等类似的声明,视为无效声明; 5、在未拍下前,双方在QQ上所商定的交易内容,亦可成为纠纷评判依据(商定与描述冲突时,商定为准); 6、因聊天记录可作为纠纷评判依据,故双方联系时,只与对方在百创上所留的QQ、手机号沟通,以防对方不承认自我承诺。 7、虽然交易产生纠纷的几率很小,但一定要保留如聊天记录、手机短信等这样的重要信息,以防产生纠纷时便于百创介入快速处理。
查看详情
  • 1、百创作为第三方中介平台,依据交易合同(商品描述、交易前商定的内容)来保障交易的安全及买卖双方的权益; 2、非平台线上交易的项目,出现任何后果均与百创无关;无论卖家以何理由要求线下交易的,请联系管理举报。
查看详情
  • 免责声明 1、百创网作为第三方中介平台,依据交易合同(商品描述、交易前商定的内容)来保障交易的安全及买卖双方的权益; 2、非平台线上交易的项目,出现任何后果均与百创网无关;无论卖家以何理由要求线下交易的,请联系管理举报。 3. 百创网网站的资源均由店家上传出售,本站无法判断和识别资源的版权等合法性属性。如果您对本网站上传的信息资源的版权存有异议,请您及时联系 我们。如果需要删除链接,请下载下面的附件,正确填写信息后并发给我们,本站核实信息真实性后,在24小时内对商品进行删除处理。 联系邮箱:baicxx@baicxx.com (相关事务请发函至该邮箱)
查看详情

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务

  • 0 +

    访问总数

  • 0 +

    会员总数

  • 0 +

    文章总数

  • 0 +

    今日发布

  • 0 +

    本周发布

  • 0 +

    运行天数

你的前景,远超我们想象