Как задать объекту передвижение по окружности на осях x, y, z | Three js
я пытаюсь сделать анимацию перемещения сферы по окружности, создаю все это с помощью three js, вот все, до чего я смог додуматься
Здесь каждый кадр изменяется позиция объекта, но проблема в том, что я не знаю как наклонить окружность по которой перемещается сфера
Здесь я вывел оси для удобства, синяя - z, зеленая - y, оранжевая - x. В данном случае сфера перемещается по окружности, используя оси y и z, но мне нужно еще как то перемещать ее по x, чтобы сфера смогла перемещаться по окружности, которую вы можете увидеть на картинке. Для общего понимания, я хочу сделать анимированный 3д атом. Надеюсь на чью-то помощь, спасибо!
Ответы (2 шт):
Не понятен весь код того что хотите сделать, но может проще камеру повернуть по оси. Допустим camera.rotation.z = Math.pi * 0.1 //вся окружность 2ПИ.
Можно сделать что-то такое. Логика заключается в том чтобы добавить все частицы и выстроить их вокруг ядра, после чего создать группы-контейнеры для частиц, добавить частицы в контейнеры, а контейнеры сместить вращая по оси Y на равные углы, затем просто вращать контейнеры по оси Z... Можно поиграться с настройками эффектов, цветами, скоростями изменяя значения...
const playButton = document.getElementById('playButton');
let requestID = false;
playButton.addEventListener('click', function() {
//Запускаем анимацию по нажатию на кнопку одновременно с аудио
if(!requestID) requestID = window.requestAnimationFrame(animate);
let audio = document.querySelectorAll('.player');
if (audio[0].paused) {
audio[0].play();
audio[1].play();
playButton.textContent = 'Pause';
} else {
audio[0].pause();
audio[1].pause();
playButton.textContent = 'Play';
}
});
body {
margin: 0;
}
#playButton{
display: none;
position: absolute;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Rudi animation</title>
</head>
<body>
<audio class="player" loop="true">
<source src="https://zvukoviku.ru/sounds/1573719407_66163fbb0aef075.mp3" type="audio/mp3">
</audio>
<audio class="player" loop="true">
<source src="https://zvukoviku.ru/sounds/1573719603_ec8dfcc179543b1.mp3" type="audio/mp3">
</audio>
<button id="playButton">Play</button>
<script>
// Создадим переменную чтобы её было видно в других тэгах <script>, в <script type="module"> присвоим ей функцию
let animate;
</script>
<script type="module">
//Импортируем необходимые зависимости
import * as THREE from "https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.js";
import { EffectComposer } from "https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/postprocessing/EffectComposer.js";
import { RenderPass } from "https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/postprocessing/RenderPass.js";
import { UnrealBloomPass } from "https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/postprocessing/UnrealBloomPass.js";
import { AfterimagePass } from 'https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/postprocessing/AfterimagePass.js';
import { OrbitControls } from 'https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/controls/OrbitControls.js';
let w = window.innerWidth;
let h = window.innerHeight;
const scene = new THREE.Scene();
scene.fog = new THREE.FogExp2(0x000000, 0.01);
const camera = new THREE.PerspectiveCamera(75, w / h, 0.1, 1000);
camera.position.set(0,1.6,0);
camera.rotation.set(0,-90,0);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(w, h);
document.body.appendChild(renderer.domElement);
const light = new THREE.AmbientLight( 0x00B2B2FF );
scene.add( light );
// Orbit Controls
const controls = new OrbitControls(camera, renderer.domElement);
controls.target.set(0, 0, 0);
controls.update();
// Настройка эффектов
const renderScene = new RenderPass(scene, camera);
// resolution, strength, radius, threshold
const bloomPass = new UnrealBloomPass(new THREE.Vector2(w, h), 7, 0.9, -0.25);
const afterImagePass = new AfterimagePass();
afterImagePass.uniforms["damp"].value = 0.980;
const composer = new EffectComposer(renderer);
composer.addPass(renderScene);
composer.addPass(bloomPass);
composer.addPass(afterImagePass);
//Создадим объекты оболчку и ядро
const shellGeometry = new THREE.SphereGeometry(0.5, 8, 8);
const shellMaterial = new THREE.MeshStandardMaterial({ color: 0x000F0FFF, emissive: 0xfffff, emissiveIntensity: 0.1, wireframe: true });
const shell = new THREE.Mesh(shellGeometry, shellMaterial);
scene.add(shell);
const nucleusGeometry = new THREE.SphereGeometry(0.1, 16, 16);
const nucleusMaterial = new THREE.MeshStandardMaterial({ color: 0x00FFFFFF, emissive: 0x00FFFFFF,emissiveIntensity: 0.1});
const nucleus = new THREE.Mesh(nucleusGeometry, nucleusMaterial);
scene.add(nucleus);
const atoms = [];
const atomContainers = [];
const totalAtoms = 5; // количество частиц оптимально от 3 до 6
for (let i = 0; i < totalAtoms; i++) {
const atomGeometry = new THREE.SphereGeometry(0.05, 16, 16);
const atomMaterial = new THREE.MeshStandardMaterial({ color: 0x003131E7 });
const atom = new THREE.Mesh(atomGeometry, atomMaterial);
atoms.push(atom);
scene.add(atom);
}
//расставляем частицы вокруг ядра
atoms.forEach((atom, index) => {
const angle = (index / totalAtoms) * Math.PI * 2;
const radius = 0.9;
atom.position.x = radius * Math.cos(angle) + nucleus.position.x;
atom.position.y = radius * Math.sin(angle) + nucleus.position.y;
});
for (let i = 0; i < totalAtoms; i++) {
//Добавляем контейнер для частицы
const atomContainer = new THREE.Group();
//Добавляем частицу в контейнер attach не учитывает позицию частиц
atomContainer.attach(atoms[i]);
atomContainers.push(atomContainer);
scene.add(atomContainer);
//Вращаем каждый контейнер по оси Y на равные углы
atomContainer.rotation.y = (Math.PI * ((360/totalAtoms)*i)) / 360;
}
//Флаг для контроля пульсации
let flag = true;
function update() {
let scale = nucleus.scale;
let scaleSh = shell.scale;
if(flag){
shell.scale.set(scaleSh.x+0.01, scaleSh.y+0.01, scaleSh.z+0.01);
nucleus.scale.set(scale.x+0.12, scale.y+0.12, scale.z+0.12);
}else{
shell.scale.set(scaleSh.x-0.01, scaleSh.y-0.01, scaleSh.z-0.01);
nucleus.scale.set(scale.x-0.12, scale.y-0.12, scale.z-0.12);
}
if(nucleus.scale.x > 2.5){
flag = false;
}else if(nucleus.scale.x <= 0.09){
flag = true;
}
//Вращаем все контейнеры для частиц по оси Z
for (let i=0; i< totalAtoms; i++){
atomContainers[i].rotation.z += 0.1;
//Вращаем оболочку по осям YZ
shell.rotation.y += 0.02;
shell.rotation.z += -0.02;
//Рендер эффектов. Можно поиграться, вынести за пределы цикла
composer.render(scene, camera);
}
}
//Присваиваем функцию переменной созданной в первом <script>
animate = function () {
update();
window.requestAnimationFrame(animate);
}
function handleWindowResize () {
w = window.innerWidth;
h = window.innerHeight;
camera.aspect = w / h;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
window.addEventListener('resize', handleWindowResize, false);
</script>
<script>
//Дожидаемся полной загрузки и отображаем кнопку Play
addEventListener("DOMContentLoaded", (event) => {
document.getElementById('playButton').style.display = "block";
});
</script>
</body>
</html>