Текстуровані планети, кеплерівські орбіти, емісивне Сонце, кільця та
постобробка UnrealBloom — усе з'єднано в одному HTML-файлі
з Three.js r160.
1
Сцена, рендерер та камера
Почніть зі стандартного шаблону Three.js —
WebGLRenderer, що заповнює вікно,
PerspectiveCamera та чорне тло, що імітує
космос.
import * as THREE from
'https://cdn.jsdelivr.net/npm/three@0.160/build/three.module.js';
import { OrbitControls } from
'https://cdn.jsdelivr.net/npm/three@0.160/examples/jsm/controls/OrbitControls.js';
import { EffectComposer } from
'https://cdn.jsdelivr.net/npm/three@0.160/examples/jsm/postprocessing/EffectComposer.js';
import { RenderPass } from
'https://cdn.jsdelivr.net/npm/three@0.160/examples/jsm/postprocessing/RenderPass.js';
import { UnrealBloomPass } from
'https://cdn.jsdelivr.net/npm/three@0.160/examples/jsm/postprocessing/UnrealBloomPass.js';
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(devicePixelRatio); renderer.setSize(innerWidth,
innerHeight); renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 0.9;
document.body.appendChild(renderer.domElement); const scene = new
THREE.Scene(); scene.background = new THREE.Color(0x000008); // Зоряне
поле — 10 000 випадкових точок const starGeo = new
THREE.BufferGeometry(); const starPos = new Float32Array(30_000); for
(let i = 0; i < 30_000; i++) starPos[i] = (Math.random() - 0.5) *
2000; starGeo.setAttribute('position', new
THREE.BufferAttribute(starPos, 3)); scene.add(new
THREE.Points(starGeo, new THREE.PointsMaterial({ color: 0xffffff,
size: 0.35 }))); const camera = new THREE.PerspectiveCamera(60,
innerWidth / innerHeight, 0.1, 5000); camera.position.set(0, 80, 200);
window.addEventListener('resize', () => { renderer.setSize(innerWidth,
innerHeight); camera.aspect = innerWidth / innerHeight;
camera.updateProjectionMatrix(); });
Установіть renderer.toneMapping = THREE.ACESFilmicToneMapping —
це підсилює контраст середніх тонів і саме це використовує більшість ігор. Без цього
bloom виглядає вицвілим.
2
Сонце з емісивним сяйвом
Сонце випромінює власне світло. Використайте PointLight у
початку координат і MeshStandardMaterial з високим
emissiveIntensity, щоб воно залишалося яскравим незалежно від інших
джерел світла.
const loader = new THREE.TextureLoader(); // Сонце const sunTex =
loader.load('https://cdn.jsdelivr.net/gh/mrdoob/three.js@r160/examples/textures/planets/sun.jpg');
const sunMat = new THREE.MeshStandardMaterial({ map: sunTex,
emissiveMap: sunTex, emissive: new THREE.Color(1.0, 0.7, 0.1),
emissiveIntensity: 2.5, }); const sun = new THREE.Mesh(new
THREE.SphereGeometry(16, 32, 32), sunMat); scene.add(sun); // Світло
від Сонця const sunLight = new THREE.PointLight(0xfff4cc, 4, 2000,
1.5); scene.add(sunLight); // Розсіяне світло для підсвічування scene.add(new
THREE.AmbientLight(0x111122, 1.5));
map та emissiveMap використовують одну й ту саму
текстуру. Емісивний канал змушує поверхню світитися незалежно від
точкового джерела світла — це важливо, коли камера далеко від джерела
світла.
3
Текстуровані планети та кільце Сатурна
Кожна планета — це SphereGeometry, згрупована зі своїм орбітальним
опорним об'єктом (pivot), щоб обертання відбувалося навколо початку координат Сонця.
Намалюйте еліптичні лінії орбіт і анімуйте планети, використовуючи період Кеплера.
Масштабуйте 1 земний рік до 1 реальної секунди, щоб Сонячна система завжди
рухалася.
// Малюємо еліпс орбіти (коловий для простоти — задайте ексцентриситет для
точності) function addOrbitLine(sma) { const curve = new
THREE.EllipseCurve(0, 0, sma, sma, 0, Math.PI * 2); const pts =
curve.getPoints(256).map(p => new THREE.Vector3(p.x, 0, p.y)); const
geo = new THREE.BufferGeometry().setFromPoints(pts); scene.add(new
THREE.Line(geo, new THREE.LineBasicMaterial({ color: 0x334155,
transparent:true, opacity:0.5 }))); } planets.forEach(p =>
addOrbitLine(p.sma)); // Цикл анімації const YEAR_SECS = 1.0; // 1
земний рік = 1 секунда екранного часу let last = performance.now();
function animate() { requestAnimationFrame(animate); const now =
performance.now(); const dt = Math.min((now - last) / 1000, 0.05);
last = now; planets.forEach(p => { // Кутова швидкість: ω = 2π / T (T
у роках) p.pivot.rotation.y += (Math.PI * 2 / p.period) * dt *
YEAR_SECS; p.mesh.rotation.y += dt * 0.5; // обертання навколо власної осі });
sun.rotation.y += dt * 0.1; controls.update(); composer.render(); }
animate();
Третій закон Кеплера: T² ∝ a³. Співвідношення періодів закладене у
p.period (у земних роках). Множте на
YEAR_SECS, щоб керувати швидкістю анімації.
5
OrbitControls, підписи та повзунок швидкості
Додайте OrbitControls для навігації мишею та простий HTML-оверлей
з повзунком швидкості й назвами планет.
З'єднайте EffectComposer з
UnrealBloomPass, щоб Сонце та інші яскраві об'єкти отримали
м'який ореол сяйва.
const composer = new EffectComposer(renderer); composer.addPass(new
RenderPass(scene, camera)); const bloom = new UnrealBloomPass( new
THREE.Vector2(innerWidth, innerHeight), 1.2, // сила 0.4, //
радіус 0.85 // поріг — світяться лише пікселі, яскравіші за це );
composer.addPass(bloom); // Обробляємо зміну розміру вікна також для композера
window.addEventListener('resize', () => { composer.setSize(innerWidth,
innerHeight); }); // Замініть renderer.render() на composer.render()
у циклі // (вже зроблено на Кроці 4 — composer.render() всередині
animate()) // --- Порада: вибірковий bloom --- // Щоб світилося лише Сонце
(а не тьмяні планети): // 1. Рендеримо сцену двічі — раз з
bloom, раз чисто // 2. Використовуємо шари: sun.layers.enable(1); прохід bloom
рендерить лише шар 1 // Див. приклад selective-bloom у Three.js для повного
налаштування
Поріг має значення: установіть threshold близько
1.0, щоб його перевищувало лише емісивне Сонце. Якщо задати 0, уся
сцена світиться й усе виглядає туманно. Поєднуйте з
ACESFilmicToneMapping для найкращого результату.
Часті запитання
Чого я навчуся в цьому уроці?
Покроковий урок: створіть інтерактивну 3D Сонячну систему у Three.js з текстурованими планетами, кеплерівськими орбітами, OrbitControls та постобробкою UnrealBloom.
Які теми розглядаються в цьому уроці?
Цей урок охоплює такі теми: Сцена, рендерер та камера, Сонце з емісивним сяйвом, Текстуровані планети та кільце Сатурна, Кеплерівські орбітальні шляхи, OrbitControls, підписи та інтерфейс, Постобробка UnrealBloom.