Ostatnimi czasy, rozwój w technologiach internetowych daje nam coraz większe możliwości uatrakcyjnienia naszej witryny internetowej, sklepu, czy wizytówki firmy. Obecne w serwisach internetowych mamy opcje wstawiania filmików w tła, różnego rodzaju animacje i efekty poszczególnych elementów, paralaksy i wiele innych. Jednym z ciekawszych rozwiązań jest umieszczenie na naszej stronie elementów trójwymiarowych, na co również mamy kilka opcji. Może to być przykładowo filmik prezentujący jakiś trójwymiarowy obiekt z każdej strony. Możemy np. wstawić zdjęcie prezentujące dany obiekt z różnych perspektyw. Mamy też opcje zbudowania pseudo trójwymiarowego elementu w samych css. Jednym z najciekawszych jest fizyczne umieszczenie trójwymiarowego obiektu na stronie www z wykorzystaniem WebGL, który zapewnia dostęp do trójwymiarowego API w przeglądarkach.
Jedną z najpopularniejszych bibliotek wykorzystujących WebGL jest Three.js, która umożliwia nam importowanie dowolnych plików z obiektami 3d oraz dowolną ich manipulacje. W dzisiejszym artykule zajmiemy się podstawami wykorzystania biblioteki i możliwościami, jakie nam daje.
WebGL – Three.js
WebGL jest rozszerzeniem możliwości języka JavaScript, dający nam możliwość dostępu do grafiki 3D. WebGL korzysta w tym celu z elementu canvas występującego w HTML5. Sam kod WebGL może być bardzo długi i skomplikowany, z uwagi na to, mamy dostęp do kilku bibliotek, które ułatwiają nam zadanie i umożliwiają znacząco pisanie kodu i pracę z samymi obiektami.
W artykule zajmiemy się biblioteką three.js. Najważniejszymi elementami, niezbędnymi do uruchomienia projektu 3d w przeglądarce, przy wykorzystaniu ww. biblioteki, potrzebna jest deklaracji sceny, kamery i renderera.
Scena jest przestrzenią, w której umieszczane są wszystkie obiekty, które chcemy pokazać na stronie. Kamera jest szczególnym obiektem, który jest zawieszony w tej przestrzeni i jest punktem odniesienia, z którego spoglądamy na obiekt. Natomiast renderer w uproszczeniu jest silnikiem graficznym wykorzystywanym do pokazania całej sceny z perspektywy właśnie kamery.
W zależności od rodzaju posiadanych przez nas materiałów 3d będą jeszcze przydatne biblioteki ładujące dane pliki do projektu.
Przykładowa deklaracja podstawowych komponentów:
var scene = new THREE.Scene();
var camera = new THREE.PerspectiveCamera(50, $wrapper.innerWidth/$wrapper.innerHeight, 1, 5000);
var renderer = new THREE.WebGLRenderer({antialias: true});
Światła
Dodatkowym istotnym, niekoniecznym elementem do umieszczenia na scenie są światła. Mamy wiele rodzajów oświetlenia sceny, dzięki czemu możemy uzyskać różne efekty imitując przykładowo światło naturalne rozproszone na całym obiekcie, bądź studyjne skierowane bezpośrednio na sam obiekt. Generalnie wszystkie światła mogą mieć różne warianty kolorystyczne, jak i intensywność co może znacząco wpłynąć na efekt końcowy. Podstawową klasą, od której dziedziczone są inne typy świateł, jest Light. Nie możemy jednak wykorzystać jej bezpośrednio, ona jest tylko podstawą dla innych i zawiera w sobie dwa parametry wspomniane wcześniej, mianowicie kolor w postaci szesnastkowej, oraz intensywność w formie numerycznej.
Jednym z przykładów światła często wykorzystywanym w doświetlaniu obiektów na scenie może być AmbientLight, który doświetla obiekt równomiernie z każdej strony, dając efekt ambientu, jak sama nazwa wskazuje.
const light = new THREE.AmbientLight( 0x404040 ); // soft white light
scene.add( light );
Kolejnym może być HemisphereLight, który ma symulować rodzaj światła naturalnego, skierowanego na obiekty z góry na dół, „z nieba do podłoża”.
const light = new THREE.HemisphereLight( 0xffffbb, 0x080820, 1 );
scene.add( light );
Jeszcze jeden istotny rodzaj oświetlenia to PointLight, który działa jak osadzona w konkretnym miejscu na scenie żarówka o konkretnej barwie. Działa na zasadzie rozchodzącego się nieskończenie, w każdy kierunku, światła o określonej barwie z konkretnego jednego punku na scenie.
const light = new THREE.PointLight( 0xff0000, 1, 100 );
light.position.set( 50, 50, 50 );
scene.add( light );
Jest jeszcze kilka innych rodzajów światła i tylko od nas zależy, jakiego użyjemy i jaki efekt chcemy uzyskać, ale możliwości mamy wręcz nieograniczone.
Scena 3d
Po wstępnym przygotowaniu środowiska mamy kilka możliwości umieszczenia na scenie dowolnego obiektu. Możemy dokonać tego w samym kodzie, deklarując i łącząc ze sobą listę różnych obiektów.
var geometry = new THREE.SphereGeometry( 15, 32, 16 );
var material = new THREE.MeshBasicMaterial( { color: 0xffff00 } );
var sphere = new THREE.Mesh( geometry, material );
scene.add( sphere );
Najpierw tworzymy strukturę obiektu 3d w tym wypadku sfera, następnie nadajemy mu styl, nakładając przykładowy kolor, po czym łączymy oba elementy i wrzucamy go na scenę.
Mamy również możliwość nakładania na obiekty grafik z efektami odbicia itp:
Możemy też importować obiekty z zewnątrz, ładując stosownymi leaderami gotowe obiekty 3d np. w formie .OBJ razem z materiałami określającymi wygląd nałożony na obiekt w formie .MLT
var loader = new OBJLoader();
loader.load(
'models/dom.obj',
function ( object ) {
scene.add( object );
},
function ( xhr ) {
console.log( ( xhr.loaded / xhr.total * 100 ) + '% loaded' );
},
function ( error ) {
console.log( 'An error happened' );
}
);
W połączeniu z ładowaniem materiałów na dany obiekt wyglada to następująco:
var mtlLoader = new MTLLoader()
mtlLoader.load(
'models/dom.mtl',
(materials) => {
materials.preload()
const objLoader = new OBJLoader()
objLoader.setMaterials(materials)
objLoader.load(
'models/dom.obj',
(object) => {
scene.add(object)
},
(xhr) => {
console.log((xhr.loaded / xhr.total) * 100 + '% loaded')
},
(error) => {
console.log('An error happened')
}
)
},
(xhr) => {
console.log((xhr.loaded / xhr.total) * 100 + '% loaded')
},
(error) => {
console.log('An error happened')
}
);
A wynikiem będzie załączony na scenie nasz obiekt razem z nałożonymi materiałami.
Modyfikacje wyglądu obiektów, podmiana grafik, zmiana kolorów.
Po skonfigurowaniu sceny dodaniu konkretnych obiektów oświetlenia i innych detali mamy też możliwość manipulacji wszystkimi parametrami samego obiektu. Oczywiście wszystko jest zależne od przygotowania samego obiektu.
Większość obiektów jest podzielona na tak zwane mesh’e, mniejsze fragmenty, do których możemy się dostawać z poziomu skryptu. Możemy je ukrywać i pokazywać poszczególne elementy.
ukrywanie elementów:
function(elem, hide) {
elem.forEach(i => {
i.visible = hide;
});
this.render();
},
co daje nam następujący efekt:
Możemy również zmieniać ich wygląd nakładać inne materiały, lub zmieniać kolory:
function(elem, color) {
elem.forEach(i => {
if (i.material.color) {
i.material.color.setHex( color );
} else {
if (i.material.length > 1) {
i.material.forEach(c => {
c.color.setHex( color );
});
}
}
});
this.render();
};
Dzięki wszystkim tym opcjom mam bardzo dużo możliwości na dynamiczne generowanie treści i uatrakcyjnienie naszego serwisu internetowego. Możemy stworzyć np. konfigurator produktów, który live będzie prezentował nam pożądany przez nas produkt, co można sprawdzić na jednym naszych projektów aplikacji internetowej, aktualnie online tutaj.