粒子代码模块

<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>粒子特效</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
            background: #000;
        }

        canvas {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
        }
    </style>
</head>

<body>
    <canvas id="universeCanvas"></canvas>
    <script type="module">
        import * as THREE from "https://cdn.skypack.dev/three@0.136.0";
        import { OrbitControls } from "https://cdn.skypack.dev/three@0.136.0/examples/jsm/controls/OrbitControls";
        import { FontLoader } from "https://cdn.skypack.dev/three@0.136.0/examples/jsm/loaders/FontLoader";
        import { TextGeometry } from "https://cdn.skypack.dev/three@0.136.0/examples/jsm/geometries/TextGeometry";

        // 创建宇宙星辰场景
        const scene = new THREE.Scene();
        const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 1, 1000);
        const renderer = new THREE.WebGLRenderer({ canvas: document.getElementById("universeCanvas") });
        renderer.setSize(window.innerWidth, window.innerHeight);
        camera.position.set(0, 4, 21);

        const controls = new OrbitControls(camera, renderer.domElement);
        controls.enableDamping = true;

        const gu = { time: { value: 0 } };
        const sizes = [];
        const shift = [];
        const pushShift = () => {
            shift.push(
                Math.random() * Math.PI,
                Math.random() * Math.PI * 2,
                (Math.random() * 0.9 + 0.1) * Math.PI * 0.1,
                Math.random() * 0.9 + 0.1
            );
        };

        const pts = new Array(50000).fill().map(() => {
            sizes.push(Math.random() * 1.5 + 0.5);
            pushShift();
            return new THREE.Vector3().randomDirection().multiplyScalar(Math.random() * 0.5 + 9.5);
        });

        for (let i = 0; i < 100000; i++) {
            const r = 10, R = 40;
            const rand = Math.pow(Math.random(), 1.5);
            const radius = Math.sqrt(R * R * rand + (1 - rand) * r * r);
            pts.push(new THREE.Vector3().setFromCylindricalCoords(radius, Math.random() * 2 * Math.PI, (Math.random() - 0.5) * 2));
            sizes.push(Math.random() * 1.5 + 0.5);
            pushShift();
        }

        const g = new THREE.BufferGeometry().setFromPoints(pts);
        g.setAttribute("sizes", new THREE.Float32BufferAttribute(sizes, 1));
        g.setAttribute("shift", new THREE.Float32BufferAttribute(shift, 4));

        const m = new THREE.PointsMaterial({
            size: 0.125,
            transparent: true,
            depthTest: false,
            blending: THREE.AdditiveBlending,
            onBeforeCompile: (shader) => {
                shader.uniforms.time = gu.time;
                shader.vertexShader = `
                    uniform float time;
                    attribute float sizes;
                    attribute vec4 shift;
                    varying vec3 vColor;
                    ${shader.vertexShader}
                `.replace(`gl_PointSize = size;`, `gl_PointSize = size * sizes;`)
                    .replace(`#include <color_vertex>`,
                        `#include <color_vertex>
                    float d = length(abs(position)/vec3(40.,10.,40));
                    d=clamp(d,0.,1.);
                    vColor = mix(vec3(227.,155.,0.),vec3(100.,50.,255.),d)/255.;`)
                    .replace(`#include <begin_vertex>`,
                        `#include <begin_vertex>
                    float t = time;
                    float moveT = mod(shift.x + shift.z * t,PI2);
                    float moveS = mod(shift.y + shift.z * t,PI2);
                    transformed += vec3(cos(moveS) * sin(moveT),cos(moveT),sin(moveS)*sin(moveT)) * shift.w;`);
                shader.fragmentShader = `
                    varying vec3 vColor;
                    ${shader.fragmentShader}
                `.replace(`#include <clipping_planes_fragment>`,
                    `#include <clipping_planes_fragment>
                float d = length(gl_PointCoord.xy - 0.5);`)
                    .replace(`vec4 diffuseColor = vec4( diffuse, opacity );`,
                        `vec4 diffuseColor = vec4( vColor, smoothstep(0.5, 0.1, d));`);
            },
        });

        const stars = new THREE.Points(g, m);
        stars.rotation.order = "ZYX";
        stars.rotation.z = 0.2;
        scene.add(stars);

        // 创建爱心形状的粒子系统
        const heartShape = [];
        const heartCount = 1000;
        for (let i = 0; i < heartCount; i++) {
            const t = Math.PI - 2 * Math.PI * Math.random();
            const x = 16 * Math.pow(Math.sin(t), 3);
            const y = 13 * Math.cos(t) - 5 * Math.cos(2 * t) - 2 * Math.cos(3 * t) - Math.cos(4 * t);
            heartShape.push(new THREE.Vector3(x, y, 0).multiplyScalar(0.2));
        }

        const heartGeometry = new THREE.BufferGeometry().setFromPoints(heartShape);
        const heartMaterial = new THREE.PointsMaterial({
            size: 0.1,
            color: 0xff66cc,
            transparent: true,
            blending: THREE.AdditiveBlending,
        });
        const heart = new THREE.Points(heartGeometry, heartMaterial);
        heart.position.set(0, 0, -5);
        scene.add(heart);

       // 这里可以把xx改名字
        const loader = new FontLoader();
        loader.load("https://threejs.org/examples/fonts/helvetiker_regular.typeface.json", (font) => {
            const textGeometry = new TextGeometry("xxx I love you", {
                font: font,
                size: 1, // 增加字体大小
                height: 0.2,
                curveSegments: 12,
            });
            const textMaterial = new THREE.MeshBasicMaterial({ color: 0xff6699 });
            const textMesh = new THREE.Mesh(textGeometry, textMaterial);

            textMesh.position.set(-5, 0, 0); // 将文字位置置于中心偏左,以便看见
            scene.add(textMesh);

            // 使文本始终面向相机
            textMesh.lookAt(camera.position);
            textMesh.onBeforeRender = function () {
                textMesh.lookAt(camera.position);
            };
        });

        // 动画循环
        const clock = new THREE.Clock();
        const render = () => {
            requestAnimationFrame(render);
            controls.update();

            const elapsed = clock.getElapsedTime();
            gu.time.value = elapsed * Math.PI;
            stars.rotation.y = elapsed * 0.05;
            heart.rotation.y = Math.sin(elapsed) * 0.5;
            heart.rotation.x = Math.cos(elapsed) * 0.2;

            renderer.render(scene, camera);
        };

        render();
    </script>
</body>

</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值