Materiály

V této části se podíváme na materiály. Ty slouží k popisu vzhledu objektů. Už jsme se s nimi v tutoriálu setkali, ale nevysvětlovali jsme si o nich žádné velké detaily. V této části si je tedy rozebereme a podívame se, jaké máme typy materiálů.

Abychom mohli na canvas vykreslit objekt, tak k tomu potřebujeme shadery. Ty obsahují instrukce pro vykreslování. Můžeme si je sami napsat a vytvořit si tedy vlastní materiál. To si ale zkusíme až v samostatné části o shaderech. Shadery si nemusíme psát sami, můžeme použít materiály, které nám Three.js nabízí. Postupně si některé v této části projdeme.

Startovní kód

Abychom si mohli vyžkoušet a vidět různé materiály, tak si je budeme muset aplikovat na nějaké objekty. Proto je tu pro vás připravený startovní kód, který objekty vytváří, přidává je do scény a tu poté renderuje. Také vytváří OrbitControls ovládání, aby jste se po scéně mohli pohybovat. Takže si pomocí startovního kódu z části o Webpacku vytvořte nový projekt a následující kód si zkopírujte do JavaScript souboru.

import './style.css';
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';

// vytvoření scény
const scene = new THREE.Scene();

// vytvoření materiálu
const material = new THREE.MeshBasicMaterial();


// vytvoření kostky
const cube = new THREE.Mesh(
    new THREE.BoxGeometry(1, 1, 1),
    material
);
scene.add(cube);

// vytvoření koule
const sphere = new THREE.Mesh(
    new THREE.SphereGeometry(0.5, 12, 10),
    material
);
sphere.position.x = -1.5;
scene.add(sphere);

// vytvoření dodecahedronu (nebo co to je)
const dodecahedron = new THREE.Mesh(
    new THREE.DodecahedronGeometry(0.5, 0),
    material
);
dodecahedron.position.x = 1.5;
scene.add(dodecahedron);

// vytvoření kamery
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 3;
scene.add(camera);

// vytvoření rendereru
const renderer = new THREE.WebGLRenderer({
    canvas: document.getElementById("WebGLCanvas")
});
// nastavení velikosti canvasu a pixel ratio
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));

// přidání event listeneru pro změnu velikosti okna
window.addEventListener("resize", () => {
    // aktualizace poměru stran kamery
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    // změnění velikosti canvasu a pixel ratio
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
});

// vytvoření OrbitControls ovládání
const controls = new OrbitControls(camera, renderer.domElement);
// zapnutí tlumení při posunutí
controls.enableDamping = true;

// tato funkce je volána každý frame
function tick() {
    // protože máme zapnuté tlumení při posunutí,
    // tak musíme OrbitControls aktualizovat
    controls.update();
    // vyrenderování scény na canvas
    renderer.render(scene, camera);
}

// nastavení animační smyčky
// - funkce tick se bude volat každý frame
renderer.setAnimationLoop(tick);

Kromě předchozího kódu si zkopírujte také následující CSS kód, protože opět roztahujeme canvas přes celou velikost okna.

*, *::before, *::after {
    padding: 0;
    margin: 0;
}

body {
    overflow: hidden;
}

Po spuštění aplikace by jste měli vidět tři objekty. Na ty si budeme zkoušet aplikovat různé materiály.

Mesh Basic Material

Nejzákladnějším materiálem je MeshBasicMaterial. Tento materiál nepotřebuje světlo a můžeme s jeho pomocí na geometrii jednoduše aplikovat barvu nebo texturu. Co všecho můžeme tomuto materiálu nastavit za vlastnosti si můžete prohlédnout v dokumentaci. Mi si tu ukážeme jen některé.

Barva

Začneme s barvou. Tu můžeme nastavit pomocí vlastnosti color. Nastavovat materiál můžeme v konstruktoru předáním objektu s nastavením nebo až po vytvoření materiálu měněním jeho vlastností. Co vám vyhovuje víc záleží na vás. Mi si třeba materiál nastavíme předáním objektu při jeho vytváření. V kódu již máme kód pro vytvoření materiálu, takže jen do konstruktoru předáme objekt s nastavením barvy. Nastavíme třeba oranžovou barvu.

/* ... */

// vytvoření materiálu
const material = new THREE.MeshBasicMaterial({
    color: 0xFAB278
});

/* ... */

Jak si v předchozí ukázce můžete všimnout, tak barvu nastavujeme pomocí hexadecimálního zápisu čísla. Pokud si tento zápis vložíte do konzole, tak uvidíte, že nazpět dostanete číslo. Mohli bychom použít i řetězec "#FAB278", jak to znáte z CSS, ale použití čísla namísto řetězce je lepší. Také byste mohli vytvořit instanci třídy Color a tu použít jako barvu. To se vlastně automaticky děje, když instanci třídy Color nepředáme a předáme například číslo, jak jsme to udělali mi.

Po spuštění aplikace by objekty měli být oranžové.

V nastavování barvy při vytváření materiálu a po vytvoření materiálu je trochu rozdíl, protože vlastnost color bude po vytvoření materiálu instance třídy Color. Proto bychom museli barvu změnit pomocí metody set, nebo vytvořit novou instanci třídy Color a tu jako barvu nastavit. To ukazuje následující ukázka.

/* ... */

// vytvoření materiálu
const material = new THREE.MeshBasicMaterial({
    color: 0xFAB278
});
// změnění barvy na modrou po vytvoření materiálu
material.color = new THREE.Color(0x78E8FA);

/* ... */

Color textura

Kromě barvy můžeme pro MeshBasicMaterial nastavit i texturu. Z minulé části víte jak textury načítat. Není to nic složitého, vytvoříme instanci třídy TextureLoader a použijeme metodu load. Poté můžeme načtenou (nebo i načítající se) texturu pro materiál nastavit pomocí vlastnosti map a to je vše. Budeme ale nějakou texturu potřebovat abychom si to mohli vyzkoušet, proto si nějakou vyberte třeba na Poly Haven, kde jsou všechny textury zdarma. Já budu používat stejně jako v minulé části tuto texturu. Tentokrát si stáhněte všechny typy textur, jelikož je později budeme potřebovat u jiných typů materiálů. Stažené textury si umístěte do složky static v kořenové složce projektu. Následující ukázka ukazuje, jak můžeme namísto barvy nastavit pro materiál texturu.

/* ... */

// vytvoření Texture Loaderu
const textureLoader = new THREE.TextureLoader();
// načtení textury
const colorTexture = textureLoader.load("./static/brick_wall_001_diffuse_1k.jpg");

// vytvoření materiálu
const material = new THREE.MeshBasicMaterial({
    map: colorTexture
});

/* ... */

Objekty by teď na sobě měli mít aplikovanou texturu.

Pokud bychom chtěli zkombinovat barvu a texturu, tak to jde. Aplikovaná textura potom bude obarvená podle nastavené barvy. Můžeme si třeba zkusit materiálu nastavit modrou barvu.

/* ... */
    
// vytvoření materiálu
const material = new THREE.MeshBasicMaterial({
    map: colorTexture
});
// nastavení modré barvy
material.color = new THREE.Color(0x78E8FA);

/* ... */

Když si teď aplikaci spustíte, aplikovaná textura bude obarvená podle nastavené barvy.

Průhlednost

Pokud chceme materiálu nastavit průhlednost, tak to můžeme udělat pomocí vlastnosti opacity, které předáme číslo od 0 do 1. Hodnota 0 znamená, že objekt není vidět a hodnota 1 znamená, že je plně vidět. Musíme ale také nastavit, že má být být materiál průhledný, nastavením vlastnosti transparent na true. Bez toho by nastavení opacity nemělo žádný vliv.

U našeho materiálu si třeba můžeme průhlednost nastavit na polovinu. A kdyžtak si ještě odstraňte nastavení barvy, aby to bylo lépe vidět.

/* ... */

// vytvoření materiálu
const material = new THREE.MeshBasicMaterial({
    map: colorTexture,
    transparent: true,
    opacity: 0.5
});

/* ... */

Objekty by se teď měli zobrazit jako průhledné. Možná to není na první pohled vidět, ale když se podívate na nějaký objekt přes jiný objekt, tak to uvidíte lépe.

Pokud bychom nechtěli jako průhledný nastavit celý objekt, ale jen některé jeho části, tak bychom to mohli udělat přes alpha texturu, kterou bychom nastavili pomocí vlastnosti alphaMap. Jelikož u naší textury ale alpha texturu nemáme, tak si to zkoušet nebudeme. Pokud jste si stáhli texturu, která alpha texturu má, tak si to klidně můžete zkusit sami. Nesmíte ale zapomenout nastavit vlastnost transparent na true, aby to fungovalo.

Renderování obou stran polygonů

Možná jste si všimli, že se defaultně renderuje jen přední strana polygonů. Když například kameru posunute do objektu, neuvidíte jej zevnitř. Je to tak kvůli optimalizaci. Můžeme to změnit pomocí vlastnosti side, které předáme jednu z následujících hodnot:

  • THREE.FrontSide - renderuje se pouze přední strana polygonů (toto je defaultní)
  • THREE.BackSide - renderuje se pouze zadní strana polygonů
  • THREE.DoubleSide - renderují se obě strany polygonů

Pokud chceme renderovat obě strany polygonů, nastavíme vlastnost side na THREE.DoubleSide.

/* ... */

// vytvoření materiálu
const material = new THREE.MeshBasicMaterial({
    map: colorTexture,
    transparent: true,
    opacity: 0.5,
    side: THREE.DoubleSide
});

/* ... */

Po spuštění aplikace byste měli objekty vidět i zevnitř.

Vlastnosti, které jsme si na Mesh Basic Materiálu ukázali se dají použít i u některých dalších materiálu. Nebudu se k nim tedy u dalších typů materiálů vracet. Co všechno se dá u daného typu materiálu nastavit si vždy můžete prohlédnout v dokumentaci.

Mesh Normal Material

Jako druhý materiál si ukážeme MeshNormalMaterial. Jedná se vlastně o reprezentaci normálů a většinou se používá pro jejich debugování. Protože ale vypadá dobře, tak jej klidně můžeme použít ve svých projektech. Možná si říkáte co to normály jsou. U polygonů normály určují, kam polygon směřuje. Vlastně určuje jaká je přední a zadní strana polygonu. Následující obrázek normály ukazuje.

normály

Normály také u některých materiálů pracují se světlem. Čím více normál směruje ke světlu, tím bude polygon více osvětlen. Proto se vlastně normal textuře říká tak jak se jí říká. Pracuje s normály, tedy se světlem.

Na našem příkladu si můžeme MeshNormalMaterial vyzkoušet. Smažte si vytváření MeshBasicMateriálu a nahraďte jej následujícím kódem.

/* ... */

const material = new THREE.MeshNormalMaterial();

/* ... */

Po spuštění aplikace by jste měli materiál na objektech vidět aplikovaný. Když se teď budete na objekty dívat, tak polygony, které směřují směrem ke kameře budou vybarveny modře, ty které směřují jakoby nahoru od kamery budou zelené, ty doprava růžové a tak podobně. Barva se tedy aplikuje podle směru normálů vůči kameře. Podobně normály fungují se světlem.

Flat Shading

Asi jste si všimli, že u kostky má jeden polygon vždy stejnou barvu, zatímco u koule je barevný přechod přes více polygonů. Pokud modelujete, tak možná znáte Smooth shading a Flat shading. Smooth shading znamená, že se hrany spojených polygonů jakoby vyhladí a neuvidíme je. Flat shading znamená, že hrany zůstanou tak jak jsou. To jsem vám vysvětlil jen tak na povrchu, protože o tom nic moc nevím. Jestli se má použít Flat shading můžeme u materiálu určit pomocí vlastnosti flatShading. Můžeme to u našeho příkladu klidně zkusit.

/* ... */

const material = new THREE.MeshNormalMaterial({
    flatShading: true
});

/* ... */

Teď bychom již barevný přechod na kouli neměli vidět.

Mesh Matcap Material

U předchozího materiálu jste se dozvěděli co to jsou normály. Teď si ukážeme materiál, který je používá k výběru barvy na textuře a podle toho na objekt aplikuje barvu. Jedná se o MeshMatcapMaterial. K jeho vyzkoušení potřebujeme Matcap texturu. Jedná se o obrázek s koulí, ze které se bere podle směru normálu barva.

Matcap textura

Spoustu Matcap textur najdete zde, ale mylím že není tolik těžké vytvořit si v nějakém 3D modelovacím programu svoji vlastní. Je to jen o tom vytvořit kouli a vyrenderovat ji. Já jsem použil tuto texturu, takže si ji můžete také stáhnout a vložit do static složky.

Matcap texturu můžeme načíst jako každou jinou texturu pomocí Texture Loaderu. Poté ji můžeme nastavit na Matcap materiál pomocí vlastnosti matcap. Smažte si předchozí materiál, který jsme si zkoušeli, a namísto něj vložte následující kód, který Matcap materiál vytváří.

/* ... */

// vytvoření Texture Loaderu
const textureLoader = new THREE.TextureLoader();
// načtení textury
const matcapTexture = textureLoader.load("./static/Matcap.png");

const material = new THREE.MeshMatcapMaterial({
    matcap: matcapTexture
});

/* ... */

Po spuštění aplikace uvidíte, že na objektech bude matcap textura aplikována. Když se podívate na kouli, tak můžete vidět, že vypadá úplně stejně jako koule na textuře. Díky Matcap materiálu můžeme simulovat světlo na objektech bez toho, aniž bychom ve skutečnosti ve scéně nějaké světlo měli.

Mesh Lambert Material

Jako další materiál si ukážeme MeshLambertMaterial. Tento materiál již potřebuje světlo aby byl vidět, proto si do scény nějaká přídáme. Světlem se budeme zabývat v samostatné části, takže si jen zkopírujte následující kód, který světla vytváří. Nemusíte mu rozuměť. Můžete jej umístit třeba hned za kód pro vytvoření scény.

/* ... */

// přidání světel
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.7);
directionalLight.position.set(0.5, 1.5, 0.3);
scene.add(directionalLight);

/* ... */

Teď můžeme MeshLambertMaterial vytvořit. Odstraňte si kód pro vytvoření předchozího materiálu, pokud jste to ještě neudali, a namísto něj vložte následující kód. Tento kód MeshLambertMaterial vytváří a nastavuje mu jen barvu.

/* ... */

const material = new THREE.MeshLambertMaterial({
    color: 0xfddabe
});

/* ... */

Po spuštění aplikace byste na objektech měli MeshLambertMaterial vidět.

MeshLambertMaterial je výkonný, ale můžeme na objektech vidět divné vzory. V našem příkladu je asi neuvidíte, ale na ukázce v dokumentaci byste mohli. Také nemůže simulovat lesklé povrchy. Proto je často lepší použít spíš MeshPhongMaterial, který si ukážeme jako další. Pokud byste se chtěli dozvědět, jaké různé vlastnosti můžeme MeshLambertMaterialu nastavit, tak se můžete podívat do dokumentace.

Mesh Phong Material

Teď si ukážeme MeshPhongMaterial. Je podobný MeshLambertMaterialu, ale nevytváří na objektech divné vzory. Také může narozdíl od něj simulovat lesklé povrchy. Je ale samozřejmě méně výkonný než MeshLambertMaterial.

Smažte si v kódu MeshLambertMaterial a vložte si tam namísto něj kód pro vytvoření MeshPhongMaterialu.

/* ... */

const material = new THREE.MeshPhongMaterial({
    color: 0xfddabe
});

/* ... */

Po spuštění aplikace můžete MeshPhongMaterial na objektech vidět.

Lesklost

Zvýšit nebo snížit lesklost můžeme u MeshPhongMaterialu pomocí vlastnosti shininess. Také můžeme změnit barvu odlesku pomocí vlastnosti specular. Následující kód zvyšuje lesklost na hodnotu 60 (defaultní je 30) a nastavuje barvu odlesku na červenou.

/* ... */

const material = new THREE.MeshPhongMaterial({
    color: 0xfddabe,
    shininess: 60,
    specular: 0xff0000
});

/* ... */

Když si aplikaci spustíte, tak si můžete zvýšenou lesklost prohlédnout. Pod určitým úhlem na kouli uvidíte červený odlesk.

Více si toho o MeshPhongMaterialu neukážeme. V dokumentaci se o něm můžete dozvědět víc.

Mesh Toon Material

Další materiál, který si ukážeme, je MeshToonMaterial. Tento materiál vytváří takový kreslený efekt. Smažte si předchozí materiál a vytvořte si MeshToonMaterial, jak ukazuje následující ukázka.

/* ... */

const material = new THREE.MeshToonMaterial({
    color: 0x78E8FA
});

/* ... */

Po spuštění aplikace si můžete MeshPhongMaterial prohlédnout.

Gradient Map

Pro MeshToonMaterial si můžeme vytvořit gradient texturu a použít ji. Jedná se o obrázek, který může mít výšku 1 a na šířku vytváříme černobílý gradient. Tento gradient může být široký například klidně jen 5 pixelů. Gradient, který použijeme pro náš příklad si můžete stáhnout zde a vložit si jej do složky static. Poté si jej můžete načíst pomocí Texture Loaderu a můžete nastavit na MeshToonMaterial přes vlastnost gradientMap. U Gradient textury je ale ještě nutno změnit minification a magnification filter na THREE.NearestFilter, jak se píše v dokumentaci.

/* ... */

// vytvoření Texture Loaderu
const textureLoader = new THREE.TextureLoader();
// načtení textury
const gradientTexture = textureLoader.load("./static/Gradient.jpg");
// změnění minification a magnification filteru
gradientTexture.minFilter = THREE.NearestFilter;
gradientTexture.magFilter = THREE.NearestFilter;

const material = new THREE.MeshToonMaterial({
    color: 0x78E8FA,
    gradientMap: gradientTexture
});

/* ... */

Teď byste na materiálu měli gradient vidět. Když se podívate na kouli, tak uvidíte, že má 5 barevných částí, stejně jako gradient textura.

Více si o MeshToonMaterialu můžete přečíst v dokumentaci.

Mesh Standard Material

Jako další si ukážeme MeshStandardMaterial. Tento materiál narozdíl od těch předchozích používá PBR principy. Stejně jako například MeshPhongMaterial pracuje se světlem, ale používá více realistický algoritmus. Podporuje všechny typy textur, které jsme si ukazovali v minulé části o texturách.

Smažte si předchozí materiál a můžeme začít používat MeshStandardMaterial. Zatím si jej vytvořte bez žádného nastavení.

/* ... */

const material = new THREE.MeshStandardMaterial();

/* ... */

Po spuštění aplikace si můžete MeshStandardMaterial prohlédnout. Zatím je tak nějak stejný jako MeshPhongMaterial.

Textury

Zkusíme si na náš materiál aplikovat textury. Někde dříve jsem tu psal, že kromě Base Color si máte stáhnout i jiné typy textur. Teď je budeme potřebovat. Pomocí Texture Loaderu si načtěte Color, Normal a Roughness texturu. Poté načtené textury aplikujte na materiál pomocí vlastností map, normalMap a roughnessMap. Ambient Occlusion použijeme zachvíli, protože ji nemůžeme použít jen tak.

/* ... */

// vytvoření Texture Loaderu
const textureLoader = new THREE.TextureLoader();
// načtení textur
const colorTexture = textureLoader.load("./static/brick_wall_001_diffuse_1k.jpg");
const normalTexture = textureLoader.load("./static/brick_wall_001_nor_gl_1k.png");
const roughnessTexture = textureLoader.load("./static/brick_wall_001_rough_1k.png");

const material = new THREE.MeshStandardMaterial({
    map: colorTexture,
    normalMap: normalTexture,
    roughness: roughnessTexture
});

/* ... */

Po spuštění aplikace si můžete aplikované textury prohlédnout.

Ambient Occlusion

Teď si na naše objekty zkusíme aplikovat i Ambient Occlusion texturu. Ta ale vyžaduje druhý UV set. Co je to UV jsme si v předchozí části vysvětlovali. Jedná se o souřadnice vertexů na 2D ploše. Podle toho jak jsou vertexy rozmístěné, se na objekt aplikuje textura. Proč Ambient Occlusion textura druhý UV set vyžaduje nevím, jen vím že jej vyžaduje. Můžeme jej nastavit pomocí metody setAttribute, jelikož se jedná o atribut, který se posílá do shaderu. Jako název nastavíme "uv2". A klidně můžeme namísto vytváření nového UV setu jen odkázat na ten první. K tomu máme u geometrie přístup pomocí attributes.uv.array. Je to vlastně pole souřadnic vertexů na 2D ploše. Druhý UV set můžeme u každého našeho objektu vytvořit způsobem, jaký ukazuje následující ukázka. To podlě mě není něco, co byste měli chápat, spíš to berte jako fakt. Ale to je jen můj názor, já o tom totiž nic moc nevím.

/* ... */

// vytvoření kostky
const cube = new THREE.Mesh(
    new THREE.BoxGeometry(1, 1, 1),
    material
);
scene.add(cube);
// vytvoření druhého UV setu
cube.geometry.setAttribute("uv2",new THREE.Float32BufferAttribute(cube.geometry.attributes.uv.array, 2));

// vytvoření koule
const sphere = new THREE.Mesh(
    new THREE.SphereGeometry(0.5, 12, 10),
    material
);
sphere.position.x = -1.5;
scene.add(sphere);
// vytvoření druhého UV setu
sphere.geometry.setAttribute("uv2",new THREE.Float32BufferAttribute(sphere.geometry.attributes.uv.array, 2));

// vytvoření dodecahedronu (nebo co to je)
const dodecahedron = new THREE.Mesh(
    new THREE.DodecahedronGeometry(0.5, 0),
    material
);
dodecahedron.position.x = 1.5;
scene.add(dodecahedron);
// vytvoření druhého UV setu
dodecahedron.geometry.setAttribute("uv2",new THREE.Float32BufferAttribute(dodecahedron.geometry.attributes.uv.array, 2));

/* ... */

Teď si můžeme naši Ambient Occlusion načíst a použít jako ostatní textury. Nastavíme ji pomocí vlastnosti aoMap.

/* ... */

// vytvoření Texture Loaderu
const textureLoader = new THREE.TextureLoader();
// načtení textur
const colorTexture = textureLoader.load("./static/brick_wall_001_diffuse_1k.jpg");
const normalTexture = textureLoader.load("./static/brick_wall_001_nor_gl_1k.png");
const roughnessTexture = textureLoader.load("./static/brick_wall_001_rough_1k.png");
const ambientOcclusionTexture = textureLoader.load("./static/brick_wall_001_ao_1k.jpg");

const material = new THREE.MeshStandardMaterial({
    map: colorTexture,
    normalMap: normalTexture,
    roughness: roughnessTexture,
    aoMap: ambientOcclusionTexture
});

/* ... */

Po spuštění aplikace si můžete materiál s aplikovanou Ambient Occlusion texturou prohlédnout.

Možná po aplikování Ambient Occlusion textury nevidíte žádné velké rozdíly. Proto jsem tu pro vás připravil ukázku, ve které si ji můžete zkusit zapnout nebo vypnout.

Jak vidíte, tak Ambient Occlusion vytvoří takové falešné stíny v různých štěrbinách objektu (když je něco blízko u sebe).

Environment mapa

Abychom měli více realistické vykreslování, tak je dobré pro materiál ještě přidat environment mapu. Jedná se o obrázek kolem scény. Můžeme ji použít pro odrazy, ale také základní obecné nasvícení namísto AmbientLight. Podporuje ji více materiálů, ne jen MeshStandardMaterial. Třeba také MeshPhongMaterial ji podporuje. Následující ukázka environment mapu ukazuje.

Většinou environment mapu nechceme nastavit jako pozadí scény, jak to ukazuje předchozí ukázka, ale chceme ji použít pro základní osvícení objektů a odrazy. Jak to udělat si teď ukážeme. Nejdříve ale musíme nějakou environment mapu mít. Environment mapy, které jsou zdarma, najdete stejně jako textury na Poly Haven. Je to skvělý web co se týče zdrojů pro 3D grafiku. Nevýhoda ale je, že Three.js podporuje pouze Cube mapy a na Poly Haven se nacházejí jen HDRI. Cube mapa funguje tak, že máme 6 obrázků: nahoře, dole, nalevo, napravo, před námi, za námi. HDRI je pouze jeden obrázek, takže ji s Three.js použít nemůžeme. Můžeme ji ale do Cube mapy převést pomocí toho online převaděče z HDRI do Cube mapy. Já jsem to již udělal za vás a cube mapu kterou použijeme si můžete stáhnout zde. Stáhne se vám zazipovaný soubor s 6 obrázky. Umístěte si je do složky static.

Stejně jako pro načítání textur slouží TextureLoader, tak pro načítání environment map slouží CubeTextureLoader. Následující ukázka ukazuje, jak jej můžeme k načtení environment mapy použít. Je to podobné jako u načítání textur, akorát teď do funkce load předáváme cestu k 6 obrázkům.

/* ... */

// vytvoření Cube Texture Loaderu
const cubeTextureLoader = new THREE.CubeTextureLoader();
// načtení environment mapy
const environmentMapTexture = cubeTextureLoader.load([
    './static/px.png',
    './static/nx.png',
    './static/py.png',
    './static/ny.png',
    './static/pz.png',
    './static/nz.png',
]);

/* ... */

Po načtení environment mapy ji můžeme pro náš materiál použít. Ještě předtím ale odstraňte Ambient světlo, jelikož se teď o základní nasvícení bude starat environment mapa. V kódu pro vytváření světla tedy nyní zůstane jen DirectionLight.

/* ... */

// přidání světel
// const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
// scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.7);
directionalLight.position.set(0.5, 1.5, 0.3);
scene.add(directionalLight);

/* ... */

Environment mapu můžeme materiálu nastavit pomocí vlastnosti envMap.

/* ... */

const material = new THREE.MeshStandardMaterial({
    map: colorTexture,
    normalMap: normalTexture,
    roughness: roughnessTexture,
    aoMap: ambientOcclusionTexture,
    envMap: environmentMapTexture
});

/* ... */

Po spuštění aplikace by se měla pro materiál environment mapa použít.

Pokud se chcete ujistit, že se environment mapa na materiál opravdu aplikovala, tak můžete zakomentovat všechny textury a nastavit materiálu vlastnost roughness na 0 a metalness na 1. Vytvoří se vám tím v podstatě zrcadlo, ve kterém environment mapu na objektech uvidíte.

/* ... */

const material = new THREE.MeshStandardMaterial({
    // map: colorTexture,
    // normalMap: normalTexture,
    // roughness: roughnessTexture,
    // aoMap: ambientOcclusionTexture,
    envMap: environmentMapTexture,
    roughness: 0,
    metalness: 1
});

/* ... */

V našem příkladu jsme environment mapu nastavovali na materiál. Můžeme ji ale nastavit také na scénu a ta ji automaticky aplikuje na každý PBR materiál, který nemá nastavanou vlastnost envMap. Aplikuje ji ale jen na PBR materiály, takže pokud například chceme environment mapu použít třeba na Mesh Phong Materiály, tak ji musíme ručně nastavit na materiál pomocí vlastnosti envMap. Na scénu environment mapu nastavíme pomocí vlastnosti environment.

scene.environment = environmentMapTexture;

To je vše co jsme si o MeshStandardMaterialu ukázali. Více vlastností, které můžete nastavovat, najdete v dokumentaci.

Další materiály

V této části jsme si ukázali různé druhy materiálů, ale je tu ještě pár dalších materiálů, které jsme si neukázali. Chtěl bych tu u některých jen krátce popsat k čemu slouží. Zbývající najdete v dokumentaci.

Mesh Physical Material

MeshPhysicalMaterial je rozšíření MeshStandardMaterialu a poskytuje pokročilejší PBR vlastnosti. Má například podporu pro clear coat efekt. Co mu můžeme nastavit za vlastnosti a tak podobně si můžete přečíst v dokumentaci. Je tam také pár ukázek, na které se můžete podívat.

Points Material

PointsMaterial slouží k vykreslování vertexů namísto geometrie. Můžeme jej použít pro particles. Proto se k němu později vrátíme, až se jimi začneme zabývat.

Shader Material a Raw Shader Material

Tyto materiály můžeme použít k vytvoření našich vlastních materiálů. Vrátíme se k nim v části o shaderech.

Pro tuto část je to vše. Některé materiály o kterých jste se v této části dozvěděli vyžadovali světlo aby byly vidět. To jsme zatím neprobírali, takže jsme si jen zkopírovali kód, který nám nějaká světla vytvořil. V příští části světla prozkoumáme a ukážeme si jaké existují typy světel.