forked from andkok/MWS_2021
288 lines
28 KiB
HTML
288 lines
28 KiB
HTML
<!DOCTYPE html>
|
|
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
|
|
<head>
|
|
<meta charset="utf-8" />
|
|
<meta name="generator" content="pandoc" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
|
|
<title>cw6</title>
|
|
<style>
|
|
code{white-space: pre-wrap;}
|
|
span.smallcaps{font-variant: small-caps;}
|
|
span.underline{text-decoration: underline;}
|
|
div.column{display: inline-block; vertical-align: top; width: 50%;}
|
|
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
|
|
ul.task-list{list-style: none;}
|
|
pre > code.sourceCode { white-space: pre; position: relative; }
|
|
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
|
|
pre > code.sourceCode > span:empty { height: 1.2em; }
|
|
code.sourceCode > span { color: inherit; text-decoration: inherit; }
|
|
div.sourceCode { margin: 1em 0; }
|
|
pre.sourceCode { margin: 0; }
|
|
@media screen {
|
|
div.sourceCode { overflow: auto; }
|
|
}
|
|
@media print {
|
|
pre > code.sourceCode { white-space: pre-wrap; }
|
|
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
|
|
}
|
|
pre.numberSource code
|
|
{ counter-reset: source-line 0; }
|
|
pre.numberSource code > span
|
|
{ position: relative; left: -4em; counter-increment: source-line; }
|
|
pre.numberSource code > span > a:first-child::before
|
|
{ content: counter(source-line);
|
|
position: relative; left: -1em; text-align: right; vertical-align: baseline;
|
|
border: none; display: inline-block;
|
|
-webkit-touch-callout: none; -webkit-user-select: none;
|
|
-khtml-user-select: none; -moz-user-select: none;
|
|
-ms-user-select: none; user-select: none;
|
|
padding: 0 4px; width: 4em;
|
|
color: #aaaaaa;
|
|
}
|
|
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
|
|
div.sourceCode
|
|
{ }
|
|
@media screen {
|
|
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
|
|
}
|
|
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
|
|
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
|
|
code span.at { color: #7d9029; } /* Attribute */
|
|
code span.bn { color: #40a070; } /* BaseN */
|
|
code span.bu { } /* BuiltIn */
|
|
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
|
|
code span.ch { color: #4070a0; } /* Char */
|
|
code span.cn { color: #880000; } /* Constant */
|
|
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
|
|
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
|
|
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
|
|
code span.dt { color: #902000; } /* DataType */
|
|
code span.dv { color: #40a070; } /* DecVal */
|
|
code span.er { color: #ff0000; font-weight: bold; } /* Error */
|
|
code span.ex { } /* Extension */
|
|
code span.fl { color: #40a070; } /* Float */
|
|
code span.fu { color: #06287e; } /* Function */
|
|
code span.im { } /* Import */
|
|
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
|
|
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
|
|
code span.op { color: #666666; } /* Operator */
|
|
code span.ot { color: #007020; } /* Other */
|
|
code span.pp { color: #bc7a00; } /* Preprocessor */
|
|
code span.sc { color: #4070a0; } /* SpecialChar */
|
|
code span.ss { color: #bb6688; } /* SpecialString */
|
|
code span.st { color: #4070a0; } /* String */
|
|
code span.va { color: #19177c; } /* Variable */
|
|
code span.vs { color: #4070a0; } /* VerbatimString */
|
|
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
|
|
</style>
|
|
<link rel="stylesheet" href="style.css" />
|
|
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml-full.js" type="text/javascript"></script>
|
|
<!--[if lt IE 9]>
|
|
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
|
|
<![endif]-->
|
|
</head>
|
|
<body>
|
|
<h1 id="tworzenie-krajobrazu">Tworzenie krajobrazu</h1>
|
|
<p>W trakcie tych zajęć skupimy się na tworzeniu krajobrazów z wykorzystaniem pakietu <em>Terrain Tools</em> i darmowych assetów dostępnych w sklepie unity. W pierwszej części skupimy się na ręcznym kształtowaniu terenu. Z tematem można sie zapoznać także korzystając z licznych tutoriali np <a href="https://youtu.be/smnLYvF40s4">tym</a> lub <a href="https://www.youtube.com/watch?v=ddy12WHqt-M">tym</a>.</p>
|
|
<h2 id="przygotowanie">Przygotowanie</h2>
|
|
<p>Do odtworzenia wyników z zajęć w nowym projekcie wymagany jest pakietu <em>Terrain Tools</em>, który jest w wersji preview, żeby go pobrać najpierw trzeba ustawić wyświetlanie tych pakietów w menadżerze. Poza tym potrzebne będą assety terenu, można wykorzystać te, które są dostępne jako przykładowe albo znaleźć inne (można na przykład pobrać jakieś darmowe sceny i ukraść z nich assety do celów edukacyjnych) lub zrobić je samemu.</p>
|
|
<h2 id="inicjalizacja-terenu">Inicjalizacja terenu</h2>
|
|
<p>Obok zakładki <strong>Inspector</strong> powinna być zakładka <strong>Terrain Toolbox</strong>, która służy do zarządzania obiektami terenu. Jeżeli jej tam nie ma, możesz ją znaleźć pod opcją <code>Window > Terrain > Terrain Toolbox</code>. Zaznacz <strong>Create New Terrain</strong>, powinno się pojawić poniższe okno:</p>
|
|
<figure>
|
|
<img src="img\1.JPG" alt="size" /><figcaption aria-hidden="true">size</figcaption>
|
|
</figure>
|
|
<p>ustaw wymiary (szerokość wysokość i długość) terenu wedle własnego uznania, domyślnie jest to 500 na 500 na 600, ale dla oszczędzenia mocy obliczeniowej systemu w dalszych punktach zalecam ograniczyć się do 100 na 100 na 200. (Te opcje można też później zmienić w ustawieniach terenu lub globalnie dla wszystkich terenów w <code>Terrain Toolbox > Terrain Settings</code>.) Pozostaje stworzyć teren za pomocą przycisku <strong>Create</strong> na dole okna</p>
|
|
<h2 id="opcje">Opcje</h2>
|
|
<p>Stworzony teren pojawi się w postaci płaskiej szachownicy w widoku sceny i w hierarchii wewnątrz grupy terenów</p>
|
|
<figure>
|
|
<img src="img\3.JPG" alt="stworzony teren" /><figcaption aria-hidden="true">stworzony teren</figcaption>
|
|
</figure>
|
|
<p>Teraz skupimy się na opcjach jakie możliwości oferuje teren jako komponent terenu. Przełącz się na zakładkę <strong>Inspector</strong> i zaznacz teren. W inspektorze możesz zobaczyć szereg opcji jakie teren oferuje pogrupowanych w zakładki.</p>
|
|
<figure>
|
|
<img src="img\4.JPG" alt="stworzony teren" /><figcaption aria-hidden="true">stworzony teren</figcaption>
|
|
</figure>
|
|
<p>Interesujące nas części to:</p>
|
|
<ul>
|
|
<li><strong>Malowanie terenu</strong> służy do rzeźbienia powierzchni terenu i nakładaniu tekstury na terenie.</li>
|
|
<li><strong>Rozmieszenie drzew</strong>, jak nazwa wskazuje służy do rozmieszczania drzew.</li>
|
|
<li><strong>Rozmieszczenie detali</strong> takich jak trawy, kwiaty polne czy kamienie</li>
|
|
</ul>
|
|
<h2 id="formowanie-powierzchni">Formowanie Powierzchni</h2>
|
|
<p>Kształt terenu jest opisywany przez heightmapę. Czyli maskę, której jasność oznacza wysokość terenu. Ta jest interpretowana przez unity i przetwarzana na mesh. Dzięki temu podejściu projektant nie musi martwić się o geometrię terenu, która jest generowana przez silnik. Wadą jest, że wszelkie wypukłości i lub jaskinie muszą być obsługiwane w inny sposób.</p>
|
|
<p>Tworzenie sceny zaczniemy od wyrzeźbienia powierzchni terenu. Przejdź do zakładki <strong>Malowanie terenu</strong>. Pod paskiem z zakładkami jest lista rozwijana, w której można wybrać tryby malowania. Poniżej listy jest pole tekstowe, które opisuje co robi i dana opcja. Pod nią opcje pędzla, przede wszystkim można wybrać jakiego pędzla chce się używać, poza tym można modyfikować jego parametry, czyli rozmiar siłę, nacisku i spacing. Można dodawać swoje własne pędzle. Jeszcze niżej są opcje poszczególnych trybów - istotniejsze są omówione poniżej.</p>
|
|
<p>Do formowania terenu interesuje nas pierwsze pięć i ostatnie cztery opcji, są to:</p>
|
|
<ul>
|
|
<li><p>Sculpt - zbiór narzędzi związanych z rzeźbieniem, należą do nich:</p>
|
|
<ul>
|
|
<li>Bridge - łączy dwa zaznaczone obszary mostem.</li>
|
|
<li>Clone - kopiuje zaznaczony obszar w wybrane miejsce.</li>
|
|
<li>Noise - modyfikuje teren z uwzględnieniem tekstury szumu - opcje pozwalają dostosowywać teksturę szumu.</li>
|
|
<li>Terrace - tworzy tarasy na wzniesieniach - opcje pozwalają modyfikować liczbę tarasów i ostrość kątów.</li>
|
|
</ul></li>
|
|
<li><p>Effects - Różnego rodzaju efekty.</p>
|
|
<ul>
|
|
<li>Contrast - zwiększa rożnicę wysokości - opcje pozwalają ustalić rozmiar cech jakie będą brane pod uwagę.</li>
|
|
<li>Sharpen Peaks.</li>
|
|
<li>Slope Flatten.</li>
|
|
</ul></li>
|
|
<li><p>Erosion - różne rodzaje erozji</p></li>
|
|
<li><p>Mesh Stamp - pozwala odcisnąć mesh znajdujący się w assetach projektu.</p></li>
|
|
<li><p>Raise or Lower Terrain - podnosi lub opuszcza teren, główne narzędzie przy formowaniu.</p></li>
|
|
<li><p>Transform - ściskanie, przesuwanie i obracanie.</p></li>
|
|
<li><p>Set Height - ustawia teren na wpisanej przez użytkownika wysokości.</p></li>
|
|
<li><p>Smooth Height - wygładza teren.</p></li>
|
|
</ul>
|
|
<p>Poza tym można dodawać filtry na maski modyfikując ich możliwości.</p>
|
|
<p>Przydatne skróty:</p>
|
|
<ul>
|
|
<li><strong>A</strong> Modyfikuje siłę nacisku pędzla.</li>
|
|
<li><strong>S</strong> Modyfikuje rozmiar pędzla.</li>
|
|
<li><strong>D</strong> Modyfikuje obrót pędzla.</li>
|
|
<li><strong>Control+Lewy Przycisk Myszy</strong> Odwraca działanie pędzla lub uruchamia jego alternatywny tryb.</li>
|
|
<li><strong>Shift+Lewy Przycisk Myszy</strong> Przełącza na wygładzanie.</li>
|
|
</ul>
|
|
<blockquote>
|
|
<p>Nim zaczniesz modelować teren dodaj jakiś obiekt, który będzie służył za punkt odniesienia, na przykład model postaci albo jakąś figurę geometryczną. Model wykorzystany w trakcie zajęć pochodzi <a href="https://sketchfab.com/3d-models/shrek-3d-model-541d5a5dd9914679919cc1d9a437097e">stąd</a>.</p>
|
|
</blockquote>
|
|
<h3 id="zadanie">Zadanie</h3>
|
|
<p>wybierz jeden z krajobrazów znajdujących się w folderze <code>landscapes</code> i wymodeluj teren nimi inspirowany. Zdjęcia nie będą punktem odniesienia w ocenianiu. służą jedynie jako inspiracja do zrobienia terenu.</p>
|
|
<p>Gdy skończysz, przenieś kamerę w miejsce docelowe. Możesz założyć, że scena jest statyczna, to znaczy, kamera się nie porusza. Zaznacz kamerę i użyj <code>Ctrl+Shift+F</code> by ustawić kamerę z widokiem sceny.</p>
|
|
<h2 id="teksturowanie-terenu">Teksturowanie terenu</h2>
|
|
<blockquote>
|
|
<p>Tekstury terenu są jak cebula, mają warstwy</p>
|
|
</blockquote>
|
|
<p>Na teren nakłada różne tekstury odpowiadające za rożne rodzaje powierzchni, takie podejście pozwala uniknąć monotonii i czyni teren bardziej atrakcyjnym. Osiąga się to za pomocą palety warstw oraz splatmapy, która opisuje z jakimi parametrami silnik ma mieszać warstwy.</p>
|
|
<p>By przejść do teksturowania, należy wybrać opcję <strong>Texture Paint</strong> dostępną w rozwijanym menu.</p>
|
|
<h3 id="paleta-tekstur">Paleta Tekstur</h3>
|
|
<p>Pierwszym krokiem jest stworzenie lub wczytanie palety tekstur, które będą nakładane na teren. Ustawienia palety znajdziemy w zakładce <strong>Layers</strong>.</p>
|
|
<figure>
|
|
<img src="img\5.JPG" alt="details" /><figcaption aria-hidden="true">details</figcaption>
|
|
</figure>
|
|
<p>Gotowe warstwy można dodać za pomocą przycisku <strong>Add Layer</strong> a nowe za pomocą <strong>Create</strong>. Jednak tutaj trzeba wziąć pod uwagę, że dodaje się tylko teksturę, która odpowiada za kolor, pozostałe trzeba dodać do warstwy ręcznie.</p>
|
|
<p>Warstwa terenu składa się z 3 tekstur:</p>
|
|
<ul>
|
|
<li>Diffuse - kolor warstwy</li>
|
|
<li>Normal - normalna</li>
|
|
<li>Mask - zawiera na poszczególnych dodatkowo kanałach informacje standardowo to są:
|
|
<ul>
|
|
<li>Czerwony - Metallic</li>
|
|
<li>Zielony - Occlusion</li>
|
|
<li>Niebieski - Height poprawia jakoś mieszania tekstur</li>
|
|
<li>Alfa - Smoothness</li>
|
|
</ul></li>
|
|
</ul>
|
|
<p>Nie ma potrzeby, żeby wszystkie tekstury znalazły sie w warstwie, zalecane jest, żeby były przynajmniej dwie pierwsze.</p>
|
|
<p>Kolejność tekstur w palecie można swobodnie zmieniać, ale najlepiej ustalić ją na początku. Tekstury są indeksowane w splatmapie po ich kolejności w palecie, więc zmiana jej w trakcie malowania spowoduje nieprzewidziane w efekcie końcowym.</p>
|
|
<p>Warstwy podobnie jak materiały można skalować za pomocą opcji tilling, z jednej storny pozwoli to na dopasowanie ich do sceny, z drugiej, stworzenie kilku warstw różniących się tylko tym parametrem może być dobrym sposobem na szybkie urozmaicenie sceny</p>
|
|
<h3 id="rysowanie-terenu">Rysowanie terenu</h3>
|
|
<p>Pierwsza warstwa od góry jest tą domyślną, więc umieść ją na szczycie. Kolejność pozostałych nie ma znaczenia, póki nie zaczniesz nakładać ich na teren. Tekstury nakładasz wybierając teksturę i pędzel, następnie nakładasz ją na teren kliknięciami i pociągnięciami myszki. Spróbuj różnych ustawień pędzla. Przykładowo zwiększenie wartości <em>Brush Scatter</em>, <em>Brush Spacing</em> i <em>Jitter</em> i użycie nieregularnego pędzla da efekt rozrzucenia plam w losowych miejscach.</p>
|
|
<h3 id="zadanie-1">Zadanie</h3>
|
|
<p>Utwórz paletę korzystając z dostępnych warstw i tekstur. Następnie wykorzystaj ją do oteksturowania swojego terenu. Dodaj do swojego krajobrazu jakąś ścieżkę i nadaj jej odpowiednie tekstury.</p>
|
|
<h2 id="rozmieszczenie-drzew">Rozmieszczenie drzew</h2>
|
|
<blockquote>
|
|
<p>Zanim zaczniemy dodaj do kamery skrypt <code>Simple Camera Controller</code>, ułatwi on poruszanie się w scenie</p>
|
|
</blockquote>
|
|
<p>Kolejne narzędzie służy do rozmieszczania drzew i innych większych elementów krajobrazu.</p>
|
|
<figure>
|
|
<img src="img\6.JPG" alt="trees" /><figcaption aria-hidden="true">trees</figcaption>
|
|
</figure>
|
|
<p>Nowy rodzaj drzew dodaje się za pomocą <code>Edit Trees > Add Trees</code>, opcje w <strong>Edit Trees</strong> służy także do zmiany modelu drzewa czy usuwaniu rodzaju drzewa.</p>
|
|
<p>Poniżej są suwaki odpowiadające za opcje ustawiania drzew. Dwa pierwsze modyfikują rozmiar i gęstość pędzla. kolejne odpowiadają za dostosowanie wielkości drzew. Opcja Lock <strong>Width to Height</strong> uzależnia szerokość drzewa od wysokości. Jej wyłączenie zwiększy różnorodność drzew, ale może prowadzić do niepożądanych efektów, przy źle dobranych parametrach.</p>
|
|
<p>Można też umieścić drzewa losowo za pomocą <code>Mass Place Trees</code>, gdzie użytkownik może wybrać ile drzew ma się pojawić, a te zostaną umieszone losowo w scenie.</p>
|
|
<h2 id="umieszczanie-detali">Umieszczanie detali</h2>
|
|
<p>Kolejna zakładka służy do dodawania detali, jak trawa i rośliny polne. Jest bardzo podobna do tej od drzew. Podobnie za pomocą Edit Details można dodać edytować lub usuwać detale. Dodatkowo jest opcja <code>Add Grass Texture</code>, która pozwala dodać teksturę jako <a href="https://youtu.be/puOTwCrEm7Q">bilboard</a>. Działanie pierwszego suwaka odpowiada za wielkość pędzla. Natomiast trzeciego za maksymalną ma być na tym terenie, a drugi za tępo w jakim tą wielkość się osiągnie. Jakby to porównać do malowania, to <strong>Target Strength</strong> by odpowiadało za siłę nasycenia, ale <strong>Opacity</strong> za siłę krycia.</p>
|
|
<figure>
|
|
<img src="img\7.JPG" alt="details" /><figcaption aria-hidden="true">details</figcaption>
|
|
</figure>
|
|
<h3 id="dodawanie-detali">Dodawanie Detali</h3>
|
|
<p>Poniżej jest okno jakie się pojawia przy dodawaniu/edytowaniu detalu. Można w nim dostosować rozmiar, żeby zgadzał się z rozmiarem reszty obiektów w scenie. Wartości kolorów odpowiadają za modyfikacje odcienia detali w zależności od położenia, by nadać im większą różnorodność. Warto dopasować wartości kolorów, <strong>Healthy Color</strong> z reguły powinien być biały, natomiast <strong>Dry Color</strong> nie powinnien zbytnio odbiegać od oryginalnego koloru obiektu.</p>
|
|
<figure>
|
|
<img src="img\8.JPG" alt="details" /><figcaption aria-hidden="true">details</figcaption>
|
|
</figure>
|
|
<h2 id="dodatkowe-informacje">Dodatkowe informacje</h2>
|
|
<h3 id="dodawanie-skał-i-innych-obiektów">Dodawanie Skał i innych obiektów</h3>
|
|
<p>Narzędzia terenu same w sobie się nie nadają na tworzenie ostrych skał czy klifów, by je dodać do sceny lepiej dodać je jako osobne obiekty. Można to zrobić za pomocą systemu drzew, co jednak może dać nierealistyczne efekty lub umieścić je samemu ręcznie.</p>
|
|
<p>Druga opcja jest preferowana, gdy chcemy wystającą skałę lub klif umieścić blisko kamery lub w centralnym punkcie naszej sceny. Słabym punktem takiego obiektu jest miejsce połączenia z terenem. Można je zamaskować poprzez dodanie w tym miejscu detali, jak trawa i/lub małe kamyki.</p>
|
|
<figure>
|
|
<img src="img\9.JPG" alt="details" /><figcaption aria-hidden="true">details</figcaption>
|
|
</figure>
|
|
<h3 id="post-processing">Post-processing</h3>
|
|
<p>Post processing to zbiór technik wykorzystywanych wykonywanych na wyrenderowanej klatce. Dzięki nim można poprawić wygląd sceny lub dodać efekty jak mgła, bloom czy flary.</p>
|
|
<p>Unity oferuje pakiet, który udostępnia podstawowe efekty postprocessingu o nazwie <strong>PostProcessing</strong>. By go zainicjalizować należy dodać do kamery komponenty <code>Post-Proces Layer</code> i <code>Post-Proces Volume</code>. Następnie dodać dodać nową warstwę w <code>Layer > Add Layer...</code>, nazwij ją <strong>Post Processing</strong>. Na koniec ustawić warstwę na <strong>Post Processing</strong> w kamerze i w <code>Post-Proces Layer</code>.</p>
|
|
<figure>
|
|
<img src="img\10.JPG" alt="details" /><figcaption aria-hidden="true">details</figcaption>
|
|
</figure>
|
|
<p>Teraz wystarczy stworzyć profil w <code>Post-Proces Volume</code> i dodać do niego komponenty.</p>
|
|
<blockquote>
|
|
<p>Ustaw opcję <code>Is Global</code> żeby efekty były widoczne także w widoku sceny</p>
|
|
</blockquote>
|
|
<h4 id="niektóre-dostępne-obiekty-efekty">Niektóre dostępne obiekty efekty</h4>
|
|
<p><strong>Color Grading</strong> - pozwala dostosować kolorystykę sceny, zmodyfikować ekspozycję i kontrast. Do prawidłowego funkcjonowania należy zmienić przestrzeń kolorów na liniową można to zrobić w <code>Edit > Project Settings > Player > Rendering > Color Space</code>.</p>
|
|
<p><strong>Ambient Occlusion</strong> - dodaje okluzję otoczenia, czyli zacienienie dla światła rozproszonego wynikającego z geometrii. Zalecane jest wybrać <code>Scalable Ambient Obscurance</code> jako typ.</p>
|
|
<p><strong>Vigniette</strong>, <strong>Chromatic Aberration</strong>, <strong>Bloom</strong> - efekty symulujące działanie rzeczywistych kamer zwiększają <em>filmowość</em> obrazu.</p>
|
|
<p><strong>Motion Blur</strong> - rozmycie w ruchu, nada więcej realizmu ruchom trawy i gałęzi.</p>
|
|
<figure>
|
|
<img src="img\11.JPG" alt="details" /><figcaption aria-hidden="true">details</figcaption>
|
|
</figure>
|
|
<h3 id="zadanie-domowe">Zadanie domowe</h3>
|
|
<p>Znajdź w internecie model domku lub innego budynku i zbuduj wokół niego scenę przedstawiającą go na odludziu w otoczeniu przyrody. Wymodeluj teren, dodaj drzewa, trawę i inne detale, wykorzystaj post-processing. Możesz wykorzystać assety znajdujące się w projekcie lub ściągnąć własne. Postaraj się, żeby teren wyglądał estetycznie. Efekt końcowy może być statycznym ujęciem, w takim przypadku umieść kamerę w odpowiednim miejscu.</p>
|
|
<h2 id="teskturowanie-w-oparciu-o-ukształtowanie-terenu">Teskturowanie w oparciu o ukształtowanie terenu</h2>
|
|
<p>Teksturowanie można częściowo zautomatyzować uzależniając występowanie warstwę od własności terenu, takich jak wysokość czy kąt nachylenia. Przypomnijmy, że to jaka i w jakim stopniu dana warstwa zostanie narysowana jest dyktowane przez splatmapę. Po stronie skryptu jest to tablica trójwymiarowa, której 2 pierwsze współrzędne to szerokość i wysokość w mapie a trzecia jest indeksem warstwy.</p>
|
|
<p>Otwórz Scenę <code>Procedural Terrain</code>. Wewnątrz znajduje się teren z podpiętym skryptem <code>Procedural Texture Script</code>, otwórz go w edytorze. Skrypt zawiera funkcję <code>runProcedrualTexturing</code>, w która ma teksturować teren. W tej chwili przypisuje każdemu punktowi losową wartość i wygląda następująco.</p>
|
|
<div class="sourceCode" id="cb1"><pre class="sourceCode c#"><code class="sourceCode cs"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a> <span class="kw">public</span> <span class="dt">void</span> <span class="fu">runProcedrualTexturing</span>() {</span>
|
|
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">var</span> terrain = gameObject.<span class="fu">GetComponent</span><Terrain>();</span>
|
|
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">var</span> layers = terrain.<span class="fu">terrainData</span>.<span class="fu">alphamapLayers</span>;</span>
|
|
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">var</span> height = terrain.<span class="fu">terrainData</span>.<span class="fu">alphamapWidth</span>;</span>
|
|
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">var</span> width = terrain.<span class="fu">terrainData</span>.<span class="fu">alphamapHeight</span>;</span>
|
|
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a></span>
|
|
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a></span>
|
|
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a> <span class="dt">var</span> newSplatMap = <span class="kw">new</span> <span class="dt">float</span>[width, height, layers];</span>
|
|
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a> </span>
|
|
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a> <span class="kw">for</span> (<span class="dt">int</span> i=<span class="dv">0</span>; i < width;i++) {</span>
|
|
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a> <span class="kw">for</span> (<span class="dt">int</span> j = <span class="dv">0</span>; j < width; j++) {</span>
|
|
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a> <span class="dt">float</span> x = j / (<span class="dt">float</span>)height;</span>
|
|
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a> <span class="dt">float</span> y = i / (<span class="dt">float</span>)width;</span>
|
|
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a></span>
|
|
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a> <span class="dt">var</span> splatWeights = <span class="kw">new</span> <span class="dt">float</span>[layers];</span>
|
|
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a></span>
|
|
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a> <span class="kw">for</span> (<span class="dt">int</span> k = <span class="dv">0</span>; k < layers; k++) {</span>
|
|
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a> splatWeights[k] = Random.<span class="fu">RandomRange</span>(<span class="fl">0.0f</span>,<span class="fl">1.0f</span>);</span>
|
|
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a> }</span>
|
|
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a> <span class="dt">float</span> sum = splatWeights.<span class="fu">Sum</span>();</span>
|
|
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a></span>
|
|
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a> <span class="kw">for</span> (<span class="dt">int</span> k = <span class="dv">0</span>; k < layers; k++) {</span>
|
|
<span id="cb1-23"><a href="#cb1-23" aria-hidden="true" tabindex="-1"></a> newSplatMap[i,j,k]=splatWeights[k]/sum;</span>
|
|
<span id="cb1-24"><a href="#cb1-24" aria-hidden="true" tabindex="-1"></a> }</span>
|
|
<span id="cb1-25"><a href="#cb1-25" aria-hidden="true" tabindex="-1"></a> }</span>
|
|
<span id="cb1-26"><a href="#cb1-26" aria-hidden="true" tabindex="-1"></a> }</span>
|
|
<span id="cb1-27"><a href="#cb1-27" aria-hidden="true" tabindex="-1"></a> terrain.<span class="fu">terrainData</span>.<span class="fu">SetAlphamaps</span>(<span class="dv">0</span>, <span class="dv">0</span>, newSplatMap);</span>
|
|
<span id="cb1-28"><a href="#cb1-28" aria-hidden="true" tabindex="-1"></a> }</span></code></pre></div>
|
|
<p>Przeanalizujmy instrukcje funkcji. Pierwsza pobiera komponent terenu. Następne trzy pobierają odpowiednio liczbę warstw, wysokość i szerokość splatmapy. Linia <code>var newSplatMap = new float[width, height, layers];</code> tworzy tablicę, która będzie służyć za nową splatmapę. Następnie w pętli przechodzi po wszystkich indeksach splatmapy.</p>
|
|
<div class="sourceCode" id="cb2"><pre class="sourceCode c#"><code class="sourceCode cs"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="dt">float</span> x = j / (<span class="dt">float</span>)height;</span>
|
|
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="dt">float</span> y = i / (<span class="dt">float</span>)width;</span></code></pre></div>
|
|
<p>Powyższe instrukcje dają współrzędne unormowane, które będą przydatne póżniej. Tablica <code>splatWeights</code> będzie przechowywać wagi warstw.</p>
|
|
<div class="sourceCode" id="cb3"><pre class="sourceCode c#"><code class="sourceCode cs"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">for</span> (<span class="dt">int</span> k = <span class="dv">0</span>; k < layers; k++) {</span>
|
|
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a> splatWeights[k] = Random.<span class="fu">RandomRange</span>(<span class="fl">0.0f</span>,<span class="fl">1.0f</span>);</span>
|
|
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
|
|
<p>Ustawia indeksy na losowe wartości</p>
|
|
<div class="sourceCode" id="cb4"><pre class="sourceCode c#"><code class="sourceCode cs"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="dt">float</span> sum = splatWeights.<span class="fu">Sum</span>();</span>
|
|
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="kw">for</span> (<span class="dt">int</span> k = <span class="dv">0</span>; k < layers; k++) {</span>
|
|
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a> newSplatMap[i,j,k]=splatWeights[k]/sum;</span>
|
|
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>}</span></code></pre></div>
|
|
<p>Umieszcza wagi w splatmapie i normalizuje je. Suma wag powinna być równa zero, dlatego dzielimy przez sumę tablicy.</p>
|
|
<div class="sourceCode" id="cb5"><pre class="sourceCode c#"><code class="sourceCode cs"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>terrain.<span class="fu">terrainData</span>.<span class="fu">SetAlphamaps</span>(<span class="dv">0</span>, <span class="dv">0</span>, newSplatMap);</span></code></pre></div>
|
|
<p>Ustawia nową splatmapę</p>
|
|
<h3 id="zadanie-2">Zadanie</h3>
|
|
<p>Zmodyfikuj funkcję tak, żeby teren, który znajduje się wyżej niż <code>snowHeight</code> był śniegiem a poniżej trawą. Wykorzystaj metodę <code>terrain.terrainData.GetInterpolatedHeight</code> by uzyskać poziom we współrzędnych <code>x</code> i <code>y</code>.</p>
|
|
<p>Wykorzystanie zwykłego warunku logicznego da ostre przejście, które wygląda nierealistycznie. Napisz funkcję <code>transition(float start, float end,float value)</code> która:</p>
|
|
<ul>
|
|
<li>zwróci 0, jeżeli <span class="math inline">\(\text{value}<\text{start}\)</span>;</li>
|
|
<li>zwróci 1, jeżeli <span class="math inline">\(\text{value}\ge \text{end}\)</span>;</li>
|
|
<li>będzie liniowo interpolować między 0 a 1 jeżeli <span class="math inline">\(\text{end}>\text{value}\ge\text{start}\)</span>,</li>
|
|
</ul>
|
|
<p>I wykorzystaj ją by zrobić bardziej stopniowe przejście</p>
|
|
<h3 id="zadanie-domowe-1">Zadanie domowe</h3>
|
|
<p>Wykonaj coś podobnego dla tekstury kamieni, teraz zamiast wysokości terenu wykorzystaj kąt nachylenia, możesz go uzyskać za pomocą metody <code>terrain.terrainData.GetSteepness</code>.</p>
|
|
</body>
|
|
</html>
|