threejs实现烟花效果

大家好!我是 [数擎 AI],一位热爱探索新技术的前端开发者,在这里分享前端和 Web3D、AI 技术的干货与实战经验。如果你对技术有热情,欢迎关注我的文章,我们一起成长、进步!
开发领域 :前端开发 | AI 应用 | Web3D | 元宇宙
技术栈 :JavaScript、React、ThreeJs、WebGL、Go
经验经验:6 年+ 前端开发经验,专注于图形渲染和 AI 技术

找工作,就上智简未来

又是一年岁末,又是辞旧迎新的时刻。寒冬虽冷,但人们心中的那份期待和喜悦,让整个世界变得格外温暖。烟花,作为新年的象征之一,总是在夜空中为我们带来光彩夺目的祝福。

用代码点亮新年

今年,我尝试用代码模拟烟花绽放的画面,融入一些对新年的期待与祝福。烟花不仅是视觉上的震撼,它也能在技术中被表现得充满活力与艺术感。以下是一段基于 Three.js 的烟花效果代码片段,送给所有热爱编程的人们:

javascript 复制代码
import * as THREE from 'three';

// Vertex Shader
const vertexShader = `
varying vec2 vUv;

void main() {
    vUv = uv;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`;

// Fragment Shader
const fragmentShader = `
#define PI      3.141592653589793
#define TWO_PI   6.283185307179586

uniform float iTime;
uniform vec2 iResolution;

varying vec2 vUv;

float star5SDF(vec2 p, float r, float m) {
    const vec2 k1 = vec2(0.809016994375, -0.587785252292);
    const vec2 k2 = vec2(-k1.x, k1.y);
    p.x = abs(p.x);
    p -= 2.0 * max(dot(k1, p), 0.0) * k1;
    p -= 2.0 * max(dot(k2, p), 0.0) * k2;
    p.x = abs(p.x);
    p.y -= r;
    vec2 ab = m * vec2(-k1.y, k1.x) - vec2(0, r);
    float h = clamp(dot(p, ab) / dot(ab, ab), 0.0, 1.0);
    return length(p - ab * h) * sign(p.y * ab.x - p.x * ab.y);
}

float hash1(float p) {
    p = fract(p * .1031 * 9811.164); 
    p *= p + 33.33; 
    p *= p + p;
    return fract(p);
}

vec2 hash21(float p) {
    vec3 p3 = fract(vec3(p) * vec3(.1031, .1030, .0973) * 1023.468);
    p3 += dot(p3, p3.yzx + 33.33);
    return fract((p3.xx + p3.yz) * p3.zy);
}

vec3 colorRibbon(float t) {
    return abs(mod(vec3(0., 1., 2.) / 3.0 + t, 1.0) - 0.5) * 4.0 - 0.5;
}

vec2 getHeartPosition(float t) {
    return vec2(
        16.0 * sin(t) * sin(t) * sin(t),
        -(13.0 * cos(t) - 5.0 * cos(2.0 * t) - 2.0 * cos(3.0 * t) - cos(4.0 * t))
    );
}

void main() {
    float t = iTime * 0.50;
    vec2 uv = vUv * 2.0 - 1.0;
    uv.x *= iResolution.x / iResolution.y;

    vec3 color = vec3(0.0);
    const float jmax = 10.0;
    const float imax = 20.0;

    for (float j = 0.0; j < jmax; j++) {
        float ja = j / jmax;
        t -= hash1(ja * 33.669);
        float t1 = floor(t);
        float t1f = fract(t);

        float t2fa = min(0.3, t1f) / 0.3;
        float t2fb = max(t1f * (step(0.3, t1f)) - 0.3, 0.0) / 0.7;
        float flasht = t2fb * (step(0.1, t2fb) - step(0.0, t2fb)) * 10.0;

        vec2 layer1_pos = hash21(t1 * j);
        vec3 col = colorRibbon(hash1(layer1_pos.y));

        for (float i = 0.0; i < imax; i++) {
            float ia = i / imax;
            vec2 layer2_pos = getHeartPosition(ia * TWO_PI) * t2fb * -0.028;
            layer2_pos -= vec2(
                1.0 - layer1_pos.x * 2.0,
                1.0 - max(layer1_pos.y + 0.75, 0.75) * t2fa
            );

            float blink = step(1.0, mod(i, 2.0));
            float sdf = star5SDF(uv - layer2_pos, 0.05, 0.09) + 0.05;

            color += col * smoothstep(
                -0.016,
                flasht * 3.6 + 4.5 + sin(t2fb * 30.0) * blink,
                (0.02 / sdf)
            );
        }
    }

    gl_FragColor = vec4(color, 1.0);
}
`;

// Three.js Scene Setup
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 2;

const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

// Uniforms
const uniforms = {
    iTime: { value: 0.0 },
    iResolution: { value: new THREE.Vector2(window.innerWidth, window.innerHeight) },
};

// Shader Material
const material = new THREE.ShaderMaterial({
    uniforms: uniforms,
    vertexShader: vertexShader,
    fragmentShader: fragmentShader,
});

const geometry = new THREE.PlaneGeometry(2, 2);
const plane = new THREE.Mesh(geometry, material);
scene.add(plane);

// Animation Loop
function animate() {
    uniforms.iTime.value += 0.01;
    renderer.render(scene, camera);
    requestAnimationFrame(animate);
}

// Resize Listener
window.addEventListener('resize', () => {
    renderer.setSize(window.innerWidth, window.innerHeight);
    uniforms.iResolution.value.set(window.innerWidth, window.innerHeight);
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
});

animate();

在这段代码中,烟花的效果随着时间流逝不断变化,绽放出丰富的色彩,就像我们对未来的期待一样,无限可能。

对你的新年祝福

烟花再美,最重要的还是与亲人、朋友一同分享的瞬间。新年是回顾过往、展望未来的时刻。愿你在新的一年里:

身体健康,平安喜乐。

工作顺利,勇敢追梦。

家庭幸福,爱与温暖常伴。

无论过去一年经历了什么,愿烟花的绽放点亮你的内心,也点燃你的希望。新年快乐,愿你拥有一个充满惊喜和幸福的 2025 年!

相关推荐
程序猿000001号2 小时前
DeepSeek模型:开启人工智能的新篇章
人工智能·deepseek
不写八个3 小时前
Vue3.0教程004:ref和reactive对比
前端·javascript·vue.js
梅羽落5 小时前
JavaScript_03 超简计算器
前端·javascript
梦云澜5 小时前
论文阅读(十四):贝叶斯网络在全基因组DNA甲基化研究中的应用
论文阅读·人工智能·深度学习
前端 贾公子6 小时前
axios如何利用promise无痛刷新token
前端
忆~遂愿7 小时前
3大关键点教你用Java和Spring Boot快速构建微服务架构:从零开发到高效服务注册与发现的逆袭之路
java·人工智能·spring boot·深度学习·机器学习·spring cloud·eureka
新生派7 小时前
HTML<hgroup>标签
前端·html
纠结哥_Shrek7 小时前
pytorch逻辑回归实现垃圾邮件检测
人工智能·pytorch·逻辑回归
辞落山7 小时前
自定义数据集,使用 PyTorch 框架实现逻辑回归并保存模型,然后保存模型后再加载模型进行预测
人工智能·pytorch·逻辑回归
timer_0178 小时前
Tailwind CSS 正式发布了 4.0 版本
前端·css