Melampaui teknologi untuk menciptakan alam: proyek dari akar ke daun – Beragampengetahuan
Setelah liburan musim panas, saya tahu saya akan memiliki waktu luang, jadi saya menganggapnya sebagai kesempatan untuk membuat situs web yang penting bagi saya dan juga berfungsi sebagai taman bermain untuk menguji hal-hal baru dan meningkatkan pengetahuan saya. Ini akhirnya menjadi pengalaman WebGL yang memadukan alam dan teknologi. Mari kita lihat bagaimana saya berhasil membuatnya mulai dari desain hingga pengembangan.
Contents
indeks
- Membangun konsep yang kuat
- bentuk dan materi
- tumpukan
- Fitur utama
- tip bonus
- Poin utama
konsep
Saya tahu sejak awal bahwa saya ingin membuat karya yang menakjubkan secara visual, animasi yang indah, dan pada akhirnya akan mencakup beberapa WebGL. Tidak apa-apa, tapi saya memerlukan konsep yang kuat untuk membangun pengalaman visual ini.
Saya sangat mengagumi alam dan kompleksitasnya yang tak terbatas. Alam telah menciptakan sistem yang sangat efisien dan mandiri. Oleh karena itu, saya memilih salah satu bagian alam yang paling ikonik sebagai dasar proyek saya: pepohonan. Semua orang mengenalnya, tapi mereka juga misterius.
Saya punya tema saya, tapi tidak cukup; itu belum menjadi sebuah konsep. Saya ingin berbicara tentang alam dengan cara yang berbeda, jadi saya memerlukan perspektif lain, jauh dari suasana hijau hangat yang dapat kita bayangkan.
Kemudian saya menemukan beberapa proyek keren, Aether1, Ion, dan 8Bit, yang semuanya merupakan karya hebat dan menciptakan suasana yang baik seputar presentasi produk berteknologi tinggi. Tiba-tiba, semua bagian menjadi satu: Saya mendapatkan konsep saya – pohon sebagai kreasi teknologi kelas atas.
desain
Sekarang saya perlu mengubahnya menjadi layar. Saya suka meluangkan waktu mencari inspirasi di berbagai bidang; bisa berupa situs web, bisa berupa seni, desain, film, atau animasi.
Karya Quaiola dan seri Remains-nya ada di pikiran saya. Saya juga menemukan Joanie Lemercier dan karyanya di Prairie and All the Trees. Kedua referensi ini berdampak besar pada suasana proyek saya dan rasa hormat serta penekanan pada pepohonan. Menggabungkan tiga situs web yang dikutip sebelumnya, saya memiliki pemahaman yang jelas tentang proyek ini.
3D
Pilihan 3D adalah pilihan yang wajar. Saya memiliki latar belakang dalam desain gerakan 3D dan saya ingin melampaui batas saya dengan WebGL, namun masuk akal juga untuk menelusuri berbagai fitur pohon.
Saya tidak punya waktu untuk membuat model 3D khusus, jadi saya mengambil satu dari Sketchfab dan mulai melakukan penyesuaian awal di Three.js untuk menemukan suasana yang tepat.
Untungnya, model ini memiliki kelompok titik untuk kulit kayu dan daun, jadi saya dapat dengan mudah memisahkannya menjadi dua objek agar mudah dimanipulasi nanti. Saya harus membuat akarnya, saya memilih untuk membuatnya dengan beberapa kurva, nanti saya bisa membuat geometri dalam kode.
Gaya rendering 3D secara keseluruhan dicapai dengan menggunakan beberapa transparansi pada material yang dikombinasikan dengan kabut gelap, memberikan ilusi bahwa pemandangan menghilang dan menambah kedalaman pada dedaunan.
Saya kemudian menambahkan beberapa aset bergaya techno, seperti latar belakang wireframe icosahedral, lantai poli rendah, dan kompas untuk melacak rotasi, untuk memperkuat ide simulasi.
antarmuka pengguna
Karena saya ingin karya ini bernuansa teknologi, saya melihat beberapa antarmuka pengguna video game (inspirasi besar di sini) dan layar film fiksi ilmiah untuk mendapatkan inspirasi. Kartu informasinya memang terinspirasi dari FPS UI seperti Call of Duty.
Saya ingin menyeimbangkannya dan tidak membuatnya terlalu teknis, jadi saya memilih font sans serif cantik yang cocok untuk judul dan body copy, menambahkan sentuhan gaya bersih pada karya tersebut. Saya juga menambahkan beberapa fungsi kecil untuk melacak pengguliran dan bagian saat ini.
tumpukan
Saya menggunakan tumpukan biasa untuk memulai proyek ini, jadi ini adalah pengaturan WordPress dengan Bedrock/Sage, menanganinya sebagai MVC, dan menggunakan Vite sebagai bundler. Saya tetap menggunakan WordPress karena pada akhirnya saya berencana untuk menerjemahkan situs tersebut sehingga dapat dilakukan dengan mudah.
Saya menggunakan wadah Docker khusus untuk menangani server dan database lokal. Namun saya tidak menggunakannya untuk penerapan karena server web tidak kompatibel.
Saya menggunakan Tailwind dengan konfigurasi khusus untuk menangani gaya. Saya sangat suka betapa cepatnya iterasi, dan penggunaan v4 membuatnya lebih mudah untuk menggabungkannya dengan beberapa gaya CSS lama yang bagus.
Mengenai scripting, saya menggunakan TypeScript dan perpustakaan utamanya adalah:
- Pasca-pemrosesan dengan Three.js dan WebGL
- GSAP/ScrollTrigger/TextSplit untuk menangani garis waktu, animasi gulir, dan pemisahan
- Lenis mencapai kehalusan pengguliran yang luar biasa
- Piece.js untuk menangani komponen web khusus
Oke, jadi untuk tumpukannya, mari kita lihat beberapa bagian proyek.
Fitur utama
Antarmuka pengguna grafis
Selama pengembangan WebGL, saya suka menambahkan banyak penggeser dan tombol GUI untuk mengontrol parameter sebanyak mungkin. Itu membuat penyetelan lebih cepat; bahkan jika Anda membuang waktu selama implementasi, Anda akan mendapatkan banyak keuntungan dengan menemukan nilai yang benar secara intuitif. Saya suka membuat manajer GUI tunggal yang dapat saya akses dari mana saja dalam aplikasi.
import glMainStore from '@scripts/stores/gl/glMainStore';
import createGUI from '@scripts/utils/loadGui';
export type GUIS =
parent: Awaited<ReturnType<typeof createGUI>>;
mainGui: Awaited<ReturnType<typeof createGUI>>;
animGui: Awaited<ReturnType<typeof createGUI>>;
effectGui: Awaited<ReturnType<typeof createGUI>>;
;
type cbT = (guis: GUIS | undefined) => void;
export default class GUIMananger {
static #instance: GUIMananger;
GUIS: GUIS;
guiCbs: cbT[];
hideGui: boolean;
constructor()
this.hideGui = false;
if (import.meta.env.DEV)
this.guiCbs = [];
this.initLilGui().then(() =>
this.trigger();
);
public static get instance(): GUIMananger
if (!GUIMananger.#instance)
GUIMananger.#instance = new GUIMananger();
return GUIMananger.#instance;
async initLilGui()
const parentGui = await createGUI();
glMainStore.parentGui = parentGui;
this.hideGui && parentGui?.hide();
// Init Debugger
const mainGui = await createGUI(
parent: parentGui,
title: 'main',
);
glMainStore.gui = mainGui;
const animGui = await createGUI(
parent: parentGui,
title: 'animations',
);
const effectGui = await createGUI(
parent: parentGui,
title: 'effects',
);
this.GUIS =
parent: parentGui,
mainGui,
animGui,
effectGui,
;
Lalu saya bisa melakukan ini di mana saja di aplikasi saya:
import GUIMananger, GUIS from '@scripts/eventManagers/GUIManager';
// calling GUIMananger.instance returns
// if already created the instance of GUIMananger
// if not it creates it
const animGui = GUIMananger.instance.GUIS;
animGui?.add(object, 'property').name('name');
Hasilnya adalah kekacauan yang terorganisir:
animasi kamera
Bagian penting dari pengalaman adalah kamera itu sendiri, karena ini adalah sudut pandang pengguna. Saya telah membuat perlengkapan di sekitar kamera perspektif Three.js dasar. Saya pertama kali membuat objek kosong yang posisi dan rotasinya saya sesuaikan berdasarkan interaksi mouse. Lalu saya menambahkan kamera ke dalamnya sehingga meniru posisi dan rotasi. Ini memperjelas dan memisahkan fokus kamera dari rotasi/posisi interaksi. Saya juga menggunakan perangkat lain untuk menangani posisi dan rotasi. Tekniknya sama: Saya meng-parent rig pertama ke objek 3D baru. Sekarang saya bisa mengatur posisi, radius, dan rotasi kamera dengan menggerakkan posisi rig1 Z.
Lalu saya menambahkan penyesuaian di GUI untuk mengontrol semuanya.
partikel
Untuk proyek ini saya mengandalkan dua sistem partikel: partikel medan vektor GPGPU dan partikel pemandu kurva.
Untuk partikel yang ada di seluruh adegan, serta partikel di bagian kontrol iklim, saya menggunakan bidang vektor yang dihitung oleh GPUComputationRenderer di Three.js. Singkatnya, ini memungkinkan saya menghitung posisi XYZ partikel sebagai komponen tekstur RGB pada GPU, sehingga cepat meskipun saya memiliki banyak partikel. Saya kemudian dapat memperbarui posisi berdasarkan tekstur itu langsung di dalam vertex shader.
Di sisi lain, untuk mengilustrasikan fitur tertentu, saya memerlukan partikel mengikuti kurva. Untuk melakukan ini, saya mengekspor kurva Blender ke JSON. Kemudian di Three.js saya membuat a CatmullRomCurve3lalu saya dapat membuat sistem partikel BufferGeometry tradisional.
import rainCurves from '@3D/scenes/tree-scene-1/curves/rain.json';
export default class RainParticles
// rest of the class ...
createCurves()
const rotationMatrixX = new Matrix4().makeRotationX(degToRad(90));
const rotationMatrixY = new Matrix4().makeRotationX(degToRad(180));
const tempVec = new Vector3();
for (let i = 0; i < rainCurves.length; i++)
const curve = rainCurves[i];
const points = curve.points.map(( x, y, z ) =>
tempVec
.set(x, y, z)
.applyMatrix4(rotationMatrixX)
.applyMatrix4(rotationMatrixY)
.clone()
);
const threeCurve = new CatmullRomCurve3(points);
this.curves.push(threeCurve);
Pada saat yang sama, saya membuat serangkaian objek untuk menyimpan dan memperbarui informasi tentang setiap partikel. Saya menyimpan posisi pada kurva (dari 0 — awal hingga 1 — akhir), bergantung pada kurva, kecepatan dan skalanya.
createPoints()
this.points = [];
for (let i = 0; i < this.curves.length; i++)
for (let j = 0; j < this.density; j++)
this.points.push(
curve: this.curves[i],
offset: Math.random(),
speed: minmax(0.5, 0.8, Math.random()) * 0.01,
currentPos: Math.random(),
opacity: minmax(0.5, 0.7, Math.random()),
);
Jadi, dalam loop render saya, saya dapat mengulangi objek data partikel ini, memperbarui posisi berdasarkan kecepatan yang dipilih, lalu menghitung koordinat titik yang sesuai dengan kemajuan baru pada kurva, dan memperbarui posisi saya BufferAttribute.
Peneduh hari hujan
Saya ingin mengilustrasikan bahwa pohon tidak hanya dapat meningkatkan curah hujan, tetapi juga membantu mengatur curah hujan yang tinggi. Apa yang lebih intuitif daripada tetesan air yang jatuh dari langit?
Untuk menciptakan efek ini saya memerlukan dua hal: garis-garis hujan dan tetesan air pada kamera virtual yang membiaskan pemandangan. Keduanya dibuat menggunakan pasca-pemrosesan dan pass shader khusus.
Untuk garis-garis, caranya cukup sederhana. Saya mendapatkan UV layar, memutarnya, lalu menskalakannya pada sumbu x dengan angka yang lebih besar dan pada sumbu y dengan angka yang lebih kecil karena saya ingin garis-garis yang panjang. Saya membuat grid dengan mendapatkan fract Bagian dari UV baru. Lalu saya jiplak garis-garisnya menggunakan smoothstep()lakukan beberapa animasi pada posisinya, dan buat berkedip untuk mendapatkan efek yang diinginkan.
Untuk membuat tetesannya, saya juga menggunakan jaring UV yang berskala besar. Lalu saya mendapatkan jaring UV melalui fract bagian dari itu. Di setiap sel saya menggunakan panjang ke tengah dan smoothstep Fungsi. Saya menambahkan nilai noise untuk mensimulasikan beberapa distorsi tetesan air agar terlihat lebih realistis. Saya juga menghitung offset waktu setiap tetesan air sehingga muncul dengan penundaan yang acak. Saya kemudian mengalikan subset UV dengan bentuk masker untuk mendapatkan tetesan UV. Langkah terakhir adalah mengurangi UV yang dirender dari UV tetesan dan menerapkan UV hujan ini ke render saya sebelumnya.
Daun terbuka
Efek menarik lainnya yang harus saya ciptakan adalah tampilan daun holografik. Awalnya, ini harus berupa kombinasi zoom in dan fade in. Namun begitu animasi ditayangkan, rasanya agak tidak menarik, jadi saya memutuskan untuk mengalihkannya ke presentasi bergaya laser.
Efeknya merupakan kombinasi mask, efek noise pada saluran alfa, dan garis mengkilap dengan sedikit noise di fragment shader.
Pasca pemrosesan
Untuk lebih meningkatkan suasana, saya menambahkan beberapa pas pasca-pemrosesan. Pertama, saluran noise halus membantu menciptakan kesan digital/teknis pada aset 3D dan sedikit menyatukan gradien warna.
Saya kemudian menambahkan saluran mekar untuk memberikan fokus dan intensitas pada elemen yang lebih ringan. Saya menetapkan ambang batas relatif tinggi untuk menghindari terlalu banyak keburaman pada pepohonan. Saya sengaja menyempurnakan beberapa warna agar mekar – misalnya, laser adalah a vec3(2.) alih-alih vec3(1.). Warnanya sama (putih), namun melebihi ambang batas mekar sehingga menjadi buram.
Selain itu, saya juga menyelesaikan efek khusus – efek hujan dan dingin/dingin, karena efek tersebut akan muncul langsung di layar kamera.
sentuhan interaktif
Proyek ini sangat naratif dan linier dan pengguna mungkin merasa sedikit pasif sepanjang pengalaman, jadi saya ingin menambahkan beberapa interaktivitas. Interaksi pertama adalah penguasaan adegan intro. Itu hanya event handler drag and drop khusus yang menambahkan kecepatan pada vektor rotasi adegan. Kemudian ketika pengguna menggulir ke bagian ini, saya mengunci dan melanjutkan rotasi karena saya ingin animasi saya fokus pada bagian pohon yang tepat.
Yang kedua adalah kebisingan dari pergerakan partikel air di bagian pengatur suhu. Pertama, saya membuat Raycaster dari kamera dan memperbaruinya dengan kursor XY di loop render. Saya mendapatkan perpotongan sinar ini dengan bidang di depan pohon, selalu melihat ke arah kamera. Ini memberi saya koordinat Vector3 dari kursor virtual. Saya kemudian menambahkan nilai noise ke setiap posisi partikel jika jaraknya cukup dekat.
Teknik lain-lain tambahan
segala sesuatu di antaranya [0 – 1] atau [-1, 1]
Saya menggunakan beberapa fungsi pemetaan/penjepitan secara ekstensif di seluruh proyek saya untuk mengonversi rentang [x, y] tiba [0, 1]. Ini berguna saat menerapkan nilai dalam shader. Misalnya, saya memetakan ulang MouseEvent clientX dan clientY menjadi serangkaian [0, 1] Cocokkan UV shader fragmen.
Saya juga memetakan ulang banyak cakupan lainnya, seperti kemajuan panggilan balik ScrollTrigger.onUpdate. Sesuai kebutuhan, saya dapat mempercepat atau memperlambat nilai, atau memulai/menghentikan sebelum akhir.
// convert a value from [a, b] to [A, B] keeping ratio
const map = (a: number, b: number, A: number, B: number, x: number): number =>
(x - a) * ((B - A) / (b - a)) + A;
// convert value to a [0, 1] range
const normalize = (min: number, max: number, value: number): number =>
map(min, max, 0, 1, value);
// clamp values
const clamp = (min: number, max: number, value: number): number =>
value < min ? min : value > max ? max : value;
// convert from [0 - 1] to [-1, 1]
value * 2 - 1;
// convert from [-1, 1] to [0, 1]
(value + 1) * 0.5
solarPanels:
el: getSectionEl('solar-panels'),
scrollTriggerOptions:
id: 'solar-panels',
...baseStartEnd,
markers: showMarkers,
onUpdate: (self) =>
const pCamera = mapProgress(0, 0.5, 0, 1, self.progress); // from [0-0.5] to [0-1] for camera to finish animation when progress is 50%
const pLeaf = mapProgress(0.3, 0.6, 0, 1, self.progress); // from [0.3-0.6] to [0-1] for the leaf reveal
const pLeafBack = mapProgress(0.7, 1, 0, 1, self.progress); // from [0.7-1] to [0-1] for the leaf back animation
// Circle and title number
this.uiAnim.titleNumbers.circleProgress.progress(self.progress);
showHideTitle(
this.uiAnim.titleNumbersElements[0],
self,
0.01,
0.99
);
// Camera and leaf
anims?.firstTraveling.camera.progress(pCamera);
anims?.firstTraveling.leaf.progress(pLeaf - pLeafBack);
// Anim the title
titleStore.solarPanel &&
showHideTitle(titleStore.solarPanel, self, 0.01, 0.9);
// Show hide Card
showHideCard(this.uiAnim.cards.solarPanel, self, 0.4, 0.9);
// Show hide step
showHideStep(progressStepsObj[0]!, self, 0.683);
,
,
Fungsi pelonggaran khusus
Saya sering menggunakan fungsi easing dalam JavaScript, yang berhubungan dengan map() atau normalize() untuk mendapatkan rasio yang halus.
const easeInQuad = (x: number): number => x * x;
const easeOutQuad = (x: number): number => 1 - (1 - x) * (1 - x);
const easeInOutQuad = (x: number): number =>
x < 0.5 ? 2 * x * x : 1 - Math.pow(-2 * x + 2, 2) / 2;
// ... Cubic, Expo ...
Saya juga mengaturnya di konfigurasi Tailwind saya untuk mendapatkan lebih banyak kemungkinan daripada pengaturan default.
/* ex: class="ease-in-cubic" */
@theme
--ease-in-sin: cubic-bezier(0.12, 0, 0.39, 0),
--ease-out-sin: cubic-bezier(0.61, 1, 0.88, 1);
--ease-in-out-sin: cubic-bezier(0.37, 0, 0.63, 1);
/* ... other timing functions */
Kontrol warna SVG
Saya sering menggunakan utilitas ini untuk menyesuaikan warna SVG secara dinamis.
@utility svg-color-*
--col : --value(--color-*);
--col : --value([color]);
[fill]:not([fill="none"]):not([fill="transparent"])
fill: var(--col);
[stroke]:not([stroke="none"]):not([stroke="transparent"])
stroke: var(--col);
sebagai kesimpulan
Sebagai kesimpulan utama, menurut saya bagian terpenting dari proyek ini sebenarnya adalah konsepnya. Setelah Anda memiliki inti yang berani, sisanya akan mengalir dengan lancar dan konsisten.
Kedua, menurut saya mencoba hal-hal baru dan mendorongnya hingga berhasil adalah kunci lainnya. Jika Anda belum tahu cara melakukan sesuatu, cari tahu – itulah cara terbaik untuk belajar dan maju.
Terakhir, jika Anda memulai proyek seperti ini sendirian seperti saya, tetaplah fokus pada tujuan. Anda mungkin harus membuat beberapa kompromi di sana-sini. Bagi saya, ini menggunakan tumpukan situs web saya, tetapi ini memungkinkan saya memulai dengan cepat dan memberi saya waktu untuk fokus pada gaya yang bersih dan animasi yang indah.
Pada akhirnya, saya dapat mengatakan bahwa proyek ini adalah sebuah perjalanan melalui setiap bagian pembuatan situs web, mulai dari konsep dan desain, kode, hingga konten. Saya pasti belajar banyak dan meningkatkan pengetahuan saya. Saya juga bangga mempersembahkan karya yang menghubungkan bentuk dan materialitas.
rencana pengembangan website
metode pengembangan website
jelaskan beberapa rencana untuk pengembangan website, proses pengembangan website, kekuatan dan kelemahan bisnis pengembangan website
, jasa pengembangan website, tahap pengembangan website, biaya pengembangan website
#Melampaui #teknologi #untuk #menciptakan #alam #proyek #dari #akar #daun
