Обещаю, еще несколько постов о частицах.

Эта статья является частью моей текущей серии руководств по ThreeJS средней сложности. Я давно хотел что-то среднее между уровнями вступления Как нарисовать куб и Давайте заполним экран шейдерным безумием. Итак, вот оно.

До сих пор мы использовали только одно изображение текстуры для каждого эффекта. "Вот этот":

Этот отлично подходит для множества эффектов, но мы можем сделать гораздо больше, используя разные текстуры. Я скачал этот удивительный набор изображений от мастера игрового арта Кенни. Вы только посмотрите на все крутые изображения!

Теперь мы можем дать волю нашему воображению. Вот пять различных примеров с использованием одного из изображений Кенни, а также настройки, которые я использовал для каждого из них.

Частицы магии

Живая демонстрация

const options = {
    position: new THREE.Vector3(0,2,0),
    positionRandomness: 0.0,
    velocity: new THREE.Vector3(0.0, -0.5, 0.0),
    velocityRandomness: 1.0,
    acceleration: new THREE.Vector3(0.0,0.0,0.0),

    color: new THREE.Color(1.0,0.0,1.0),
    endColor: new THREE.Color(0.0,1.0,1.0),
    colorRandomness: 0.0,

    lifetime: 2.0,
    fadeIn:0.001,
    fadeOut:0.001,
    size: 60,
    sizeRandomness: 0.0,
}

parts = new GPUParticleSystem({
    maxParticles: 10000,
    particleSpriteTex: texture,
    blending: THREE.AdditiveBlending,
    onTick:(system,time) => {
        for (let i = 0; i < 10; i++) {
            options.velocity.set(rand(-1,1),rand(-1,1), 0)
            system.spawnParticle(options);
        }
    }})

Радуга звезд

Живая демонстрация

const options = {
    position: new THREE.Vector3(0,2,0),
    positionRandomness: 0.0,
    velocity: new THREE.Vector3(0.0, -0.5, 0.0),
    velocityRandomness: 1.0,
    acceleration: new THREE.Vector3(0.0,-1.0,0.0),

    color: new THREE.Color(1.0,0.0,1.0),
    endColor: new THREE.Color(0.0,1.0,1.0),

    lifetime: 20.0,
    fadeIn:0.001,
    fadeOut:0.001,
    size: 100,
    sizeRandomness: 0.0,
}

parts = new GPUParticleSystem({
    maxParticles: 10000,
    particleSpriteTex: texture,
    blending: THREE.AdditiveBlending,
    onTick:(system,time) => {
        for (let i = 0; i < 1; i++) {
            options.color.setHSL(rand(0,1),1.0,0.5)
            options.endColor = options.color
            options.position.set(rand(-2.5,-2),2,0)
            options.velocity.set(rand(1.2,1.4),1, 0)
            system.spawnParticle(options);
        }
    }})

Периодические огненные шары

Живая демонстрация

Этот немного отличается тем, что использует условие, чтобы решить, когда стрелять. Код (floor (time)% 6 === 0) означает, что каждые шесть секунд он будет срабатывать непрерывно в течение одной секунды.

const options = {
    position: new THREE.Vector3(0,2,0),
    positionRandomness: 0.0,
    velocity: new THREE.Vector3(0.0, 0, 0.0),
    velocityRandomness: 1.0,
    acceleration: new THREE.Vector3(0.0,0.0,0.0),

    color: new THREE.Color(1.0,0.0,1.0),
    endColor: new THREE.Color(0.0,1.0,1.0),

    lifetime: 2.0,
    fadeIn:0.001,
    fadeOut:3.0,
    size: 60,
    sizeRandomness: 0.0,
}

parts = new GPUParticleSystem({
    maxParticles: 10000,
    particleSpriteTex: texture,
    blending: THREE.AdditiveBlending,
    onTick:(system,time) => {
        if(Math.floor(time) %6 == 0)                 for (let i = 0; i < 6; i++) {
            options.color.setHSL(0.1, 1.0, 0.5)
            options.endColor.setHSL(0.0, 0.0, 0.8)
            options.position.set(0,0,0)
            const s = 0.05
            options.velocity.set(rand(-s,s), rand(-s,s), rand(-s,s))
            system.spawnParticle(options);
        }

    }})

Эффект транспортера

Живая демонстрация

const options = {
    position: new THREE.Vector3(0,2,0),
    positionRandomness: 0.0,
    velocity: new THREE.Vector3(0.0, 0, 0.0),
    velocityRandomness: 1.0,
    acceleration: new THREE.Vector3(0.0,0.0,0.0),

    color: new THREE.Color(1.0,0.0,1.0),
    endColor: new THREE.Color(0.0,1.0,1.0),

    lifetime: 2.0,
    fadeIn:0.001,
    fadeOut:3.0,
    size: 200,
    sizeRandomness: 0.0,
}

parts = new GPUParticleSystem({
    maxParticles: 10000,
    particleSpriteTex: texture,
    blending: THREE.AdditiveBlending,
    onTick: (system, time) => {
        if(Math.floor(time/1) % 2 === 0) {
            options.color.setHSL(0.1, 1.0, 0.5)
            options.endColor.setHSL(0.0, 0.0, 0.8)
            options.position.set(0, 0, 0)
            const s = 0.05
            options.velocity.set(rand(-s, s), rand(-s, s), rand(-s, s))
            system.spawnParticle(options);
        }

    }
})

Бенгальское кольцо

Живая демонстрация

Обратите внимание, что приведенный ниже код вычисляет начальную позицию под случайным углом с использованием sin и cos. Это то, что создает форму круга. Так же просто сделать квадрат или другую форму.

const options = {
    position: new THREE.Vector3(0,2,0),
    positionRandomness: 0.0,
    velocity: new THREE.Vector3(0.0, 0, 0.0),
    velocityRandomness: 1.0,
    acceleration: new THREE.Vector3(0.0,0.0,0.0),

    color: new THREE.Color(1.0,0.0,1.0),
    endColor: new THREE.Color(0.0,1.0,1.0),

    lifetime: 2.0,
    fadeIn:0.001,
    fadeOut:3.0,
    size: 30,
    sizeRandomness: 0.0,
}

parts = new GPUParticleSystem({
    maxParticles: 10000,
    particleSpriteTex: texture,
    blending: THREE.AdditiveBlending,
    onTick: (system, time) => {
        for(let i=0; i<10; i++) {
            options.color.setHSL(0.1, 1.0, 0.5)
            options.endColor.setHSL(0.0, 0.0, 0.8)
            const theta = rand(0,Math.PI*2)
            const size = 0.4
            options.position.set(Math.sin(theta)*size,Math.cos(theta)*size, 0)
            const s = 0.02
            options.velocity.set(rand(-s, s), rand(-s, s), rand(-s, s))
            system.spawnParticle(options);
        }
    }
})

До скорого

Помните, если вы работаете над классным интерфейсом WebVR, который вы хотели бы продемонстрировать прямо в Firefox Reality, дайте мне знать.