1. Предпосылки
Спецэффекты частиц - это производственные модули, разработанные различным программным обеспечением 3D для имитации в реальности эффектов воды, огня, тумана, газа и т. д. Их общее или индивидуальное движение имитирует реальный эффект. three.js — это сторонняя библиотека WebGL, написанная на JavaScript. three.js предоставляет богатые API-интерфейсы, которые помогают нам создавать эффекты трехмерного движения. В этой статье в основном рассказывается, как использовать three.js для достижения эффектов перехода частиц и основных операций взаимодействия с мышью. (Примечание: API three.js, используемые в этой статье, основаны на версии r98.)
2. Этапы реализации
1. Создайте сцену сцены рендеринга
Сцена на самом деле эквивалентна трехмерному пространству, используемому для размещения и отображения всего, что мы определяем, включая камеры, объекты, источники света и т. д. В реальной разработке для удобства наблюдения могут быть добавлены некоторые вспомогательные инструменты, такие как сетки, оси координат и т.д.
scene = new THREE.Scene();
scene.fog = new THREE.Fog(0x05050c, 10, 60);
scene.add( new THREE.GridHelper( 2000, 1 ) ); // 添加网格
2. Добавить камеру
В THREE реализовано несколько камер: PerspectiveCamera (перспективная камера), OrthographicCamera (ортогональная проекционная камера), CubeCamera (кубическая камера или панорамная камера) и StereoCamera (3D-камера). В этой статье представлена камера PerspectiveCamera, которую мы в основном используем:
Визуальный эффект почти большой и далеко маленький.
Параметры конфигурации PerspectiveCamera (fov, аспект, близко, далеко).
fov: Угол обзора камеры.
аспект: Соотношение сторон видимого диапазона камеры.
рядом: дальнее расстояние относительно плоскости отсечения глубины.
far: Дальнее расстояние относительно плоскости отсечения глубины.
camera = new THREE.PerspectiveCamera(45, window.innerWidth /window.innerHeight, 5, 100);
camera.position.set(10, -10, -40);
scene.add(camera);
3. Добавьте источники света, необходимые для рендеринга сцены.
Источники света, реализованные в three.js: AmbientLight (окружающий свет), DirectionalLight (параллельный свет), HemisphereLight (полушарный свет), PointLight (точечный источник света), RectAreaLight (плоский источник света), SpotLight (прожектор) и т. д. При настройке параметров источника света необходимо обращать внимание на эффект суперпозиции цветов, например, цвет окружающего света будет напрямую влиять на текущий цвет объекта. Параметры конфигурации различных источников света несколько различаются.В данном случае будут использоваться следующие два источника света.
let ambientLight = new THREE.AmbientLight(0x000000, 0.4);
scene.add(ambientLight);
let pointLight = new THREE.PointLight(0xe42107);
pointLight.castShadow = true;
pointLight.position.set(-10, -5, -10);
pointLight.distance = 20;
scene.add(pointLight);
4. Создайте, экспортируйте и загрузите загрузчик файлов модели.
Чтобы создать модель, вы можете использовать редактор three.js для создания или использовать базовый класс генерации модели three.js для создания Относительно сложные или специальные модели необходимо создавать с помощью инструментов моделирования (c4d, 3dmax и т. д.).
Созданный с помощью редактора three.js, вы можете добавлять базовую геометрию и настраивать различные параметры геометрии (положение, цвет, материал и т. д.).
let geometryCube = new THREE.BoxBufferGeometry( 1, 1, 1 );
let materialCube = new THREE.MeshBasicMaterial( {color: 0x00ff00} );
let cubeMesh = new THREE.Mesh( geometryCube, materialCube );
scene.add( cubeMesh );
Экспортируйте необходимый файл модели (здесь используется файл модели в формате obj).
Загрузите и проанализируйте данные файла модели.
let onProgress = function (xhr) {
if (xhr.lengthComputable) {
// 可进行计算得知模型加载进度
}
};
let onError = function () {};
particleSystem = new THREE.Group();
var texture = new THREE.TextureLoader().load('./point.png');
new THREE.OBJLoader().load('./model.obj', function (object) {
// object 模型文件数据
}, onProgress, onError);
5. Преобразуйте импортированный файл модели в системные точки частиц.
Получите значения координат модели.
Скопируйте значение координаты частицы в новый атрибут position1, который является конечной координатной позицией эффекта перехода частицы.
Добавьте случайное значение трехмерной координаты в систему частиц, цель состоит в том, чтобы зашифровать положение каждой частицы и установить начальную позицию.
let color = new THREE.Color('#ffffff');
let material = new THREE.PointsMaterial({
size: 0.2,
map: texture,
depthTest: false,
transparent: true
});
particleSystem= new THREE.Group();
let allCount = 0
for (let i = 0; i < object.children.length; i++) {
let name = object.children[i].name
let _attributes = object.children[i].geometry.attributes
let count = _attributes.position.count
_attributes.positionEnd = _attributes.position.clone()
_attributes.position1 = _attributes.position.clone()
for (let i = 0; i < count * 3; i++) {
_attributes.position1.array[i]= Math.random() * 100 - 50
}
let particles = new THREE.Points(object.children[i].geometry, material)
particleSystem.add(particles)
allCount += count
}
particleSystem.applyMatrix(new THREE.Matrix4().makeTranslation(-5, -5,-10));
6. Реализовать преобразование координат частиц из position в position1 через библиотеку анимации движения.
Используйте алгоритм плавности TWEEN для расчета положения координат при каждом изменении каждой частицы. Время от начального положения до конечного положения устанавливается равным 2 с (настраивается). После каждого расчета свойство атрибутов position должно быть установлено в значение true. Чтобы напомнить сцене, что ее необходимо обновить, рендеринг будет использовать последнее вычисленное значение для следующего рендеринга.
let pos = {
val: 1
};
tween = new TWEEN.Tween(pos).to({
val: 0
}, 2500).easing(TWEEN.Easing.Quadratic.InOut).onUpdate(callback);
tween.onComplete(function () {
console.log('过渡完成complete')
})
tween.start();
function callback() {
let val = this.val;
let particles = particleSystem.children;
for (let i = 0; i < particles.length; i++) {
let _attributes = particles[i].geometry.attributes
let name = particles[i].name
if (name.indexOf('_') === -1) {
let positionEnd =_attributes.positionEnd.array
let position1 =_attributes.position1.array
let count =_attributes.position.count
for (let j = 0; j < count *3; j++) {
_attributes.position.array[j] = position1[j] *val + positionEnd[j] * (1 - val)
}
}
_attributes.position.needsUpdate = true // 设置更新
}
}
7. Добавьте рендеринг сцены
Создайте контейнер.
Определите средство рендеринга и установите различные параметры.
Добавьте средство визуализации в контейнер.
Пользовательская функция рендеринга, в которой мы используем TWEEN.update для обновления состояния модели.
Вызовите пользовательскую функцию выполнения анимации цикла animate и используйте метод requestAnimationFrame для покадровой визуализации.
let container = document.createElement('div');
document.body.appendChild(container);
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setClearColor(scene.fog.color);
renderer.setClearAlpha(0.8);
renderer.setSize(window.innerWidth, window.innerHeight);
container.appendChild(renderer.domElement); // 添加webgl渲染器
function render() {
particleSystem.rotation.y += 0.0001;
TWEEN.update();
particleSystem.rotation.y += (mouseX + camera.rotation.x) * .00001;
camera.lookAt(new THREE.Vector3(-10, -5, -10))
controls.update();
renderer.render(scene, camera);
}
function animate() { // 开始循环执行渲染动画
requestAnimationFrame(animate);
render();
}
8. Добавьте события операций мыши для достижения контроля угла
Мы также можем добавить события операции мыши для достижения контроля угла, где winX и winY составляют половину ширины и высоты окна соответственно.Конечно, конкретная координатная позиция может быть рассчитана в соответствии с нашими собственными потребностями, и показан конкретный эффект. на следующем рисунке.
document.addEventListener('mousemove', onDocumentMouseMove, false);
function onDocumentMouseMove(event) {
mouseX = (event.clientX - winX) / 2;
mouseY = (event.clientY - winY) / 2;
}
3. План оптимизации
1. Уменьшить количество частиц
С увеличением количества частиц вычисление положения и размера каждой частицы будет занимать очень много времени, что может привести к зависанию анимации или зависанию страницы, поэтому мы можем минимизировать количество частиц при построении модель Эффективно улучшить производительность.
В приведенном выше примере мы меняем точность экспортируемой модели, и мы можем получить различное количество систем частиц.Когда количество частиц достигает сотен тысяч или даже миллионов, вы можете почувствовать очевидное явление заикания при загрузке анимации, что в основном Это потому, что частота кадров относительно низкая. Конкретный эффект сравнения показан на рисунке ниже. Количество частиц слева составляет 300 000, а количество частиц справа - 60 000. Можно ясно видеть, что левый кадр явно пропускает, а правый в основном сохраняет относительно гладкое состояние.
Напишите код фрагментного шейдера, используйте webgl для обеспечения аппаратного 3D-ускорения для холста, а браузеры смогут более плавно отображать страницы. В настоящее время большинство устройств уже поддерживают этот метод.Следует отметить, что на младших устройствах из-за аппаратных причин скорость рендеринга может быть не такой высокой, как рендеринг на основе вычислений на процессоре.
4. Резюме
Подводя итог, можно сказать, что ключом к реализации движения частиц является вычисление и поддержание состояния положения каждой частицы, а three.js предоставляет более удобный метод, который можно использовать для рендеринга всей сцены частиц. Когда количество частиц чрезвычайно велико, для достижения более плавного эффекта анимации необходимо уделить внимание оптимизации кода, сокращению вычислений и т. д., а также добиться эффекта можно за счет улучшения аппаратной конфигурации. Случай в этой статье показывает, как добиться динамических эффектов 3D-частиц, и вы можете создавать более интересные динамические эффекты в соответствии с вашими реальными потребностями.