Hej! Michalis, autor tej strony który prowadził wykład z Blendera na uniwerku, prowadzi teraz warsztaty z Blendera we Wrocławiu.
4 spotkania w niedziele, po 4 godziny, gdzie można nauczyć się od podstaw jak używać Blendera, w szczególności do tworzenia gier. Opowiadamy dużo o modelowaniu, texturowaniu, animacji i masie istotnych technik przy tworzeniu modeli do gier. Warsztaty prowadzimy a ramach naszego małego studia gier indie Cat-astrophe Games:)
2012 |
2011 |
2010 |
2008 |
Kurs Blendera na II UWr w semestrze letnim. Kurs obejmuje wszystko związane z Blenderem: modelowanie, renderowanie, tworzenie animacji 3D. Spróbujemy opanować część tej listy możliwości Blendera.
Nie ma egzaminu.
Pojawi się około ~10 łatwych zadań na pracowniach. Zazwyczaj będą to zadania do zrobienia "na miejscu" w 2 godziny, zazwyczaj łatwe, zazwyczaj będę bezczelnie wykorzystywać istniejące tutoriale do Blendera w sieci. Jeżeli ktoś nie zdąży zrobić zadania na pracowni (albo nie będzie obecny na pracowni) — będzie musiał zrobić zadanie sam i przysłać mi plik .blend.
Terminy: dla osób obecnych na pracowni, termin wynosi tydzień od daty Waszej pracowni, przy czym spóźnienia ~kilku dni będę traktował liberalnie. Więc mam nadzieję że fakt że grupa czwartkowa zazwyczaj pozna treść zadań nieco wcześniej od poniedziałkowej nie będzie dla nich zbytnią przewagą :) Zobaczymy jak to wyjdzie w praniu.
Jeżeli ktoś nie będzie obecny na pracowni: macie wtedy tydzień czasu od momentu publikacji zadania na tej stronie. Przy czym haczyk jest taki że do spóźnień będę podchodził bardziej rygorystycznie. Dla osób które nigdy nie będą obecne na żadnej pracowni, dozwolone są tylko 3 spóźnienia. Dla osób chodzących w kratkę, będziemy ustalać coś pomiędzy.
Spóźnienie = oddanie zadania o max tydzień później. Jeżeli nie oddacie zadania w ciągu 2 tygodni, traktuję to jako 2 spóźnienia i już nie musicie oddawać zadania w ogóle.
Wybaczcie że nieobecność traktuję tak surowo. Sam jestem notorycznym spóźnialskim, zasypialskim, zawalaczem wszelkich deadline'ów etc., więc osoby którym nie chce się pojawić na pracowni mają moją pełną sympatię. Tym niemniej — praktyka pokazuje że niektóre takie osoby robią bardzo mało w czasie 15 tygodni pracowni, do czego mam sympatię dużo mniejszą. Jeżeli jesteście dobrzy, i zobaczycie że kurs jest dla Was łatwy, i będziecie się wyrabiać w tydzień — cool, możecie pojawiać się na pracowni tylko na oddawanie projektów (patrz niżej), a "normalne" zadania mi przysyłać. Wszystkim innym, polecam chodzić na pracownię.
Ponadto będą dwa większe projekty.
Projekty będą oceniane nieco bardziej pod kątem jakości "artisticznej" (podczas gdy normalne co-tygodniowe zadania będą raczej oceniane zero-jedynkowo: zrobił OK, albo nie zrobił wcale).
(W miarę) realistyczny rendering statycznej sceny. (Sprawdzamy modelowanie, podstawy materiałów. Prawdopodobnie tekstury i zaawansowane oświetlenie nie będą tu wymagane.)
Animacja (kości z actions, curves). Lub swobodny projekt, z wykorzystaniem czegoś advanced.
Na zaliczenie (na 3) trzeba zrobić 2 projekty byle jak, i wyrobić się z oddawaniem (większości) co-tygodniowych zadań. Na zaliczenie na 5, trzeba zrobić 2 projekty, i to dobrze, i oddać wszystkie zadania.
Normalne, ~co-tygodniowe zadania: trzeba przysłać mailem do prowadzącego
pracownię (Michalis: michalis.kambi@proton.me). Zwyczajnie załączcie
do maila plik Blendera, xxx.blend
. Możecie też wystawić plik
gdzieś w sieci i przysłać mi tylko URL, jeśi tak Wam wygodniej.
Kiedy rendering trwa długo a jest ważny dla zadania, prosiłbym też przysłać mi gotowy obrazek / film.
W przypadku niektórych zadań część danych pochodzi z zewnętrznych plików, np. tekstury UV będziemy często ładować ze "zwyczajnych" plików obrazków (png, jpg, etc.). Na szczęście Blender pozwala "spakować" takie zewnętrzne pliki do pliku .blend, co ułatwi Wam wysyłanie a mi odbieranie: wystarczy użyć menu File -> External Data -> Pack into .blend file (pojawi się ikonka "paczki" na menu i obok spakowanych tekstur).
Na oddawaniu projektów będę chciał zobaczyć Was osobiście.
Co trzeba zrobić:
Należy wiernie wymodelować jakiś istniejący (choćby tylko w Waszej wyobraźni i na rysunkach :) ) obiekt/scenę etc. Może to być budynek, przedmiot, pokój, pojazd, samolot, postać... Musi być tylko stosunkowo nietrywialny, najlepiej składać się z kilku części (dlatego np. nie polecam modelowania samej sylwetki człowieka, chyba że zrobicie wystarczająco dużo szczegółów / akcesoriów / ciekawych materiałów / tekstur).
Chcemy też zrobić możliwie ładny rendering tego obiektu/sceny. (Przynajmniej jeden rendering, ale można zrobić kilka, np. z kilku interesujących kamer.) Czyli poza modelowaniem trzeba będzie trochę pobawić się z materiałami i teksturami.
Proszę konsultujcie ze mną czy Wasz pomysł nadaje się na projekt — wystarczy napisać mailem co chcecie zrobić. Najlepiej przysłać od razu zdjęcia / rysunki na podstawie których będziecie modelować żebym mógł ocenić trudność.
Z boku niniejszej strony widzicie galerię renderingów z poprzednich edycji naszego kursu.
Dobre wskazówki:
Koniecznie używajcie obrazków referencyjnych ("Background Image" Blendera), tak jak robiliśmy z modelem głowy. Dwa dobre widoki to minimum, najlepiej mieć trzy (z góry, boku, przodu), a w idealnym świecie najlepiej mieć 6 widoków (z przodu, z tyłu, z prawa, z lewa, z dołu, z góry). Nawet własne zdjęcia choćby z komórki albo własne (choćby brzydkie, ale zachowujące proporcje :) ) rysunki są bezcenne żeby dobrze wymodelować realistyczny obiekt.
Na dole niniejszej strony zamieściłem kilka linków do "blueprints", czyli właśnie rysunków referencyjnych. Czyli można znaleźć w Internecie wiele takich rysunków.
Zastanówcie się jakie modyfikatory będą użyteczne. SubSurf, Mirror, EdgeSplit są przydatne bardzo bardzo często. Array, Curve, Boolean, Lattice, Displace bywają niezwykle użyteczne dla szczególnych części obiektu. Oszczędźcie sobie pracy używając odpowiednich modyfikatorów zamiast mozolnie "rzeźbić" trudną geometrię.
Nie narzucamy w tym projekcie aby model był "low-poly". Jeżeli po nałożeniu modyfikatorów model robi się złożony, i rendering trwa długo — to nic, jest OK. Po prostu dla własnego dobra nie komplikujcie sobie (za bardzo) geometrii (meshy) pod spodem.
Jak należy oddawać:
Należy przysłać model (plik .blend) razem z wszelkimi zasobami (rysunkami/zdjęciami referencyjnymi, użytymi teksturami itd.). Możecie po prostu spakować (do zip, tar.gz etc.) plik blend razem z zasobami, upewniając się że wszystkie ścieżki do zasobów są względem katalogu modelu (przy otwieraniu obrazków, zaznaczajcie Relative paths; ścieżka do pliku w Blenderze będzie zaczynała się wtedy od "//"). Albo (prościej): spakujcie wszystkie dane do jednego pliku .blend poprzez polecenie menu File -> External Data -> Pack into .blend file. Wtedy wszystkie obrazki etc. zostaną zapisane w pliku .blend.
Załączcie też rendering jaki wykonaliście. (Chociaż powinienem też móc łatwo odtworzyć Wasz rendering samemu przez proste F12 po otwarciu modelu.)
Temat projektu: animacja.
Nie narzucam wymagań na długość animacji. W zależności od pomysłu, kilka sekund może być równie trudne do wykonania co kilka minut. Za standard uznajmy kilkadziesiąt sekund. Naturalnie chodzi tylko o zrobienie jednej sceny, nie robimy całych filmów.
Kluczowe wymaganie to że animacja musi zawierać co najmniej cztery nie-trywialne animowane elementy.
Nie-trywialne oznacza że sam ruch kamery, albo przesuwanie obiektu za pomocą dwóch kluczy w dwóch różnych ramkach są zbyt proste żeby je liczyć do tej trójki. Nie-trywialny może być elegancki krok postaci, albo soft body które przedstawia coś realnego (nie "ręcznik spada na stół" :), albo cząsteczki które wyglądają jak eleganckie ognisko / komary / iskry / cokolwiek realnego, albo woda rozpryskująca się ładnie... etc. Ogólnie, trzeba użyć poznanych technik aby stworzyć animację w której "o coś chodzi", która przedstawia jakieś wiarygodne, ciekawe zdarzenie.
Znamy różne rodzaje animacji: curve follow, armatura, shape keys, cząsteczki, włosy, soft body, cloth pod wpływem siły, rigid body... Można wykorzystać dowolne spośród nich.
Naturalnie trzeba też ładnie wymodelować, użyć materiałów, oteksturować, oświetlić swoją scenę. Filmik ma być ładny — można pobawić się np. compositorem.
Przykładowa animacja jaką sobie wyobraziłem: człowiek idzie ścieżką przez las (kamera obserwuje go z góry i zza pleców) (krok przez armature = 1. nietrywialna animacja). Dochodzi do mostu, takiego klasycznego baśniowego starego skrzypiącego mostu z drewnianymi deskami i linami po obu stronach. Człowiek wchodzi na most, most chwieje się (odpowiednie chwianie, tak żeby różne kawałki mostu nieco różnie się chwiały, może być np. zrobione przez odpowiednie dobranie prostego animowania rotacji z nieznacznym ruchem softbody pod wpływem wiatru — 2. nietrywialna animacja). Człowiek idzie dalej po moście, po czym deska w moście łamie się i człowiek spada (razem 3. nietrywialna animacja, różnie można to wykonać) do rzeki po mostem (rozprysk wody w rzece przez fluid simulation - to już 4. nietrywialna animacja).
Proszę przysyłać mi wynik jako plik .blend oraz wyrenderowany filmik. Tak jak przy poprzednim projekcie, będę też chciał zobaczyć Was osobiście przy zaliczaniu projektu.
Projekt polega na zrobieniu w zasadzie czegokolwiek efektownego w Blenderze. Własne pomysły (po konsultacji ze mną) mile widziane, propozycje:
Uwaga: prosty eksporter (z Blendera do innego formatu danych 3D) nie wystarczy (eksportery są za łatwe do pisania w Blenderze :). Ale jeżeli eksporter będzie robił / pozwalał na coś nietrywialnego (np. dodawał kontrolki pozwalające kontrolować specyficzne efekty danego formatu) to Ok.
Dokumentacja:
Na potrzeby pierwszego wykładu, interesują Was głównie rozdziały "Introduction" i "Interaction in 3D" ("Wprowadzenie" i "Interakcja w 3D") w powyższej dokumentacji.
Poniżej znajduje się skrót wykładu. Notka: różne wykłady na poniższej stronie mają różnej jakości omówienia. Niniejszy wykład, pierwszy, ma najgorsze omówienie, kompletny skrót głównie dla prowadzącego. Umówmy się że tak jest celowo: dla własnego dobra, nauczcie się najpierw korzystać z oficjalnych manuali Blendera do których linki są powyżej. Podstawy obsługi Blendera są omówione wyczerpująco we wszystkich manualach, wszystkich początkowych tutorialach etc.
Wstęp: krótkie demo możliwości Blendera — fragmenty open movies i zabawa ich modelami, eksport modeli do gier, game engine i symulacja fizyki, skrypty do generowania ciekawych rzeczy 3D.
Requirements wykładu: trochę pracy, i elementarna znajomość j. angielskiego (wiele tutoriali i dokumentacji jest po angielsku).
Wersja Blendera: na wykładzie omawiamy i mocno zalecam używanie najnowszego stabilnego Blendera z blender.org, czyli obecnie wersji 2.62.
W pracowni 7 jest zainstalowany Blender 2.49 pod Linuxem. Ale można samemu ściągnąć i używać bez problemu najnowszego Blendera. Ściągamy, rozpakowujemy gdziekolwiek w katalogu domowym, uruchamiamy i działa — sprawdziłem. Pod Windowsem, pamiętamy sciągnąć wersję "Zip Archive" (wersja "Installer" wymaga uprawnień admina do instalacji).
Okna Blendera
Okna które widać w widoku domyślnym: 3d (z "tool shelf" pod "t"), properties po prawej, reszta. Można zmienić widok na inny niż "default".
Przycisków do "natychmiastowych akcji" szukamy w "tool shelf" po lewej. Przycisków do właściwości szukamy w properties po prawej.
Okna można rozciągać, dodawać nowe, zmieniać typ i ogólnie konfigurować własny widok.
Podstawy operowania w widoku 3D i Object Mode
1/3/7 na numpad: podstawowe widoki. Uwaga dla laptopów: "Emulate numpad" w user preferences.
5 na numpad: perspektywa/równoległy.
Mysz (środowy klawisz): zoom, shift, rotate view.
Zaznaczanie obiektów: prawy klawisz. Shift + prawy klawisz.
Przesuwanie obiektów.
Dodawanie obiektów z menu.
Kasowanie (x).
Więcej o zaznaczaniu
select a, aa
select b (box)
select c (circle). rolki myszy zwiększają / zmniejszają promień koła.
Edit Mode
Wchodzimy do środka zaznaczonego obiektu, operujemy na vertex/edges/faces. Ctrl+Tab przestawia które.
Wszystko o zaznaczaniu i przesuwaniu ciągle działa, tylko teraz na vertex/edges/faces.
Więcej o operacjach przesuwania etc.
Przesuwanie (G), rotacje (R), skalowanie (S): Locking: klawisze X, Y, Z podczas operacji (lokowanie do global/local osi, lokalne osie zmieniamy robiąc rotacje na obiekcie). Podczas skalowania użyteczne też są Shift+X/Y/Z, żeby zmieniać dokładnie 2 osie a 3 się nie zmienia.
Snap to grid (trzymaj Ctrl). Rozmiar grid zmienia się gdy robimy zoom.
Scalanie/rozbijanie obiektów: separate (P), join (Ctrl+J).
Kursor: ustawia gdzie pojawiają się nowe prymitywy. Ustawiaj przez LMB click. Często jest też przydatne tutaj snap cursor to grid (Shift+S+3).
Co to są wektory normalne, smooth / solid
Extrude
Och, początek będzie naprawdę łatwy. Zrobimy to od czego zaczynają wszyscy: 1. Static Gingerbread Man. Opcjonalnie (kto chce, żeby się nie nudzić na pracowni): zrób także 2. Animating the Gingerbread Man. Wersja tych tutoriali dla starszego Blendera 2.4x jest tu. i tu.
Tutorial pokazuje podstawy kilku technik które będziemy w pełni omawiać na wykładzie dopiero za kilka tygodni. Fear not: te podstawy są naprawdę łatwe i nie wymagają żadnego "przygotowania teoretycznego".
Alternatywnie, jeżeli już ktoś to robił w domu: wymodeluj dowolny prosty przedmiot + pokryj podstawowymi materiałami + dodaj podstawowe oświetlenie + wyrenderuj + opcjonalnie dodaj dowolną animację.
Różne uwagi które pokażę na początku pracowni:
(Podstawowe narzędzia — przesunięcie, rotacja, skalowanie, extrude, remove doubles były na 1 wykładzie).
Kopiowanie przez Alt+D vs Shift+D, obiekt vs object data (jak mesh, curve).
Parenting, przez wybieranie i przez Ctrl+P.
Ogólne uwagi o modyfikatorach: 1. można składać wiele modyfikatorów. Proste demo to mirror i subsurf. 2. staramy się nie robić apply, tak długo jak się da.
Wygładzanie, modyfikator EdgeSplit. Kilka słów o wektorach normalnych, żebyśmy wiedzieli dlaczego display wygląda jak wygląda, co to są wektory normalne?
W Blenderze: set smooth, set solid, auto-smooth. [docs], [pl docs]. Niekiedy także przydatne "recalculate normals inside/outside" (Ctrl+N, Shift+Ctrl+N).
Wygodniejsza alternatywa dla "Auto Smooth" (efekt widoczny
także w interaktywnym podglądzie Blendera,
pozwala też oznaczyć konkretne krawędzie jako sharp):
EdgeSplit modifier:
Więcej narzędzi edycyjnych:
(Większość z narzędzi poniżej jest aktywna tylko w EditMode.)
Mniej vertexów? merge (Alt+M). Wiecej vertexów? sudivide (W natychmiastowe, albo modyfikator).
Proportional editing (klawisz O).
[docs],
[pl docs].
Uwaga: czasami modyfikator Lattice jest bardziej wygodny.
Subdivide (menu pod klawiszem W) (multi, fractal, smooth).
Uwaga: zamiast multi, czasami modyfikator
subsurf z Simple subdiv jest bardziej wygodny.
Edge specials (Ctrl+E), "edge ring select", "edge loop select". Oraz rip (klawisz V). Oraz "select linked" (klawisz L).
Mirror - odbicie lustrzane
Mirror wokół center (origin) obiektu, który można przesuwać, i w/g lokalnych axis obiektu (czyli obrót obiektu ma znaczenie).
Clipping (przyklejanie do warstwy środkowej),
Merge i Merge Limit,
Mirror Object.
Subdivision surface (subsurf):
Arcy-użyteczne narzędzie do modelowania obiektów gładkich. Subsurf z Catmull-Clark subdivision pozwala bardzo łatwo modelować obiekty naturalnie gładkie (organiczne etc.) za pomocą prostych meshy (de facto, używając takiego subsurfa modelujemy za pomocą krzywych: każda iteracja (poziom, level) subsurfa modyfikuje nasz mesh do krzywej/płatu który podąża wzdłuż naszego mesha). Subsurf z simple subdivision pozwala łatwo zwiększyć triangulację nie zmieniając kształtu (np. jeżeli chcecie zwiększyć triangulację Plane, zapewne zauważycie że Catmull-Clark subdivision zmienia kwadrat w koło; simple subdivision nie).
Generalnie, unikajcie stosowania "natychmiastowego" polecenia subdivide (w menu pod klawiszem W). Takie "natychmiastowe" subdivide powinno być używane tylko wtedy kiedy chcecie zwiększyć triangulację w lokalnym miejscu mesha (np. kiedy chcecie mieć dodatkową krawędź etc. żeby lepiej kontrolować mesh w jakimś lokalnym punkcie). Natomiast nigdy nie powinniście używać "subdivide" globalnie, tzn. na całym meshu. Wadą "natychmiastowego" subdivide jest fakt że nie można (zbyt łatwo) go cofnąć (są metody jak decimate, ale one komplikują mesha, mesh staje się mniej regularny). Zamiast tego używajcie modyfikatora subsurf (który pozwala pracować z prostym meshem) albo multires (który pozwala pracować z dowolną wersją mesha — prostą albo skomplikowaną, przed lub po subsurfie).
Crease SubSurf (Shift+E) do kontroli subsurfa. Uwaga: najlepiej obserwować efekt crease przy "set solid". Przy "set smooth" jesteśmy trochę oszukiwani, i efekt wydaje się dużo bardziej subtelny i mniej użyteczny. Często krawędzie na których zmieniamy crease mają też ustawiane "mark sharp", czyli trzeba osobno zadbać o subsurfa i osobno o smoothing. Albo: najpierw zróbcie "mark sharp", a potem bawcie się z crease.
Multi Resolution (MultiRes) — nowy, inny sposób pracy z subsurfem. Generalnie bardzo wygodny, ale nie można zmieniać topologii mesha (tzn. można zmieniać tylko pozycje wierzchołków (ścian,krawędzi), nie można dodawać / usuwać / zmieniać połączeń etc.).
Idea w skrócie: W przeciwieństwie do subsurf modifier, możemy pracować na faktycznym meshu po subsurfie — jednocześnie, ciągle możemy wrócić do pracy na meshu przed subsurfa.
Szczególnie wygodny ze sculpt mode, które właśnie typowo wymaga pracy na meshu mocno striangulowanym (czyli po subsurfie). Czyli prosty subsurf modifier nie byłby użyteczny, a ręczne robienie "subdivide" byłoby trochę niewygodne (bo nieodwracalne).
Modyfikator Screw.
Poprzednio (ciągle dostępne, ale niezalecane) polecenia
spin (aka "lathe" w innych programach,
podobno "tokarka" po polsku), "Duplicate" albo nie, Screw.
[docs]
[pl docs].
Spin to w skrócie wielokrotne Extrude+Rotate.
Wersja z "Dupli" to to samo, ale bez łączenia (czyli wielokrotne Duplicate+Rotate).
Te operacje są wykonywane natychmiastowo.
Pamiętajcie ustawić się w odpowiednim widoku w którym spin ma się wykonać. Spin jest robiony wokół kursora.
Pamiętajcie o "remove doubles".
Modyfikatory: kolejność, typowe przyciski (enable when rendering / interactive display / editmode, apply).
[docs - cały rozdział Modifiers & Deformation]
Wiele z operacji które można wykonać modyfikatorami było (i często ciągle jest) dostępnych na inne sposoby. Czasami jako operacja "natychmiastowa" (np. boolean operations, mirror) albo wymagająca zależności parent/child (np. stare "Curve Deform"). My będziemy już uczyć się podejścia na modyfikatorach, jest nowsze, bardziej intuicyjne i bardziej elastyczne (fakt że nie trzeba wykonywać operacji natychmiast, i że nie trzeba się martwić o skomplikowane drzewo relacji parent/child jest bardzo wygodny). Po prostu nie zdziwcie się jeżeli zobaczycie wzmianki o operacjach które wydają się nam po prostu skrótem dla stworzenia modyfikatora + apply. Poza tym, jest kilka operacji które w pewien sposób robią coś podobnego co modyfikatory, ale inaczej — np. często zamiast proportional editing wygodniej jest użyć Lattice.
Inne modyfikatory do modelowania:
Większe demo wszystkiego powyżej: obejrzyjmy i "przeanalizujmy" jak są zrobione obiekty na stronie z docs o Array, są tam połączenia Array + Curve + Subsurf.
Dalej modyfikatory:
Używanie: Tworzymy mesh który ma otaczać nasz obiekt. Dodajemy modyfikator mesh deform. Klikamy Bind. Od momentu bind edycja mesha deformującego będzie odpowiednio wpływała na właściwy obiekt. Hint: meshowi deformującemu wygodnie ustawić drawtype na wire, żeby nie zasłaniał właściwego obiektu.
demo human_with_mesh_deform i na chinchilla. Note: na chinchilla domyślnie jesteśmy w proportional editing z dość dużym promieniem i mamy x-axis mirror, dlatego deformujemy łatwo całego gryzonia. Naturalnie możemy je wyłączyć żeby operować bardziej drobiazgowo.
(Modyfikatory o których opowiemy na innych wykładach:
Armature, Build, Hook (opowiemy przy animacji),
UVProject (opowiemy przy teksturach).)
Notki do tworzenia landscapes: omówiliśmy w sumie aż trzy metody:
Wszystkie te metody można mieszać. Displace i Lattice są modyfikatorami, więc możemy używać na jednym obiekcie wiele różnych Displace (z różnymi teksturami) i różnych Lattice (np. z różnymi rozdzielczościami, jedna lattice modeluje ogólny wygląd terenu, a w specjalnych miejscach (kiedy chcemy nasz teren uczynić ciekawszym) dodajemy mniejsze Lattice). Oba modyfikatory pozwalają na określenie VGroup, czyli mogą działać tylko na podzbiorze wierzchołków, poza tym Lattice w naturalny sposób wpływa tylko na wierzchołki w pobliżu.
Text. Słowo o obiektach typu tekst. Jak zrobić credits gdzie postacie skaczą po napisach — pokaż demo credits z BBB, i plik .blend z nimi.
Vertex groups: vertex group to po prostu "zapamiętane i nazwane zaznaczenie wierzchołków" w naszym meshu. Innymi słowy, możemy stworzyć nową grupę wierzchołków i przypisać niektóre wierzchołki naszego mesha do niej. Grupy nie muszą być rozłączne, nie muszą sumować się do całego mesha etc.
Po co nam grupy? Dużo zastosowań. Poza tym naturalnym (żeby szybko zaznaczać raz zapamiętaną grupę wierzchołków), vertex groups są w Blenderze metodą aby ograniczać wiele efektów (które typowo są aplikowane do całego mesha) tylko do kawałka mesha. Np. wiele modyfikatorów (np. Displace) ma parametr VGroup który pozwala ograniczyć działanie modyfikatora tylko do danej grupy wierzchołków.
Sculpt Mode [docs] [release docs]
Demo funkcji na panelu "Sculpt", na mocno subdivided plane. Menu sculpt, skróty klawiszowe (szczególnie zapewne F). (Nie próbowałem ale docs twierdzą że działa z tabletem i używa siły nacisku.)
Panel "Brush" pozwala użyć istniejącej tekstury (np. dodanej do "World" z panelu tekstur) do sculpt. Drag (rysuj teksturę z takimi współrzędnymi jak kliknąłem) / Tile (rysuj teksturę ze współrzędnymi wziętymi z ekranu). Efekt jest taki że drag generalnie tworzy doliny/wierchy z prawie każdej tekstury, natomiast Tile powiela wzór tekstury na obiekcie.
Zabawimy się w modelowanie low-poly głowy człowieka. Będzie tu trochę zabaw z meshem, orientowaniem się w nisko-poziomowej edycji siatki (będziemy "ręcznie" dodawać ściany etc. podążając za tutorialem), tak żeby uchwycić proporcje w/g rysunku.
Chciałbym żebyśmy zrobili pierwszą część tego tutoriala, razem z wypełnieniem "And the back of the head:" (bez "The back of the neck" i późniejszych). Ponadto pomijamy zabawę ze sferami w oczach ("You can also extrude in the eyelids by", "let's go ahead and add a sphere for the eyeball") — wystarczą nam otwory na oczy. I pomijamy zabawę z ustami ("Modeling the lips") — wystarczy nam otwór w kształcie warg.
Różne uwagi (ułożone ~w miarę w takiej kolejności w jakiej będą przydatne do tutoriala) :
Pamiętajcie o "Axis" w ustawieniu Background. W lewym-górnym rogu widoku 3D macie napisane jaki widok pokazuje, po 1/3/7 na numpad. Ustawcie okna jak należy, i nieustannie kontrolujcie w jednym widoku czy to co robicie w drugim na sens.
Zamiast Background można też spróbować obrazki powiązane z obiektem Empty — jest to nieco inne, z kilku względów lepsze (nie znika po skasowaniu 3d view, swobodne obracanie/skalowanie), podejście.
Osobiście lubię ułożyć sobie 2-3 okna z widokiem 3D, i co chwila maksymalizować / przywracać jedno z nich przez Ctrl+Up (albo Ctrl+Down, to to samo).
Pamiętajcie ustawić background offsets idealnie, inaczej jeden widok będzie przekłamywał drugi: front: 1.85, 0 left: -2.8, -0.1 (uh, albo na odwrót, tzn. zamienić left / front; rozpoznacie na pracowni).
Po Ctrl+R (edge loop) escape sprawi że utniecie sześcian dokładnie na środku.
Większość operacji na siatce robimy w edit mode, chcemy żeby center pozostał w centrum głowy. Więc już przy początkowym ustawieniu chin najlepiej przesuwajcie / obracajcie go tylko w edit mode.
Pamiętajcie o "Do Clipping" — żeby vertexy na środku ładnie się łączyły. Na chwilę można to wyłączać (kiedy przypadkiem nasz vertex "zlapał" się w płaszczyznę mirrora, i chcemy go oddalić od niej, trzeba na chwilę wyłączyć "Do Clipping"), ale tylko na chwilę! Normalnie pracujemy z "Do Clipping" włączonym cały czas.
Starajcie się robić ~taką samą ilość kroków extrude co autor — to jest ważne później, zbyt duża / zbyt mała może sprawić ze później będziecie mieli trochę więcej pracy. Np. 3 kroki extrude od chin do początku ucha, etc. Patrzcie na screenshoty gdzie autor zaczyna / kończy swoje extrude — przy zagięciu kości etc.
W jednym widoku zazwyczaj chcecie przesuwać wierzchołki tak żeby nie zepsuć drugiego widoku — MMB w trakcie przesuwania robi lock żeby przesuwać wzdłuż jednej osi.
Na początku pracujemy z jednym meshem w którym są rozłączne elementy. Pamiętajcie o zaznaczaniu prez L (linked).
Przydatne zaznaczenie to także "Zaznacz edge + Ctrl+E + edge loop select".
Pamiętajcie przestawiać się pomiędzy vertex/edge/face select (jest na headerze, Ctrl+Tab klawiszami). Osobiście przełączam się pomiędzy nimi co chwila.
W okolicach wypełniania (pomiędzy nosem a ustami) można już zacząć nieznacznie odpobiegać topologią od oryginału, bo i screenshoty nie pokazują już wszystkich szczegółów. To jest Ok — tylko ostrożnie!
Pamiętajcie że można zawsze rozbić krawędź na dwie (np. Ctrl+R i tnij na środku, albo K i midpoints), i zmienić krawędź w punkt (np. Alt+M, merge, na jej vertexach).
Przy wypełnianiu: jeżeli topologia nam nie pasuje, to 1. patrz wyżej — można zawsze zrobić sobie +1 wierzchołek po drodze, 2. można wypełniać trójkątami, które zawsze jakoś wepchniemy żeby załatać topologię. Klawisz F umie robić i trójkąty i czworokąty.
Uwaga: nie używamy dzisiaj więcej-kątów, nie używamy beautify fill etc. Dzisiaj dodajemy każdy trojkąt/czworokąt osobno, to nam daje większą kontrolę.
Ważne jest przy wypełnianiu "jechać" zazwyczaj ~stosunkowo podobnymi 4-kątami.
Nienegocjowalny warunek: pamiętajcie że koniecznie musicie zrobić model ładnie "zamknięty" (każda krawędź ma 1 lub 2 sąsiadów). Żadnych ukrytych trójkątów o 0 powierzchni w modelu, żadnej dodatkowej geometrii w środku!
Pod koniec pracy warto zobaczyć jak to "naprawdę" wygląda: set smooth, + modifier subsurf.
Podstawy przypisywania materiałów (Ten punkt w zasadzie zrobiliśmy na 1 wykładzie, chociaż powtórzymy go teraz.).
Przyciski na dole: po pierwsze, można je skalować/przesuwać przez RMB oraz Ctrl+RMB, podobnie jak scenę 3D. Podobnie jak dla sceny 3D działa też klawisz Home.
Materiały są linked, widać w outlinerze. Więc jeden materiał może
być współdzielony przez kilka meshy. Można też nakładać materiały
na kawałki meshy, o tym później.
Podstawy ustawiania kamery:
(W zasadzie, to początek innego wykładu... ale musimy umieć ustawiać kamerę i renderować żeby de facto zobaczyć nasze materiały w całej okazałości).
Ustawianie aktywnej kamery (menu View -> Cameras, skrót Ctrl+Numpad 0). Ustaw aktualny widok 3D na widok z kamery (Numpad 0), arcy-użyteczne kiedy konfigurujemy ustawienie kamery.
Metody ustawiania kamery:
Faktyczne przesuwanie, obroty etc. kamerą: no cóż, obiekt Camera możemy przesuwać i obracać tak jak każdy inny (G, R, S). Przydaje się wtedy drugi widok z kamery (Numpad 0), żeby na bieżąco widzieć efekt naszych operacji na kamerze.
(Demo, przy okazji demo array + array żeby mieć 2D grid).
Hint: w przypadku kamery obroty wokół osi local X (przyciśnij R, X, X), local Y i local Z są często szczególnie przydatne.
Inna (często znacznie wygodniejsza) metoda ustawiania kamery: menu View -> Align View -> Align Active Camera to View.
Jeżeli tradycyjne metody ustawiania view nie pozwalają nam ustawić się tak jak chcemy, być może jest sens zmieniać ustawienia View zoom i View rotation w User preferences. Jeszcze inna metoda ustawiania widoku: Fly Mode (Shift+F).
Jeszcze inna (wygodna jeżeli kamera ma być skierowana idealnie na dany obiekt) metoda ustawiania kamery: track (Ctrl+T TrackTo Constraint).
Parametry kamery w panelu Editing (kiedy kamera jest aktualnie zaznaczonym obiektem): Lens/Scale, Orthographic to podstawowe ustawienia, chyba jasne. Dla bardzo małych/dużych scen, zwracam uwagę na Start/End i pomocne do tego Show Limits.
Name, Title Safe (przydatne przy robieniu filmów, po prostu wyznacza jakiś margines w kamerze, raczej rzadko użyteczne — można śmiało wyłączyć). Passepartout (razem z Alpha) to tylko konfiguracja widoku 3D kiedy patrzymy przez Camera (Numpad 0).
Size (podobnie jak skala obiektu kamery) konfigurują tylko rysowanie kamery w trybie interactive (nie mają wpływu na żadne zachowanie przy renderingu).
Shift jest przydatne kiedy chcemy wyrenderować część obrazka która nie jest dokładnie wycentrowana pod kamerą. Innymi słowy, chcemy przesunąć widok który renderujemy ale bez przesuwania frustum perspektywy. Demo sprawi że będzie to oczywiste (i przy okazji będzie jasne po co jest ta różowa obwódka wokół Passepartout).
Podstawy renderowania:
No cóż, kiedy mamy kamerę i światło (domyślna scena Blendera zawiera już przykładowe światło), po prostu przyciskamy Render (F12, przycisk jest w grupie "Scene" (F10)). Zapamiętujemy obrazek dla potomnych przez menu "File -> Save Image" (F3).
Żeby przyspieszyć testowy rendering, dobrze jest wyłączyć OSA (over-sampling, czyli anti-aliasing), można też szybko zmniejszyć obrazek używając przycisków 25%, 50%, 75% (rozmiar 100%, czyli normalny rendering, ustawiamy tuż obok — SizeX, SizeY).
Różne render types w widoku 3D, w szczególności "Shaded" do materiałów.
Nazywajmy materiały, auto-name jest nienajgorsze dla leniwych.
Podstawowe kolory:
[sample - recursive mirror with alien (By Michalis)]
Demo fresnel na siatce małp.
A = Alpha, 1.0 = nieprzezroczyste.
Mask jest ~bezwartościowe (tylko z tłem),
ZTransp jest Ok ale bez załamania (działa jak blending w OpenGLu),
Raytrace faktycznie rzuca promienie (robi załamanie,
najładniejsze ale też mocno powolne w porównaniu z ZTransp).
Shaders: osobne do diffuse i specular. "Shadow" — kontroluj czy cienie pojawiają się na materiale (Pojawianie się cieni można kontrolować też na inne sposoby: "Shadbuf" w materiale określa czy dany obiekt rzuca cienie (dla świateł używających shadow buffer). Światło też ma ustawienie czy rzucać cienie.) Różne shaders mają różne parametry. Demo Spec, Hard.
Amb (wpływ ambient świata na ten materiał), ambient świata kontrolujemy przy World. Idea: ambient symuluje global illumination.
Emit: wymusza rozjaśnienie koloru. Idea: ustawiamy to jeżeli obiekt jest źródłem światła w świecie rzeczywistym (żarówka etc.). W praktyce: to powoduje sztuczne rozjaśnienie koloru, czasami przydatne aby wymusić wygląd czegoś taki jaki chcemy. Emit skaluje diffuse color.
Ray Transparency czyli pół-przezroczysty materiał w sposób bardziej realistyczny niż ZTransp, poprzez ray-tracing, a więc z załamywaniem promieni etc. Podobnie jak przy "Ray Mirror", to wymaga używania ray-tracera przy renderowaniu (domyślnie w nowszych wersjach Blendera; przy pracy ze starszymi plikami, trzeba włączyć "Ray" na zakładce "render").
Demo: złam łyżkę w zupie.
Wiele materiałów na jednym meshu — w Edit Mode, odpowiednie kontrolki na panelu Editing.
Materiał może być przywiązany do mesh'a (domyślnie) lub do samego obiektu . To ma znaczenie np. kiedy kopiujemy obiekt przez Duplicate Linked (Alt+D) — wtedy mamy 2 obiekty powiązane z jednym mesh'em, więc jeżeli nasz materiał jest przywiązany do mesha, to obie kopie będą zawsze miały ten sam materiał. Jeżeli materiał jest przywiązany do obiektu, to możemy go zmieniać na każdym obiekcie niezależnie.
(Kto nie pamięta różnicy między "obiektem" a "meshem" — polecam powtórzyć eksperyment z kopiowaniem obiektu przez Duplicate Linked (Alt+D) lub Duplicate (Shift+D) i porównać rezultaty w okienku Outliner (po przestawieniu się na widok grafu — View->Show Oops Schematic).)
De facto bardziej precyzyjne byłoby zdanie "Materiał może być przywiązany do danych obiektu (Object Data, w skrócie ObData, domyślnie) lub do samego obiektu." W przypadku obiektów stworzonych przez Add->Mesh, object data oznacza mesh. W przypadku innych obiektów (np. curves) objects data oznacza... no cóż, inne rzeczy. Ogólnie, "object data" to jest to co edytujemy kiedy wchodzimy w "edit mode" na danym obiekcie. No dobrze, dla uproszczenia można (na razie) myśleć że Object Data (ObData) = to samo co Mesh w przypadku naszych scen.
Patrz ustawienie User preferences -> Edit Methods -> Material Linked To jeżeli preferujecie przypisywać materiał do obiektu. Przy okazji, ustawienie User preferences -> Edit Methods -> Duplicate with object powinno być zrozumiałe: ono konfiguruje co tak naprawdę oznacza polecenie Duplicate (Shift+D). Zwracam uwagę że polecenie Duplicate Linked (Alt+D) nie jest konfigurowalne, ono zawsze tworzy tylko nowy obiekt, połączony z takimi samymi danymi (mesh, materiał, cała reszta) co oryginalny obiekt).
Wreszcie, najważniejsze: to wszystko napisałem żeby wyjaśnić sens przycisków "OB" oraz "ME" na "Links and Pipeline" materiału. Za ich pomocą możecie przestawiać widok pomiędzy oglądaniem materiałów przypisanych do mesha a materiałów przypisanych do obiektu (i można te powiązania swobodnie reorganizować jak ktoś lubi).
Ciąg dalszy o materiałach jeszcze nastąpi. Wykłady o teksturowaniu, węzłach materiałów, konfiguracji świata (World), i jeszcze kilku rzeczach będą znacznie wzbogacały nasze materiały.
Coś free style i łatwego, w sumie odpoczynek. Nie ma dokładnego tutorialu, ale mamy cel: dążymy do czegoś jak na screenshocie Clear Glass ale niekoniecznie idealnie takiego — można fantazjować. Chcę zobaczyć kilka kopii czegoś przypominającego kieliszek lub kubek, zrobionego przez przekrój + Spin + subsurt + dostrajanie subsurfa przez "create subsurf". Zamiast "spin" można też próbować z modyfikatorem "Screw", chociaż niekiedy ma on problemy z wygładzaniem, tzn. z prawidłowymi wektorami normalnymi. Kieliszki mają stać na powierzchni i na tle (tzn. najprościej postawić je na sześcianie z 3 ścianami usuniętymi).
Chcę żebyście pobawili się materiałami, w szczególności lustrami i przezroczystością poprzez ray-tracing. Kieliszki mają wyglądać na szklane, i muszą mieć co najmniej przezroczystość (w wersji "Raytrace"), tzn. musimy wyraźnie widzieć (nieznacznie zniekształconą) scenę za nimi. Ponadto chcę żeby coś było wyraźnym lustrem, tzn. niech jakiś obiekt ewidentnie pokazuje odbity w lustrze kawałek sceny (najłatwiej wstawić sześcian(y) pomiędzy kieliszki i poobracać je tak żeby w lustrze widzieć coś sensownego).
Nie mówiliśmy jeszcze zbyt wiele o oświetleniu, ale pierwszy hint: nie ograniczajcie się do 1 światła, wrzućcie z ~3-4 światła żeby na scenie było jasno i mieć nieco mniej nudne cienie.
Zaczynamy: Dodajemy krzywe przez Add->Bezier/NURBS Curve. Uzyskujemy obiekt który w środku (tzn. po wejściu w edit mode) jest, no właśnie — krzywą, a nie meshem znanym z dotychczasowych wykładów. Kształt krzywej kontrolujemy przez punkty kontrolne, które zachowują się trochę jak normalne wierzchołki (możemy je przesuwać, obracać, skalować).
Na początek będziemy bawić się z krzywymi Beziera. Od razu widzimy że poza "Bezier curve" mamy gotowe "Bezier circle" — dodaje krzywą ułożoną w (prawie — o tym później) idealne koło, czasami wygodniej jest od tego zacząć.
Dodawanie wierzchołków: w zasadzie tak samo jak przy pracy z meshem. Dodawanie nowego wierzchołka połączonego z poprzednio zaznaczonym przez Ctrl+left click. Mamy też subdivide (pod klawiszem W, tak jak przy meshu) kiedy chcemy dodać wierzchołek w środku krzywej.
Kasowanie przez X, jak zawsze. Możemy także rozerwać krzywą na rozłączne części.
Uchwyty krzywych Beziera.
(Notka dla osób znających matematykę za krzywymi: Blender, podobnie jak chyba wszystkie inne programy do modelowania 3D, trochę upraszcza terminologię. To co Blender nazywa "jedną krzywą" to tak naprawdę ciąg sklejonych krzywych Beziera, "uchwyty" to wewnętrzne punkty kontrolne w środku prawdziwych krzywych, "punkty kontrolne" to końcowe punkty kontrolne prawdziwych krzywych. W skrócie: zapomnijcie na chwilę o terminologii znanej z innych wykładów.)
Każdy punkt kontrolny ma dodatkowo dwa sąsiednie wierzchołki: uchwyty. Uchwyt wyznacza styczną do krzywej w danym kierunku. Domyślnie trzy punkty (kontrolny i jego dwa uchwyty) są współliniowe, i generalnie zaznaczanie/obracanie wierzchołków działa tak że ta współliniowość jest zachowana. (Demo: klik na punkt kontrolny zaznacza (i pozwala obracać) całą trojką, przesuwanie jednego uchwytu odpowiednio przesuwa drugi.) Wspołliniowość oznacza że krzywa jest gładka w danym punkcie — o to nam właśnie chodzi, przynajmniej zazwyczaj. To domyślnie zachowanie Blender nayzwa "Aligned".
Kiedy rzeczywiście chcemy "złamać" uchwyt, używamy V mając zaznaczony punkt kontrolny i przełączamy na "Free". We free mode możemy swobodnie operować jednym uchwytem — naturalnie powstaje wtedy załamanie (ostry kant) w krzywej.
Kiedy tylko jeden uchwyt jest w stanie Free (czyli użyliśmy V mając zaznaczony tylko jeden uchwyt, nie punkt kontrolny) to lądujemy z kolei w najbardziej ograniczonym trybie: uchwyty pozostają współliniowe, ponadto na jednym uchwycie możemy zmieniać tylko długość uchwytu. Przydatne kiedy chcemy "zablokować" pozycję drugiego uchwytu.
Notka: handle na końcach krzywej nie robią nic naturalnie. W zasadzie, nie ma większego znaczenia w jakim trybie (aligned czy free) są uchwyty na pierwszym i ostatnim punkcie krzywej.
Zmiana na "Vector" oznacza że dany uchwyt "celuje" w poprzedni/następny punkt krzywej. Kiedy ustawimy dwa kolejne uchwyty (drugi na pierwszym punkcie kontrolny, pierwszy na drugim punkcie kontrolnym... ech, pokażę demo) w trybie vector to dostajemy prosty odcinek.
Jest jeszcze jeden rodzaj handle, "Automatic". Oznacza że uchwyty nie tylko są zawsze współliniowe, ale ponadto blender w pełni kontroluje oba uchwyty (czyli zarówno obrót uchwytów jak i ich odległość). W ten sposób oddajemy Blenderowi pełną kontrolę nad uchwytami, jedyna rzecz jaką możemy zmieniać to położenie punktu kontrolnego. Efekt: idealnie gładka krzywa.
Podsumowanie:
Przy próbie poruszenia uchwytem Vector albo Automatic, jego typ zmienia się na (odpowiednio) Free albo Aligned.
Ogólnie, używamy krzywych kiedy chcemy zrobić kształt generalnie gładki. Przestawianie uchwytów na free albo vector pozwala nam miejscami uczynić krzywą bardziej kanciastą w wybranych punktach.
Demo obrysowywania prostego kształtu + 1. convert to mesh i spin. 2. lub modyfikator screw.
Zamykanie krzywej: Alt+C w edit mode (Toggle Cyclic, może się też kojarzyć z Closed). To jest inaczej niż z meshem (na meshu łączyliśmy pierwszy z ostatnim wierzchołek przez F, które tworzy face oraz krawędzie; na curve nie mamy takiej swobody, F służy tylko do łączenia dwóch rozłącznych curves (czyli nie zmienia stanu "zamkniętości" krzywej)).
Pytanie kontrolne: To jak samemu zrobić Bezier circle, wychodząc od Bezier curve.(hint: 4 wierzchołki idealnie ułożone, uchwyty auto, closed curve).
2D / 3D, back/front: domyślnie krzywa jest 2D. Możemy przełączyć ją na 3D żeby uzyskać kontrolę 3D.
Wprawdzie krzywa 3D jest bardziej swobodna, ale tracimy też trochę możliwości. Na krzywych 2D możemy mieć back/front wypełnienia krzywej, na krzywej 3D nie.
Wiele krzywych w jednym obiekcie: Podobnie jak w przypadku meshy: de facto obiekt klasy curve to zbiór krzywych, niekoniecznie ze sobą połączonych. Innymi słowy: będąc w Edit Mode na krzywej, ciągle mamy menu Add które pozwala nam dodawać nowe krzywe do obecnego obiektu. Polecenia Separate (P) i Join (Ctrl+J) działają analogicznie jak w przypadku meshy. Naturalnie, join curve z meshem nie działa (obiekt ma klasę mesh albo curve, nie oba na raz...).
Częste zastosowanie tego: kiedy mamy closed curves, wewnętrzna curve wycina kształt w środku zewnętrznej (demo). Naturalnie, front/back, bevel działają ciągle Ok.
Operacje na całej krzywej:
Z krzywą nie możemy robić wielu operacji (oraz nakładać większości modyfikatorów) które mieliśmy do dyspozycji podczas edycji mesha. Tym niemniej, panel "curve and surfaces" daje nam trochę możliwości: width, extrude, bevel.
Wytłaczanie (aka extrude) krzywych za pomocą innych krzywych: Bevel (wytłocz krzywą wskazaną przez Bevel wzdłuż aktualnej krzywej), Taper (dodatkowo zdefiniuj grubość wytłoczenia przez krzywą wskazaną jako Taper).
Przypominam też o bardzo ważnym modyfikatorze Curve, czyli wygnij mesh wzdłuż krzywej (nakładanym na mesha, w parametrach modyfikatora podajemy nazwę krzywej). Przypomnijmy: czasem użytecznie jest połączyć to z modyfikatorem Array na meshu, czasem użytecznie jest użyć "CurveStretch" na krzywej.
Convert to... (Alt+C w object mode) pozwala konwertować pomiędzy różnymi rodzajami obiektów. Dla krzywej, możemy zamienić ją na naszego "klasycznego" mesha. Zapewne przed konwersją chcemy się dobrze zastanowić jak dobrać resolution krzywej (przez "Default Resolution" (kontroluje resolution całego obiektu krzywej) albo "Resolution" (w edit mode; kontroluje resolution danego odcinka krzywej)). Naturalnie konwersja do mesha jest "bez powrotu" — więcej staramy się unikać jej dopóki możemy.
Trochę pojęć (patrz panel "Curve Tools"): Uniform/Endpoint/Bezier: jakiego knot vector użyć. Nie trzeba znać tu matematycznego znaczenia, znaczenie intuicyjne: endpoint gwarantuje że krzywa trafi w swoje końcowe punkty kontrolne (przy uniform, krzywa "gdzieś" się urywa). Z kolei przy uniform, wszystkie punkty są traktowane bardziej na równi. Generalnie, do krzywych zamkniętych zazwyczaj uniform jest lepsza, do krzywych otwartych — endpoint. Przy Bezier krzywa symuluje krzywe sklejane Beziera (stopień krzywej określa stopnień symulowanej krzywej Beziera) — generalnie, praktyczny efekt jest taki że krzywa co jakiś czas przechodzi przez punkty kontrolne w środku.
Order: jak wiele punktów kontrolnych wpływa na dany kawałek krzywej. W ten sposób mamy kontrolę nad tym czego nie mamy w przypadku Beziera: punkt kontrolny może (lub nie, jak chcemy) wpływać na dalsze elementy krzywej. Dobieramy to pod kątem tego jak dokładnie chcemy podążać wzdłuż punktów kontrolnych, jak drobno będziemy rozkładać punty kontrolne etc. (czyli w praktyce po prostu dobieramy eksperymentalnie żeby dobrze wyglądało :), domyślne 4 jest zazwyczaj sensowne).
Dla krzywych ważne są tylko przycisku z "U". Dla powierzchi pojawią się dodatkowo "V".
Wagi: Punkty na krzywych NURBS mają wagi, Weights. Patrz i zmieniaj "W" (weight) na panelu (N w widoku 3D, jak traNsform properties).
Hint: nie szalejcie z wagami na początku.
Powierzchnie parametryczne (płaty) NURBS:
[docs - Surfaces],
[docs - Editing Surfaces]
Dodajemy z Add->Surface. Zwracam uwagę że Surface to zupełnie inny rodzaj obiektu niż Curve, oraz inny niż Mesh. Nie możemy łączyć Surface z Curve (ani z Mesh, jeśli już o tym mowa) — wewnętrznie są one po prostu innymi typami obiektów.
Demo prymitywów Surfaces. Zwracam uwagę: jest NURBS curve i NURBS circle w menu "Surface". Na początku, efekt tych prymitywów jest taki sam jak analogicznych w menu "Curve" — ale prymitywy które są wewnętrznie surface'ami możemy rozszerzyć do płatów (np. mogę zrobić ich extrude). Czyli można powtórzyć: wewnętrznie obiekty klasy Surface są po prostu czymś innym niż obiekty klasy Curve.
Podstawowe operacje na płaszczyznach są w zasadzie takie same jak na krzywych NURBS, tyle że mamy teraz dwa wymiary. Knots (Uniform/Endpoint/Bezier), Order, Resolution działają tak samo — ale mają teraz dwie wersje, jedna w "U", druga w "V". Wagi też są i działają tak samo.
Punkty kontrolne można przesuwać, obracać, skalować jak poprzednio.
Dodajemy nowe wierzchołki przez Extrude krawędzi albo Subdivide w środku, więc podobnie jak przy pracy z meshem. Tyle tylko że Surface ma zawsze topologię siatki X na Y wierzchołków. Więc np. Extrude działa tylko wtedy kiedy mamy zaznaczoną całą krawędź boczną płata. Subdivide tylko jeśli mamy zaznaczony cały pas płata. Podobnie łączenie (F). Zaznaczanie wiersza (Row, Shift+R) jest tutaj przydatne (przyciśnij zaraz potem drugi raz Shift+R jeżeli chcesz zaznaczyć kolumnę).
Chciałbym żebyście zrobili oba tutoriale poniżej:
Obrysowywanie kształtu krzywymi Beziera (przy czym nie chodzi o uzyskanie takiego renderingu jak na końcu tutoriala, nam wystarczy samo modelowanie symbolu krzywymi + bevel, bez materiałów / tekstur etc.).
A Ride Through the Mines (updated link do blendernation.com) (przy czym zależy nam tylko na zrobieniu kształtu konstrukcji, bez animacji, czyli przy "For lighting, create a spotlight..." możecie przestać czytać :) ).
Ogólnie o teksturach: Tekstura pozwala na modyfikację różnych parametrów materiału. Każdy pixel tekstury to inna wartość, więc tekstura pozwala nam łatwo wyrażać drobne zróżnicowanie materiału (chropowatości, wypukłości, nawet nieregularne obramowanie jak w przypadku liścia). Takie drobne zróżnicowanie materiału byłoby kłopotliwe do wymodelowania, bo powodowałoby drastyczny wzrost ilości ścian (faces) naszej geometrii.
Przypomnienie: jeżeli jednak w jakimś momencie stwierdzicie że chcecie mieć "prawdziwe" wypukłości, nie musicie rezygnować z tekstury: pamiętajcie o modyfikatorze Displace (najlepiej nałożonym na mocno striangulowaną powierzchnię, a więc np. najpierw użyjcie modyfikatora subsurf z simple subdivision).
Kolejne zalety tekstur wynikają z faktu że mogą być generowane przez Blendera:
Sporą część tego wykładu poświecimy na zaznajomienie się z różnymi rodzajami i parametrami losowo generowanych tekstur, aby nauczyć się ich efektywnie używać.
Tekstury stworzone w ten sposób (z ambient occlusion, z cieniami?) są też bardzo przydatne jeżeli myślimy o eksporcie naszego modelu z Blendera do prostszego programu 3D (np. do postaci lub levelu Quake'a).
Tekstury powiązanie z materiałami (obiekty TEX)
[docs - rozdział
"Textures"]
Materiał ma 10 "kanałów" na tekstury.
Przypisywanie tekstur — Add New, używanie istniejącej z listy, używanie schowka do kopiowania ustawienia tekstur (jaka tekstura + parametry Mapping, Influence; tworzy drugi link do tego samego obiektu tekstury; sam obiekt tekstury możemy sklonować tradycyjnie przez "make single user copy" obok nazwy tekstury na panelu "texture buttons"). Disable/enable kanały tekstury do testowania.
"Preview" materiału je pokazuje. Są widoczne na renderingu, i naturalnie w "render preview". Niestety nie można oglądać takich tekstur nałożonych na materiały w trybie interaktywnym (typ widoku "textured", Alt+Z, pokazuje inne tekstury) — jest to uzasadnione przez ilość opcji jaką oferują nam takie tekstury, po prostu nie da się ich wszystkich symulować OpenGLem. To nie jest problem — zobaczymy przy UV editing jak szybko "włączyć" te tekstury do widoku 3D.
Na początek, trochę ogólnych uwag o teksturach Blendera (w obiektach TEX, czyli takich jakie będziemy przypisywać do materiałów):
Są 3D.
Wszystkie tekstury proceduralne są generowane jako 3D. Tekstury 3D to wspaniały wynalazek który sprawie że nie trzeba używać skomplikowanego mapowania tekstury 2D (np. przez unwrapping), zamiast tego proste mapowanie w stylu "Cube" jest wystarczające dla dowolnie złożonych obiektów 3D — intuicyjnie, tekstura 3D oznacza że obiekt 3D został "wyciosany" z bryły danego materiału, jak blok marmuru albo drzewo.
Także tekstury Image (ładowane z obrazków) są w pewien sposób "rozciągane" na 3D (mimo że sam obrazek jest naturalnie 2D), więcej o tym później (Clip, ClipCube).
Tekstury w Blenderze mogą dostarczać różne komponenty: RGB, intensywność (intensity, grayscale), przezroczystość (czyli kanał alpha), a także wektory normalne.
Zobaczymy demo wszystkich tych ustawień.
Od razu wyjaśnienie tego ostatniego, najmniej oczywistego stwierdzenia (wektory normalne): większość tekstur proceduralnych ma "wbudowane" generowanie wektorów normalnych razem z generowaniem koloru (kiedy generujemy teksturę, możemy wygenerować też wektor normalny znając nachylenia (pochodne), aka tangent i binormal). Tak jest, to jest kolejna zaleta tekstur proceduralnych: razem z generowaniem koloru możemy też generować inne pożyteczne rzeczy jak właśnie wektory normalne.
Tekstury Image też mogą generować wektory normalne — kiedy są ustawione w trybie "Normal map". Demo będzie później.
Parametry tekstur połączonych z materiałami (hint: wygodnie jest zrobić sobie dwa okienka przycisków, jeden z parametrami materiału, drugi z teksturą, patrz plik [sample - various_procedural_textures]):
Mapping kontroluje jak ustalać współrzędne tekstury.
Przyciski na górze (z "Orco", domyślnym) mówią skąd brać współrzędne tekstury. "Orco" to skrót od "original coordinates", czyli po prostu współrzędne obiektu (lokalne, a więc przesuwanie/obracanie itd. obiektu nie zmienia położenia tekstury na obiekcie).
[sample - human with superman logo]: demo używania mapowania "Object" z obiektem "Empty", tekstura ma "ClipCube" oraz "Use Alpha". To jest wygodny sposób umieszczania "naklejek" na dużo większych obiektach. Czy naklejka będzie na jednej stronie koszuli, czy z tyłu też? Demo "Clip" vs "ClipCube". Pamiętajcie że tekstury są 3D — nawet te ładowane z obrazków 2D.
Demo "Window" (mapuje do współrzędnych ekranu, dobre żeby zrobić np. znak od latarki na kamerze).
"Global" — z globalnego położenia na scenie. Np. kiedy obiekt "płynie" przez daną teksturę 3D (chociaż mapowanie "Object" bywa tu często wygodniejsze). Albo kiedy na scenie jest światło które "rzuca" daną teksturę (chociaż to można zrobić lepiej, teksturami światła, ale o tym później).
"Normal" — to jest bardzo użyteczne do równych sztuczek. [sample - dolphin and fake fresnel spheres] Zwróć uwagę że użyta tam tekstura blend ma kształt "sphere" w 3D.
Notka: nie mylcie tego z "Normal" w "Influence", które jest czymś zupełnie innym i niezależnym (tamto pozwala modyfikować wektory normalne teksturą; tutaj, na "Mapping", możemy modyfikować współrzędną tekstury za pomocą wektora normalnego). [docs w tutorialu: Incidence Angle dependent Textures]
"Reflection" — zazwyczaj do robienia luster przez environment mapping. Znacznie szybsza, ale i bardziej "trickowa" (trudniejsza do ustawienia i opanowania) metoda na lustra niż ray mirror.
Demo: texture typu EnvMap, z object empty, na MapInput ustaw "Refl" (bez "Refl" wynik mało sensowny).
Istotne ustawienia: ClipSta/End, Don't Render Layers, Cube/Plane.
Zapisywanie danych: przy przycisku "Render" musi być włączone EnvMap żeby były generowane. Wynik można zapisać do pliku. (Użycie przy okazji: w naszej grze można załadować taką env mapę, patrz OpenGL cube map texturing + texture gen reflection mapping). Ponadto "Load" nie są generowane nigdy, są odczytywane z pliku (pozwalając na tricki w postaci modyfikowania tekstur).
Dla skomplikowanych sposobów mapowania, których nie da się wyrazić łatwo, zawsze mamy opcję "UV" na górze Mapping. Ona pozwala użyć współrzędnych tekstury przypisanych przez UV editing, co jest bardziej elastycznym sposobem przypisywania współrzędnych. O UV editing później.
Trzy wiersze przycisków X/Y/Z mówią jak te współrzędne zamieniać (np. możemy sprawić żeby współrzędna Y obiektu kontrolowała współrzędną U tekstury, a współrzędna X obiektu kontrolowała współrzędna V).
Flat / Cube / Tube / Sphere to typowe mapowania tekstur. [docs - docs Blendera o Map_Input zawierają eleganckie screenshoty pokazujące różne mapowania].
ofsX/Y/Z, sizeX/Y/Z pozwalają nam przesuwać/skalować współrzędne tekstury. Note: size mogą być ujemne aby odwrócić teksturę.
Influence mówi jak tekstura wpływa na zachowanie materiału w tym punkcie. Standardowy "Col", oznacza że kolor tekstury będzie użyty jako kolor (diffuse) materiału, czyli w sumie takie najbardziej klasyczne zastosowanie tekstur z wszystkich gier 3D. Bardziej precyzyjnie, mieszanie "Mix" oznacza że alpha tekstury będzie użyte do zmieszania tekstury z materiałem — tekstura bez alpha po prostu zastąpi kolor, tekstura z alpha nałoży się jak maska.
Jeżeli tekstura jest grayscale (tzn. samo intensity, bez RGB), jak wiele tekstur proceduralnych (albo sami tego zażądaliśmy przez "No RGB") to kolor RGB tekstury jest dodatkowo przeskalowanym kolorem default, też konfigurowanym na "Influence". Domyślnie jest to kolor różowy (R = B = 1, G = 0), właśnie po to abyście łatwo zauważyli "oho, to jest tekstura grayscale, zapewne chce ją specjalnie skonfigurować" (np. ustawiając kolor RGB na biały).
Mieszanie ("Mix") miesza kolory RGB, biorąc pod uwagę kolory alpha. A jak są mieszane same kolory alpha? Tzn. co jeśli chcemy zmienić właśnie kolor alpha materiału, np. żeby zrobić liść za pomocą tekstury z kanałem alpha na pojedynczym prostokącie? Kanał alpha jest mieszany używając suwaka "DVar", "default/destination value (no rgb)". Trochę eksperymentując można dojść do wniosku że zachodzi:
alpha_wynikowe = (1-intensywność_tex) * alpha_mat + intensywność_tex * dvar
Wzorek powyższy wygląda na trochę złożony, a sprowadza się do tego że intensywność tekstury nie wpływa na alpha bezpośrednio, tylko moduluje pomiędzy alpha materiału a DVar (de facto, DVar jest jeszcze mnożone przez Var). Czyli gdy DVar = 1 i alpha materiału = 1 (domyślnie) to... nic się nie dzieje, tzn. nie zmienimy wynikowego alpha za pomocą tekstury. Żeby móc zmienić wynikowe alpha, należy przestawić alpha materiału na 0 (wtedy intensywność tekstury podaje wprost wynikowe alpha). Albo zmienić dvar na 0, wtedy efekt jest odwrotny (można było to też uzyskać ustawiając alpha materiału na 0 i aktywując Alpha na "on inverted").
Demo: [sample - leaf alpha test], także w [sample - texture tests]. Hint: kolor specular, czyli rozbłysk, jest dodawany przez Blendera, mimo że alpha jest 0 w jakimś miejscu. Czyli trzeba generalnie zrobić ze "Spec" tą samą sztuczkę (albo tą samą, albo inną teksturą), tzn. nałożyć na kolor Spec taką samą maskę jaką nałożyliśmy na alpha.
Tekstura może wpływać na wiele parametrów materiału, tzn. wiele przycisków na górze "Influence" może być jednocześnie wciśniętych. Przyciski na górze "Influence" mają trzy stany — off, on (+), i on inverted (-). (Przycisk "Neg" działa tylko na tekstury grayscale, więc nie zawsze działa jak chcemy; po to jest właśnie stan "on inverted", który działa zawsze.)
Mamy wiele kanałów tekstur nie tylko po to żeby używać różnych tekstur do różnych efektów. Możemy też mieszać tekstury na tym samym efekcie: pierwsza tekstura modyfikuje jakiś parametr materiału, druga tekstura modyfikuje wynik poprzedniej itd. Notka: w trybie "Mix", alpha tekstury jest używane do mieszania kolorów RGB. To znaczy tyle że jeżeli tekstura na wierzchu jest RGB i nie ma kanału alpha, to zastępuje poprzedni kolor RGB, zasłaniając tekstury pod nią. Jeżeli chcemy wymieszać dwie tekstury przez mnożenie RGB, przestawiamy tryb ma "Multiply". (Jeżeli chcemy użyć "Mix" z kanałem Alpha tekstury obrazka, pamiętajcie o "Use Alpha" na teksturze.)
"Nor" to standardowy sposób tworzenia rowków/wgnieceń/chropowatości za pomocą tekstury. Znane jako "bump mapping", tekstura modyfikuje wektor normalny. Suwak "Nor" reguluje siłę działania. Wewnętrznie, są tak naprawdę dwie metody bump mappingu:
Normal map — tekstury które mają zawarte w sobie zawsze wektory normalne (jak proceduralne, albo specjalnie przygotowane Image z włączonym normal map).
Tekstury proceduralne mogą takie wektory normalne po prostu generować, tekstury Image mogą zawierać wektory normalne zakodowane (Red = X wektora zakodowane z -1..1 do 0..1, Green = Y wektora zakodowane jak X, Blue = Z wektora (nie zakodowane, wektor normalny wskazuje w górę; chociaż wiele programów 3D i gier koduje Z tak jak inne współrzędne)). Trzeba włączyć "Normal Map" na teksturze Image.
Można w Blenderze wygenerować obrazek normal map z high-poly obiektu przez baking do normal map. O tym później.
Można też stworzyć normal mapę z mapy wysokości GIMPem (patrz plugin normalmap GIMPa), chociaż to ma mniejsze zastosowanie (Blender umie bezpośrednio zastosować mapę wysokości, patrz niżej).
Demo używania stucci. Demo użycia bardziej regularnego obrazka — 4 gradients z GIMPa. [sample - texture tests]
Suwak "Warp" jest często szczególnie użyteczny kiedy używamy tekstury modyfikującej wektory normalne. "Warp" ogólnie sprawia że tekstura modyfikuje współrzędne następnych tekstur (w następnych kanałach), proste zastosowanie to właśnie włączenie tego na teksturze z "Nor". Wtedy nie tylko światło, ale też kolejne tekstury odzwierciedlają nasze "rowki". Demo na [sample - texture tests] (te dwa prostopadłościany do dole po lewej).
"Stencil" pozwala łączyć kilka tekstur. Tam gdzie jest czarny, tam wyższe poziomy tekstur nie będą mogły zmieniać parametrów materiału. Notka: żeby stencil działał dobrze, tekstura musi być tylko grayscale (intensity, bez RGB). Jest to domyślnie prawdziwe dla niektórych tekstur proceduralnych, teoretycznie też jest prawdziwe dla tekstur Image ładowanych z obrazków grayscale (ale to w praktyce zależy od formatu obrazka, np. moje PNG grayscale są uparcie rozpoznawane jako RGB). Należy wtedy włączyć "No RGB", żeby wymusić konwersję tekstury na grayscale. Demo: proste demo ze star_stencil i star_smooth_stencil w [sample - simple stencil demo]. Demo: piasek (Noise) z wodą (Distorted Noise, Wood) połączone stencilem (Blend) w [sample - texture tests].
"Ref" zwiększa reflectivity, czyli rozjaśnia kolory shadera diffuse. Generalnie, używajcie aby stworzyć lokalnie świecące miejsca na materiale — jeżeli materiał jest posypany czymś błyszczącym (cukrem, złotem, piaskiem etc.) to tekstura "Ref" jest dobry pomysłem.
"Disp" to alternatywna dla modyfikatora Displace. Tak samo jak przy modyfikatorze Displace, pamiętajcie że obiekt musi być mocno striangulowany żeby to działało dobrze. Zazwyczaj modyfikator Displace jest wygodniejszy, jego efekt widzimy natychmiast w widoku 3D (natomiast efekt kanałów tekstur jest widoczny tylko przy renderingu, albo w (wolnym) podglądzie renderingu). "Disp" może wykorzystać wektory normalne zawarte w teksturze: jeżeli tekstura ma wektory normalne (bo jest wygenerowana, albo jest teksturą Image z "normal map" włączonym) to obiekt będzie przesuwany także wzdłuż wektorów normalnych (modyfikator Displace też to umie, patrz jego parametry Normal/RGB->XYZ). Dwa suwaki są tu użyteczne: suwak "Nor" kontroluje wpływ wektorów normalnych na displace. Suwak "Disp" kontroluje wpływ intensity na displace.
Różne sposoby mieszania: o "Mix" (mieszaj w/g alpha) i "Multiply" (wymnóż) już mówiliśmy. Patrz [docs - Compositing Editor: Mix Node] po wyjaśnienie reszty.
Typowe parametry:
Konfiguracja kolorów: jeden kolor albo colorband. Brightness i contrast. Colorband zmienia teksturę która ma tylko intensity na teksturę RGB.
Nabia: wpływa na generowanie wektorów normalnych, intuicyjnie jaką "grubość" ma tekstura. Większe wartości szybko dają mało realistyczny efekt — w końcu powierzchnia pozostaje płaska, zmieniamy tylko wektory normalne.
"Default Var" — powrót do domyślnych parametrów danego rodzaju tekstury, przydatne kiedy tak namieszamy że już nie wiemy jak wrócić...
Noise size — ziarnistość tekstury. Noise Depth — wielkość ziaren, czyli "globalnych" feature'ów na całej teksturze. Turbulence, czyli lokalne zaburzenie (zwiększaj aby mieć bardziej zróżnicowaną teksturę, zmniejszaj aby mieć regularną, "matematycznie wyglądającą" teksturę). Te parametry różnie ze sobą współpracują na różnych teksturach, niekiedy turbulence i noise określają ten sam efekt i wtedy zmiana noise nie jest widoczna dopóki turbulence pozostaje 0.
Sin/Saw/Tri czyli różne sposoby modelowania fal na teksturze.
Przegląd różnych tekstur proceduralnych ([sample - various_procedural_textures]):
Tekstura Image — Trochę ciekawych rzeczy, np. "Normal Map". Demo z gotową normal mapą (brick31, leaf). Demo tworzenia normal map w Blenderze będzie przy opisie baking.
Żeby użyć kanału alpha naszej tekstury, zaznacz "Use Alpha". Naturalnie alpha nie musi być tak/nie (0-1), może być dowolną wartością pomiędzy (np. na PNG) i jest uwzględniane jak należy.
Mamy sposób powtarzania tekstury. Domyślnie jest "Repeat", widzieliśmy też demo [sample - human with superman logo] "ClipCube" oraz "Clip".
Z użytecznych ciekawostek, jest SVG vector texture plugin for Blender aby ładować bezpośrednio tekstury z obrazków SVG.
Tekstury przypisane w trybie UV editing
[docs -
UV Unwrapping And Texturing i kilka kolejnych stron]
Idea: tekstury przypisywane do materiałów, z poprzedniego wykładu, są dość potężne, głównie dlatego że generalnie są 3D i są generowane proceduralnie. Ale powoduje to też problemy:
Nie widać ich w podglądzie interaktywnym Blendera (ponieważ obliczanie ich w czasie interaktywnym jest praktycznie niemożliwe),
Nie są eksportowane do innych formatów 3D (ważne dla osób chcących w Blenderze robić modele np. do Quake'a; powód: nie ma jak wyrazić tekstur proceduralnych w formacie Quake, przecież Quake nie zna algorytmów generowania tekstur Blendera).
Mamy stosunkowo ograniczone możliwości mapowania (mapowanie określa jakie współrzędne tekstury są używane na ścianach 3D): panel "Mapping" zawiera trochę przydatnych rzeczy, ani nic co dawałoby nam absolutną swobodę (poza "UV", o którym właśnie teraz będziemy sobie opowiadać...). Zwłaszcza kiedy musimy nałożyć teksturę typu Image na złożony obiekt, mapowania na "Mapping" mogą okazać się niewystarczające. A przecież rzeczy takich jak rysy twarzy nie wygenerujemy (w każdym razie niezbyt łatwo) teksturą proceduralną.
Tekstury przypisywane w trybie UV rozwiązują ten problem. Po prostu, w trybie UV można przypisywać tylko tekstury 2D. Ba, z punktu widzenia Blendera przypisywane tak tekstury nawet nie są "pełnowartościowymi teksturami" (obiektami typu TEX, takimi jakie umieszczaliśmy w kanałach tekstur na materiałach): mamy tylko obrazek, obiekt IM, a więc coś co (prawie zawsze) pochodzi z prostego pliku 2D jak PNG czy JPG. Ponadto, nie mamy praktycznie żadnej kontroli na to jak tekstura wpływa na nasz obiekt — zawsze wpływa na kolor. (Bez obaw, oczywiście można taką teksturę "podłączyć" do tekstury materiału i uzyskać wszystkie możliwości; ale o tym za chwilę).
Można na dzisiejszy wykład patrzeć jak na:
Dzięki uproszczeniu tekstur UV, znikają wady tekstur proceduralnych: tekstury UV widać w trybie interaktywnym Blendera. Mapowanie tekstur możemy swobodnie modyfikować w podobny sposób jak pracowalibyśmy z meshem ograniczonym do dwóch wymiarów.
Dla przypomnienia: nazwa UV pochodzi od tego że pierwsza współrzędna tekstury jest tradycyjnie nazywana U, druga V (żeby nie myliły się z XY).
Demo: pokaż textures_unwrapped_examples - face, knight and mage simple unwrapping.
Dodawanie współrzędnych tekstury UV do obiektu: W edit mode zaznacz faces, przypisz im współrzędne tekstury przez UV Calculation (klawisz U). Zwróć uwagę że to automatycznie dodaje współrzędne UV w "Object Data" (można mieć wiele — multitexturing). Potem przypisz im obrazek i poprawiaj współrzędne tekstury w okienku "UV/Image Editor" (najlepiej przejść na widok "UV Editing" w nowym Blenderze).
Tak przypisane tekstury są widoczne interaktywnie w widoku 3D (Alt+Z). Ponadto, przy eksporcie (np. gdy tworzycie modele 3D do gier), eksportery używają tych właśnie tekstur.
Mała konfiguracja tego jak widzimy ściany w widoku "Texture" jest w panelu "Game Settings" w materiale. Żeby go zobaczyć trzeba przejsć na tryb "Blender Game" (na headerze zmień "Blender Render" na "Blender Game").
Kilka opcji pod klawiszem U: project
(demo na face).
sphere, cube, cylinder, reset są naturalne.
Demo reset.
Demo cylinder naokoło ścian labiryntu (take texture from castle).
O arcy-ważnym uwrap za chwilę.
Na renderingu?
Domyślnie tekstury przypisane przez UV editing nie są widoczne na renderingu. Jeżeli chcecie żeby były, trzeba ustawić Face Textures na materiale (jest teżFace Textures Alpha). Zwróćcie uwagę że tekstury przypisywane przez UV editing są generalnie "słabsze" od tekstur powiązanych z materiałami — jest tylko jedna tekstura (tzn. jedna aktywna), która może wpływać tylko na kolor materiału, i jej źródło pochodzi bezpośrednio z obrazka (obiektu IM (Image), zamiast TEX (Texture Blendera, która może być generowana proceduralnie etc.)).
Jeżeli pracujecie tylko w Blenderze (zależy Wam na zrobieniu filmu/renderingu w Blenderze, nie interesuje Was eksport) to raczej nie chcecie włączać Face Textures. UV editing jest dla Was przydatne żeby użyć tak stworzonych / edytowanych współrzędnych UV na teksturze powiązanej z materiałem — patrz "Mapping", przycisk "UV". Teksturę przypisaną przez UV traktujecie tylko jako coś testowego, co pozwoli Wam widzieć podgląd tekstury i przypisać odpowiednie współrzędne UV.
Możecie też stworzyć teksturę Image i przypisać jej ten sam obrazek którego używa tekstura UV. W ten sposób (jeżeli materiał używa UV coordinates, tekstura używa tego samego obrazka co UV editing) macie poprawnie zdefiniowany materiał, który nie używa Face Textures (które należy traktować jako "szybki hack", nie poprawną metodę tworzenia ładnych materiałów, jeżeli interesuje Was rendering Blendera). To pozwala Wam wykorzystać zarówno zalety tekstur powiązanych z materiałami (milion opcji do renderingu) jak i swobodnie edytować współrzędne UV.
Demo: sama UV na rendringu brak, włącz Face Textures, bez Face Textures tekstura w "Image or Movie" - możemy włączyć "Normals".
Żeby stworzyć obrazek tekstury który zawiera jej teksturę proceduralną (czyli żeby zamienić tekstury powiązane z materiałami na prosty obrazek, żeby mieć dobry podgląd tekstury albo może żeby wyeksportować model razem z jego teksturą) można zrobić unwrap i "bake" do tekstury, demo za chwilę.
Edycja współrzędnych UV tekstury w widoku Image — w skrócie,tak jak edycja wierzchołków mesha. Zaznaczanie (RMB, box select B, select linked pod L albo trochę inne pod Ctrl+L), Grab/Rotate/Scale (łącznie z lokowaniem do osi XY) działają jak zawsze. Jest proportional editing.
Kilka użytecznych opcji w edycji tekstury, jak tryb zaznaczania (znane vertex, edge, faces, ale też islands, czyli skrót dla L (linked)).
Różne zastosowania tekstur wymagają różnych podejść. Np. jeżeli chcemy pokryć nasz obiekt wielokrotnością naszej tekstury (np. ściany, podłogi w grze 3D) to zapewne zaczynamy od UV Calculation: Cube, Cylinder, Sphere etc. Po drugiej stronie, kiedy chcemy żeby każda ściana zajmowała inny kawałek tekstury, zapewne chcemy zrobić unwrapping, o tym zaraz.
Aktualnie pracujemy tylko na tych faces które są zaznaczone w edit mode. Więc jest sens zmieniać zaznaczenie w widoku 3D żeby operować na wygodnym pozbiorze ścian.
New image, UV test grid.
Image Paint (dobre do tworzenia szybkich "szkiców" jak ma wyglądać tekstura, które potem zazwyczaj chcemy poprawić w normalnym edytorze jak GIMP). [docs] Note: pamiętajcie że Blender nie zapamiętuje obrazków, ponieważ domyślnie zakłada że obrazki pochodzą z plików zewnętrznych. Jeżeli chcecie zachować swój obrazek, zapamiętajcie go (image->save) do pliku zewnętrznego, albo włączcie jego pakowanie.
Jest też trochę analogiczna metoda pozwalająca malować w 3D, vertex painting. Zabawka w sumie bez związku z teksturami UV, ale warto o niej wspomnieć bo używa podobnej metodologii jak "Image Paint" — tylko że w widoku 3D.
Update automatically (kłódka) — bardzo wygodne.
Możemy mieć wiele mapowań UV na naszym meshu, patrz panel "Editing" — możemy usuwać i nazywać mapowania tam.
[sample - eyeball], dość specyficzne mapowanie UV pozwalające użyć większość powierzchni tekstury na najciekawszy element, czyli źrenicę.
UV unwrapping. Szczególnie użyteczny sposób mapowania tekstur na trudniejszych obiektach.
Najpierw, zamiast standardowego unwrap, zobaczmy "Smart UV Project". To jest świetny unwrapping kiedy nie zależy nam strasznie na dobrym mapowaniu (np. kiedy chcemy mieć tylko podgląd tekstury w widoku 3D), ponieważ działa w pełni automatycznie i zawsze sobie radzi, nawet z trudnymi obiektami.
Standardowy unwrapper: generalnie, trochę głupszy algorytm i polega na obecności krawędzi "mark seams". To oznacza że wprawdzie na trudniejszych modelach zupełnie sobie nie radzi automatycznie, ale mamy nad nim kontrolę. Przy odrobinie pracy z "mark seams" można sprawić żeby działał idealnie (nawet lepiej niż "smart projections").
Sens "seams" w Blenderze (Ctrl+E, Mark/Clear Seam ): mówią jak rozłożyć mesh na płaszczyźnie, pomagają unwrapperowi w trudniejszych sytuacjach. Krawędzie ścian nie będą stykać się na teksturze — a więc grafikowi 2D będzie dużo trudniej zrobić "seamless" przejście na teksturze na krawędziach oznaczonych jako seams.
Skrypt "UVs->Export UV Layout": tworzenie obrazka z siatką po wyjściu z unwrappera. Bardzo użyteczne żeby teraz pracować z teksturą w innym programie, jak GIMP (zazwyczaj wygodnie jest wrzucić sobie siatkę na osobną pół-przezroczystą warstwę, w ten sposób można wygodnie pracować i ukryć siatkę przy zapisywaniu ostatecznego pliku tekstury.)
Keep UV and edit mode selecion in sync — ogólne narzędzie przy UV editing, szczególnie użyteczne kiedy chcemy się dowiedzieć do dokładnie zrobił unwrapper, jaka ściana UV odpowiada jakiej w 3D. Zaznaczamy wszystkie ściany i przy włączonym "Active face select" klikamy na ściany w UV. (Jeżeli chcesz w drugą stronę, to klikanie na 3D też widać na UV (np. dwa razy shift+RMB na ścianie, żeby ją odznaczyć+zaznaczyć; ściana "mignie" w UV editor).
Ogólnie, standardowy unwrapper jest świetny kiedy chcemy mieć kontrolę nad unwrappingiem. Trzeba się trochę napracować żeby mieć dobre seams i dobre unwrapping, ale możemy otrzymać dowolnie dobry możliwy unwrapping (co zazwyczaj oznacza że żadna face nie jest zdeformowana, i faces są możliwie połączone; to ułatwia malowanie tekstury).
"Follow active" i inne dają trochę więcej kontroli nad uv mappingiem, wyznaczyliśmy mapping na jednej ścianie i chcemy żeby uv mapping się do niej dostosował. Zakładka "Display" na "UV Image Editing" — trochę prostych zabawek, szczególnie "Stretch".
[sample - unwrap na knadze przy użyciu "mark seams"]. Idea na podstawie tutoriala o UV mapping.
Demo: unwrap tekstury na model człowieka, zabawy z image paint na teksturze i "Save UV Face Layout" + bardziej precyzyjny painting tekstury w GIMPie.
UV project modyfikator. See [docs] i sample plik tam. W przeciwieństwie do mapowania "ręcznego" (za pomocą klawisza "U") to jest modyfikator — a więc zmiany w meshu będą automatycznie uaktualniały współrzędne UV.
Ten modyfikator jest w sumie trochę na przekór idei tekstur UV: Ideą tekstur UV w Blenderze jest że użytkownik ma pełną kontrolę nad UV. Jeśli chcesz mieć automatycznie obliczane UV, to używaj tekstur przy materiałach. Ale w praktyce, tekstury przy materiałach mają mało mapowań automatycznych (tylko Flat, Cube, Tube, Sphere, a tekstury na node'ach nawet tylko Flat), więc ten modyfikator jest często niezwykle użyteczny — pozwala zdefiniować trudne mapowanie w taki sposób że zmiany w meshu będą automatycznie uwzględniane.
Jeszcze zobaczymy demo tego na następnym wykładzie, przy okazji nodes: jak zrobić landscape który automatycznie jest teksturowany na podstawie wysokości.
Baking (wypiekanie) tekstury Czyli tworzenie tekstury w Blenderze poprzez dość specjalistyczny rendering.
Bake to Texture only, Full render. W ten sposób "konwertujemy" tekstury przypisane do materiałów na proste 2D tekstury UV. Oczywisty efekt to żeby widzieć podgląd tekstur w interaktywnym widoku 3D Blendera. Ale inny (fantastyczny!, jeżeli ktoś projektuje modele do gier) efekt to że można taką teksturę zapamiętać, wyeksportować model 3D, i mamy model 3D który w prostych teksturach 2D ma zawarte takie efekty jak tekstury proceduralne, oświetlenie, cienie etc. — wszystko co Blender renderuje.
Demo: najpierw wypiekanie tekstur proceduralnych na modelu. Same bake "Texture Only" jest idealne żeby zamienić teksturę proceduralną na klasyczny obrazek.
[sample - trawa z drzewami, z cieniem zawartym w teksturze dzięki bake z "full render"] W środku archiwum znajdziecie, poza plikiem blend, wyeksportowany model do Wavefront OBJ i VRML 2.0. Kto ma program do odczytu modeli 3D w jednym z tych formatów (np. zrobił go na PGK) może teraz otworzyć taki model i zobaczyć cienie zawarte w teksturze. Ustawienia tekstur są nieco egzotyczne, ponieważ już mamy na modelu jedną teksturę UV trawy (która nie jest unwrapped, tylko repeated), a jednocześnie potrzebujemy drugiej tekstury UV (unwrapped) do której trafi wynik baking.
Ambient occlusion. Generuje teksturę z ambient occlusion (Co to jest ambient occlusion?). Czyli mamy kolejny ciekawy efekt który możemy zawrzeć na prostej teksturze 2D, dla naszej gry etc. (Jeżeli zależy nam na ambient occlusion tylko na renderingu Blendera, to naturalnie nie potrzebujemy do tego tekstury; możemy po prostu włączyć ambient occlusion dla World — [docs], zresztą o ustawieniach World jeszcze sobie poopowiadamy na późniejszych wykładach.)
[sample - human body with ambient occlusion baked as texture] Ten model człowieka widzieliście już wcześniej, patrz "human with superman logo" sample. Tutaj zrobiłem mu proste unwrap po czym bake ambient occlusion. Nawiasem mówiąc, widać też że zrobiłem to niedbale — przydałoby się lepsze unwrap, używając ręcznie zaznaczanych seams. Zapewne większa rozdzielczość tekstury też byłaby dobra. Liczę że sami umiecie już to poprawić...
Normals — wygeneruj mapę wektorów normalnych. Jeżeli silnik 3D naszej gry ma zaimplementowane bump mapping, to w ten sposób możemy w Blenderze wygenerować dla niego normal mapę. Jeżeli jesteśmy zainteresowani tylko renderowaniem w Blenderze, to możemy użyć tej tekstury (jako tekstura Image na materiale z włączonym "Normal Map"), chociaż nie ma to wiele sensu — w końcu Blender i tak "zna" te wektory normalne i ich używa. Chyba że w Blenderze zmieniamy model high-poly na low-poly.
Uwaga: zapewne tangent space jest najlepsze dla normal map, i dla Blendera i dla innych programów 3D. Przełączamy na tangent space, włączamy "selected to active" (inaczej normal mapa zawsze będzie ~niebieska, wektory normalne samego siebie są nieciekawe). Zaznaczamy dwa obiekty, high-poly i low-poly (low-poly jako ostatni, "active"), i robimy "bake".
Displacement — [release docs]. Zastosowanie podobne jak Normals, kiedy zmieniamy model high-poly na low-poly.
Tekstury można też animować na różne sposoby. Pobawimy się tym przy okazji animacji.
Poza manualem, jeden z przydatnych artykułów o materiałach i teksturach (chociaż teraz już trochę stary, pisany pod starszego Blendera) jest tutaj.
Przy okazji: Blender Open Material Repository. Można podglądać materiały i ściągać pliki blend z ich ustawieniami. "All materials are completely free and the creators agree to set them under public domain".
Oto model w Blenderze dwóch pomieszczeń z levelu DOOMa E1M1.
Jest tam geometria (całość jako jeden mesh Blendera), wstawiłem Wam też kilka byle-jakich świateł (zwykłe światła punktowe Lamp z cieniami RayShadow) i dwie kamery.
Ściągnijcie go, i zróbcie rendering z obu kamer. (Pamiętaj że możesz zmieniać aktywną kamerę (z której jest robiony rendering) przez View->Set Active Object As Active Camera w menu widoku 3D.)
Zadanie: oteksturuj jeden z pokoi. Który chcesz, i jak chcesz.
svn checkout \ http://svn.code.sf.net/p/castle-engine/code/trunk/castle/data/textures/doom/
Przeglądać kolekcję tekstur można np. gthumb
,
albo przeglądarkami Linuxowymi w widoku ikon,
albo przestaw w "File->User Preferences->File->Show Thumbnails" na true
i wtedy Blenderowe "Image->Open" pokaże miniaturki tekstur.
A można też użyć innych tekstur (choćby ściągniętych z Internetu), można też użyć tekstur proceduralnych. Czyli można też cudować samemu i zrobić zupełnie inny (byle sensowny) wygląd niż w DOOMie.
Pamiętajcie przejść na widok "Texture" (Alt+Z) żeby w ogóle widzieć tekstury UV w widoku interaktywnym.
Pamiętajcie że w widoku "Texture" działa backface culling, czyli ściany które są z tyłu (z innej strony niż wskazują wektory normalne) są ukryte. "Recalculate Normals" outside/inside przestawia która strona jest widoczna (checkbox "inside" zobaczysz zaraz po wykonaniu "recalculate normals" w "tool shelf" po lewej; Ctrl+N, Ctrl+Shift+N). Można też wyłączyć backface culling: w nowym Blenderze 2.6 mamy do tego prosty checkbox, w trybie "Blender Game" (na headerze zmień "Blender Render" na "Blender Game") na materiale zobaczymy panel "Game Settings" w którym znajdziemy "Backface culling" (i kilka innyc związanych opcji).
Dobre rady: mamy do czynienia z nieco niewygodną geometrią, bo pokoje są zamknięte, a nas interesuje wygląd tekstur w środku pokoju. Część zabawy to nauczyć się sobie z tym radzić:
Dla wygody można skasować sobie drugi pokój którego nie teksturujecie.
Można też wydzielić sufit i/lub podłogę jako osobne obiekty.
Pamiętajcie o możliwości ukrywania obiektów (H, Alt+H pokazuje). Działa zarówno na całe obiekty (w object mode) jak i na zaznaczone vertexy (w edit mode).
Inne sposoby ukrywania obiektów: warstwy Blendera (patrz wykład 1). Local view (\). Widok box (alt+b i zaznacz prostokąt, jeszcze raz alt+b żeby usunąć). Polecam wypróbować.
Uwaga do przysyłania: jeśli używacie tekstur z obrazków, pamiętajcie zrobić File -> External Data -> Pack into .blend file. Jeżeli celujecie w ładny wygląd na renderingu, please załączcie wyrenderowany obrazek dla mojej wygody :)
Nodes (węzły) materiałów czyli jak wygodnie składać materiały i tekstury. (Przy okazji, to jest też odpowiedź na pytanie "co zrobić kiedy 10 kanałów tekstur to za mało").
Docs ogólnie o nodes:
Docs o nodes dla materiałów:
Okienko Nodes. Każdy materiał może mieć 1 mapę nodes, ponadto jest też mapa "Composite nodes" (1 na całą scenę) która pozwala w podobny sposób robić różne post-processing renderingu. O "Composite nodes" opowiemy na późniejszym wykładzie o renderowaniu, na razie skupimy się na węzłach dla materiałów.
Materiał ma przycisk "Nodes" który jest tym samym co "Use Nodes" na okienku nodes.
Idea nodes: możemy składać w grafy różne nodes (węzły). Węzeł (zazwyczaj) dostaje coś na wejściu i produkuje coś na wyjściu. Podstawowy węzeł to "Material", czyli znany nam Blenderowy materiał, oraz "Output", który określa kolory wynikowe. Jak widać na zakładce "Links and pipeline" materiału, kiedy aktywowaliśmy nodes, to obiektem "nadrzędnym" który kontroluje renderowanie materiału jest nasz graf nodes, Node tree (NT), natomiast klasyczny materiał Blendera (MA) staje się tylko jedną z "cegiełek" naszego grafu. Kiedy klikamy na node "material", zmienia się "active material node" który edytujemy. Czyli panel "Material buttons" pełni teraz dwie role: "Links and pipeline" kontroluję mapę nodes przypisaną do aktualnego obiektu/mesha. "Nodes" jest... no, na razie mało użyteczne (wyświetla to samo GUI co sam węzeł, użyteczne tylko jeżeli macie skomplikowaną mapę węzłów i trzymacie węzły w formie hidden i nie chcecie robić im unhide). Reszta przycisków służy do konfiguracji jedynie pojedynczego węzła typu Material.
Notka: żeby umożliwić łatwą migrację na system nodes, w Blenderze materiał rodzaju NT pamięta też w środku ustawienia klasycznego materiału, MA. W listach rozwijanych gdzie wybieramy materiały, mamy teraz dostępne i "klasyczne" materiały MA i nasze nowe materiały oparte na węzłach, NT. Materiały oparte na węzłach są oznaczone "N" w listach. To jest sposób żeby bez żadnych zmian przejść na nodes, kiedy już zrobiliśmy klasyczny materiał: klikamy "Use Nodes", po czym na węźle materiału klikamy na "Add new" i wybieramy ten sam materiał. W ten sposób ten sam materiał jest używany na dwa sposoby: 1. jako nodes tree, NT, określające wygląd całego obiektu 2. jako pojedyncza cegiełka na mapie nodes, MA.
Operowanie w okienku nodes:
Podstawy operowania (takie jak w widoku 3D albo podobne): Kasowanie (X). Zaznaczanie box (B) albo zaznaczanie z lewym lub prawym klawiszem myszy, zaznaczanie z shift dodaje, zaznacz nothing/all (A). Hide/unhide (H (działa jak switch) albo ta strzałeczka w lewym-górnym rogu). Przesuwanie G. Undo (Ctrl+Z), Redo (Shift+Ctrl+Z). Czyli wszystko tak samo albo bardzo podobnie jak na widoku 3D — tyle że pracujemy z czymś innym. Przesuwanie widoku (MMB), skalowanie widoku (Ctrl+MMB, rolki myszy).
Podstawy operowania (inne funkcje): cut link (ctrl + drag). execute (E) — przepuszcza preview przez węzły, odświeżając widok wszystkich preview. Show Cyclic Dependencies (C).
Make group (Ctrl+G) — jak w widoku 3D, ale efekt jest ciekawszy — grupa jest faktycznie wyświetlana jako jeden element; ktoś się bawił w robienie układów bramek logicznych? "Wchodzimy" i wychodzimy z grupy przez Tab, trochę analogia do edit mode. Arcy-ważne zastosowanie grup to że mogą być współdzielone przez różne grafy nodes (poprzez Add->Group mamy możliwość dodania istniejącej grupy do aktualnego grafu).
Gniazda (sockets, connectors):
Rodzaj danych: yellow: kolor, gray: intensity aka grayscale, blue/purple: vector 3d inny niż kolor. Generalnie kiedy łączymy nodes, połączenie między różnymi kolorami powoduje konwersję (np. wektor może zostać zamieniony na skalar (średnią) jeżeli puścimy wektor do gniazda które akceptuje tylko skalary). Są też węzły do konwertowania bardziej explicite.
Wejściowe / wyjściowe: to chyba widać, po lewej stronie node są wejściowe gniazda (dane dla node), po prawej stronie są wyjściowe gniazda (co node produkuje). Z jednego gniazda można pociągnąć wiele nitek, odpowiednie dane będą po prostu kopiowane do wszystkich celów. Natomiast do jednego gniazda może prowadzić maksymalnie jedna nitka (kiedy chcemy połączyć kilka danych, to w końcu od tego są właśnie nodes: żeby zdefiniować różne sposoby łączenia).
Tworzenie i przesuwanie nitek jest intuicyjne, po prostu chwyć i przeciągaj z odpowiedniego gniazda.
Ukrywanie nieużywanych gniazd: przycisk "+".
Rodzaje węzłów:
Sfera: włącz/wyłącz preview (tylko na materiałach albo output).
Edytowanie curves, przy okazji demo node Color->RGB Curves. W zasadzie taki mini-edytor znanych nam już krzywych Beziera.
Node Input->Material oraz Output->Output są jasne, jeden produkuje normalny materiał drugi mówi skąd brać wynik. Kiedy nie ma żadnego węzła Output, wygląda na to że Blender zbiera "wiszące" gniazda wyjściowe, czyli w prostych sytuacjach renderuje coś sensownego, ale ogólnie kiedy używamy nodes to zazwyczaj chcemy mieć nad tym lepszą kontrolę więc dobrze jest trzymać jeden node Output. Dodatkowe Output są przydatne jako preview w środku grafu nodes, demo.
Input->Texture node który zawiera tylko teksturę (naturalnie ciągle można używać też tekstur w środku klasycznych materiałów). Node Input->Geometry doczepiony jako wejście tekstury pełni podobną rolę co "Mapping" w klasycznej metodzie.
Input->Material pozostaje ciągle najważniejszym materiałem (chociaż możliwe byłoby symulowanie pewnych shaderów innymi nodes, jest ciągle łatwiej po prostu używać normalnego materiału). Jego najważniejszym gniazdem jest wyjściowy kolor, ale ma też kilka innych ciekawostek. Np. ma też gniazda wejściowe.
Domyślnie (kiedy nic nie jest pod nie podczepione) kolory Col, Spec i Refl materiału są określone przez "material buttons", czyli tak jak już się bawiliśmy na poprzednich wykładach (czyli jeżeli materiał nie ma texture channels, to są stałe). Możemy pod nie "podczepić" różne rzeczy, np. stałą wartość (z Input->RGB dla koloru, albo Input->Value do Refl) albo Color->Mix różnych wartości. Np. Mix koloru tekstury z jakimś stałym kolorem RGB, przy czym factor Mix wziąć z Value tekstury — to symuluje "klasyczne" Mix koloru na "Influence" w klasycznych materiałach. Możemy też np. zmieszać wyjście koloru materiału z kolorem tekstury, żeby uzyskać trochę mniej subtelny (i mniej realistyczny) efekt.
Domyślnie (kiedy nic nie jest pod niego podczepione) wektor normalny dla materiału pochodzi z geometrii. Możemy to wyrazić explicite, podczepiając Geometry.Normal do Material.Normal — nic się nie zmieni. Żeby modyfikować wektor normalny, możemy "podczepić się" Material.Normal ciekawsze rzeczy, np. możemy zrobić Mix pomiędzy Normal tekstury a Normal geometry (efekt podobny jak znane "Normal" na "Influence"). Jeżeli poprowadzimy bezpośrednio normal od tekstury do materiału to całkowicie zignorujemy geometrię, co zazwyczaj nie jest dobrym pomysłem — chyba że do specjalnych sztuczek.
Vector->Normal możemy użyć do podobnych sztuczek co poprzednio "Mapping" z "Normal", tyle że teraz jest bardziej konfigurowalne. "Dot" robi dot wejściowego wektora normalnego z kierunkiem świecenia sfery, przy czym material preview sfery jest w stronę kamery. Innymi słowy, przy domyślnej sferze, dot = 1 kiedy wektor normalny na wejściu jest skierowany w stronę kamery, dot = 0 kiedy jest prostopadły. Możemy taki dot podłączyć jako factor np. do Mix pomiędzy dwoma kolorami, i mamy efekt podobny jaki widzieliśmy ze sztuczką "Map Input" "Nor". Tyle że było nam dużo łatwiej go uzyskać, nie potrzebowaliśmy sztuczki ze specjalną teksturą Blend etc.
Łączenie materiałów/tekstur: wprawdzie można robić z node'ami mnóstwo rzeczy (nawet re-implementować samemu różne sposoby cieniowania, patrz node's jak Convertor->Vector Math i Convertor->Math), to zazwyczaj jednak proste materiały łatwiej jest wyrażać "normalnymi" materiałami. Natomiast to gdzie nodes szczególnie pokazują siłę i swobodę to łączenie różnych materiałów i tekstur. Wcześniej umieliśmy łączyć tylko tekstury, i to byliśmy dość ograniczeni — tekstury było ułożone w 10 kanałów po kolei, najciekawszy "operator" łączenia (czyli tekstura stencil) działał niesymetrycznie (tekstury ponad nim nie miały szansy modyfikować części obszaru, natomiast tekstury pod nim miały szansę modyfikować cały obszar). Kiedy chcieliśmy wyrazić foto-realistyczne materiały, z wieloma warstwami rowków/wypukłości/plam etc. mieliśmy trochę problemów. Teraz wszystko jest prostsze. Kluczowym węzłem jest Mix — mały i niepozorny, ale bardzo ważny.
[sample - rocky landscape], mały krajobrazik który zrobiłem, pokazuje umiarkowanie nietrywialną kompozycję węzłów materiałów — całe rozróżnienie pomiędzy górami / trawą / ścieżką jest zrobione teksturami.
Demos.
Patrz [samples from Blender material nodes].
Odtworzymy sobie też model z toon shading jako demo że umiemy to sami zrobić :) Eee, zresztą widzę że to łatwe, shaderami OpenGLa symuluje się toon shading tak samo :) Oto wynik: [sample - toon shading].
Idea: jak wszyscy zapewne zauważyli robiąc swoje renderingi, renderer Blendera oferuje tylko kiepską symulację rzeczywistości. Zasadniczy renderer Blendera to scan-line renderer. Kiedy mamy przyciśnięty przycisk "Ray" mamy raytracer (raytracer klasyczny, nie żaden distributed), co pozwala na efekty jak przezroczystość (z załamaniem, zamiast prostego alpha blending) / lustra (bez potrzeby używania tekstur environment maps) / twarde cienie z każdego światła (bez potrzeby konfigurowania shadow buffer). Ciągle jednak zasadnicza symulacja światła jest prosta, fotony są rzucane ze źródła światła na obiekt, oświetlają go... i tyle, nie odbijają się od niego żeby świecić dalej (indirect illumination). Dlatego używamy sztuczek żeby uzyskać efekty zbliżone do global illumination, jak ambient occlusion, radiosity (później) oraz, przede wszystkim, używanie wielu źródeł światła Blendera na raz. Jedno źródło światła na rzeczywistej scenie jest zazwyczaj symulowane przez wiele źródeł światła Blendera.
Podstawy (które już pewnie wszyscy przetestowali na własną rękę): kolor światła (pamiętajcie że generalnie jest mnożony przez kolor materiału, tak jak w rzeczywistości materiał absorbuje niektóre długości fal; np. światło R=B=1,G=0 na obiekcie R=G=1,B=0 da kolor czerwony). energy czyli jasność światła.
Ustawianie świateł — przesuwamy, obracamy, skalujemy (w przypadku świateł dla których ma to sens) tak samo jak każdy inny obiekt, tak samo jak kamerę. Hint: pamiętacie sposób ustawiania kamery przez TrackTo constraint (Ctrl+T)? To jest też często wygodne żeby ustawić kierunek różnych świateł.
Spadek jasności razem z odległością
Falloff określa jak odległość od światła wpływa na postrzeganą jasność. Najbardziej realistyczne są równania kwadratowe, czyli Inverse Square lub Lin/Quad Weighted. Są dobre dla świateł które symulują rzeczywiste i słabe źródła światła na naszej scene (lampy w nocy etc.)
Na konkretne potrzeby, zwłaszcza na światła silne lub o dużej powierzchni (w rzeczywistości), niekiedy łatwiej jest zmienić na prostsze Inverse Linear, albo nawet Constant. Dokładniej:
Constant - naturalnie, wyłącza spadek jasności z odległością. (poza kontrolką "Sphere", która działa niezależnie.)
Inverse Linear - Distance określa odległość na jakiej światło ma połowę energii, dokładny wzorek to Distance / (Distance + odległość), czyli światło nigdy absolutnie znika i jest połową gdy Distance = odległość.
Lin/Quad Weighted - jasność ~ 1/odległość^2. Bardziej precyzyjnie:
(Distance / (Distance + Linear * odległość )) * (Distance^2 / (Distance^2 + Quadratic * odległość^2))Czyli slidery Linear oraz Quadratic kontrolują jak bardzo mamy liniowy spadek, a jak bardzo kwadratowy. Domyślne jest Linear = 0 oraz Quadratic = 1 czyli całość działa jako prosty kwadratowy spadek (tak samo jak Inverse Square, o ile wiem), zwróćmy uwagę że Distance ciągle oznacza proste "odległość na jakiej siła światła jest połową".
[sample - street_lights_sphere_demo]
Gdy Linear = 1 oraz Quadratic = 0 mamy ten sam efekt co Inverse Linear.
Gdy Linear = Quadratic = 0, mamy to samo co Constant.
Sphere pozwala ograniczyć jasność światła precyzyjnie do danej sfery, czyli światło poza Dist nie będzie świeciło. Wzorki powyżej (dla linear albo dla quad) są mnożone przez (Dist - odległość) / Dist (czyli gdy odległość przebiega od 0 to Dist, mamy skalowanie światła od 1 do 0) oraz gdy odległość > Dist wymuszamy siłę światła na 0. W ten sposób światło w gładki sposób spada do 0 na granicy sfery.
Rodzaje świateł:
Lamp: klasyczne w grafice 3D światło punktowe świecące we wszystkich kierunkach. Ma pozycję, nie ma kierunku. (De facto wszystkie obiekty Blendera mają pozycję + kierunek + skalowanie, po prostu dla Lamp kierunek i skala nie mają żadnego znaczenia przy renderingu.)
Spot: światło spotlight, czyli skupiona wiązka promieni.
Kontroluj rozmiar spota przez SpotSi (Spot size), gładkość na brzegach stożka przez SpotBl (Spot blurriness).
Hint: w Blenderze dowolny obiekt może być aktywną kamerą. Aby ustawić spot light (albo testować jego ClipSta, ClipEnd), czasami wygodnie jest na chwilę uczynić spotlight aktywną kamerą (Ctrl+Numpad 0).
Bardzo ważną cechą spotlight to że może generować cienie przez buffer shadows. O tym więcej zaraz.
Area: symuluje światło powierzchniowe z czworokąta. Zwiększając ilość Samples dla Ray shadow sprawiamy że będzie sprawdzanych kilka promieni cienia na światło (samples jest w pojedynczym wymiarze, tzn. mamy Samples^2 świateł punktowych) — duża wartość Samples pozwala uzyskać bardzo realistyczne gładkie cienie, ale szybkość renderowania spada bardzo drastycznie.
Notka: zmienianie rozmiaru światła przez skalowanie oraz zmienianie go przez kontrolki Size działa inaczej. Efekt jest taki że skalowanie skaluje także energię.
Zwiększając Gamma oraz ustawiając Umbra możemy symulować bardziej miękkie cienie w sposób mniej realistyczny ale bez drastycznego zwiększania czasu renderowania. Czyli trzeba dobrać Samples oraz resztę tak żeby uzyskać dobry efekt i czas renderowania był znośny.
[sample - room area light] (i rendering)
Sun: klasyczne w grafice 3D światło kierunkowe.
Wprawdzie Blender pokazuje jego pozycję, jest ona tylko po to żebyśmy mogli w Blenderze za coś nasze światło "chwycić". Ta pozycja nie ma znaczenia przy renderingu. Oświetlenie, cienie patrzą tylko na kierunek światła, co można łatwo samemu sprawdzić.
Zastosowanie: jak nazwa sugeruje, dla mocno zaakcentowanego światła punktowego położonego bardzo daleko poza sceną. (dla "słabiej zaakcentowanego", np. w środku słonecznego dnia, Hemi może być lepsze, a Sun można użyć tylko do rzucania cieni).
Hemi: światło świecące z półsfery (hemisphere).
Tak jak dla Sun, pozycja nie ma znaczenia. Liczy się tylko kierunek, który wyznacza półsferę.
Zastosowanie: Znakomite do symulacji kopuły nieba, czyli do robienia scen outdoors.
Cień: Jako jedyne światło, nie może rzucać cienia (ani przez shadow buffer, ani przez ray-casting). Nie rzuca cienia (ponieważ nie ma jak go łatwo obliczyć, trzeba by sprawdzić dla każdego punktu wszystkie promienie do półsfery naokoło), zresztą w scenach outdoors (prawie) wszystko jest jakoś oświetlone. Jeżeli potrzebujecie cienia, zasymulujcie go innym światłem z "Only Shadow".
Cienie: Mamy dwie metody generowania cieni: ray-tracer (ray shadows) i shadow buffer (buffer shadows). Każde światło poza Hemi ma "ray shadows". Jedynie Spot ma "buffer shadows". Notka: światła rzucające cienie są rysowane z dodatkową przerywaną obwódką w widoku 3D, żeby łatwo jest rozpoznać.
Buffer shadows:
Wada: trzeba ustawić ClipSta, ClipEnd dobrze. Możliwie duże ClipSta, możliwie małe ClipEnd, ale ciągle obejmujące obiekty które rzucają cienie. Zupełnie podobnie jak parametry Clipping Start/End kamery, bo też zasada działania (bufor głębokości) jest taka sama. Na szczęście jest ustawienie "Auto" (ale jest przeliczane przed każdym renderingiem — więc nie zdziwcie się że "render preview" nie będzie idealny dopóki nie zrobicie raz "prawdziwego" render).
Zaleta: może generować miękkie cienie. Ray shadows są za to dość twarde, czasami niedobre kiedy symulujecie światło zewnętrzne (tzn. outdoors).
Inna zaleta, dość mało znacząca: czasami ustawianie dużego ClipSta pozwala łatwo ominąć cienie rzucane przez obiekty w pobliżu światła. Np. kiedy umieścimy źródło światła w środku wymodelowanej żarówki, zauważymy że żarówka zasłania źródło światła. Naturalnie moglibyśmy też po prostu wyłączyć "Traceable" lub "Shadbuf" w materiale żarówki.
Jedynie światło spot rzuca cienie poprzez shadow buffer, pozostałe światła mogą rzucać tylko cienie przez ray-casting. Dlatego dla scen outdoors zazwyczaj przydaje się kombinacja 1. światło sun/hemi, nie rzucające cieni (żeby dać ogólną jasność na scenie) + 2. światło spot (żeby generować jakieś miękkie cienie, położenie spot symuluje położenie słońca/księżyca w rzeczywistej scene).
[sample - simple_winter_scene] (i rendering)
Ważne kontrolki: ShadowBufferSize (nie można zrobić mniejszego niż 512). Samples (ile razy próbkować shadow mapę, właściwie próbkowany jest kwadrat z Samples^2 próbek; Samples = 1 daje cienie na których widać aliasing). Soft określa jak duży obszar shadow mapy próbkować, i zwiększanie go (razem ze zwiększaniem Samples) to klasyczny sposób na miękkie cienie.
Bias służy rozwiązywaniu problemu shadow buffers: obiekt może rzucać cień na samego siebie. W ramach testu, można spróbować ustawić bias minimalne (0.01) i niewątpliwie zobaczymy dziwne efekty... Gdy bias jest zbyt duże, z kolei widać że cień jest dziwnie odsunięty od obiektu.
[sample - simple_scene] z różnymi ustawieniami.
Ray shadows: uhm, tak jak powyżej tylko na odwrót...
Cienie są bardzo łatwe w konfiguracji, po prostu włącz "Ray Shadow" (i upewnij się że przy renderowaniu włączyłeś "Ray", ale to jest domyślnie już od jakiegoś czasu w Blenderze).
Cienie wychodzą bardzo twarde, tzn. ostre — czasami to dobrze, ale czasami daje to nierealistyczny efekt. Ponadto, geometryczne "silhouette" wyznacza teraz granicę cienia — co oznacza że czasami paskudnie widać że np. nasza kula tak naprawdę jest złożona z płaskich czworokątów.
sample: też winter_scene, tylko przestaw na "ray shadow". Widać problemy.
Typowe kompozycje świateł ("lighting rigs"). [docs - Lighting rigs] Nie bójcie się tworzyć dużej ilości świateł. Żeby symulować global illumination, zazwyczaj najprostsze i najlepsze jest właśnie użycie wielu świateł. (Jest zdecydowanie lepsze np. niż używanie nieładnych sztuczek jak Ambient.) Dla sztucznych świateł zazwyczaj chcemy wyłączyć rzucanie cieni, żeby oglądający nie zorientował się łatwo w sztuczce.
Moja prywatna wykładnia: kiedy masz trudne oświetlenie, myśl osobno o ogólnej jasności i osobno o rodzaju cieni. Nie próbuj za wszelką cenę osiągnąć i jednego i drugiego tym samym światłem, to zbyt często prowadzi do nierozwiązywalnych problemów ("nie mam jak ustawić tego światła żeby i zacienione i nie zacienione części sceny wyglądały Ok!"). Zamiast tego zawsze można użyć zestawu świateł które nie rzucają cienia aby rozjaśnić scenę. Jeżeli jedno z nich jest dobrym kandydatem żeby rzucać cień, to super — jeżeli nie, to bez mrugnięcia okiem dodajemy kolejne światło (choćby w tym samym miejscu) z "only shadow" które będzie jedynie powodowało cień, bez rozjaśniania sceny. Po to właśnie Blender ma osobne przyciski pozwalające kontrolować czy światło rzuca cień ("ray shadow", "buf shadow") i czy światło rozjaśnia scenę ("only cast"): żeby te dwa parametry były "ortogonalne".
No Diffuse / No Specular: przydatne kiedy robimy sztuczne światło tylko po to aby pokazać rozbłysk specular na jakimś szczególnie ważnym lśniącym przedmiocie na scenie, albo na odwrót: kiedy dodajemy sztuczne światło żeby rozjaśniało scenę, ale nie chcemy go "zdradzić" przez rozbłysk specular.
Czyli kolejne kontrolki pozwalające nam bardziej niezależnie kontrolować różne funkcje świateł Blendera.
Efekt Halo spotlight. Aka "volumetric light", "volumetric shadows".
HaloInt daje silniejsze halo.
Żeby mieć volumetric shadow w środku halo, musimy używać cieni przez buffer shadows oraz ustawić Halo step na coś > 0.
[sample - precious]
(i rendering)
[sample - precious_accent_halo]
(i rendering)
Efekt Negative: trochę zabawna sprawa, światło zmniejsza kolor. Ot, taka lokalna czarna dziura. Kiedy musimy zaakcentować to że jakaś powierzchnia jest w cieniu, a jest zbyt trudno odpowiednio ustawić cienie? Różne artystyczne efekty? Pamiętajcie też że światło ma kolor, więc można np. "odjąć" od sceny R=G=1 i w rezultacie światło pozostawia tylko niebieskie elementy sceny.
Separowanie wpływu lights: "Layer" (działa tylko na tej warstwie). Tylko na niektórych materiałach: light group pozwala explicite podać grupę lights które wpływają na ten materiał. "Exclusive" oznacza ponadto że ta grupa świateł nie będzie działać na inne materiały (chyba że też mają podaną taką samą grupę lights).
Tekstury można ustawić światłom.
To jest świetne kiedy symulujemy źródło światła które jest w/za skomplikowanym obiektem (np. lampa w lampionie w którym kręcą się muchy, albo słońce świecące zza liści drzewa). Pomijając już nawet fakt że źródło światła może być daleko poza widoczną sceną (więc byłoby trochę głupio modelować skomplikowany obiekt 3D, jak drzewo z liśćmi, którego nie widać bezpośrednio na scenie), byłoby też trudno sprawić żeby cienie wyglądały elegancko. 1. Kiedy źródło światła jest daleko od obiektu (słońce jest daleko od drzewa na ziemi) powstaje cień bardzo miękki. Przez cienkie liście światło "nieznacznie przechodzi" (subsurface scattering, nawiasem mówiąc nauczymy się później jak symulować takie materiały). Chociaż można byłoby symulować to przez cienie za pomocą shadow buffer... 2. Przez muchy w lampionie światło świeci w ciekawy sposób :). I jest to już trudniejsze — np. mucha która jest o 3cm bliżej żarówki niż inna mucha rzuca już dużo twardszy cień.
Wszystkie te problemy oznaczają że dużo łatwiej jest przygotować teksturę dla światła. Stworzenie tekstury z rozmytym zarysem drzewa/liści jest bardzo łatwe (przynajmniej dopóki na scenie nie widać faktycznego drzewa, więc nie ma problemu z nałożeniem tej tekstury tak żeby rzeczywiście wyglądała jak cień pod drzewem). Stworzenie tekstury z muchami i krawędziami lampionu jest ciekawsze, ale ciągle chyba łatwiejsze od precyzyjnego modelowania pół-przezroczystych skrzydełek muchy.
[sample - light_tex_bug] (i rendering)
Notka: ustawianie tekstury światłom jest w sumie podobnym trickiem co używanie modyfikatora UVProject z teksturą materiałów. Różnica polega na tym że tekstura światła działa wszędzie gdzie pada światło, nie trzeba modyfikować materiałów.
Proste sztuczki z renderowaniem.
[docs - rozdział
"Rendering" podręcznika]
Omówimy pokrótce najważniejsze / najciekawsze (patrz manual po więcej):
Textura wpływająca na background: czyli użyj tekstury (może prostego obrazka?) jako tło renderingu. Na World, na teksturę, zmień typ na "World", zwiększ "Influence" dla "Horizon". Można też użyć tekstury proceduralnej, można też użyć Influence dla Blend aby wymieszać dwa kolory (albo kolor z teksturą).
Edge, Edge Settings (EInt = edge intensity). Proste renderowanie obrysu obiektów, dla > 10 wszystkie edges mogą być rysowane (dla <= 10 tylko silhouette). Np. w połączeniu z toon shading daje nam zupełnie kreskówkowe efekty.
Render Display: pozwala przekierować wynik renderowania do UV/Image Editor, który często jest wygodniejszy od tradycyjnego pop-up okienka z wynikiem. Będzie też wygodny żeby oglądać render-layers, o tym za chwilę.
Link Scene (ten combo box do wyboru sceny): pozwala dołączać inną scenę z tego samego pliku blend do renderingu. Wygodne np. kiedy nasz świat do renderowania jest tak olbrzymi, że 20 warstw Blendera nam nie wystarcza i chcemy rozbić nasz świat na sceny Blendera.
W render window:
Pokaż alpha layer. Tak jest, alpha channel obrazka jest renderowany. Jeżeli wybierzemy np. output format PNG + RGBA, wtedy alpha channel będzie nawet elegancko zapisany w pliku. To jest świetne jeżeli chcemy np. renderować sprite'y (potworków, wybuchów etc.) do gry.
Klawisz J: przestawia pomiędzy slotami.
Sampled Motion Blur: Zazwyczaj będziesz chciał też wyłączyć Anti-aliasing, bo "Sampled Motion Blur" już robi anti-aliasing.
W zasadzie, Sampled Motion Blur to uogólnienie statycznego Anti-aliasing, tyle że działa trochę wolniej ponieważ zakłada że każda ramka jest inna ze względu na animację.). Samples mówi ile klatek wziąć, a Shutter mówi w ciągu jakiego czasu je wziąć (w klatkach Blendera). Czyli np. Shutter = 2.0 oznacza że wynik renderingu pokazuje położenie w czasie 2 klatek naokoło (czyli 1 klatka przed i po aktualną klatką). Samples mówi ile obrazków zostało przez ten czas wyrenderowanych — większa wartość to lepsza jakość ale i dłuższe renderowanie.
Render-layer to nazwana lista warstw do renderowania. Można myśleć że Render-layer to zestaw ustawień do renderowania. Każde render-layer powoduje inny rendering, te renderingi będziemy mogli za chwilę mieszać ze sobą w różny sposób.
Żeby warstwa była renderowana, musi być włączona i w aktualnym render-layer, i być widoczna (czyli włączona "normalnie", w widoku 3D).
Ustawienia Solid, Halo etc. kontrolują co właściwie będzie renderowane w danym render-layer, np. można wyłączyć renderowanie obiektów wypełnionych (Solid, czyli meshy, surface etc.), tła (Sky, czyli z ustawień World). Szczerze mówiąc, już tutaj możemy robić pewne sztuczki do nietypowych filmów, np. wyrenderować same krawędzie albo tylko halo obiektu bez właściwego obiektu.
Ponadto każde render-layer ma swoje ustawienia "Deliver ..." (te przyciski na dole). One mówią co będzie dostarczone do compositora przez ten render-layer, o tym za chwilę.
Wszystkie render-layer są renderowane jednocześnie. Widać to kiedy przekierujemy wynik render do Image Editor, możemy wtedy oglądać wynik renderowania każdego render-layer z osobna. Przyciskiem "Single" możemy włączyć renderowanie tylko aktywnego render-layer, ponadto mamy checkbox obok każdej render-layer żeby swobodnie włączać/wyłączać render-layer jak chcemy.
Compositing, Compositor nodes.
[docs -
rozdział "Compositing" z podręcznika]
Jest to przyjemny sposób post-processingu obrazka, przyjemny tym bardziej że okienko i interfejs już znamy — pracujemy w Node Editor, które już poznaliśmy przy okazji Material Nodes.
W okienku nodes, przełączamy się na compositor nodes. Cała scena może mieć tylko jedną mapę compositor nodes. Klikamy na Use Nodes... i już wszystko wiemy. Dostajemy podstawowy node wejściowy Render layer, czyli wynik renderowania pojedynczej render-layer. I dostajemy podstawowy node wyjściowy, czyli Composite. Pozostaje jeszcze włączyć "Do Composite" na panelu "Render buttons" (F10), żeby Blender faktycznie generował jako wynik renderowania to co wychodzi z mapy composite, czyli to co dostajemy w ostatecznym węźle Composite.
Zmiany parametrów nodes są na bieżąco widoczne w podglądzie węzła composite.
Kiedy przekierujemy wynik renderowania do Image Editor (co jest zdecydowanie zalecane przy pracy z composite nodes) będziemy mogli oglądać zarówno wszystkie render-layers i ostateczny wynik composite. Możemy wtedy obserwować wynik zmian parametrów nodes w pełnej okazałości, Blender po prostu przelicza te części grafu composite które się zmieniły.
I w zasadzie to wszystko o compositor nodes... Odtąd operujemy węzłami, dodajemy, grupujemy, przepinamy je tak samo jak material nodes. Tyle że mamy nieco inny zestaw nodes, pozostaje je tylko omówić — na oko jest ich zaledwie około 40 :) No dobrze, kilka najważniejszych uwag (ale naprawdę, kto chce się tym pobawić musi przeglądnąć podręcznik, zawiera pełne omówienie, z wieloma przykładami, wszystkich nodes):
Render layer: jak już wiemy, to jest obrazek wyrenderowany przez daną render-layer. Zwróćmy uwagę że poza Image ma też inne wyjścia: Alpha (np. aby prosto nałożyć jedno render-layer na inne), Z (wyniki Z bufora, czyli odległości od kamery; do wielu sztuczek) i wiele innych: każdy przycisk "Deliver ..." w ustawieniach naszego render-layer daje nam dodatkowe dane na wyjściu którymi możemy teraz operować.
Image pozwala użyć gotowego obrazka (a nawet filmu) jako dane wejściowe.
Texture pozwala użyć tekstury Blendera (a więc także tekstur proceduralnych, 3D) jako dane wejściowe.
Viewer to prosty node wyjściowy, pomocny jako "preview" które możemy wstawić aby zobaczyć wynik compositora w danym punkcie.
Węzły jak Hue Saturation Value, Brightness / Contrast, Gamma, RGB Curves są bardzo pomocne do różnego rodzaju korekcji kolorów obrazu. Możemy w ten sposób łatwo nadać scenie inny odcień ("ciepło"), jasność, etc.
Vector Blur: metoda robienia blur na podstawie kierunku ruchu, alternatywna (i szybsza w renderowaniu) od MBlur. Wystarczy włączyć "Vec" ("Deliver Speed Vector pass") w render-layer, i użyć węzła Vector Blur, jako wejście podając mu nasze Image, Z, Speed.
Blur to rozmywania obrazka. Np. żeby zrobić blur na dalszych obiektach wystarczy podłączyć Z wyjściowe z render-layer do Size węzła Blur. Trzeba jeszcze zwiększyć X, Y węzła blur: X, Y są mnożone przez Size, więc wszystkie muszą być > 0 żeby był jakikolwiek blur.
W razie potrzeby, można przeskalować/przesunąć wartość Z obrazka przez węzeł Map Value. Żeby "debugować" działanie ustawień wygodnie jest podłączyć sobie ColorRamp + Viewer do wyjścia z takiego "Map Values", w ten sposób widzimy wprost jakie są wartości Size używane na obrazku.
[sample - distance_blur] (i rendering)
Za pomocą blur możemy robić różnego rodzaju rozmycia. Np. depth of field możemy osiągnąć za pomocą sprytnego użycia dwóch bluri: jeden blur sprawia że obiekty przed focal plane są rozmyte, drugi blur sprawia że obiekty za focal plane są rozmyte, łączymy ich wyniki za pomocą węzła Z combine tak aby wybrać bardziej rozmytą wersję. Dokładniejszy opis jest w podręczniku, ale w nowym Blenderze można to zrobić łatwiej: węzłem Defocus.
Defocus służy wprost do robienia efektu depth of field.
Specjalnie dla tego efektu mamy też ustawienie kamery Dof Dist, czyli distance to point of focus (jak zwykle, możemy włączyć Limits kamery żeby widzieć je w widoku 3D — mały żółty krzyżyk. Uwaga: czasami trudno go zauważyć, wtedy warto najpierw ustawić na jakąś znaną wartość jak Clip Start lub End kamery, i wtedy go szukać.) Jest też Dof Ob, czyli po prostu obiekt na którym ma być focus, w nowszym Blenderze.
Przy włączonym Preview, bardzo kiepska wersja efektu (ale szybka!) będzie widoczna. Po dopasowaniu wszystkiego, możemy wyłączyć Preview i podziwiać efekt.
No zbuffer jest do specjalnych sztuczek, kiedy podłączamy Z z obrazka zazwyczaj chcemy go wyłączyć — innymi słowy, używać Z z obrazka.
fStop to najważniejszy parametr kontrolujący rozmycie. 128 = brak rozmycia, mniejsze wartości powodują większe rozmycie.
Naturalnie pamiętajcie że "dane wejściowe" dla compositora to pojedyncze render-layer. Więc wszystkie efekty compositora można aplikować tylko na wybrane warstwy (np. tylko na wybrane obiekty), można też aplikować inne efekty na różne rodzaje elementów (np. zrobić specjalne render-layer tylko dla Edges obrazka, aby je rozmyć). Możliwości jest milion...
[docs - cały rozdział "Animation Basics"]
Czas: na headerze mamy liczbę = current animation frame, czyli po prostu czas. Czas jest w klatkach animacji — domyślnie mamy 25 klatek na sekundę, co jest prawie zawsze Ok. Ctrl+T przestawia pomiędzy osią ramek/sekund.
Możemy zmieniać czas jak normalne slidery Blendera (klikając na strzałki, kliknięcie z Shiftem pozwala wpisać nową wartość z klawiatury). Mamy też wygodne skróty: strzałka lewo/prawo (-1,+1), dół/góra (-10,+10) (dół/góra pozwalają iść tylko tam gdzie są klatki kluczowe, o tym zaraz).
W nowym Blenderze zakres ramek jest swobodny, mogą być ujemne jeśli chcemy. Umieszczamy naszą animację w czasie tak jak chcemy.
Start/End to zakres filmu który jest renderowany. Nic nam nie przeszkadza tworzyć animacje poza tym zakresem, to jest tylko informacja które ramki renderować kiedy klikniemy "Animation". Klawisze S i E pozwalają łatwo ustawić aktualną ramkę na Start lub End. Mamy też alternative zakres start/end (przełączamy się na niego pod przyciskiem z zegarkiem na headerze), to zmienia zakres animacji tylko dla Alt+A — wygodne żeby oglądać pod Alt+A preview tylko kawałka animacji.
Pierwsze zabawy: Insert Keyframe: Insert Key (klawisz I) to podstawowy przycisk do robienia animacji. Idea: zapamiętaj, dla aktualnego numeru klatki, położenie/wartość/etc. (wiele opcji) aktualnego obiektu.
Czyli najprostsza animacja: insert key np. pozycji obiektu na frame 1, potem idź do frame 11, przesuń obiekt i znowu insert key pozycji tego samego obiektu. Efekt: mamy animację która od ramki 1 do 11 będzie przesuwała dany obiekt.
Podstawy oglądania animacji: klawisz Alt+A włącza animację w widoku 3D (Escape wyłącza). To jest bardzo szybki podgląd animacji (ponieważ jest renderowany tak samo jak normalny widok 3D, czyli OpenGLem), więc będziemy tego używać co chwila kiedy robimy animację. W nowym Blenderze można nawet edytować scenę w trakcie animacji.
Można też po prostu "chodzić" po klatkach zmieniając aktualną ramkę. Jak widać, ramki na których nie ustawiliśmy explicite key (np. ramki pomiędzy 2-10 w przykładzie, de facto także wszystkie ramki powyżej 12) mają daną wartość interpolowaną, czyli Blender sam robi gładkie przejście pomiędzy jednym key a drugim. My ustawiamy key tylko w kluczowych ramkach, Blender sam robi "przejścia".
Notka: kiedy założyliśmy key na jakiejś wartości, a potem ją zmienimy i nie założymy od nowa key (np. załóż key na location, potem przesuń obiekt) to ta zmiana jest bardzo chwilowa, i generalnie zniknie podczas wielu operacji (jak zmiana i powrót ramki, albo render). Czyli: jeżeli na jakiejś wartości (np. pozycji obiektu) założyliście chociaż jeden key (w jakiejkolwiek ramce), to już zawsze pamiętajcie żeby po przesunięciu obiektu w którejkolwiek ramce założyć key. Inaczej Wasza zmiana zniknie.
W ustawieniach mamy Automatic keyframe (ten przycisk jak "record"), i można wybrać keying set — czyli na jakich wartościach ustawiamy klucze. Jest to wygodne, unika problemu z zapominaniem o klawiszu I. Ale ostrożnie — zazwyczaj nie chcemy tworzyć zbyt dużo niepotrzebych keys po drodze. Jak to wygląda wewnętrznie (w Graph Editorze) za chwilę.
Klawisz insert key w widoku 3D ustawia key dla obiektu. Ale właściwie możemy ustawić klucz na wszystkim — wystarczy kliknąć I kiedy mysz jest ponad odpowiednią kontrolką (np. kolory i inne właściwości materiałów, textur etc., także wartości dyskretne jak aktualna warstaw).
Renderowanie animacji:
Na zakładce Output ustawcie katalog gdzie ma być zapamiętany plik (albo pliki) z wyrenderowaną animacją.
Na zakładce Format można ustawić typ output, np. AVI Raw
albo AVI Jpeg. Jeżeli output będzie wskazywał na normalny obrazek
(np. sam Jpeg) to w katalogu Output zostanie zapisany ciąg plików
w stylu 0001.jpg
, 0002.jpg
, 0003.jpg
Samo renderowanie: klikamy wielki przycisk "Animation" i czekamy... Zapewne warto w trakcie pracy renderować tylko małe kawałki, i ze zmniejszonymi % resolution.
Formaty filmów:
Uwagi o formatach filmów. Są dwie rzeczy:
1. sposób kompresji (kodowania) filmu, i
2. sposób opakowania filmu (wrapper, , czasami nazywany po prostu "formatem pliku").
Samo opakowanie determinuje rozszerzenie pliku
(.avi
, .ogg
, .mpg
),
mówi jak zapisywane są metadane i jak przeplatać dźwięk z obrazem.
Generalnie, te dwie rzeczy są ortogonalne (z pewnymi "haczykami").
See
What is a Codec (e.g. DivX?), and how does it differ from a File Format (e.g. MPG)?
"raw" (dosłownie: surowy) oznacza "nieskompresowany". AVI raw to jest by design format który w żaden sposób nie kompresuje obrazków, w szczególności nie powoduje żadnej straty jakości, ale zazwyczaj produkuje olbrzymie pliki. Używajcie tylko jeżeli macie duży dysk, i jeżeli chcecie później Wasz film przetwarzać innymi narzędziami i nie chcecie tracić jakości.
Jeżeli chcesz skompresować plik, wybierz format inny niż "AVI raw".
AVI jpeg kompresuje każdy obrazek z osobna standardową kompresją jpeg. To jest kompresja stratna (tak jak jpeg; jest suwak "Quality" żeby dostosować jakość). W praktyce nie jest najgorsza, ale wiele playerów jej nie obsługuje. Poza tym nie jest to też najlepsza kompresja — kompresuje każdy obrazek z osobna.
W praktyce, raczej nie używajcie — chyba że opcje poniżej nie działają, np. bo nie ma zainstalowanych bibliotek. Ta opcja nie wymaga żadnej egzotycznej biblioteki, i w praktyce jest zawsze dostępna.
H.264, MPEG, OggTheora to popularne formaty obsługiwane przez wiele programów.
OggTheora jest szczególnie ukochany w open-source, bo bez patentów i z otwartą implementacją, ale z kolei poza Linuxem niektóre playery go nie obsługują (chociaż to hopefully szybko się zmieni z wejściem HTMLa 5).
H.264 i MPEG są obsługiwane właściwie wszędzie (chociaż gdzieniegdzie niechętnie ze względu na patenty).
We wszystkich trzech wypadkach, możesz rozwinąć panel "Encoding" (zaraz pod panelem "Output" gdzie wybierasz format) i dostosować jakość/format kompresji. Zauważysz tam także że de facto powyższe omówienie to mocne uproszczenie — format kompresji obrazu (jak Theora) jest w pewnej mierze ortogonalny do formatu "opakowania" pliku (jak Ogg).
Workflow robienia filmów:
Można wygenerować od razu skompresowany film Blenderem. Albo można wygenerować Blenderem film nieskompresowany (jako "AVI raw", albo wręcz ciąg obrazków jak PNG), i dopiero później go przetwarzać. To drugie rozwiązanie wymaga olbrzymiej ilości miejsca na dysku (20-30 GB na kilku-minutowy film to normalne), ale w zamian za to można swobodnie później bawić się sposobem kompresji filmu (bez potrzeby ponownego renderowania wszystkiego).
Nieskompresowany film (ciąg obrazków lub "AVI raw") można
przetwarzać na film końcowy różnymi programami.
Pod Linuxem, polecam ffmpeg
i mencoder
do przetwarzania
filmów w trybie wsadowym, oba open-source i z milionem opcji.
(De facto, wewnątrz Blendera znajduje się biblioteka ffmpeg.)
Są też bardziej przyjazne edytory filmów z GUI, to już pogooglujcie sami.
Samym Blenderem można też przetwarzać filmy. Używamy do tego "Video Sequencera" (zmień widok z "Default" na "Video Editing" w Blenderze). "Video Sequencer" to całkiem powerski edytor filmów wmontowany w Blendera — można go używać do przetwarzania dowolnych filmów (nie tylko tych które stworzyliśmy renderując animację Blendera).
VSE operuje na gotowych paskach animacji. Paski animacji to gotowe filmy, dźwięki, a także animacje ze scen Blendera. Możemy w nim sklejać, edytować i nakładać efekty na takie paski. To jest ostateczny etap produkcji filmu w Blenderze.
Samo okienko VSE ma kilka własnych trybów. Najważniejszy to Sequence, i nim się najpierw zajmiemy. Widzimy w nim paski naszej animacji rozpięte w czasie. Poruszanie się w okienku jak zwykle (Shift+MMB przesuwa okienko, Ctrl+MMB skaluje). Klawisz T przestawia czy widzimy podziałkę z sekundami czy z ramkami.
Add Sequence Strip (pod spacją, jest też menu Add na headerze)
to podstawowa operacja. Możemy dodawać gotowe filmy, audio (audio połączone
z video też jest Ok), więc można nawet używać VSE jako edytora filmów
zupełnie bez związku z 3D ani z resztą Blendera. Możemy też
dodawać film skomponowany z obrazków (to jest też odpowiedź na
pytanie "co zrobić kiedy przez przypadek wyrenderowałem moją animację
do ciągu obrazków zamiast do jednego pliku z filmem — czy muszę
renderować od nowa?" odp: nie, można te obrazki połączyć w film używając
VSE; chociaż ffmpeg -f image2 -i %04d.jpg /tmp/a.mpg
też działa
Ok). Naturalnie jest też strip Scene,
czyli animacja sceny z aktualnego pliku Blendera.
Channels — channel (kanał) to jedna pozioma linia w VSE. Channel 0 jest specjalny (to jest channel do którego trafia wynik miksowania VSE), do pozostałych kanałów swobodnie dodajemy i rozmieszczamy nasze strips. W jednym miejscu jednego kanału może być tylko jeden strip (ale możemy swobodnie wrzucać wiele strips do jednego kanału jeżeli nie zachodzą na siebie).
To wszystko można "poczuć" kiedy spróbujemy przesuwać kanały (jak zwykle w Blenderze, G). Wiele normalnych operacji na strips działa jak wszędzie w Blenderze (zaznaczanie RMB, A, A A, border select B, kasowanie X). LMB zmienia aktualny czas w VSE.
Inne tryby VSE: tryby Image Preview, Histogram i inne pozwalają oglądać w VSE podgląd i rozkład kolorów w aktualnej ramce. Możemy zauważyć że mają kontrolkę Chan pozwalającą wybrać który kanał oglądamy — przypominam że channel 0 to po prostu wynik VSE. Co dokładnie znaczy luma i chroma i do czego mogą się przydać przy edycji filmów — patrz manual. Uwaga: kiedy mamy strip ze sceny Blendera (tzn. strip Scene), każdy z tych podglądów wymaga faktycznego wyrenderowania jednej klatki naszej animacji — a więc działa trochę wolno. W praktyce, albo nie używamy podglądów, albo pracujemy z gotowym, wyrenderowanym wcześniej do pliku filmem.
Renderujemy VSE włączając "Sequence" w Post-Processing (domyślnie jest już włączone) i klikając normalne "Animaion" Blendera. To miksuje filmy, dźwięki, nakłada efekty (za chwilę), w przypadku animacji Scene po prostu ją renderuje. Przy okazji zwróćmy uwagę: przycisk "Composite" ciągle określa czy scena przechodzi przez compositor nodes. Czyli jeżeli używamy sceny z composite, i używamy VSE, to włączamy zarówno "Composite" i "Sequence", i wtedy rendering przechodzi przez compositor nodes zanim trafi i zostanie zmiksowany przez VSE.
Operacje edycyjne na stripach: Paski możemy ciąć, jak przystało na video edytor: po prostu zaznacz pasek (RMB), zaznacz czas (LMB) i tnij (K). Potem zaznacz i skasuj (X) niechcianą część. Możemy też duplikować paski (Shift+D).
I to były podstawy VSE. Umiemy łączyć i edytować paski animacji. Co dalej? Istnieje wiele efektów które możemy wykonać w VSE. W przeciwieństwie do efektów compositora, które skupiają się na post-processingu jednego obrazka, efekty VSE skupiają się na łączeniu kilku stripów animacji i efektach zmieniających się w czasie. Pełna referencja efektów: patrz "VSE Built-in Effects" oraz "VSE plugins".
Demo prostych efektów: Cross, Add, Multiply. Notka: strip bardziej na górze jest widoczny, więc zazwyczaj chcemy trzymać efekty jak Cross czy Multiply ponad pozostałymi strips, inaczej byłyby przez nie zasłaniane.
Pokaż Alpha Over - łączenie filmu z renderowaną sceną?
[sample - gate_composite_vse] (i wyrenderowany filmik)
Demo efektu z pluginu: cartoon.
[sample - octopus_vse_cartoon_plugin] (i wyrenderowany filmik)
Mamy cały panel z konfiguracją strips: F10 dwa razy (Sequencer buttons).
Graph Editor. [docs - referencja okienka Ipo Curve Editor (obecnie Graph Editor)]
Pozwala bardziej bezpośrednio obserwować i edytować wszystkie założone keys, oraz interpolację pomiędzy nimi (czyli motion curve), na przestrzeni czasu.
Można przesuwać się podobnie jak w normalnym widoku: MMB, Shift+MMB, Ctrl+MMB, mouse wheel. Pionowa kreska pokazuje aktualny czas, LMB zmienia czas. Kiedy zgubicie się, zawsze działa Home, ciemniejsze paski na liniach czasu i wartości pokazują jaki zakres punktów aktualnie widać (całe ciemne = widzicie wszystkie keys).
Niespodzianka: Graph Editor działa stosunkowo podobnie jak edycja curve. Tak, każda krzywa ruchu to po prostu krzywa 2D Beziera (chociaż można to przestawiać Curve->Interpolation Mode na constant albo linear). Można śmiało wejść w tryb edycji dowolnej krzywej (Tab) i edytować uchwyty / punkty kontrolne w sposób znany nam z wykładu o krzywych (łącznie ze zmianą Handle Type pomiędzy Vector, Free, Aligned, i Auto Aligned). Ogólnie, większość poleceń i skrótów klawiszowych znanych z normalnej edycji krzywych mamy dostępne i tutaj. Naturalnie, krzywa musi pozostać funkcją czas->wartość, więc nie możemy jej "zawrócić", przerwać, zamknąć etc. Ctrl+click dodaje punkty, hint: pozwala łatwo zrobić cokolwiek losowy ruch obiektu.
Jak widać, insert key to tak naprawdę tylko skrót do dodania punktu (rodzaju Auto Aligned) na motion curve dla danej wartości w danej klatce. Patrząc na Graph Editor, widzimy co się dzieje "wewnątrz". Jeżeli trzeba, to można operować tylko krzywymi w Graph editor (tzw. f-curves), nie używając insert key. Wewnętrznie, Blender animuje więc dowolną wartość wzdłuż krzywej — ustawianie keys to tylko jeden ze sposobów ustalania tej krzywej.
Modyfikatory na curve, jak noise.
Prawie wszystkie wartości są animowalne. Wystarczy ustawić mysz ponad wartością w panelu, i przycisnąć I jak "insert key". Dodamy w ten sposób nową krzywą do okienka Graph Editor, początkowo z jednym punktem.
W Graph Editor widzimy wszystkie krzywe, czyli channels, czyli animowane wartości aktywnego obiektu. Zaznaczanie na obszarze kanałów działa (A, A A, LMB, Shift+LMB, B jak box, etc.), także kasowanie: X. Checkboxy po lewej określają które krzywe widzimy i edytujemy, przydatny klawisz V (toggle visibility): ustawia widoczne := zaznaczone.
Demo: I ponad Location / Rotation / Scale w "Object". Także "Delta Transform", czasami wygodne żeby móc swobodnie przesuwać obiekt w widoku 3D (bez żadnych insert key) i ciągle mieć krzywą ruchu dla tego obiektu.
Channel -> Extrapolation mode określa co dzieje się z wartościami poza zakresem punktów kontrolnych.
Krzywe layer: pozwalają zmieniać istnienie obiektu na odpowiedniej warstwie w trakcie animacji. Warstwy mają wpływ na rendering kiedy niektóre są ukryte (w ten sposób można ukrywać/pokazywać postać) albo kiedy są światła ustawione z Layer (w ten sposób postać jest nagle oświetlona innym światłem). Przejście pomiędzy warstwami jest zawsze nagłe, krzywa ma zawsze interpolation mode = constant. Nie można w ten sposób ładnie sprawiać że jakiś obiekt się pojawia/znika, do tego trzeba używać animacji alpha materiału.
Bardzo wiele rzeczy może mieć swoje Graph Curve, nie tylko obiekt. Także świat (World), materiał aktywnego obiektu, tekstura aktywnego obiektu... Możemy wybrać też coś innego niż mesh: mamy edycję parametrów światła, parametrów Curve (tylko channel Speed, bardzo użyteczny, o animacji wzdłuż path jeszcze opowiemy później), i wiele innych. Opowiemy sobie o nich.
sample: animacja koloru materiału
[sample - sunrise] (i wyrenderowany filmik), animacja energy światła oraz koloru world.
sample: proste fale przez animację ustawień tekstury.
(Przypuszczamy omówienie tego na wykładzie, większość z tego już wiecie) Operowanie transformacjami:
Jak wiadomo, każdy obiekt w Blenderze ma swoją transformację i swoje center. Transformacja wyznacza wiele rzeczy, np. "local axis" (np. co się dzieje kiedy przyciskamy G, X, X). "Local axis" wyznaczają też co się dokładnie dzieje kiedy mamy np. "track to constraint" (Ctrl+T). Center też jest używane do wielu rzeczy, chociażby jako pivot do skalowania/obrotów/mirrora. Na potrzeby animacji, musimy umieć operować tymi rzeczami dobrze — ponieważ takie rzeczy jak constraints i parent to najbardziej podstawowe i proste narzędzia pomocne przy animowaniu większych scen.
Zmianę center już kiedyś pokazywałem — przyciski Center, Center New, Center Cursor Początkowo center jest tam gdzie był kursor kiedy dodawaliśmy obiekt.
Widzimy transformację jako liczby w "transform properties" (klawisz N, ale to już znacie, prawda?), możemy ją też tam zmieniać kiedy znamy wartości liczbowe do jakich dążymy. Naturalnym sposobem zmiany transformacji jest po prostu zrobienie przesunięcia/obrotu etc. obiektu. Inne sposoby o których teraz warto powiedzieć: Clear/Apply z menu transform->clear/apply w object mode. Clear oznacza po prostu wyczyszczenie transformacji, a apply oznacza nałożenie transformacji na wierzchołki po czym wyczyszczenie jej — czyli apply czyści transformację obiektu jednocześnie nie zmieniając tego jak obiekt wygląda.
Inne pożyteczne funkcje: copy attributes pozwala skopiować dowolny element transformacji z jednego obiektu na drugi.
sample parenting.
Constraints czyli ograniczenia obiektu. Każde constraint ma nazwę (na czerwono jeśli constraint z jakiegoś powodu nie działa, np. nie wypełniono nazwy target Ob albo przy Track To osie To i Up są takie same) oraz influence (które zresztą też może być animowane, patrz przyciski Key i Show). Króciutkie omówienie najprostszych:
Copy Location (dowolna kombinacja 3 wymiarów, ew. z negacją), Copy Rotation, Copy Scale. Pozwalają w bardziej elastyczny sposób uzyskiwać trochę to samo co robi za nas parenting, czyli śledzenie transformacji jednego obiektu przez drugi.
Limit Location, Rotation, Scale, czyli ograniczenia na transformację. Używane często kiedy wpływ czegoś innego (chociażby powyższe Copy ...) ma być ograniczony do jakiegoś zakresu.
Track To. To już znamy i używaliśmy — oś jednego obiektu wskazuje na inny. Użyteczne żeby kamera patrzyła na dany obiekt, źródło światła świeciło na dany obiekt i generalnie żeby jeden obiekt wskazywał na coś.
Locked Track. Coś jak Track To, ale jedna oś rotacji jest ograniczona — dobry przykład to wskazówka kompasu.
sample: compass.
Floor: blokuj pozycję obiektu według zadanego plane.
Stretch: obiekt jest spłaszczany w Y (i ew. rozciągany) kiedy zbliża się do target.
Animacja za pomocą krzywych w 3D (follow path).
Dowolny obiekt może podążać wzdłuż path, czyli po prostu krzywej w trybie 3D. Notka: można animować także kamerę (wzdłuż krzywej, albo zwyczajnie zmieniając jej location/rotation etc., jak wyżej).
Można użyć dowolnej krzywej, trzeba jej włączyć Path animation i ustawić w tryb 3D. Jeżeli dodamy obiekt Path w Blenderze to dostaniemy krzywą NURBS (z knot endpoints) z zaznaczonymi powyższymi opcjami. (Czyli nie ma żadnej "magii" w obiekcie Path, moglibyśmy to samo zrobić z dowolną krzywą dodaną z grupy Curves).
Jak przypisać obiekt do ścieżki?
Stara metoda: uczyń ścieżkę rodzicem (parent, Ctrl+P) obiektu.
Hint: Shift+Ctrl+P (make parent without inverse) zamiast Ctrl+P sprawi że obiekt dziecko będzie położony i obrócony idealnie na początku path (inaczej być może będziecie musieli "walczyć" z faktem że domyślne położenie obiektu jest nieco przesunięte względem ścieżki).
Przycisk "Follow" na "Path animation" krzywej pozwala obiektowi używać też kierunku i nachylenia krzywej. Bez "Follow" obiekt jest tylko przesuwany wzdłuż ścieżki, i nic więcej.
Nowa metoda: Add Constraint -> Follow Path na obiekcie który ma podążać wzdłuż ścieżki.
Żeby obiekt był położony idealnie na początku ścieżki można wyczyścić jego location, Alt+G (a także rotation jeżeli jego nachylenie ma być początkowo takie jak ścieżki, Alt+R).
Ustawienia axis mamy teraz w panelu dla danego constrainta (constraint = ograniczenie). Tam jest "Follow" (używaj kierunku i up ścieżki) oraz ustawienia mówiące jakie osie naszego obiektu są uważane za kierunek i up.
Jak widać jest wygodniej, mamy wszystkie ustawienia w jednym miejscu, ponadto wpływ constraint można regulować (Influence constrainta) i łączyć z innymi constraints dla skomplikowanych animacji.
Animujemy prędkość ruchu wzdłuż krzywej poprzez parametr "Path animation -> Evaluation Time" krzywej. Parametr "Path animation -> Frames" określa skalowanie dla "Evaluation Time", żeby było wygodniej. Naturalnie można bawić się tą krzywą, zmieniać kierunek ruchu etc.
Jak widać, ścieżka w 3D jest wyświetlana trochę inaczej: ma strzałki które określają kierunek ruchu. Można go zmieniać przez W -> Switch Direction w edit mode. (bardziej wewnętrznie, kierunek mówi gdzie jest punkt 0.0 ścieżki a gdzie 1.0; de facto nachylenie krzywej "Evaluation Time" też kontroluje co jest początkiem a co końcem).
[sample - eye_chopper] - flying along the curve.
sample: karuzela.
Notka: path może sama podążać wzdłuż innej path.
Animacja poprzez deformację:
Hooks: przypisujemy obiekt (zazwyczaj Empty) jako hook innego obiektu (np. mesha, ale też curve, lattice, surface) poprzez modyfikator Hook. Efekt: transformacje obiektu Empty powoduje lokalną deformację tego innego obiektu.
Przykład: za pomocą hook możemy np. otworzyć usta, zrobić uśmiech, zamknąć / otworzyć oczy.
Jest to najprostsza metoda deformacji, najmniej czasochłonna ale też najmniej elastyczna.
Tworzenie jest trywialne: w edit mode zaznacz wierzchołki które chcesz deformować. Potem dodaj hook przez Ctrl+H, pojawi się menu które pozwala wybrać dodanie do nowego Empty albo dodanie do zaznaczonego innego obiektu (tak, możesz zaznaczyć inny obiekt w edit mode: Ctrl+RMB).
Efekt jest dość intuicyjny, tak jak mieliśmy parent w object mode, tak teraz hook jest parentem zaznaczonych wierzchołków.
Kiedy już mamy jakieś hooks, menu pod Ctrl+H zawiera dodatkowe opcje do łatwego usuwania, przypisywania na nowo, zaznaczania, albo usuwania deformacji danego hooka (wszystkie opcje z "..." pytają nas na jakim hook mają działać). Ponadto, każdy hook jest także modyfikatorem, więc możemy je też usuwać jako modyfikator i konfigurować (Falloff i Recenter pozwalają nam ustawić hook który wpływa tylko na wierzchołki w danym promieniu, Force jest jasne).
Shape Keys:
Shape key to po prostu zapamiętane ułożenie wierzchołków. Animacja pomiędzy różnymi shape keys pozwala na swobodną deformację pomiędzy dowolnymi obiektami (ale topologicznie równoważnymi, tzn. połączenia muszą być takie same, wolno nam tylko swobodnie przesuwać wierzchołki; kiedy zmienimy topologię, zmiana pojawi się we wszystkich shapes, zazwyczaj nie chcemy się tak bawić). Wewnętrznie, każdy shape key to zapamiętana zmiana przesunięcia wierzchołków w stosunku do oryginału.
Samo tworzenie shape keys jest łatwe, dodaj shape keys w "Object Data". Jak nazwa sugeruje, pierwsze shape key, "Basis", jest trochę specjalne — powinno określać pozycję bazową (pozostałe będą pamiętane względem niego). Pozostałe shape key to modyfikacja tego basis. (De facto, bardziej skomplikowane ustawienia są możliwe, patrz checkbox "relative" oraz "Blend->Shape used as relative key". Ale zazwyczaj ich nie potrzebujemy. Jedno "Basis" + wszystkie pozostaje shape względem Basis zazwyczaj wystarcza.) Każdy shape key (poza Basis) ma swoje "Value", czyli jak bardzo modyfikuje mesh — i to jest parametr który będziemy animować (kliknij I ponad nim) kiedy już stworzymy nasze shape keys.
W Graph editor dla danego obiektu możemy przełączyć się na Shapes. Krzywa dla każdego shape określa jak duży wpływ ma dany shape na mesha. Mówiąc wprost, wartość tej krzywej jest mnożona przez wszystkie zmiany w danym shape. Czyli 0 oznacza że shape nie ma wpływu, 1 oznacza że shape jest w pełni zaaplikowany do mesha. Tak, możemy nawet przesuwać krzywą na wartości mniejsze od 0 albo większe od 1, chociaż zazwyczaj ma to mały sens.
Naturalnie, zaletą tej zabawki jest że można na raz robić blend wielu shapes. Np. jeden shape zamyka oczy, drugi wygina usta w uśmiechu etc.
Wpływ shape można też mnożyć per-vertex ustawiając mu odpowiednie vertex group.
Patrz także na zaznaczonych wierzchołkach W -> Shape Propagate oraz W -> Blend from Shape.
sample: head_anim.
Lattice:
Możemy potraktować Lattice poprzednimi technikami, tzn. użyć Hook albo Shape Key na Lattice. Jeżeli Lattice wpływa na innego mesha, to animując Lattice animujemy też (potencjalnie bardziej skomplikowany) inny obiekt.
Inny sposób animacji przez lattice: "przeciskanie" obiektu przez lattice. Pamiętajcie że to jak lattice obejmuje nasz obiekt w object mode, wpływa na to jak lattice deformuje nasz obiekt. Czyli jeżeli przesuwamy obiekt, ale lattice nie (albo na odwrót) to obiekt jest przeciskany przez lattice.
sample: Dżin w butelce
... i inne obiekty deformujące: Mesh Deform Modifier w Blenderze z SVN, całkiem jak Lattice tyle że teraz dowolny mesh może modyfikować innego mesha. Jest to ogólne narzędzie do modelowania, tak samo jak Lattice, w szczególności można go też używać do modelowania, analogicznie jak Lattice.
Uwaga: to nie wszystko. Jak łatwo sobie wyobrazić, robienie skomplikowanej animacji przez deformację zbyt szybko sprowadza się do modelowania każdej pozy osobno, poza tym mamy dość małą kontrolę nad przejściami pomiędzy pozami. Lattice pomaga tylko w niektórych przypadkach. Cały następny wykład będzie poświęcony kolejnej, niezwykle elastycznej metodzie animowania meshy (i innych obiektów): armature, czyli szkielety i kości.
Zadanie składa się z czterech punktów, ale don't panic. Nie zależy nam na żadnym specjalnym modelowaniu, byle tylko była sugestia tego o czym piszę. Nie zależy nam też na żadnych materiałach ani oświetleniu ani kamerze, w ogóle nie zależy nam na renderowaniu. Animacje które stworzycie powinny być w 100% obserwowalne w interaktywnym widoku Blendera (pod Alt+A etc.). Obok screen z moim wynikiem podpunktów 1-2: o coś takiego mi chodzi.
Zabawa z ruchem wzdłuż krzywej:
Stwórz prosty teren z dwoma wzgórzami (zwykły grid z dwoma wzgórzami wyciągnietymi przez proportional editing jest Ok).
Stwórz tory które leżą mniej-więcej na powierzchni tego terenu i przechodzą przez szczyty obu wzgórz. Tory mają być stworzone przez proste wygięcie przekroju torów wzdłuż krzywej, zupełnie tak samo jak robiliśmy w zadaniu Ride through the mines.
Stwórz prosty model wagonika. Może być naprawdę trywialny, wystarczy sześcian z usuniętą górną ścianą i nieco zwężonym dołem.
Podczep pod wagonik 4 kółka, tak żeby wagonik był parentem kółek (przesunięcia/obroty etc. wagonika mają przesuwać też kółka). Kółka mają się obracać w nieskończoność — zrób to poprzez krzywą z Extrapolation = Linear (być może przyda się też Copy Keyframes / Paste Keyframes, jeżeli najpierw zduplikowaliście kółka a dopiero potem dodajecie animację; wystarczy dodać dowolną krzywą na Rotation przez "I", i na nią wkleić poprzednią krzywą przez Paste Keyframes). Żeby obrót kółek był widoczny, niech będą albo mocno kanciaste (np. "kółko" de facto jest 8-kątem) albo dodaj byle-jaką sugestię "szprych" w kółkach. Podkreślam żeby nie przejmować się zbytnio modelowaniem, to ma być sugestia szprych — prostopadłościany odpowiednio włożone w spłaszczony cylinder wystarczą.
Animacja jazdy wagonika: wagonik na początku jest po lewej stronie lewego wzgórza. Chcemy żeby wagonik wjechał na szczyt lewego wzgórza, potem zjechał w dół pomiędzy dwa wzgórza, potem spróbował z rozpędu wjechać na prawe wzgórze... i nie dał rady. Tuż przed szczytem prawego wzgórza, wagonik zwalnia, i zsuwa się z powrotem w dolinę pomiędzy wzgórzami. Po czym z rozpędu podjeżdza kawałek pod lewe wzgórze, zawraca i z rozpędu podjeżdża mniejszy kawałek pod prawe wzgórze, i tak kilka razy aż w końcu zatrzymuje się nieruchomo na środku pomiędzy wzgórzami.
Chcemy to zrobić przez zupełnie trywialną animację wagonika wzdłuż krzywej. Zamiast robić to przez Ctrl+P, zrobimy to lepiej: dodaj constraint Follow Path do wagonika, skonfiguruj go dobrze, po czym dodaj klatki kluczowe na Evaluation Time krzywej. Pierwszą klatkę dodajemy przez "I" kiedy mysz jest ponad kontrolką Evaluation Time, potem patrzymy na krzywą ruchu (funkcja czas->pozycja wzdłuż krzywej) w okienku Graph Editor, i ustawiamy tą krzywą tak żeby realizowała powyższą animację.
Do sceny z poprzedniego podpunktu dodaj prostą kałużę z falującą wodą:
Zrób wgłębienie w terenie (zwykłe wyciągnięcie wzgłębienia przez pociągnięcie w dół vertexa z proportional editing wystarczy).
Dodaj mały grid nieznacznie wsunięty poniżej poziomu płaskiego terenu, i ustawiony tak żeby udawał powierchnię wody w zagłębieniu.
Za pomocą modyfikatora Displace i tekstury proceduralnej (Clouds jest tutaj dobrym, ale nie jedynym, wyborem) dodaj falki na wodzie.
Animuj teksturę przesuwając jej współrzędne: Ustaw Texture Coordinates modyfikatora Displace aby współrzędne tekstury były brane z położenia nowego obiektu Empty, animuj ten Empty.
Zupełnie nie przejmujemy się materiałem wody.
Weź model głowy zrobiony na poprzedniej pracowni. Za pomocą Shape Keys dodaj animację zamykania / otwierania ust.
Do modelu głowy z poprzedniego zadania: Za pomocą Hooks dodaj animację uśmiechania się (poprzez ciagnięcie w gorę kącików ust), ale bez otwierania ust.
Pobaw się kombinacjami dwóch animacji z 3 i 4: np. uśmiech z jednoczesnym rozdziawieniem ust. Zamiast uśmiechu można wybrać inny grymas ust. Albo inny kawałek twarzy i inna animacja. Ważne jest aby pobawić się Shapes i Hooks na pobliskich miejscach twarzy.
[docs -
cały rozdział "Character Animation & Armatures"]
[Introduction to Character Animation] — świetny tutorial, przeprowadzający od absolutnych podstaw (łącznie z modelowaniem) poprzez używanie armatury, weight painting, shape keys, action editor, NLA editor. Zawiera większość informacji które będą dzisiaj na wykładzie. Polecam.
[Introduction to Rigging] — dużo wartościowych, niekiedy zaawansowanych, uwag o tworzeniu armatury. Także przykłady armatury dla konkretnych zastosowań. Polecam przejrzeć kiedy będziecie już obznajomieni z armaturą.
Sample models do dzisiejszego wykładu: "Introduction to Character Animation" zawiera gotowy model i filmik dla leniwych, można też zobaczyć na moją wersję ((i filmik z niej). Będziemy też bawić się [sample - octopus] (i wyrenderowany filmik). Pokażę zapewne też kilka stworków z mojej gry, ale nie podam linku, bo są zbyt kiepskie :)
Idea armature: w przypadku skomplikowanych obiektów, złożonych z wielu wierzchołków, których "ruch" w skomplikowany sposób wpływa na wszystkie inne wierzchołki... no właśnie, robienie animacji staje się wtedy trudniejsze. Myślimy np. o modelu człowieka, który chcemy animować tak żeby wykonał np. krok. Obiekt Armature Blendera pozwala nam zbudować coś w rodzaju szkieletu postaci z kości. Po przyczepieniu (rigging) takiego szkieletu do naszej postaci (np. mesha) będziemy mogli animować naszą postać poprzez animowanie Armature.
Sam proces rigging, tak żeby armatura pozwalała nam swobodnie operować postacią a jednocześnie nie powodowała różnych dziwnych deformacji (np. typowe problemy na zgięciach modelu — na łokciach, kolanach, pod pachami etc.) czasami nie jest łatwy. Ale robimy go raz, potem możemy już łatwo ustawiać nasz obiekt w najróżniejszych pozach. Sens armature jest taki że jest ona dużo prostsza od oryginalnego obiektu, więc łatwo nam nią operować.
Armatura daje nam kilka rzeczy: Kości są połączone, jak w drzewie, więc obracając np. ramię, obraca się też przedramię i ręka. Co lepsze, Blender, znając połączenia kości, może przeprowadzić odpowiednie obliczenia, i działa to także w drugą stronę: kiedy odpowiednio go poinstruujemy, to przesuwając rękę, ramię i przedramię zostaną odpowiednio dopasowane i obrócone, tak jak u normalnego człowieka. Drobne dodatki to łatwe pozowanie symetryczne, biblioteka póz (to ostatnie w SVN Blendera).
Zaczynamy: dodaj armature. W środku armature mamy bones, kości. Kość zachowuje się jak zwyczajny odcinek, dwa końce kości to root i tip (korzeń i czubek? Będę je nazywał zazwyczaj po prostu "początek i koniec".). Gdy jesteśmy w edit mode armatury, edytujemy właśnie kości.
W "Object Data" dla armatury mamy konfigurację wielu rzeczy. Na razie zwróćcie uwagę na różne sposoby rysowania kości — Octahedron, Stick, B-Bone, Envelope. Ponadto mamy X-Ray żeby zawsze widzieć kości (inaczej kości są często zasłonięte przez mesh w środku którego są).
Możemy zaznaczyć całą kość albo tylko jej początek/koniec. Zaznaczamy RMB, all/none (A, A), przesuwamy G, obracamy/skalujemy kość przez R/S, czyli generalnie tak jak przy normalnej edycji mesha. Dodajemy nową kość z poprzedniego punktu przez E (extrude) albo Ctrl-click, czyli też normalnie.
Nazywanie kości: wszystkie zaznaczone kości są widoczne też w zakładce "Bones". Mamy ten konfigurację każdej kości, m.in. jej nazwę. Wygodnie jest włączyć Draw Names przy nazywaniu kości.
Symetryczne tworzenie kości (bardzo użyteczne gdy mamy typowy symetryczny model): przy włączonym "X-Axis mirror" w tool sheft w Armature Options, klawisz Shift+E robi extrude symetryczne (Shift+E jest potrzebne żeby z 1 kości zrobić 2 symetryczne; potem zwykłe E działa równie dobrze, o ile tylko "X-Axis Mirror" pozostaje włączony). Od razu widać że Blender nazywa je z suffixami _L, _R — to jest bardzo dobrze. Kości nazwane w ten sposób są cały czas edytowane symetrycznie.
Jest bardzo ważne żeby nasz szkielet był ładnie połączony. Wolimy mieć połączoną armaturę, a więc używać extrude. W ten sposób kości są połączone w drzewo, kość-rodzic wpływa na (deformuje) także swoje kości-dzieci. To jest niezwykle użyteczne przy układaniu póz w pose mode.
Uwagi o ustawieniu:
Generalnie, nie obracajcie Armature względem mesha w object mode. Armatura powinna być cały czas nałożona na mesh. Zalecane jest użyć constraint Copy Location, Rotation, Scale aby związać transformację obiektu z armaturą. (lepiej nie używać normalnego parenta, powiązanie obiekt-armatura chcemy później zrobić modyfikatorem; to zdanie zyska sens za chwilę).
Ponadto, żeby używać różnych narzędzi do edycji X-axis mirror (możemy edytować kości z X-axis mirror, możemy edytować mesha, możemy robić weight painting — o tym wszystkim za chwilę) nasz model powinien być symetryczny wzdłuż lokalnej osi X. Na początku, kiedy zajmujemy się dopiero tworzeniem szkieletu, najprościej i najłatwiej jest po prostu ustawić model zgodnie z nazwami widoków: włączmy View Name (w okienku User Prerefences, zakładka View & Controls) żeby widzieć nazwę widoku. W widokach Front / Back (numpad 1 / Ctrl + numpad 1) powinniśmy widzieć właśnie przód/tył naszego człowieka, w widokach Right / Left (numpad 3 / Ctrl + numpad 3) powinniśmy widzieć człowieczka z boku. Ponadto niech lokalna oś X będzie taka sama jak globalna — innymi słowy nie obracamy obiektu ani armatury w object mode (jeżeli już to zrobiliśmy, zawsze jest Ctrl+A, "Apply scale and rotation"; obrót obiektu widzimy w "transform properties" (klawisz N) w object mode).
Pose Mode (Ctrl+Tab przełącza, gdy jesteśmy na armature).
Na razie nie dzieje się wiele ciekawego póki nie podpięliśmy jeszcze kości do mesha.
Pose Mode pozwala na przesuwanie/obracanie/skalowanie kości. Ale to co w nim robimy nie jest zapamiętywane jak w edit mode. Zamiast tego, zmiany w pose mode są jakby dodawane do armatury, tzn. oryginalna pozycja armatury pozostaje stała (i zawsze można ją zobaczyć poprzez Rest position, albo wchodząc w Edit Mode). Idea: w edit mode, dopasowujemy armaturę do mesha. Rest position armatury powinno się idealnie nakładać na mesha, żeby móc zrobić rigging. W pose mode faktycznie animujemy armaturę. Mamy insert key w pose mode, najprościej: zrób pozę jaką chcesz, potem A (zaznacz wszystkie kości) i I (insert key, np. LocRot). Zrób w ten sam sposób inną pozę w innej ramce, i zobaczysz elegancką animację pomiędzy pierwszą a drugą pozą. Czyli wracamy do sposobu robienia animacji z poprzedniego wykładu, różnica jest taka że animujemy teraz tylko pozę armatury. Naturalnie, każda kość ma swoje F-Curve, widoczną i edytowalną też w Graph Editor (przejdź na "Pose", zaznacz wybraną kość).
W pose mode mamy mniej-więcej normalne operacje przesuwania/obracania/skalowania. Gdy chcemy explicite ustawić domyślną pose, zawsze możemy zrobić Alt+R (clear rotation) i podobne dla pozycji i skali (Alt+G, Alt+S).
Tradycyjne operacje w pose mode to forward kinematics, czyli wykorzystywanie zależności parent-child kości w normalny sposób: poruszaj rodzicem żeby zmienić dziecko. Dużo wygodniejszy sposób to inverse kinematics, który możemy łatwo włączyć przez Auto IK w Blenderze. Teraz przesuwanie kości przesuwa także jej rodziców — cały szkielet (de facto, ścieżka od aktualnej kości wzdłuż jej rodziców aż do "pra-kości" (bez rodzica)) próbuje się dopasować do nowego położenia kości. Inverse kinematics wymaga nieco dostosowania przy nietrywialnej armature, ale chyba widać że pozwala dużo swobodniej i wygodniej układać różne pozy.
Checkbox Connected (Connect this bone to parent) dla kości w edit mode pozwala zerwać łańcuch IK. Np. kiedy ruszamy ręką w pose mode, chcemy zapewne żeby ramię, łokieć się odpowiednio dostosowały — ale kręgosłup nie. Oczywiście, w praktyce wszystko zależy od tego jaką swobodę chcemy sobie dać podczas animacji, jakie animacje planujemy tworzyć.
Rotacja trackball (dwa razy R) często jest wygodna do ustawiania kości. Inny sposób rotacji kości: roll, Ctrl+R (jest też na transform properties (klawisz N) dla kości).
Extrude z root kości nie ustawia tej kości jako parent. Demo: przywiązywanie nogi do głównej kości kręgosłupa. Bez "Connected", zazwyczaj.
Modyfikator Armature. Mówi żeby zmiany armature w pose mode wpływały na mesha.
Można nałożyć go ustawiając armaturę jako parent naszego obiektu, i wybierając odpowiednią opcję pod Ctrl+P (możemy tam np. od razu automatycznie ustawić wagi na podstawie envelopes, albo sprytnego algorytmu Blendera). Obecnie, takie Ctrl+P też dodaje automatycznie odpowiedni modyfikator Armature, i wszystko jest pięknie. (kiedyś, przez jakiś czas Ctrl+P było traktowane jako metoda deprecated i zalecane było dodawać modyfikator ręcznie, a synchronizację robić przez constraint "copy location"; co ciągle jest możliwe, ale obecnie to Wasz wybór, obie wersje są sensowne).
Sam modyfikator Armature nie działa magicznie (chyba że dodaliście go przez Ctrl+P, wtedy pewna magia jest automatycznie stosowana). Tzn. Blender ciągle nie wie jaka kość przesuwa jakie wierzchołki. Są dwa sposoby ustawienia tego (i można używać obu jednocześnie):
Envelopes: to jest łatwiejszy sposób, ale też działa tylko w łatwych sytuacjach.
Jeżeli wybraliśmy "Envelopes" przy modyfikatorze to po prostu zwiększamy Dist kości, on określa w jakim promieniu dana kość wpływa na mesha. Bardzo użyteczne ustawienie wyświetlania to Envelopes, aby widzieć zasięg kości w widoku 3D w edit mode.
Envelopes jest łatwe, i wtedy kiedy działa dobrze na naszym modelu — można go używać. Ale dla skomplikowanych kości/modeli nie będzie działać dobrze, w szczególności raczej nie zadziała dobrze nawet na modelu jakiegoś humanoida. Wtedy używamy vertex groups poniżej.
Jeżeli wybraliśmy "Vertex Groups" przy modyfikatorze, to musimy ustawić vertex grupy na naszym meshu które nazywają się tak samo jak kości. Vertex przypisany do grupy ma w tej grupie wagę, czyli "jak mocno będzie deformowany przez kość" — zazwyczaj 1.0, ale wartości pomiędzy 0 a 1 są bardzo ważne żeby mieć elegancko działające deformacje na zgięciach modelu (łokcie, pod pachami etc.) (animacja z użyciem wag pomiędzy 0..1 nazywana jest gdzieniegdzie "vertex blending".)
Vertex grupy i Mirror: Modyfikator Mirror trzeba albo nałożyć, albo włączyć tworzenie symetrycznych vertex grup (przez checkbox Vertex Groups w opcjach modyfikatora).
Generalnie, modyfikatory które tworzą wierzchołki daleko od innych, jak Array, zapewne chcemy nałożyć — chyba że wszystkie części mają się animować "razem". Nie trzeba nakładać Subsurfa, bo on tworzy wierzchołki mniej więcej pomiędzy oryginalnymi wierzchołkami.
Można "ręcznie" tworzyć grupy, tzn. wejść w edit mode mesha, dodać nowe grupy nazywające się tak samo jak kości, i dodawać do tych grup wierzchołki.
Naturalnie jest to potwornie męczące i niewygodne dla nietrywialnych obiektów. Nie należy tego robić w praktyce (dla trudnych obiektów jest niewygodne, dla prostych obiektów lepsze będzie Envelopes).
Weight paint. [docs] Generalnie najwygodniejsza i najbardziej elastyczna metoda jeżeli bawimy się w vertex groups. Pozwala poprzez "malowanie" na meshu w widoku 3D tworzyć vertex grupy dla odpowiednich kości i ustawiać wierzchołki oraz siłę wpływu kości w danej grupie. Niebieski = wpływ 0, czerwony = wpływ 1, zorientujecie się w reszcie.
Po pierwsze, przejdź w tryb Pose Mode armatury. Potem przejdź na swoją postać, i wejdź w Weight Paint (Ctrl+Tab). Dzięki temu że armatura jest w pose mode, możesz w trybie Weight Paint zaznaczać jej kości (mimo że pracujesz na meshu, masz jakby dostęp do armatury która jest aktualnie w pose mode).
Wygodnie jest przy okazji ustawić sobie kości na wyświetlanie jako Stick, żeby nie zajmowały zbyt dużo miejsca w widoku 3D.
Aktualnie zawsze malujemy wagi zaznaczonej kości (tylko 1 kość może być zaznaczona). Śmiało, malujemy przez LMB.
X-Mirror, Topology Mirror, Restrict, Auto-Normalize. Są też narzędzia w Weight Tools jako Normalize All. Prawie zawsze chcemy trzymać sumę wag = 1 na wierzchołku.
Pamiętamy że malujemy na oryginalnych wierzchołkach, tych które widzimy w edit mode, nie na wierzchołkach dodanych przez modyfikator jak subsurf.
W trybie Weight Paint możemy też poruszać kośćmi armatury, tak jakby jesteśmy jednocześnie w pose mode. To jest naturalnie użyteczne żeby na bieżąco sprawdzać jak zachowuje się nasz mesh.
Można śmiało zmienić położenie kości i malować na wynikowym meshu. To jest też jeden sposób żeby pomalować trudno dostępne wierzchołki.
sample: paint human.
Hint: Weight Paint to ogólne narzędzie do przypisywania vertex groups, i wag w obrębie tych vertex groups. Jak widzieliśmy już, vertex groups mają też inne zastosowania (np. jako ograniczenia działania niektórych modyfikatorów jak Decimate), więc Weight Paint przydaje się nie tylko przy animacjach. Będzie dla nas jeszcze bardzo użyteczne np. przy omawianiu systemu particle (za 1-2 wykłady), wtedy malując vertex grupę będziemy malowali także gęstość włosów.
Czasami możemy też chcieć ustawić kość jako parent obiektu. Naturalnie niweluje to cały sens armatury, ale czasami mamy obiekt który znajduje się w całości pod wpływem jednej kości: np. oczy ludzika. Jeżeli zrobimy armaturę, możemy oczy ludzika uczynić dziećmi kości głowy.
Dodawanie IK solvera explicite. Widzieliśmy już jak działa Auto IK. "Auto" oznacza że Blender robi za nas automatycznie wszystko związane z IK solving (my tylko ustawiamy połączenia pomiędzy kośćmi).
Można, i czasami trzeba, robić to bardziej ręcznie: dodajemy constraint Inverse Kinematics do kości. To oznacza że dana kość (oraz jej rodzice) będzie deformowana przez Target constrainta. Kość "celuje" w swój target (zazwyczaj dziecko), i deformuje rodziców, czyli np. ustawiamy constraint na łydce z target = pięta, żeby przesuwanie pięty deformowało łydkę i udo.
Normalne "Auto IK" działa tak jakby każda kość miała constraint IK solver do wszystkich swoich dzieci (chyba że zerwaliśmy połączenie przez odkliknięcie "Con"). Constraint IK dodany explicite pozwala dodać IK solver bez tworzenia zależności rodzic-dziecko (a więc także bez łączenia kości). Ponadto, taki constraint ma kilka ciekawych ustawień. Np. możemy zerwać długość łańcucha IK poprzez ChainLen (zamiast bawić się w odklikiwanie "Con").
Zwracam uwagę że kiedy kość ma łańcuch IK (explicite albo automatyczny przez Auto IK, ale przy automatycznym widać to dopiero kiedy zaczynamy przesuwać kość) to widać innym kolorem dokąd prowadzi łańcuch IK. Widać to kiedy zmieniamy ChainLen.
Notka: pamiętajcie wyłączyć "Auto IK" kiedy pracujecie z kośćmi które wpływają odpowiednio przez constrainty IK solver.
Różne hinty Dalej praca z modelem to w zasadzie układanie różnych póz i zmuszanie powyższego systemu żeby działał jak należy.
Odpowiednie animacje i deformacje mogą zmusić nas do poprawienia vertex painting (pamiętajcie że można malować kiedy poza jest już nałożona! To jest często wspaniały sposób poprawiania malowania, kiedy mamy brzydką deformację w jakimś zgięciu.) Być może nawet trzeba będzie edytować mesha aby mieć więcej wierzchołków aby lepiej rozgraniczyć obszary malowania (np. więcej edge loops na łokciach, kolanach etc.).
Większa kontrola nad IK solverem: często nogi zginają się zbyt swawolnie, ponieważ IK solver nie wie że kolana zginają się tylko w jedną stronę i generalnie nie powinny się za bardzo rozjeżdżać na boki. Jest kilka sposobów wymuszenia tego, najlepszy to chyba dodać specjalną kość na kolano (oderwaną od reszty modelu i wysuniętą do przodu), i ustawić constraint IK solver dla uda aby kierowało się na tą kość. (sample). Kiedy IK solver jest włączony explicite (tzn. przez constrainta) mamy łatwe przyciski do lokowania rotacji (Lock X Rot), albo czynienia rotacji bardziej "niechętną" (Stiff X, od "stiffness"), albo ograniczania zakresu rotacji (Limit X, po kliknięciu pojawią się pola do wprowadzenia min/max). Na kości możemy też nakładać constraints, jak Limit Rotation (oraz inne Limits...), Copy ..., Track ... i wszystkie inne.
Copy Pose, Paste Pose, Paste Flipped Pose są bardzo użyteczne przy tworzeniu różnych animacji. Żeby Paste Flipped działało, kości muszą być odpowiednio ponazywane, tak samo jak do X-axis mirror w editing (hand_L i hand_R, albo hand.l i hand.r, albo hand.left i hand.right... Blender ma dość elastyczny mechanizm wykrywania symetrycznych nazw, patrz manual).
DopeSheet (Action Editor). DopeSheet pokazuje krzywe
animacji w znacznie prostszej postaci. Przede wszystkim,
pozwala przestawiać i tworzyć nowe akcje kiedy zmienimy tryb
na "Action Editor".
[docs - manual o
Action Editor], [docs -
referencja okienka Action Editor]
Idea: wprawdzie umiemy już robić pełne filmiki z naszą postacią używając pozowania i zapamiętując każdą pozę w aktualnej ramce przez Insert Key, jest to bardzo nieefektywna metoda tworzenia filmów, nawet bardzo krótkich. Powód: każda postać ma wiele swoich typowych ruchów (jak chociażby krok, ale podczas każdego filmiku znajdziecie ich milion więcej...). Byłoby głupio co chwila układać nową pozę, albo nawet korzystać z kopiowania póz. Zamiast tego chcielibyśmy umieć stworzyć jakby bibliotekę prostych animacji, i potem komponować film z tych podstawowych animacji. Taka "podstawowa animacja" nazywa się Action w Blenderze i definiujemy akcje właśnie w Action Editor (później jeszcze zobaczymy okienko NLA Editor do składania i komponowania takich akcji).
Zakładając nową akcję w Action Editor tworzymy tak naprawdę kopię aktualnych F-Curves ustawionych na kościach (a więc w pozowaniu), a także Shape Keys z poprzedniego wykładu. Każda akcja ma swoje własne Ipo Curves, więc możemy komponować każdą akcję niezależnie, nie martwiąc się tym w jakiej kolejności po sobie następują, w jakich momentach filmu etc.
Widok w Action Editor jest trochę podobny do Graph Curves, tyle że (celowo) prostszy, w szczególności nie widzimy teraz samych krzywych. Widzimy tylko jakie kości mają w ogóle jakieś krzywe ruchu, i na jakich klatkach mają ustawione klucze.
Podstawowe poruszanie się (Ctrl+MMB albo rolki myszy skalują widok, MMB przesuwa) i zaznaczanie (A, A A, RMB, Shift+RMB, B) jak wszędzie w Blenderze. Podstawowa edycja kluczy też działa (Shift+D duplikuje, G, S transformują, Shift+S robi snap, X kasuje).
Tworzymy nową, nazywamy, przełączamy się pomiędzy istniejącymi akcjami przez combo box na headerze. Kiedy tworzymy nową akcję, domyślnie mamy kopię poprzedniej. Bez obaw — można ją śmiało wyczyścić (A A X), to jest tylko kopia, poprzednia akcja zostanie tam gdzie była.
Kilka notek o używaniu shape keys z action editor:
Timeline Editor: niewiele ciekawego, ale można omówić dla kompletu. Jak widać, wyświetla ramki na których dzieje się coś ciekawego.
Przesuwanie / skalowanie widoku znamy: MMB, Ctrl+MMB. LMB przesuwa czas, tak jak w Graph Editor.
Żółte pionowe kreski to keyframes aktualnie aktywnego obiektu.
Markery: pozwalają oznaczyć i nazwać jakiś znaczący moment w czasie, użyteczne kiedy robimy dłuższą i bardziej skomplikowaną animację. M dodaje marker na aktualnej ramce, RMB może zaznaczać markery, Ctrl+M pozwala nazwać aktualny marker. Patrz menu Marker, w Timeline window, Graph Editor, Action Editor i wielu innych okienkach.
Daje łatwy dostęp do "Auto Keyframe" (przycisk "Record"), wygodne do pozowania.
NLA (Non-Linear Animation) Editor czyli komponowanie
animacji.
[docs - manual o
NLA Editor], [docs -
referencja okienka NLA Editor]
Poruszanie się, zaznaczanie etc. tak jak w Action editor i w ogóle wszędzie w Blenderze, więc już nie będę się powtarzał.
Na początku widzimy wszystkie animacje naszych obiektów. Każdy romb oznacza ramkę na której jest ustawiony jakiś klucz. Dla obiektów którym utworzyliśmy jakieś akcje (na armature lub na shape keys) mamy też podpiętą aktualnie wybraną akcję.
Przede wszystkim, wybieramy akcję (w DopeSheet -> Action Editor), i w NLA klikamy na "śnieżynkę" obok nazwy naszej akcji, aby rozpocząć pracę z NLA. To dodaje pasek do NLA z naszą akcją.
Pasek możemy przesuwać, zaznaczać, kasować, jak zawsze w Blenderze. Bez obaw, nasza akcja jest ciągle w pełni edytowalna, mozemy ją zmieniać jak nam się podoba. Ew. może tylko zajść potrzeba dostosowania długości jej paska w NLA.
Dodajemy kolejne paski przez Add -> Add Action Strip. Możemy też dodawać tracks, czyli poziome linie (w danym czasie może działać kilka animacji; są inteligentnie mieszane, zwłaszcza jeżeli używają różnych kości).
Aby pod Alt+A wrócić do widoku pojedynczej akcji (zamiast oglądać rezultat NLA) zawsze można w DopeSheet ponownie wybrać konkretną akcję.
Transform Properties (klawisz N) w NLA Editor pozwalają edytować aktualny strip. Np. ustawiać Repeat, rozciągać go, przesuwać (te dwa ostatnie można też robić skalowaniem i przesuwaniem jak zwykle w Blenderze, S i G). Zwracam uwagę na rozciąganie: a więc w NLA editor możemy rozciągać/skracać animację, nie musimy przerabiać naszych klatek w Action Editor żeby np. ludzik szybciej chodził. Notka: skalowanie jest względem aktualnej ramki. Jeżeli skalowanie nie działa Wam jak chcecie, to zapewne chcecie ustawić się na innej ramce przed skalowaniem.
Żeby ludzik faktycznie chodził po czymś (tzn. nie chodził w miejscu) dodajemy powtarzającą się akcję Walk z przesunięciem ludzika + armatury (warto ustawić constraint Copy Location (i rotation i scale w sumie też) na ludzika żeby kopiował je z armatury; wtedy transformacje armatury w object mode będą aplikowane też do mesha ludzika, i wszystko będzie łatwe). Trzeba też wtedy dobrać odległość jaką powinien przebyć w czasie 1 kroku — taką żeby nie było wrażenia że ludzik płynie/sunie/ zatapia się po powierzchni.
Blending. Kiedy mamy kilka strips które zachodzą na siebie w czasie (ludzik robi dwie akcje na raz): normalnie, bez blending, każda krzywa zasłania animację tej samej krzywej w poniższych tracks. Czasami to jest Ok, np. jeżeli nasze dwie akcje dotykają zupełnie innych krzywych (np. dwie animacje armatury które używają zupełnie innych kości) to takie zachowanie zupełnie wystarcza.
Można jednak lepiej: blending oznacza że animacje w danym czasie będą odpowiednio mieszane, tzn. potencjalnie wszystkie paski w aktualnym czasie contribute do ostatecznej animacji. Możemy ustawić Number of frames easy-in oraz ease-out aby Blender robił gładkie przejście pomiędzy poprzednim stripem a nowym stripem. Jest też auto blending, widać jak działa kiedy nasuwamy jeden pasek pod spodem drugiego.
Opcja "oczka" obok każdego kanału w NLA pozwala szybko wyłączyć/włączyć niektóre kanały.
Co się dzieje pod Alt+A i renderowaniem - NLA czy konkretna akcja?
Dla każdego obiektu z osobna (mesha, armatury) jest 1. wybrana konkretna akcja (kiedy jest widoczny czerwony pasek ze śnieżynką w NLA) albo 2. wynikiem jest mieszanie pasków NLA (kiedy nie ma tego czerwonego paska ze śnieżynką). Klikając na śnieżynkę zamieniamy akcję na pasek NLA (to jeden sposób przejścia 1->2), możemy też uczynić akcję nieaktywną klikając na krzyżyk obok jej nazwy w "Action Editor" (to drugi sposób przejścia 1->2). Sposób przejścia 2->1 to wybranie konkretnej akcji w "Action Editor".
Dodawanie dźwięku (wykraczamy już poza ten wykład, ale może zdążę o tym krótko opowiedzieć): w Video Sequencer, dodaj dźwięk (RAM oznacza że dźwięk jest trzymany w całości w pamięci, HD jest strumieniowany z dysku twardego; w każdym przypadku możesz wybrać plik WAV). Sync, Scrub.
Można miksować audio i obraz do jednego eleganckiego filmu dzięki FFMpeg. (Na zakładce "Audio" włącz "Multiplex audio").
Więcej o Video Sequencer na późniejszym wykładzie.
Wersja aktualna dla 2012 poniżej.
Proponuję przerobienie niewielkiego kawałka tutoriala Character Animation z Blender Summer of Documentation. Cały tutorial jest dość długi, i stanowi eleganckie ćwiczenie właściwie z wszystkich istotnych narzędzi animacji: kości, shapes, actions,... Ale jest na tyle długi że nie będziemy go robić całego.
Wasze zadanie to jedynie podpięcie kości pod nogi człowieczka i stworzenie eleganckiej animacji kroku. Czyli robimy:
Jako punkt początkowy można wziąć gotowy .blend z modelem (tylko meshem) humanoida z poprzednich części tutoriala (na końcu większości sekcji są do pobrania pliki ze skończonymi kawałkami). Albo można zrobić własny model, zupełnie "na oko" i byle jak (ważne jest tylko żeby był eleganko pozamykany, perfekcyjnie symetryczny (zapewne robiony pod modyfikatorem "Mirror", pamiętajcie aby był symetryczny w lokalnej osi X żeby później "X-axis mirror" działało), miał mniej-więcej kształt dwunożnego humanoida, nakładamy na niego też "subdivision surface").
Dla osób obecnych na wykładzie, w ramach przeprosin za moje spóźnienie, bonus: robicie z tutoriala tyle ile zdążycie zrobić w czasie 2 godzin pracowni, po czym zadanie macie zaliczone :)
[docs - cały rozdział "Effects and Physical Simulation" z podręcznika]
"Physical Simulation" z Blender Summer Of Documentation
Particles: cząsteczki. Sama cząsteczka to tylko punkt (chociaż za pomocą Visualization Object, można sprawić by była odpowiednio przesuniętą i obróconą kopią dowolnego obiektu). Cząsteczki mogą być emitowane, podlegają różnym siłom (fields, o tym za chwilę) i można łatwo stworzyć dużo cząsteczek. Czyli są dobre do symulowania zjawisk fizycznych gdy mamy dużo "luźnych" elementów — ogień, dym etc. Ponadto hair(static) particles pozwolą nam łatwo tworzyć efekty jak włosy, trawa etc.
Podstawy: dodajemy particles. Będzie wyemitowanych Amount cząsteczek w czasie od Sta(rt) do End. Życie cząsteczki jest określone przez Life i może być randomizowane przez Random (dla hair particles, to określa długość włosów). Cząsteczki są emitowane z Faces lub Verts lub Volume (wnętrze dobrze zamkniętego obiektu), mogą być mniej lub bardziej losowo rozłożone (patrz Random, Even, i inne przyciski w tej okolicy).
Za pomocą Velocity nadajemy cząsteczkom kierunek ruchu (albo wzrost włosów, dla hair particles), najpierw zazwyczaj zwiększamy Normal. Mamy też Random, mamy stałe Acc X, Y, Z (Force w starym Blenderze) i jeszcze wiele innych. Cząsteczki są też pod wpływem zewnętrznych sił, o tym zaraz.
Wygląd particles: mogą mieć materiał (używany jest zadany materiał z naszego mesha). Używane są kontrolki z grupy Halo, więc możemy włączyć Halo na materiale i tak kontrolować rozmiar cząsteczek przez HaloSize. Polecam pobawić się kontrolkami w "Shaders" do halo, nie było o halo wykładu ale efekty są mniej więcej intuicyjne (można np. zmienić Amount particles np. na 10, żeby widzieć pojedyncze cząsteczki, i wtedy śmiało bawić się ustawieniami halo i obserwować efekty). Poza "Shaders", warto w przypadku halo zmniejszyć alpha, można też zmieniać kolory (mamy kolory Halo, Line, Ring zamiast kolorów normalnego materiału).
Inne obiekty mogą kolidować z cząsteczkami: wystarczy ustawić im Collision (Deflection w starszym Blenderze). Dobrze jest wtedy przeliczyć particles, np. zacząć animację z powrotem od 1 ramki (albo Recalc All w starszym Blenderze).
[sample - particle_sparkles] (i wyrenderowany filmik)
Cząsteczki mogą być wyświetlane jako inne obiekty. Używamy Visualization Object (albo zależności child-parent i DupliVerts w starszym Blenderze).
[sample - particle_water_metaballs] (i wyrenderowany filmik)
Można wyrenderować też samego mesha przez Emitter (Mesh w starym Blenderze). Można renderować też nienarodzone (unborn) / martwe (dead) cząsteczki.
Particles: Hair (włosy) (Static w starym Blenderze) sprawia że renderowane są wszystkie cząsteczki na drodze od początku do końca życia. Type = Hair (zamiast Emitter) zmienia ustawienia na włosy, większość kontrolek pozostaje taka sama — tylko teraz zamiast tor lotu kontrolujemy kształt włosa.
Włosy są renderowane jako tzw. Strands (pasemka). W skrócie, oznacza to że włosy wyglądają dobrze, także pod wpływem oświetlenia (są wprawdzie odcinkami, ale mają odpowiednie wektory normalne — po prostu skierowane do kamery). W materiale mamy opcje Strands (a także specjalny preview do strands) aby dobrać grubość włosów (Root / Tip to grubości na końcach, shape to jak grubość zmienia się wzdłuż włosa — polecam wypróbować obydwa ekstrema, efekty widać).
Mamy też "Strand" w "Map Input" tekstury. Czyli możemy dodać teksturę np. typu Blend, ustawić jej color ramp i w ten sposób kolorować nasze włosy tak jak lubimy.
[sample - particle_hair] (i rendering)
Włosy też mogą być pod wpływem sił -- np. grawitacji, vortex etc. To czasami dobry sposób na dobranie początkowego ułożenia włosów.
Particles: edytowanie włosów (czesanie) / toru cząsteczek
Przełączamy tryb na "Particle Mode". Od tego momentu wiele ustawień, jak Amount, Initial Velocity etc. nie będzie działać — ponieważ jesteśmy już w trybie edycji (a więc zazwyczaj zanim zrobimy "Particle Mode" chcemy ustawić dobre wyjściowe położenie włosów). Naturalnie możemy zrobić "Free Edit" i odzyskać kontrolę nad przyciskami jak Amount etc., ale wtedy tracimy nasze zmiany podczas edycji.
Kiedy mamy particle w trybie edycji mamy edycję włosów / toru lotu — każdy włos to po prostu linia łamana złożona z Segments odcinków. Możemy zaznaczać/odznaczać grupy włosów i pojedyncze włosy tak jak wierzchołki mesha, możemy je przesuwać etc. System edycji particles stara się zachować długość włosa i pozycję korzenia, czyli "ciągniemy" za końcówki włosów podczas edycji.
Na tool shelf w trakcie "Particle Mode" mamy kilka użytecznych opcji. "Comb" jest najprostsze do dość intuicyjnego czesania włosów, możemy też dodawać i usuwać włosy.
demo.
Fields, czyli dodatkowe siły działające na obiekty (soft body, particles). Np. wiatr.
Dodajemy obiekt typu "Force field". Albo dla dowolnego obiektu (często do Empty) ustawiamy Fields np. na Wind, wybieramy Strength na coś > 0. Wind to najprostszy rodzaj: po prostu siła ma jakiś kierunek. Vortex i Force są podobnie proste (kierunek jak trąba powietrzna oraz jak kierunki od centrum sfery).
Jest też Fall-off, i minimalny/maksymalny zasięg siły.
Strength i fall-off siły można animować. W ogóle, wszystko naturalnie można animować :)
Field Curve Guide pozwala stworzyć siłę działającą wzdłuż krzywej.
Soft body: obiekt który może się wyginać. Wewnętrznie, taki obiekt to połączona siatka elementów. Niektóre elementy mają zadany ruch (bo np. działa na nie bezpośrednia siła), pozostałe elementy dopasowują się. W Blenderze oznacza to że każdy wierzchołek ma swoją masę a krawędzie działają jak sprężyny. Generalnie, chcemy pracować z obiektami subdivided (przez normalne subdivide albo przez modyfikator subsurf z simple subdivision) żeby mieć dużo wierzchołków.
Włączamy Soft Body na obiekcie który ma się wyginać. Notka: soft body dodaje się od razu jako modyfikator do naszego obiektu.
Konfigurujemy Soft Goal jeżeli chcemy żeby na wierzchołki działała jakaś siła trzymająca je w miejscu — możemy ustawić tą siłę tylko na jakieś vertex group, i to jest najczęstsze zastosowanie kiedy nasz obiekt jest "trzymany" w jakichś miejscach. Kiedy wyłączymy Soft Goal, nasz obiekt nie będzie trzymany w miejscu, co znaczy tyle że będzie spadał zgodnie z gravity (i ew. zatrzymywany przez kolizje). G stiff mówi jak sztywny jest obiekt. Pull / Push (przy włączonych Use Edges, nazywają się E Stiff w starszym Blenderze) mówią jak sztywny jest obiekt w innych miejscach, można się też bawić Stiff Quads i kilkoma innymi przyciskami w tamtej okolicy .
[sample: softbody_basics z test237a.zip] zawiera kilka przykładów efektów przez Use goal, połączonych z normalną animacją obiektu — obiekt wtedy na różne sposoby "drga" podążając za swoją pozycją.
Włączamy Collision (Deflection w nowym Blenderze) aby obiekt kolidował z innymi obiektami soft body. Notka: obiekt nie musi sam być soft body żeby kolidować z innymi soft body. Hint: obiekty muszą być na tej samej warstwie (layer) żeby kolizje pomiędzy nimi działały!
[sample - soft_body_simple_collision]
Jest też Self Collision.
W Solver mamy ustawienie Error Limit aby lepiej kontrolować obliczenia — mniejszy error limit to większa precyzja, ale też dłuższy czas oczekiwania na wynik.
Chociaż możemy oglądać i renderować działanie soft body po prostu przez chodzenie po klatkach strzałkami i przez Alt+A, jednak tak wygenerowane położenie punktów soft body będzie chwilami znikać (będzie zachowywało się trochę tak jak przesuwanie obiektu na którym był ustawiony jakiś klucz — przy pewnych operacjach obiekt wraca do pozycji z klucza, tak samo soft body będzie przy pewnych operacjach wracało do oryginalnej pozycji). Więc możemy zrobić Bake. Ba, w nowym Blenderze możemy nawet edytować aktualną pozycję obliczoną z soft body (po włączeniu Bake Editing wejdź w "Edit mode"), a także wznowić bake od aktualnej ramki przez Rebake from current frame (np. żeby uwzględnić nasze bake editing w kolejnych ramkach). W przypadku zależności z innymi obiektami, kiedy wygląda na to że nasz obiekt nie reaguje na zmiany ustawień, warto zrobić Free Cache jeżeli widać "Simulation frames in disk cache" — np. miałem ten problem kiedy zmieniałem siłę wiatru, patrz niżej.
Żeby softbody działało jak należy, pamiętajcie o zależności krawędź = sprężynka. Jeżeli mamy obiekt który ma elastyczne wnętrze (np. gumowa piłeczka), to zapewne będziemy musieli dodać krawędzie w środku obiektu żeby symulacja softbody działała jak należy. (Trzeba wtedy uważać na wektory normalne, "recalculate normals" mogą nie działać jak należy — trzeba odpowiednio dobierać "recalculate normals" inside/outside na częściach obiektu albo robić "flip normals").
[sample - soft_body_volume_collision]
Soft body są pod wpływem zewnętrznych fields.
[sample: wind_soft.blend z test237a.zip]
Zadanie polega na zabawie z poznanymi na dzisiejszym wykładzie technikami animacji. Chcę żebyście użyli:
Animacji przy użyciu cząsteczek — proponuję dodanie śniegu do sceny.
Włosów — proponuję dodanie owłosienia (warkocza na głowie, albo pomysłowego owłosienia na całym ciele) dla tego ogra.
(Notka: model ogra nie jest "rigged" (nie ma armatury), i niech tak sobie po prostu stoi nieruchomi z rozpostartymi ramionami; w tym tygodniu nie interesuje nas armatura, więc nie musicie go w żaden sposób animować.)
(Notka 2: w zasadzie, ogr ma wymodelowaną sugestię włosów / warkocza na głowie. Nie przejmujemy się tym drobiazgiem — dodajemy nasze włosy / dodatkowe warkocze na wierzchu :) Interesuje nas użycie particles typu "hair" do zrobienia prawdziwych, ładnych włosów.
Sił i soft body z goal — proponuję dodanie łopoczącej flagi, model flagi możecie wyciągnąć stąd.
Czyli proponuję zrobienie kilunastosekundowego filmiku na którym owłosiony ogr stoi z rozpostartymi ramionami pod łopoczącą flągą, i naokoło pada śnieg.
Zamiast ogra i flagi możecie też użyć innych modeli z opengameart lub blendswap. W ten sposób chciałbym skorzystać z okazji i polecić Wam dwie strony skąd można czerpać przykładowe modele Blendera, na jasnych licencjach open-source:
Przy okazji, to dobry moment żebyście pobawili się używaniem "File->Append" w Blenderze, na wypadek gdybyście jeszcze nie poznali tego polecenia. Tak można dodać zasoby z innego pliku .blend do Waszego.
I jeszcze przy okazji, pamiętajcie że kiedy otwieracie modele ze starego Blendera (2.4x), zazwyczaj wygodnie jest odznaczyć checkbox "Load UI" przed załadowaniem (inaczej zostanie załadowany stary układ okien (np. properties na dole w poziomie), który jest mocno niewygodny w nowym Blenderze). Jeżeli już popełnicie ten błąd (zapomnicie oznaczyć "Load UI"), zazwyczaj najwygodniej jest Ctrl+N (załaduj z powrotem scenę i układ okien domyślny) i otworzyć model jeszcze raz (tym razem pamiętając odznaczyć "Load UI").
Rigid (sztywne) body: nie-deformowalny obiekt. Bullet = engine fizyki Blendera odpowiedzialny za obliczanie sił na takim obiekcie. Obliczany jest efekt aplikowania jakiejś siły (czyli wektora który ma jakiś kierunek i długość) na obiekt (który ma swój kształt i masę). W rezultacie obiekt przesuwa się i obraca.
Rigid body jest de facto częścią game engine Blendera, o którym jeszcze poopowiadamy sobie później. Na razie krótka instrukcja wykorzystania podstawowej fizyki: przechodzimy na tryb Blender Game (na headerze; zmienia całego Blendera, pokazując trochę nowych i ukrywając trochę poprzednich opcji):
I już. Przyciskamy P (jak Play, Start game z menu). I podziwiamy... Grawitacja działa, zderzenia działają, obiekty odbijają się od siebie, przewracają etc.
Hinty:
Do pomocy mamy m.in. Show Physics Visualization w menu, które pokazuje bounds naszych obiektów w trakcie gry.
Można oglądać animację w game engine do woli. Ale zwracam uwagę że jest ona wykonywana tylko w game engine — nie ma żadnego związku z klatkami Blendera, renderowaniem animacji etc. Do tego mamy specjalny przycisk Game->Record Animation. W czasie gry są wtedy nagrywane krzywe animacji naszych obiektów. Po zakończeniu gry, możemy je oglądać i edytować jak zwykle, mamy normalną animację w Blenderze.
Nie chcę wchodzić zbyt głęboko w game engine, ale jedna rzecz która może być użyteczna: jak nadać stałą siłę obiektowi? (Można polegać na grawitacji, albo początkowo przechylić jakiś obiekt jak domino, ale to nie są zbyt ogólne narzędzia.) Demo: Dodaj (add) sensor Always, controller Add, actuator Motion, połącz je (tak jak nodes materiałów, po prostu przeciągnij myszką pomiędzy gniazdami). Ustaw Force w Motion na co chcesz.
Będziemy jeszcze bawić się game engine, więc poznamy to wszystko bardziej od podszewki — na razie powyższe wprowadzenie pozwoli Wam wykonywać proste symulacje złożone z wielu rigid bodies które zachowują się zgodnie z prawami fizyki.
Użyteczna strona z hintami: Physics Tips - Bullet Collision Detection and Physics Library Wiki
[samples z Blender 2.42 Physics Demos]: na wykładzie zerkniemy na basic_physics_tests, PhysicsAnimationBakingDemo, Hm, może jeszcze na vehicle3_Steering fix oraz first_person_bullet jako "teaser" przed wykładem z game engine :)
Particles: Explode modifier ([docs z 2.46 release notes]). Jeszcze jeden efekt z systemem particles: eksplozja. System particles rozbija naszego mesha. W modifiers, "Particle system" musi być przed Explode!
[pokaż example.blend z release notes]
[sample - na bardziej skomplikowanym modelu, choćby moim levelu gate].
Particles: Boids ([docs z 2.46 release notes]). czyli każda cząsteczka ma prostą sztuczną inteligencję która każe jej unikać kolizji, podążać za grupą, unikać drapieżników etc. Do symulacji prostych grup, np. ptaków, ryb, much etc. Użycie jest proste: przestaw fizykę particles na Boids. Bold Brain to (ustawiona w/g priorytetów i ze skalą) lista celów naszej cząsteczki.
Emitowanie z Random Volume ma tutaj zastosowanie.
Żeby rozróżnić drapieżniki od ofiar, w nowym Blenderze ustawiamy konfigurujemy Relations na Enemy albo Friend. Boid Brain determinuje zachowanie.
Patrz trywialny tutorial Setting a prey-predator relationship using Boids particles. Uwaga: w Blender 2.5x zmieniono trochę zachowanie boids, stare modele nie będą kompatybilne. W 2.4x zamiast "relations" dodawało się siły (siła dodatnia: jak smaczne, siła ujemna: jak głodne).
[pokaż filmik i plik blend z release notes]
Zamiast latania, jest też "Allow Land" i "Allow Climbing". Demo. Disclaimer: nie wiem jak działa "Allow Climbing"... Do niektórych nowszych kontrolek z 2.5x niełatwo znaleźć dokumentację.
Wrócimy też do soft body - dopowiem jeszcze kilka szczegółów i pokażę kilka przykładów.
Fluid simulation, czyli symulacja cieczy.
Idea: dzielimy przestrzeń na wiele sześcianów, dla każdego z nich wykonujemy skomplikowane obliczenia jak się porusza / łączy z innymi. Nie potrzebujemy tutaj mocno subdivided obiektów (jak do soft body) — cała przestrzeń 3D będzie dzielona zgodnie z ustawioną resolution.
Podstawy pracy: wszystkie obiekty uczestniczące w symulacji muszą mieć Fluid simulation Enable. Każdy z obiektów ma jakiś typ, żeby symulacja miała sens potrzebujemy przynajmniej Domain i Fluid. Robimy Bake obiektu domain i podziwiamy :)
Domain (może być tylko 1 taki obiekt na scenę, żeby bake działało): bounding box tego obiektu wyznacza przestrzeń która będzie podzielona na Resolution^3 sześcianów i w niej będzie robiona symulacja. Ten obiekt będzie podmieniony na faktyczną symulację kiedy zrobimy Bake. De facto, ten obiekt będzie miał wtedy 3 wersje (przez cały czas animacji, od Start do End klatki): Geometry to normalny obiekt blendera bez symulacji, Preview to symulacja z rozdzielczością "Preview - Res", Final to symulacja z rozdzielczością "Resolution".
Pomocnicze meshe Preview i Final będą zapisane we wskazanym katalogu, domyślnie ~/.blender, jako fluidsurface_final_ i fluidsurface_preview_. Notka: kiedy przekazujecie komuś swój model Blendera, możecie przekazać też te pliki fluidsurface_* (dlatego wygodnie jest ustawić im ścieżkę względną od aktualnego pliku .blend, np. "//"). Jeżeli tego nie zrobicie, to osoba która dostanie plik .blend będzie musiała sama zrobić "Bake". (z drugiej strony, pliki z symulacją mogą być olbrzymie; na projekt 2 na naszym kursie, sugeruję żeby nie wysyłać tych plików, chyba że są stosunkowo małe, powiedzmy max około 1 MB).
Pod "Std" (Standard) - "Resolution" mamy jak mocno będzie dzielony nasz mesh na potrzeby symulacji. "Preview - Res" określa jaka będzie rozdzielczość podglądu. Pamiętajcie że Resolution jest brane do potęgi 3, więc zwiększanie Resolution drastycznie zwiększa wymaganą ilość pamięci/czasu na obliczenia. Obserwujcie "Req (required) BAKE memory" uważnie podczas zwiększania resolution i preview resolution. Domyślnie podgląd = to co widzimy w interaktywnym widoku 3D Blendera (np. po Alt+A), normalne resolution = to co widzimy na renderingu (chociaż za pomocą Disp-Qual (display quality) możemy to przestawiać).
Pod Ad (Advanced): gravity = grawitacja. Viscosity = lepkość (są presets dla typowych cieczy - woda, olej, miód). Realworld-size: rozmiar w metrach (ponieważ różne parametry fizyki mówią o czymś / metr, nie musi być 1 metr = 1 jednostka Blendera).
Domain Boundary (Bn): jak zachowują się elementy na granicy domain. Czy "lepią" się do granic domain.
Fluid wyznacza cząsteczki cieczy - volume oznacza że obiekt musi być zamknięty i cała jego objętość jest cieczą, shell oznacza że powierzchnia obiektu jest cieczą (obiekt nie musi być zamknięty), both - jednocześnie volume i shell.
Po wykonaniu Bake symulacji możemy ten obiekt ukryć (H, albo przenieść na inne layer) albo nawet usunąć (jeżeli nie będziemy już chcieli ponownie bawić się bake).
Obstacle: obiekt który będzie powodował kolizję z cieczą. Ten obiekt też może się przesuwać w czasie animacji. Może być animowany jako object (loc/rot/scale obiektu), może być animowany jako mesh (np. poprzez shape keys, armature) — w tym drugim przypadku trzeba zaznaczyć "Animated Mesh Export" (i liczyć się z dłuższym czasem bake).
Inflow / Outflow: obiekty generujące i wchłaniające ciecz. Kran z wodą / rura odpływowa (tak to się nazywa?) zlewu.
Hinty: dla Inflow dobrze jest włączyć widok Axis (na "Object buttons"), żeby dobrać odpowiednio kierunek.
[sample - fluid_in_out_flow]
[sample - fluid_obstacles]
(i wyrenderowany filmik)
[sample - rigid_and_soft_body], jeżeli będzie czas na wykładzie.
Bardzo krótkie wprowadzenie do Pythona (na chwilę zapominając o Blenderze):
Dokumentacja:
Blender 2.5x wymaga Pythona 3.x (obecnie 3.2). Ta wersja wprowadza trochę niekompatybilnych zmian w porównaniu z Pythonem 2.x.
Dokumentacja dla Pythona 3.2 jest tutaj. Najbardziej nas interesuje:
Osoby które znają poprzednie (2.x) wersje Pythona zapewne zechcą
przeczytać "What's new", szczególnie najważniejsze niekompatybilne
zmiany które zaszły w momencie wydania 3.0, "Common Stumbling Blocks".
Zapewne pierwsza zmiana o którą się potkniemy to że print
jest
teraz funkcją, tzn. wymaga normalnych nawiasów naokoło.
Ogólnie o Pythonie
Trywialny przykład:
x = 1 + 2 print(x)
python xxx.py
Konsola Pythona do zabaw interaktywnych (python
) albo
uruchamianie skryptów (python program.py
, albo
(Unix only) umieść #!/usr/bin/env python
na początku
skryptu i chmod +x program.py; ./program.py
).
Nie deklarujemy, nie kompilujemy:
Python jest językiem skryptowym, to w założeniu znaczy tyle że usiłuje być wygodny zamiast rygorystyczny. Python ma także klasy i moduły które pozwalają pisać zupełnie duże programy.
Nazw i typów zmiennych w Pythonie nie deklarujemy.
Chcąc operować jakąś zmienną, po prostu przypisujemy jej wartość x = 1
.
Żeby nie było zbyt niebezpiecznie (jak w PHP z wyłączonymi notice):
nie można używać niezainicjowanej zmiennej.
Typy są sprawdzane i ew. konwertowane w czasie wykonania programu.
Nie ma etapu kompilacji. Uruchamiamy nasz program przekazując kod źródłowy to interpretera Pythona. Mogą pojawić się w rezultacie pliki xxx.pyc (pyc = Python Compiled), które zawierają sparsowany i teoretycznie nieco zoptymalizowany kod, ale nie musimy się nimi przejmować — w 99% sytuacji Python sam nimi zarządza (odświeża widząc że plik xxx.py się zmienił) jak należy.
Jeżeli bardzo chcemy sprawdzić poprawność programu bez uruchamiania
go, jest np. pychecker
. Ale pamiętamy że typy są sprawdzane
dynamicznie, więc pychecker
wychwyci tylko proste błędy składniowe.
Składnia: 1 linia == 1 instrukcja:
Każda instrukcja na osobnej linii (jak w bash, make, podobnych językach skryptowych). Czyli nie ma też średnika na końcu linii, enter = separator instrukcji. Zamiast
x=1; y=2;albo
x=1; y=2;w Pythonie piszemy po prostu
x=1 y=1
Łączenie linii: jeżeli chcemy napisać jedną instrukcję w kilku liniach, znak backslash kontynuuje linię. Ilość białych znaków na początku linii za backslash nie ma znaczenia, linia za backslash jest po prostu doczepiana do poprzedniej linii; czyli można napisać
i=2 if i==2: print(1000 + 1000 + 1000 + 1000 + 1000 + 1000 + 1000 + 1000 + \ 1000 + 1000 + 1000 + 1000 + 1000 + 1000 + 1000 + 1000) else: print('no')chociaż bardziej czytelnie jest zrobić takie same wcięcia jak poprzednia linia, albo nawet więcej, czyli np.
i=2 if i==2: print(1000 + 1000 + 1000 + 1000 + 1000 + 1000 + 1000 + 1000 + \ 1000 + 1000 + 1000 + 1000 + 1000 + 1000 + 1000 + 1000) else: print('no')
Wyrażenia w (), [], {} mogą być kontynuowane na następnej linii bez potrzeby używania \. Zobaczymy przykłady później.
Komentarze 1-linijkowe od #. Nie ma komentarzy wielolinijkowych (niektórzy używają do tego celu wielolinijkowych stringów, """, które przecież mogą wystąpić w dowolnym miejscu kodu i nie powodują nic jeśli nie zostaną do czegoś przypisane.)
Składnia: wcięcia:
Pewnie najbardziej znany feature Pythona to że uwzględnia wcięcia, czyli białe znaki na początku linii. De facto to jest też dość mało ciekawy feature (jeśli chodzi o udowadnianie gdzie Python jest lepszy/gorszy od innych języków). Po prostu znak nowej linii + taka sama ilość wcięć jak poprzedni wiersz przechodzą do kolejnej instrukcji. Dodatkowe wcięcie zaczyna nowy blok instrukcji (a'la "begin end", "{ }"), mniejsze wcięcie kończy poprzedni blok. Gwarantuję że łatwo się przyzwyczaić.
Instrukcje które zaczynają nowy blok kończą się : (dwukropkiem). Np. if, while, for, def (definicja funkcji), class (definicja klasy) etc. Po : możemy napisać 1-linijkowy blok w tej samej linii (wygodne kiedy mamy krótką instrukcję np. za if'em), albo enter + zwiększ wcięcie + piszemy wielolinijkowy blok instrukcji pod "if"em. Kiedy zmniejszamy wcięcie, wracamy do bloku za "if"em. Przykład:
x = 2 if x == 2: print("yes") print("always printed") if x == 2: print("yes (2nd time)") print("yes (3rd time)") print("always printed")
Taby są zamieniane na 8 spacji. Więc można wcinać spacjami (1 spacją, 2 spacjami, etc. jak kto lubi), można tabami — nikt nie zmusza Was do używania tabów/spacji jeżeli ich nie lubicie albo z jakiegoś irracjonalnego powodu im nie ufacie :) (Nie czytaj tego: de facto, tab niekoniecznie jest 8 spacjami kiedy w 1 linii mieszany indentation spacjami i tabami; formalnie tab działa jak 1 spacja + tyle spacji żeby mieć wielokrotność 8.) Najlepiej używać konsekwentnie takiej samej ilości takich samych białych znaków do wcinania w swoim kodzie, i wtedy wszystko działa naturalnie.
Identyfikatory jak wszędzie: litery, cyfry, _,
pierwszy znak nie może być cyfrą. Python jest case-sensitive.
Identyfikatory zaczynające się od _ są specjalne, więc nie używajcie
ich chyba
że wiecie co robią i chcecie tego, zobaczymy przykłady użycia
później (np. konstruktor klasy nazywa się __init__
).
Integery i floaty piszemy normalnie, dzielenie integerów przez // jest dzieleniem całkowitym (zwraca integer = floor z dzielenia gdy oba argumenty są integer), / jest dzieleniem float. (Uwaga, w Pythonie 2.x było inaczej: tam dzielenie / było dzieleniem całkowitym gdy oba argumenty były całkowite, podobnie jak w C. W Pythonie 3, dzielenie / zawsze daje floaty, i trzeba używać specjalnego operatora // do dzielenia całkowitego, podobnie jak w Pascalu z "div".)
= to przypisanie, == porównanie. Czyli jak w C-podobnych.
Typy complex są wbudowane, składnia naturalna (1 + 3j
), albo
complex(1, 3)
. De facto "3j" jest imaginary, "1" jest integer,
"1" jest konwertowane automatycznie na float a potem na complex
żeby zrobić dodawanie na complex. Czyli wszystko działa Ok używając
normalnej matematycznej notacji.
Stringi są w "" albo '', jeżeli musimy zapisać literalnie końcówkę
stringa to używamy \, np. 'it\'s true'
(albo "it's true"
).
'%d is %s' % (10, 'a number')
. Drugi parametr % to single value
(kiedy jest tylko jeden argument), tuple, albo słownik
(albo dowolny inny mapping object), przykłady zobaczymy później.
Listy: [], len(l), l[0], l[1:2] działa. Listy są już mutable. Listy nie pilnują typów, można robić listę jak ['spam', 'eggs', 100, 1234], [1, [2, 3, 'xtra'], 4]. Wewnętrznie, listy to tablice, czyli wszystkie elementy są ułożone w jednym ciągu pamięci, szybki dostęp/indeksowanie, szybkie usuwanie/dodawanie na końcu, ale wolniejsze np. dodawanie/usuwanie na początku/w środku (bo powoduje przesuwanie, nie wspominając o potencjalnym realloc).
Jest też array, wymagające jednego typu i wewnętrznie też przypominające bardziej normalne tablice.
Jest collections.deque jeżeli ktoś potrzebuje "prawdziwych" list, czyli linked list, których czasy działania są inne.
Tuple: immutable (i bardziej wydajna) lista. (notka: tuple może zawierać listę, i wtedy de facto jest trochę mutable). Tuple działa jak lista, chociaż w pewnych sytuacjach jest wymagane tuple (np. jako parametr dla % na stringach, jako klucz dictionary jest wymagane w pełni immutable tuple (nie zawierające rekurencyjnie list etc.) — nie można użyć list).
Flow control:
(Poniższe notatki są już bardzo skrótowe. Szczegóły w świetnym tutorialu Pythona, i oczywiście language reference.)
if
, else
, także elif
(skrót dla else if, pozwala uniknąć indentation).
for ... in
: podstawowa pętla Pythona.
W sytuacji w której duża część programu to operowanie na kontenerach,
typy Pythona + instrukcja for działają znakomicie.
"For" bierze listę (albo cokolwiek po czym Python umie iterować).
Używaj range(11)
albo range(5, 11)
aby iterować po kolejnych liczbach).
while
.
else
, break
, continue
pass
to instrukcja pusta.
Skoro nie mamy średnika a Python ignoruje puste linie, potrzebujemy
explicite instrukcji pustej, co puryści językowi uznają nawet za zaletę.
def
.
Docstring opcjonalny, pierwszy statement w funkcji to string literal.
Zmienne lokalne: przypisanie w ramach funkcji zawsze
przypisuje (ew. tworząc) zmienną lokalną, nie można przypisywać
zmiennych globalnych. Natomiast referencja do zmiennej najpierw
patrzy na lokalne, potem na globalne — czyli można odczytać
zmienną globalną dopóki nie zasłoniliśmy jej przez lokalną.
Żeby zmienić zmienną globalną, używaj global
, trochę a'la PHP.
W środku metody,
zasady są takie same, zmienne klasy (aka pola) modyfikujesz
zawsze z explicite self.nazwa_pola
.
W zasadzie, podstawowe tworzenie modułów nie wymaga niczego nowego. To co nas dotyczy to używanie modułów — musimy to rozumieć żeby używać modułów Blenderowych:
import mójmoduł
sprawia że nazwa modułu mójmoduł
staje się dostępna. Funkcje z tego modułu można wywoływać
(i klasy używać etc.), ale trzeba je kwalifikować nazwą modułu:
mójmoduł.mojafunkcja()
. Bezpieczne, ale niewygodne.
from mójmoduł import mojafunkcja
sprawia
że nazwa funkcji staje się dostępna, czyli można wywoływać "normalnie"
bez kwalifikowanie nazwą modułu: mojafunkcja()
.
(de facto, nawet trzeba wywoływać bez kwalifikowania, bo powyższe "from" nie sprawia że sama nazwa modułu staje się dostępna. Moglibyśmy dodać "import mójmoduł" gdybyśmy tego chcieli.)
from mójmoduł import *
sprawia że wszystkie funkcje
z modułu są dostępne. Czyli jest najbliższe zwykłemu "używaniu"
modułów z innych języków programowania.
Moduły Pythona mogą mieć nazwy złożone z wielu członów oddzielonych
kropką. Na dysku człony nazwy to kolejne podkatalogi, ostatni człon
to basename nazwy pliku. Na przykład wszystkie moduły Blendera
(poza eksperymentalnymi i game engine) zaczynają się od członu Blender
.
Niekiedy może to być confusing: w Pythonie importowanie
samej nazwy modułu jest czymś niezależnym od importowania nazw
z wewnątrz modułu. Ponadto wersji "from" można używać do importowania
podmodułu z pakietu. Ogólna zasada, kiedy patrzymy na deklarację
[from xxx] import yyy
: xxx to nazwa której nie chcemy
już pisać w kodzie. Niejako "wyciągamy" z modułu xxx identyfikatory
yyy (które mogą być podmodułami, albo zwykłymi funkcjami/klasami etc.).
Podstawy są naturalne, tak jak w każdym języku skryptowym.
Deklarujemy klasę class NazwaKlasy:
która ma w środku
(czyli odpowiednio wcięte) metody.
Metoda jako pierwszy parametr
bierze self
— Python, w przeciwieństwie do innych
języków, zmusza nas do podania tego parametru explicite przy
deklaracji metody.
Konstruktor nazywa się __init__
. Tworzymy instancję
poprzez użycie nazwy klasy z parametrami dla konstruktora,
czyli x = NazwaKlasy()
. Naturalnie jest garbage collector,
nie wiemy i nie obchodzi nas kiedy obiekt zostanie zwolniony.
Podobnie jak w przypadku zmiennych, pól klasy nie deklarujemy.
Po prostu w konstruktorze (albo gdziekolwiek indziej) przypisujemy
im wartości. Pamiętamy kwalifikować pola przez self.nazwapola
w środku metod, inaczej będziemy dobierać się do zmiennych lokalnych
metody.
De facto, pozwala to na robienie w Pythonie pewnych sztuczek. Zawsze można "z zewnątrz" ustawić na instancji pole zupełnie przez tą instancję nie przewidziane (naturalnie jest to mocno odradzane na wypadek gdyby klasa chciała użyć pola o takiej nazwie to wewnętrznych zastosowań).
W Pythonie nie ma sekcji private / protected znanych z innych klas. Jeżeli chcemy żeby zmienna była prywatna, zaczynamy jej nazwę od dwóch znaków podkreślenia. De facto, taka zmienna jest ciągle widoczna, tyle że ma nazwę mangled z nazwą klasy, żeby nie kolidowała z potomkami/rodzicami klasy.
Naturalnie jest dziedziczenie. Ponieważ name resolution jest robione i tak tylko w czasie wykonania, więc wszystkie metody są automatycznie wirtualne.
Wracamy do Blendera. Integracja, uruchamianie skryptów w Pythonie z Blendera:
Dokumentacja:
Blender 2.57 Python API zawiera linki i wszystkie informacje. Zawsze odpowiednia strona dla aktualnego Blendera jest osiągalna z menu "Help->Python API reference".
Są tam linki do dwóch ogólnych opisów/tutoriali: intro overview. Po czym mamy dokumentację wszystkich modułów, klas, metod etc.
Stare docs (dla Blendera 2.4x, gdzie Python API było znacznie inne):
Wprowadzenie do skryptów Pythona w Blenderze:
Kiedy zachodzi błąd, komunikat błędu i stack trace są wyświetlane przez Blendera na konsoli (Blender mówi tylko "Python script error, see console"). Poza tym wszystko co piszecie print'em z Pythona (np. do testów) też trafia na konsolę. Dlatego kiedy bawicie się skryptami, dobrze jest uruchomić Blendera tak żeby widzieć jego konsolę.
Text editor Blendera. Ot, taki prostacki edytorek tekstowy. [docs]
Można używać do edycji normalnego tekstu (np. notek na temat modelu), można używać do edycji kodu w Pythonie. Tekst wpisany tutaj jest zapamiętywany w pliku .blend (zróbcie unlink, czyli kliknijcie "X", jeżeli tego nie chcecie; zapewne najpierw będziecie chcieli też zapamiętać tekst do odpowiedniego pliku).
Najważniejsza funkcja: wykonaj jako skrypt Pythona, Alt+P.
Zapewne będzie też wygodnie włączyć sobie Enable Syntax Highlighting (przycisk na headerze okienka Text Editor).
To trywialne spostrzeżenie, ale może warto powiedzieć: Ctrl+X, Ctrl+C, Ctrl+V, zaznaczanie z Shiftem, etc. działają normalnie w okienku tekstowym Blendera 2.5x (pamiętajcie tylko umieścić kursor myszy ponad okienkiem tekstowym). Pozwalają przenosić tekst pomiędzy buforami Blendera i/lub innymi programami, tak jak w każdym edytorze tekstowym.
Jest też reload (pod Alt+R) w edytorku tekstowym, żeby przeładować tekst bufora z pliku. Wygodne jeżeli wolimy edytować tekst w innym edytorze, i tylko przeładowywać go szybko w Blenderze.
Czyli jeżeli nie lubimy pracować w edytorku tekstowym Blendera (który w sumie nie jest taki zły, ale przecież nie próbuje konkurować z Emacsem :) to nie musimy.
Python Console (najlepiej przejść na widok "Scripts").
Uruchamia coś jak konsolę Pythona (kiedy uruchamialiśmy Pythona
standalone bez parametrów, python
) tyle że w środku Blendera
(a więc mamy dostęp do modułów Blendera, danych sceny itd.)
Tak jak przy pracy z Pythonem bez Blendera: możemy tworzyć cały plik w normalnym edytorze, albo bawić się w konsoli. Tak samo przy pracy z Blenderem, możemy tworzyć cały plik w Text Editor (albo w innym edytorze zewnętrznym i w Blenderze robić tylko Alt+R czyli refresh z pliku) albo bawić się w interaktywnej konsoli.
Bardzo fajna rzecz konsoli to auto-completion (Ctrl+Spacja), koniecznie wypróbujcie i używajcie — pozwala łatwo zobaczyć dostępne identyfikatory.
Podstawy pisania skryptów w Blenderze.
Podstawy: używamy modułu Pythona bpy
.
Dobieramy się do interesujących nas danych,
np. poprzez bpy.data.scenes[0].objects
(kolekcja obiektów, można indeksować nazwą albo indeksem),
bpy.context.selected_objects
(lista zaznaczonych obiektów),
bpy.context.object
(ostatni zaznaczony obiekt).
I robimy co chcemy :)
Blender daje nam wszystkie dane sceny, w postaci eleganckiej w Pythonie. Tzn. odpowiednie elementy sceny są opakowane w ładne obiekty Pythona, wszędzie używane są listy, kolekcje Pythona etc.
Przykład trywialny:
import bpy for pt in bpy.data.scenes[0].objects["HumanMale"].data.vertices: #print(pt.co) pt.co.x += 1.0
Pamiętajcie: macie docs, i macie auto-completion w konsoli (Ctrl+Spacja).
Struktury danych są połączone tak jak widzimy w Outliner. Czyli mamy wiele scen (jeden plik Blendera zawiera wiele scen, każda scena ma wiele obiektów) i obiekty. Obiekt ma swoje "data" (to jest miejsce gdzie znajdują się specjalne dane mesha, kamery, światła etc.).
data
obiektu jest zapewne jedną z ważniejszych funkcji.
Zawsze możemy zobaczyć lub testować typ danych, np.
o = bpy.data.scenes[0].objects["Plane"] print(o.data) isinstance(o.data, bpy.types.Mesh)
W Blenderze, obiekt może być używany wielokrotnie przez inne obiekty,
co znakomicie współpracuje z reference counting robionym przez Pythona.
Blender pozwala
trzymać wiele referencji do tych samych obiektów (nawet obiekty
które mają 0 referencji zostają przez chwilę w pamięci, do czasu
przeładowania Blendera, co czasem jest przydatne).
Mamy metody link
/ unlink
na listach obiektów etc.,
see np. SceneObjects docs.
Czyli np. działa:
o = bpy.data.scenes[0].objects["Plane"] print(o.users) # ile razy używany bpy.data.scenes[0].objects.unlink(o)
Jakie mamy metody i pola obiektów?
auto-completion w konsoli (Ctrl+Spacja),
ponadto możemy przesunąć myszkę ponad element UI i zobaczyć hint, jest tam podana nazwa klasy Pythona i nazwa pola,
ponadto możemy kliknąć prawym klawiszem na element UI i wybrać "View docs", co od razu otworzy nam w przeglądarce dokumentację,
ponadto każda akcja jaką wykonujemy odpowiada tzw. "operatorowi" Blendera. Oznacza to że wszystkie akcje (jak elementy menu bar, jak przyciski na Tool Shelf) odpowiadają odpowiedniemu wywołaniu metody Pythona.
Możemy zwiększyć wysokość okienka "Info" (gdzie
domyślnie widać tylko menu bar) i zobaczyć wszystkie te operacje.
Prawy klawisz zaznacza, Ctrl+C kopiuje, więc możemy natychmiast
taki kod wkleić do konsoli i spróbować że działa.
Naturalnie wszystko to jest udokumentowane, jako część modułu bpy.ops
.
Niektóre operatory są zdefiniowane w Pythonie, niektóre zaimplementowane
natywnie w C. Poprzez moduł bpy.ops
mamy dostęp
do wszystkich.
Jest to łatwa metoda na zamienianie interaktywnych operacji
na skrypt w Pythonie. Zazwyczaj wszystkie operacje można też
zrobić bez pomocy bpy.ops
(zamiast tego, operować
bezpośrednio na danych) — ale używanie operatorów jest
prostsze i czasami zupełnie wystarcza.
Zwróćcie uwagę na składnię argumentów przy wywoływaniu operatorów: wszystkie argumenty powinny być nazwane. Wyjątkiem jest argument mówiący jak wywołać operator, np. 'EXECUTE_DEFAULT' 'INVOKE_DEFAULT' (o tym więcej później).
Proste tworzenie obiektów, meshy:
Wiele operacji Blendera jest zaimplementowanych w czystym Pythonie.
Co oznacza tyle że możemy zajrzeć np. do
2.57/scripts/startup/bl_operators/add_mesh_torus.py
i zobaczyć gotowy, działający skrypt dodający nowego mesha.
Rzut oka na moje trywialne [sample - circle_producer_25.py].
Custom properties:
Można dodawać z Pythona własne properties do obiektów. Są pamiętane w pliku .blend. Są też widoczne i edytowalne w GUI (zakładka "custom properties"). Są nawet animowalne w normalny sposób. Innymi słowy, są pełnowartościowymi atrybutami, tak jak wbudowane właściwości obiektów w Blenderze.
# (Poniżej nieco zmodyfikowany przykład z # http://wiki.blender.org/index.php/Dev:2.5/Py/API/Intro) # "bpy.context.object" to ostatnio zaznaczony obiekt. import bpy bpy.context.object["MyOwnProperty"] = 42 if "SomeProp" in bpy.context.object: print("Property found") # Use the get function like a Python dictionary which can have a fallback value. print(bpy.context.object.get("SomeProp", "fallback value")) # dictionaries can be assigned as long as they only use basic types. bpy.context.object["SomeDictProperty"] = {"foo": 10, "bar": "spam", "baz": {}}
Moduł bpy.props zawiera specjalne klasy do definiowania properties. Możesz w ten sposób dodać property do całej klasy, określając nazwę property, początkową wartość, zakresy etc.
Zdefiniowana w ten sposób property jest nieco bardziej pełno-wartościowa:
automatycznie istnieje we wszystkich instancjach, i możemy ją czytać/zmieniać
bezpośrednio (bpy.context.object.MyOwnProperty
zamiast
bpy.context.object["MyOwnProperty"]
). Python jest językiem
skryptowym, więc takie automatycznie tworzenie identyfikatorów
o nazwie zaczerpniętej ze stringa jest możliwe.
import bpy from bpy.props import FloatProperty, IntProperty bpy.types.Object.moje_nowe_property = IntProperty(name="Testowy int", description="blah blah", default=10, min=2, max=100) print(bpy.context.object.moje_nowe_property) # już działa, powinno być 10 (przy pierwszym uruchomieniu skryptu) bpy.context.object.moje_nowe_property = 30 print(bpy.context.object['moje_nowe_property']) # powinno być 30 bpy.context.object['moje_nowe_property'] = 123 print(bpy.context.object.moje_nowe_property) # powinno być 123 # Przy okazji widać że można złamać limity min/max w Pythonie. # Chociaż wartość powróci do zakresu (123 zmieni się w 100) kiedy Blender # się zorientuje, ale to już będzie po zakończeniu skryptu.
Pamiętajcie: definicję property, czyli instancję klasy XxxProperty, dodajemy do klasy (jak Mesh). Natomiast w konkretnym meshu już tylko ustawiamy wartość tego property.
Ustawianie wartości property zanim ją zdefiniujemy przez XxxProperty oznacza że tylko konkretny obiekt ma tą property. Czasami to wystarcza do naszych zastosowań, ale czasami możemy chcieć bardziej ogólnie zagwarantować sobie istnienie tej property.
Są też PropertyGroups
, czyli nazwana grupa properties.
Użyteczne, zwłaszcza żeby skrypty nie wchodziły sobie w drogę
tworząc dużo własnych properties. See przykłady w docs.
Własne operatory
W Blenderze 2.5, wszystkie akcje wywoływane przez menu, klawisze etc. są wspólnie nazywane "operatory" i są definiowane w elegancki sposób. To dzięki operatorom mamy obecnie menu pod spacją (do przeszukiwania operatorów), konfigurowalne skróty klawiszowe (przypisz klawisz do operatora) etc.
Oczywiście możemy sami implementować operatory w Pythonie.
Operator to odpowiednia klasa dziedzicząca z bpy.types.Operator
.
Jeżeli Blender wie o takiej klasie (ma ją zarejestrowaną),
to user może uruchomić operator (co oznacza że stworzona zostanie
instancja tej klasy, na której wywołamy kilka metod).
Całą interakcję użytkownikiem skrypt powinien robić poprzez operatory. (To było znacznie bardziej messy w Blenderze 2.4x, może zerkniemy jeśli będzie czas.)
Początek: HelloWorldOperator
z przykładów bpy.types.Operator.
Spostrzeżenia:
bpy.types.Operator
bpy.ops.<wartość-bl_idname>
execute
jest wywoływana kiedy operator
ma zadziałać (to uproszczenie, zaraz więcej)
report
(docs):
self.report({'INFO'}, 'blah')
Metoda invoke: SimpleMouseOperator
z bpy.types.Operator examples.
Spostrzeżenia:
invoke
jest wywoływana kiedy uruchamiamy operator.
Jej przewaga (ponad execute
) to że dostaje szczegóły
zdarzenia które zainicjowało operator.
Kiedy nie zdefiniowaliśmy własnego invoke
,
uruchamiane jest execute
.
Dla interaktywnych akcji (kiedy, po rozpoczęciu operatora,
można dostosować jego parametry), override obu metod ma sens.
Properties, interakcja: [sample - circle_producer_25_operator.py].
Spostrzeżenia:
execute
pozostaje trywialna,
nie martwimy się o usunięcie poprzedniej wersji obiektu —
to robi za nas Blender automatycznie.
Okienka do wyboru plików: ExportSomeData
z bpy.types.Operator examples
Spostrzeżenia:
invoke
inicjuje okienko dialogowe, podając operator = self
.
Okienko dialogowe wywoła execute
na operatorze.
Czyli taka współpraca.
return {'RUNNING_MODAL'}
z invoke, inaczej staną się straszne rzeczy (operator nie będzie
"działał", w/g Blendera, a jednocześnie coś wywoła na nim
metodę execute.)
poll
pozwala sprawdzić
czy operator można wywołać. Metoda klasy (instancja operatora
nie jest utworzona dopóki operator działa).
Tutaj przykład na bardzo typowy test: czy mamy zaznaczony obiekt.
invoke
.
Ale normalne wywołanie operatora z konsoli po prostu wywoła
execute
, i property z nazwą pliku będzie ustawione
z parametru.
Okienka modalne (popup): DialogOperator
z bpy.types.Operator examples
Spostrzeżenia:
invoke_props_dialog
.
docs.
Podajemy operator z którego wziąć properties, i zarazem na którym
wywołać execute.
invoke_props_dialog
wraca natychmiast, zanim
zaakceptujemy okienko. Czyli de facto obsługujemy je z Pythona
jak niemodalne, tzn. tak jakby mogło istnieć wiele takich okienek
równocześnie, po prostu czekamy na callback execute.
Własna interakcja z użytkownikiem: ModalOperator
z bpy.types.Operator examples
Spostrzeżenia:
context.window_manager.modal_handler_add
jest kluczowe.
Dzięki temu, nasza metoda modal
będzie wykonywana
zawsze w odpowiedzi na dowolne zdarzenie (aż do zakończenia
operatora).
{'RUNNING_MODAL'}
(żeby nasz
operator cały czas działał) zarówno z invoke jak i samego modal.
(W tym przykładzie, metodę execute
wywołujemy po prostu
sami, dlatego de facto nie ma znaczenia co ona zwróci.)
Przykładowe skrypty (operatory):
see okienko tekstowe, Text -> Script Templates.
Kiedy najedziemy myszką ponad element menu, zobaczymy też pełną
ścieżkę do pliku, .../scripts/templates/...
.
Czyli można też zwyczajnie przeglądać odpowiednie pliki.
Panele:
Podobnie jak operatory, możemy też definiować własne panele (elementy okienka properties). See docs dla bpy.types.Panel.
Demo: HelloWorldPanel
Panele definiujemy i rejestrujemy zupełnie podobnie jak operatory, tylko:
bpy.types.Panel
draw
i draw_header
(De facto, operatory też miały draw
do specjalnego rysowania
properties, ale to nie było nic ciekawego.)
layout
, instancję UILayout,
która pozwala "rysować" elementy UI.
"Rysować" w cudzysłowie, bo de facto my tylko mówimy jak rozmieścić
properties. row
, column
, box
pozwalają utworzyć zagnieżdżone instancje UILayout.
Demo: ObjectSelectPanel.
layout.prop
: odnoszą się do pól klasy Object.layout.operator
: odnoszą się do nazw (bl_idname) operatorów (pełna referencja w bpy.ops).W ten sposób w Pythonie jest eleganckie rozgraniczenie na właściwości sceny (properties) i akcje które natychmiast modyfikują scenę (operatory).
Demo: ObjectSelectPanel zmodyfikowany żeby pokazywać
import bpy from bpy.props import IntProperty # To nie wystarczy: # bpy.context.object["testowe_property"] = 42 # A to będzie Ok: bpy.types.Object.testowe_property = IntProperty(name="Testowe property", description="opis testowego", default=10, min=2, max=100) class PanelForMyOwnProperty(bpy.types.Panel): bl_idname = "VIEW3D_PT_myown" bl_label = "Control custom prop" bl_space_type = 'VIEW_3D' bl_region_type = 'TOOLS' def draw(self, context): self.layout.label("Small Class") self.layout.prop(context.object, "testowe_property") self.layout.label("After Small Class") bpy.utils.register_class(PanelForMyOwnProperty)
Czas życia instancji panelu jest bardzo krótki (tylko draw). Tak mówi dokumentacja, zresztą możemy sprawdzić:
def __init__(self): print('init') def __del__(self): print('del')Dodaj powyższe do kodu dowolnego panelu. Więc nie ma sensu przechowywać informacji w panelu. Panel to tylko wizualizacja operatorów / properties!
Menus
Możemy też tworzyć własne menus i pokazywać je lub podczepiać do istniejących. Ciekawe jest tutaj że menu w sumie jest bardzo podobne do panelu. Możemy do niego dodawać operatory, ale możemy też dodać properties:
import bpy def menu_draw(self, context): self.layout.separator() self.layout.operator("wm.save_homefile") self.layout.label(text="Hello World") # self.layout.prop(context.object, "name") # też działa, chociaż wygląda brzydko self.layout.prop(context.object, "show_name") bpy.types.INFO_MT_file.append(menu_draw)
Dema na bpy.types.Menu.
Custom render engine
Przykład z bpy.types.RenderEngine. Nazwa "render engine" jest w sumie zbyt skromna: to pozwala nie tylko zmienić sposób renderowania, pozwala także ukryć pewne domyślne panele Blendera (i być może pokazać inne, własne).
Ustawianie animacji: Możemy sami ustawiać klucze, w ten sposób programując animację.
Sample animujący location[2], czyli pozycję w Z obiektu, z intro.
Sample:
import bpy import math obj = bpy.context.object radius = 20.0 for i in range(1, 100): obj.location[0] = radius * math.sin(2 * math.pi * i / 100.0) obj.location[1] = radius * math.cos(2 * math.pi * i / 100.0) obj.keyframe_insert(data_path="location", frame=i, index=0) obj.keyframe_insert(data_path="location", frame=i, index=1)
Istotne jest tutaj że keyframe_insert
jest zdefiniowane dla wszystkich bpy_struct
i może animować
naprawdę wszystko (także nasze własne properties).
(To zastępuje mechanizm scriptlinks z Blendera 2.4x, gdzie mogliśmy napisać skrypt uruchamiany przy zmianie aktualnej ramki, i aktualizujący scenę.)
Podsumowanie, rzut oka na docs:
Teraz warto rzucić okiem na listę modułów w docs, i zobaczyć że większość już ogarniamy:
bpy.context to ~aktualne zaznaczenia etc.
Uwaga: to nie jest moduł Pythona (nie można zrobić import bpy.context
).
Dokumentacja Blendera tak go nazywa, i może wygodnie jest tak o nim
myśleć (zawiera w środku masę rzeczy), ale tak naprawdę to tylko
instancja klasy Context
. Łatwy test:
# import bpy.context (nie zadziała) print(bpy.context) # powie nam że to instancja Context
bpy.data to kompletne dane sceny (Podobnie jak wyżej: de facto to nie jest moduł, tylko instancja klasy (BlendData).
bpy.ops to operatory, wykonywalne z menu bar, tool shelf, menu pod spacją etc.
bpy.types, jak nazwa wskazuje, zawiera definicje większości typów.
Rzut oka na utils, path, app. Różności.
bpy.props to więcej operacji na custom properties. Przydatne do custom properties na dowolnych obiektach, także na operatorach.
Różne sposoby uruchamiania skryptów:
Poza Alt+P w okienku tekstowym, skrypty można uruchomić na różne ciekawsze sposoby:
Skrypty addons
Skrypty w katalogu scripts/addons
instalacji Blendera będą załadowane
przy starcie. Takie skrypty muszą definiować
zmienną bl_info i funkcje register/unregister,
poza tym — mogą robić co chcą. Zapewne, chcecie w register
rejestrować Wasze nowe operatory/panele etc.
W User Preferences można włączać/wyłączać addons.
Z linii poleceń.
See blender --help
naturalnie po szczegóły.
--background
(-b
)
mówi żeby zakończyć Blendera po wykonaniu ew. skryptów,
renderowania, konsoli z linii poleceń. Kto zna Emacsa,
może też sobie kojarzyć -b
z --batch
,
bo sens jest bardzo podobny.
Dokumentacja sugeruje że zaraz po -b zawsze jest nazwa pliku do załadowania, ale w praktyce nie jest to konieczne, i tak jest nawet bardziej logicznie według mnie. Nazwa pliku .blend jest w końcu dozwolona wszędzie w trakcie command-line.
--render-frame
oraz inne opcje pozwalają renderować
ze skryptów. Np. blender --render-frame 1 --background plik.blend
--factory-startup
jest często użyteczne dla skryptów,
pozwala ominąć ładowanie startup.blend na początku z domyślnymi
ustawieniami użytkownika. Dzięki temu nasze skrypty działają
na czystym Blenderze (pewna wada to że startup.blend może
też zawierać ścieżkę "scripts" dla niestandardowych instalacji...
miejmy nadzieję że zamieszanie ze startup.blend zostanie kiedyś
naprawione, obecnie startup.blend to worek na wszystko:
preferencje użytkownika, początkową scenę, ścieżki systemowe etc.)
Wreszcie --python plik.py
(-p plik.py
)
nakazuje wykonanie odpowiedniego skryptu Blenderowego.
Przykład: blender --background --factory-startup plik.blend --python skrypt.py
Zamiast nazwy pliku z kodem Pythona można też podać nazwę bloku tekstowego w pliku .blend.
Kolejność opcji jest ważna, są generalnie (modulo pewne udziwnienia czasami) wykonywane w kolejności podawania. Jeśli podamy nazwę pliku .blend za -P, to skrypt zostanie wykonany przed załadowaniem sceny z pliku, a więc praca skryptu najprawdopodobniej pójdzie na marne (jeżeli skrypt modyfikował/tworzył coś na scenie to załadowanie nowej sceny z pliku usunie to co robił skrypt).
Pamiętamy że wszystkie polecenia menu to operatory,
a wszystkie operatory możemy wywołać ze skryptu?
Naturalnie, mamy w ten sposób bpy.ops.wm.save_as_mainfile(filepath="/tmp/blah.blend")
.
(nie wiem czy jest metoda na to poza bpy.ops, możliwe że
tak ale nie mogłem znaleźć w 2.5).
Pamiętajcie: wywołanie operatora z Pythona przez
bpy.ops...
ustawia jego properties, po czym domyślnie
robi execute
(nie invoke). Dlatego powyższy przykład
bierze filename z parametru, zamiast uruchamiać interaktywny
file selector. Porównajcie w interaktywnej konsoli
bpy.ops.wm.save_as_mainfile(filepath="/tmp/blah.blend") bpy.ops.wm.save_as_mainfile('INVOKE_DEFAULT', filepath="/tmp/blah.blend")
Sample: [sample - make_hilbert_curve.py].
Run as blender --background --factory-startup --python make_hilbert_curve.py
(make sure to adjust path at the end first!).
Sample from Blender examples:
blender --background --factory-startup \ --python ~/installed/blender/2.57/scripts/templates/background_job.py -- \ --text="Hello World" \ --render="/tmp/hello" \ --save="/tmp/hello.blend"
Inne opcje command-line warte odnotowania: --python-console
.
Uruchamianie skryptów kiedy otwieramy plik Blendera:
wystarczy zaznaczyć Register (i nazwać bufor z rozszerzeniem
.py
). Pamiętamy że nie wszyscy to zobaczą — see uwagi
o bezpieczeństwie powyżej.
Sample: register this:
import bpy class HelloOperator(bpy.types.Operator): bl_idname = "wm.hello" bl_label = "Hello Operator" def execute(self, context): return {'FINISHED'} def invoke(self, context, event): context.window_manager.invoke_confirm(self, event) return {'RUNNING_MODAL'} bpy.utils.register_class(HelloOperator) bpy.ops.wm.hello('INVOKE_DEFAULT')
Nieco o modułach Blendera i bezpieczeństwie:
Moduły Blendera w Pythonie są integralną częścią samego Blendera.
Innymi słowy, żeby zrobić w Pythonie import bpy
musimy być
w środku Blendera. Nie możemy zrobić import bpy
w normalnej
konsoli standalone Pythona, bpy
to tylko sposób dostępu do danych trzymanych przez Blendera w pamięci.
W praktyce nie jest to problemem dzięki różnym pomocom do Pythona
wbudowanym w Blendera, jak konsola w środku Blendera, jak --python-console
,
jak uruchamianie skryptów w trybie wsadowym przez -P etc.
Skrypty Blendera mają dostęp do pełnej instalacji Pythona (tej z którą Blender został zlinkowany albo skonfigurowany, see manual), skrypty mogą korzystać z dowolnych modułów Pythona zainstalowanych na Waszym systemie (nie tylko tych wbudowanych w Blendera). Więc macie rzeczywiście pełną siłę Pythona do dyspozycji.
Ten ostatni punkt wskazuje też na naturalny problem w bezpieczeństwie. Po prostu nie uruchamiajcie skryptów z nieznanych, nie zaufanych źródeł, ponieważ mogą zrobić w zasadzie wszystko (to co normalny program z uprawnieniami Waszego użytkownika), np. kasować pliki etc. Włączając skrypty (explicite przez Alt+P, czy przy otwieraniu pliku z zarejestrowanymi skryptami) pamiętajcie że właśnie uruchamiacie program, więc lepiej żebyście ufali jego autorowi (albo przejrzeli kod źródłowy).
(Niestety, standardowa implementacja Pythona na python.org ("C implementation") nie wspomaga niczego w stylu sandboxa. Kiedyś były zalążki, ale developerzy Pythona się z nich wycofali, twierdząc że prawdziwe security daje tylko chroot/jail etc.)
Jeżeli otwieracie pliki z niezaufanych źródeł odznaczcie Trusted Source przy otwieraniu, żeby nie pozwolić na automatyczne uruchamianie skryptów z "Register". Jest też w "User Preferences" checkbox "Auto Run Python Scripts". docs, docs pl.
Sample: nasty.blend
Linki do gotowych skryptów Blendera: Scripts/Catalog
Kilka starych uwag dotyczących skryptów w Pythonie w Blenderze 2.4x.
Tworzenie obiektów / meshy / powiązań (Blender 2.4x):
Sample z BSoD tworzenia sceny.
[sample - circle_producer.py] na podstawie manuala
(o GUI opowiemy później, teraz patrz tylko na funkcję tworzącą polygon)
Sample "Creating simple Materials and linking them to Objects" z BSoD.
Import / export: skoro umiemy odczytywać i modyfikować scenę Blendera z Pythona, to pisanie skryptów importujących/exportujących z Blendera staje się bardzo łatwą zabawą. Python daje nam funkcje do odczytu/zapisu plików tekstowych i binarnych, i jesteśmy w domu.
Sample: Importers-Exporters z BSoD.
Sample: any real-world exporter?
GUI w skryptach (Blender 2.4x):
Używanie gotowych powiadomień / okienek Blendera, patrz moduł Window.
Np. Window.DrawProgressBar
(sample: referencja modułu Window,
działający trywialny przykład: [sample - progress_bar_demo.py]), Window.FileSelector
.
Bardziej zaawansowane GUI używając widgetów Blendera, patrz moduł Draw.
Okienko Scripts.
Draw.Register
(rejestruje callbacki +
przełącza nas na "Scripts" + uruchamia event loop). De facto wiele skryptów
może działać jednocześnie, dlatego na headerze "Scripts" mamy listę
do wyboru które
GUI aktualnie oglądamy. Czyli każdy skrypt uruchamiany z "Text Editor"
(który wywoła Draw.Register)
dostaje jakby swoje własne "pole do popisu" w ramach okienka "Scripts".
Draw.Exit
kończy event loop, zamyka to "pole do popisu",
i wraca do poprzedniego okienka (np. Text Editor
jeśli skrypt został uruchomiony z text editor).
Dokumentacja do GUI:
Jest tutaj mały haczyk, przynajmniej dla mnie (i zapewne dla innych
którzy znają inne API do tworzenia GUI, jak GTK): w środku każdego callbacka
draw tworzymy od nowa przyciski. Funkcje jak Draw.PushButton
,
Draw.Number
nie tylko dodają przycisk do naszego okienka, ale
też rysują go. Każde glClear czyści okienko, więc w każdym draw od nowa
dodajemy wszystkie przyciski. Przycisk stworzony przez
np. Draw.Number
nie ma metody jak redraw
.
De facto, klasa Button
(zwracana przez metody tworzące
przyciski) zawiera tylko jedno pole, val
, czyli po prostu
value naszego przycisku. Jedyne
co możemy z zrobić z przyciskiem to pobrać jego wartość przez
button.val
,
i w każdym draw od nowa tworzyć (i rysować) ten przycisk,
używając jego aktualnej wartości jako początkowej. Samo Draw.Create
tylko tworzy domyślny obiekt Button, czyli po prostu opakowanie
na val i nic więcej. Czyli, w skrócie i w praktyce, jak zarządzać przyciskami:
# Wywołaj raz, przed Draw.Register. Ustala domyślną wartość, sprawiając że # my_button.val zawsze istnieje (tzn. zmienna my_button jest zainicjowana # i zawiera obiekt klasy Button) my_button = Draw.Create(666) def draw(): # ...... # Wywołaj w odpowiednim miejscu callbacka draw. # Rysuje przycisk, sprawia że będzie reagował na klawisze/mysz jak należy, # ustawia parametry (min / max sliderów etc.), # aktualna wartość przycisku to my_button.val - czyli wartość ostatnio # utworzonego przycisku (tutaj albo przez Draw.Create na początku) ew. # zmodyfikowana przez użytkownika global my_button my_button = Draw.Number("Title", MY_EVENT, 1, 1, 100, 100, my_button.val, 3, 20, "Tooltip");
Modalne (pop-up) GUI: patrz Draw.PupXxx
,
np. Draw.PupMenu
, bardziej elastyczne Draw.PupBlock
(możemy wyrazić GUI jako składankę przycisków Blendera),
najbardziej elastyczne Draw.UIBlock
(możemy podać callback do rysowania).
Space handler scripts, see [docs]
To są skrypty które można "podczepić" do okienka 3D (w przyszłości plan jest aby można było je "podczepiać" też do innych okienek). Tak podczepiony skrypt może 1. przechwytywać i przetwarzać zdarzenia okienka (kliknięcie, ruch myszką) 2. rysować coś na okienku. Mechanizm jest bardzo ogólny i pozwala tworzyć własne narzędzia interaktywne za pomocą skryptów (pierwszy prototyp Sculpt mode był wykonany właśnie jako skrypy Blendera).
# SPACEHANDLER.VIEW3D.EVENT
lub
# SPACEHANDLER.VIEW3D.DRAW
.
Wtedy skrypt rysuje lub przechwytuje zdarzenia odpowiedniego okienka. Komunikację pomiędzy kolejnymi wywołaniami naszego skryptu (i pomiędzy skryptami event i draw) zapewnia moduł Registry.
[sample - space_handler_demo (nieudany - draw nie działa jak należy)] .
Persistent dane skryptów (Blender.Registry), sample: patrz BSoD. Dokumentacja: patrz Blender Python API reference (moduł Registry oraz strona "related"), także archived email [Bf-python] Blender.Registry.
Scripts Configuration Editor (w okienku Scripts patrz menu System) jest bardzo przydatny do debugowania tego / oglądania danych innych skryptów.
Rejestrowanie skryptów w menu. Ładowanie źródła skryptu w Text Editor i uruchamianie przez Alt+P jest dobre kiedy piszemy i testujemy nasz skrypt. Kiedy chcemy po prostu używać skryptu, bez konieczności przełączania się na Text Editor, możemy zarejestrować nasz skrypt aby pojawił się w odpowiednim miejscu menu.
Dokumentacja: Blender Python API reference (strona "related"), także archived email [Bf-python] HOWTO have scripts in menus.
Okienko Scripts -> Update Menus.
Rejestracja sprawia że nasz skrypt pokazuje się w odpowiednim
menu Blendera (np. export, 3d view Object menu, UV/Image Editor).
Ponadto wszystkie zarejestrowane skrypty są też widoczne w menu
okienka "Scripts". Patrząc na menu okienka "Scripts" widzimy też
wszystkie obsługiwane nazwy dla Group
przy rejestracji.
Ponadto, zarejestrowany w ten sposób skrypt może w prosty sposób
wyświetlać modalne okienko z pytaniem, bez potrzeby używania funkcji
opisywanych wyżej przy okazji GUI. Deklaracje Submenu sprawią
że Blender automatycznie wyświetli okienko z opcjami do wyboru,
wybór użytkownika mamy w skrypcie w __script__['arg']
.
Uruchamianie skryptów kiedy trwa animacja: Możemy wyrazić rozwój naszej animacji za pomocą skryptów. Możemy napisać skrypt który za każdym razem oblicza wszystko na podstawie aktualnej ramki, albo skrypt który uaktualnia poprzednią ramkę (drugą wersję zazwyczaj łatwiej się pisze ale naturalnie działa inaczej kiedy nie chodzimy po ramkach po kolei).
sample: move.py
Scriptlink do konkretnego obiektu (albo World, albo materiału, kamery,
światła etc.) — patrz Blender.bylink
,
Blender.event
i przede wszystkim Blender.link
.
Bardzo użyteczne żeby móc "podpinać" ten sam skrypt pod wiele wybranych
obiektów.
[sample - scriptlink_simple_move]
Tylko dla 2.4, as far as I see. Dla 2.5, nie ma gdzie wstawić poniższego tekstu:
import bpy bpy.context.object.location[0] += 1.0
Aktualną ramkę mamy w... przesuń kursow myszy ponad numer ramki w domyślnym widoku, i sam zobacz :).
Introduction to the Game Engine (z Blender Summer of Documentation) — elementarne wprowadzenie do game engine.
gameBlender Documentation — dokumentacja game engine z czasów Blendera 2.12. Czyli dość stara, ale w 90% jest ciągle aktualna i zawiera naprawdę solidne omówienie wielu przycisków / opcji game engine. Wersja w HTML jest tutaj (chociaż w/g wersji jest jeszcze starsza — ale nie zauważyłem znaczących różnić).
Dokumentacja Python API specjalnie dla Blendera
Dokumentacja wiki do game engine. Trochę, ehm, miejscami surowa, w zasadzie luźny zbiór linków.
samples: poza moimi [sample - octopus_controlled] i [sample - gametests], popatrzymy też na ładne demo (z ruchem akcjami na klawiaturę, kamerą zza pleców) z 3rd Person Camera Collision Detection.
Podstawy widzieliśmy już przy okazji omawiania fizyki: rigid body na wykładzie o fizyce to był wstęp do game engine. Ultra-krótkie przypomnienie: panel Logic (F4) konfiguruje nasz obiekt dla game engine. Menu Game zawiera różne opcje game engine, z których najważniejsza to Start game (klawisz P, jak Play).
Co nam daje game engine? Blender troszczy się o renderowanie obiektów, wykrywanie kolizji, i całą fizykę (grawitacja, reakcje na kolizję (odbijanie się etc.)). Czyli my musimy tylko zrobić nasze modele (tak jak normalne modele w Blenderze; animacje, Ipo i akcje, też są "uruchamialne" z game engine!), po czym zdefiniować szczególne interakcje pomiędzy naszymi obiektami (które nie wynikają z fizyki), oraz obsłużyć użytkownika ("użytkownik", jak wiadomo, to tylko urządzenie wejściowe stanowiące połączenie myszki i klawiatury).
Widok game engine jest podobny do wybranego widoku w interaktywnym widoku 3D blendera, czyli zazwyczaj przed wejściem w game engine zmieniamy widok na textured (alt+z). Tekstury przypisane do materiałów nie są widoczne (jak już sobie opowiadaliśmy, one są tak skomplikowane że da się je renderować tylko na prawdziwym renderingu, nie w real-time) — czyli musimy polegać na teksturach UV i sekwencji unwrap + bake (przypomnienie prostego bake: w edit mode, zaznacz wszystkie ściany, w UV/image editor dodaj nowy image, w widoku 3D zrób unwrap (U) a potem bake (Ctrl+Alt+B) np. z "full render").
Materiały, oświetlenie dla game engine: dla materiałów po przyciśnięciu "DYN" mamy trochę opcji specjalnie dla game engine.
Generalnie, światła Blendera działają, chociaż z pewnymi kruczkami. Jeżeli obiekt ma jakikolwiek materiał, to musimy zadbać o włączenie "Light" dla ścian naszego obiektu: dodajmy UV Texture jeżeli obiekt jeszcze jej nie ma, potem w edit mode na panelu Editing (F9) szukamy zakładki "Texture Face". Tam jest trochę konfiguracji zapamiętywanych dla każdej ściany z osobna, i tylko wtedy kiedy UV tex jest włączone (dlatego włączyliśmy UV, nawet jeżeli nie przypisujemy tekstury). Upewniamy się że aktywna ściana jest zaznaczona (przy trybie zaznaczania ścian, klikamy prawym klawiszem na dowolną ścianę), włączamy "Light", po czym Ctrl+C kopiujemy "Active mode" (to są te ustawienia w "Texture Face") z active face do wszystkich zaznaczonych faces. Ponadto światło oświetla tylko elementy na tej samej warstwie!
Logic bricks: Sensor generuje sygnał kiedy zajdzie jakieś zdarzenie na obiekcie. Sensor łączymy z controllerem który zbiera sygnały, może ją łączyć koniunkcją, alternatywą, albo wyrażeniem. Controller może też wywołać skrypt w Pythonie. Controllery których wynik jest pozytywny uruchamiają odpowiedniego actuatora, który faktycznie coś robi (np. aplikuje siłę na obiekcie, przesuwając go itd.). Na panelu logic mamy wiele przycisków do ukrywania/pokazywania obiektów na których logic bricks aktualnie patrzymy. Dodajemy i usuwamy logic brick przez Add/X. Łączymy je po prostu przeciągając kreski od out socket do in socket (całkiem jak przy nodes materiałów), klawisz Del usuwa połączenie pod kursorem myszy. Logic brics możemy też nazywać, przesuwać w górę / w dół (click na zminimalizowanym brick aby dostać menu move up / down).
Pulsy: tak naprawdę powyższy akapit to małe uproszczenie, które sobie teraz skomplikujemy. Sensory mogą produkować "pulsy" ON albo OFF. ON oznacza że dany warunek zachodzi, OFF że nie zachodzi. Przyciski z "..." pozwalają włączać nieustanne generowanie pulsów (w każdym logic tick, albo co ileś ticks gdy f: jest większe od zera) pulsów ON lub OFF. Bez żadnych ON/OFF włączonych, sensor po prostu produkuje pojedynczy puls ON lub OFF kiedy zmienia się stan danego warunku (czyli np. sensor Always produkuje wtedy tylko pojedynczy puls, sensor Collision produkuje puls ON kiedy zaczyna się kolizja i OFF kiedy się kończy, sensor Keyboard kiedy użytkownik przyciska i puszcza klawisz). "Inv" zmienia pulsy ON na OFF i odwrotnie.
Controllery robią operacje logiczne na tych pulsach. Wynik przekazują do aktuatora, puls "ON" włącza actuatora, pulse "OFF" go wyłącza.
Powyższy akapit napisałem po części na podstawie testów (docs były niejasne dla mnie...) skryptem
# TODO: this should be fixed for Blender 2.5, no getSensor import GameLogic co = GameLogic.getCurrentController() print("controller works") sen = co.getSensor("colpulses") if sen.isPositive(): print("pulse ON") else: print("pulse OFF")
Taki skrypt można wkleić do controllera Python żeby obserwować pulsy, zaraz się będziemy tym więcej bawić.
Kolizje: pamiętajcie aby włączyć obiekty jako "aktorzy" dla game engine. Pamiętajcie że żeby kolizje działały sensownie, obiekty muszą mieć odpowiednie bounds: trzeba je wybrać, trzeba też uważać na skalowanie (generalnie, obiekt nie powinien być skalowany — w razie potrzeby Ctrl+A, czyli apply scale and rotation), center obiektu powinien być w środku (center new w razie potrzeby). Włączenie show physics visualization w menu game pozwala nam łatwo zauważyć błędne bounds obiektów. Convex hull polytope (czyli otoczka wypukła 3D) to skomplikowany obiekt bound pozwalający na ruch, Static triangle mesh (statyczne trójkąty) to skomplikowany obiekt bound który nie pozwala na ruch (dobry dla obiektów ograniczających scenę). Można też dostosowywać Radius dla bounds.
Fizyka: obiekty mogą, ale nie muszą, podlegać działaniu fizyki: przycisk dynamic. Bez fizyki też możemy ruszać obiektami, np. dLoc dla Motion actuator działa Ok. Ale siły nie działają, np. Force dla Motion actuator już nie działa bez fizyki. Samo dynamic sprawia że działa fizyka, dodatkowo Rigid body sprawia że obroty ("rolling physics") będą też działały.
Property: po lewej stronie jest Add property — property są raczej dość intuicyjne, to po prostu zmienne. Możemy je badać i ustawiać za pomocą różnych rzeczy, patrz niżej.
Różne rodzaje logic bricks: Overview of Sensors, Controllers, Actuators z BSod, a później gameBlender Documentation.
Sensor Always: zachodzi przez cały czas. Dokładniej: jest wywoływany raz na "logic tick". Ile mamy "logic ticks" na sekundę? Jak zobaczymy za chwilę, można to sprawdzić Pythonem:
import GameLogic print(GameLogic.getLogicTicRate())
i odpowiedź u mnie brzmi 60.0 (hm, chociaż docs mówią że default to 30). Wynik jest w Hz, czyli po prostu "ile razy na sekundę". Możemy nawet ustawiać ilość tych "ticków" Pythonem.
Sensor Keyboard: zachodzi gdy użytkownik kliknie podany klawisz.
Actuator Motion: poruszanie/obracanie obiektem. dLoc i dRot to proste zmiany lokacji / rotacji (bez żadnego związku z fizyką). Bardziej "fizyczne" są Force (prosta siła aplikowana do obiektu), Torque (moment siły, w praktyce po prostu siła ktora sprawia że obiekt się obraca). linV, angV ustalają szybkość ruchu, też dla fizyki.
Uwaga: bardzo ważny jest malutki przycisk "L", kontrolujący czy podany wektor jest we współrzędnych lokalnych (obiektu) czy globalnych (całej sceny). Jeżeli nasz obiekt się obraca, to jego współrzędne lokalne cały czas się zmieniają — aplikowanie do niego siły we współrzędnych lokalnych może dawać inne efekty niż pożądane.
Sensory Collision, Touch pozwalają wykrywać kolizje. Touch można ograniczyć do obiektów z zadanym materiałem, Collision do obiektów z zadanym materiałem lub property. (wartość property nie ma tu znaczenia, tylko jej istnienie).
Podobnie Near bada bliskość do innego obiektu. Zwracam uwagę że odległość (dla Dist) jest mierzona od centrum obiektu, więc dla dużych obiektów samo Dist musi być dość duże, inaczej centrum obiektu nie będzie miało jak znaleźć się blisko innych obiektów.
Actuator Edit Object pozwala np. wprowadzać do sceny nowe obiekty, usuwać aktualny obiekt, zmieniać jego mesh.
Actuator Message pozwala wysyłać wiadomości, które następnie mogą być odbierane przez inne obiekty sensorami Message. To jest metoda aby jeden obiekt przekazał swoje zdarzenie innemu/innym obiektom.
Actuator Property pozwala nam na różne sposoby modyfikować wartość naszych property.
Aktuator Camera: podpinamy go jako actuator (na Always) do obiektu kamery. W rezultacie kamera stara się zachowywać jak prawdziwy operator kamery który stara się filmować wskazany obiekt: reaguje na ruchy obiektu (z odpowiednim opóźnieniem), ustawia się tak żeby ściany nie zasłaniały obiektu etc. Szczerze mówiąc, czasami trochę trudno go kontrolować...
Ogólnie kiedy uruchomimy grę z widoku kamery (tzn. Numpad 0), aktualna kamera będzie używana do wyświetlania obrazu gry. Wtedy zobaczymy efekt aktuatora kamery, możemy też kontrolować taką kamerę bardziej "klasycznie": przez parent do obiektu. ("Track to" constraint nie działa, chyba constraints nie działają w ogóle w game engine? Chyba.)
Warning: wygląda na to że game engine chwilowo nie działa jak należy w perspective mode. To dotyczy także przypadku gdy uruchamiamy game z widoku kamery w trybie perspective.
Inne sztuczki z kamerą: patrz tutaj, także jak zrobić inteligentną kamerę zza pleców bohatera (bez camera actuator).
Actuator Action (arcy-ważny): to nasza furtka do uruchamiania animacji Blendera (zapamiętanych jako akcje, więc mogą być oparte na armaturze lub shape keys). Proste animacje zapisane tylko jako Ipo curve możemy uruchamiać przez actuator Ipo.
Hinty do Action:
Armatura musi być przypisana starym sposobem, poprzez parent, nie jako modyfikator. Nie patrzcie tak na mnie, pamiętam że mówiłem wiele razy że modyfikator jest lepszy... no i jest, tak twierdzę ja, manual Blendera i paru innych fajnych gości. Ale niestety game engine przecież nie umie używać modyfikatorów, zresztą nie umie też używać constraints (a kiedy używany armaturę jako modyfikator, to zazwyczaj używamy także constraints jako copy location / rotation...) więc armatura jako modyfikator po prostu nie działa. Tzn. armatura właściwie działa Ok, ale kompletnie nie wpływa na faktycznego mesha. Na szczęście powrót do starego sposobu jest łatwy, wystarczy skasować modyfikator i zrobić parent do armatury (wybierając "don't create groups", bo przecież już mamy pomalowane vertex grupy). Naturalnie mamy problem jeżeli używaliśmy szczególnych ustawień modyfikatora armatury, których po prostu teraz nie mamy...
W moich eksperymentach musiałem ustawić zasadniczego mesha jako Actor z Ghost — żeby nie kolidował ze swoją własną armaturą w środku.
Acha, i jeszcze zauważyłem że Armatura oparta na Envelopes nie działa... przy robieniu parent do armatury możemy wybrać create vertex groups "create from envelopes", w ten sposób przy okazji zamienimy envelopes na vertex group i Blender będzie happy.
Opcje jak "Loop Stop" mówią co się dzieje na puls ON i na OFF. Najważniejsze:
Patrz docs gameBlender Documentation po referencję reszty.
Notka do odtwarzania akcji z constraints (pamiętajcie że game engine nie umie honorować constraints): trzeba zrobić bake akcji, patrz notka "Baking Actions" z manuala o "Mesh Skin Weighting" i przycisk Bake w okienku akcji. TODO: Update: w Blenderze 2.46 tego przycisku już nie ma. Uhm, release notes twierdzą że został usunięty bo "they were not really functional anyway, and should really belong exclusively in the NLA (and/or 3D view). If and when they are reimplemented, they should not be added back to the Action Editor."
[sample - octopus_controlled]: armatura, actions, ruchy potworkiem AWD, celowo bez żadnego Pythona! (Ale bez Pythona ruch jest też nieprzyjemnie jednostajny, podczas gdy w przypadku akurat octopusa powinien mieć zmienną szybkość. Zrobienie zmiennej szybkości już naprawdę wymaga Pythona.)
Controller Python (drugi arcy-ważny)
to nasza "furtka" aby podczepić skrypty
w Pythonie do game engine. Patrz
dokumentacja
Python API specjalnie dla Blendera. Kluczem jest tutaj moduł
GameLogic
, którego import możemy zrobić tylko kiedy działamy
w trakcie gry (normalnie, nawet kiedy jesteśmy w środku z Blendera,
dostaniemy po prostu "ImportError: No module named GameLogic").
Ten moduł pozwala na rozmaite interakcje z game engine, w szczególności
także z sensorami/aktuatorami game engine:
import GameLogic co = GameLogic.getCurrentController()czyli pobierz aktualny kontroler.
sens = co.getSensor("sensorname")czyli pobierz sensor z naszego kontrolera.
actuator = co.getActuator("actuatorname") GameLogic.addActiveActuator(actuator, True)czyli pobierz i wyślij puls (ON lub OFF, drugi parametr addActiveActuator) aktuator.
I inne logic bricks, podkreślę jeszcze raz link: gameBlender Documentation.
To tylko skrót wybranych rzeczy z 2.5 release notes. Od 2011, różne elementy tego wykładu są de facto omawiane po drodze, jako normalne feature'y w nowym Blenderze.
Nowy interfejs! Wielka reorganizacja narzędzi/przycisków:
Tool shelf (T) w widoku 3D.
Na dole pokazuje aktualną akcję i pozwala zmodyfikować jej parametry. Idea: najpierw uruchamiamy narzędzie, potem dobieramy jego parametry (poprzednio było zazwyczaj na odwrót). Ładne przykłady: add uv sphere, spin.
Wielka reorganizacja zawartości Buttons Window, teraz nazywane Property Editor.
Idea: zawierają rzeczywiście tylko właściwości (różnych elementów Blendera). Np. "transform properties" (ciągle też dostępne pod "n") są tam widoczne.
Nie zawierają narzędzi (te widzimy w Tool shelf) ani konfiguracji narzędzi (te widzimy na dole Tool shelf kiedy dana akcja jest aktywna).
Idea za wieloma zmianami: see release notes i evolution_of_blenders_ui.pdf
Search tool, dzięki wewnętrznej bazie narzędzi (poprzednio menu + hotkeys + przyciski + python uaktywniały rożne rzeczy różnie, teraz to wszystko jest unified).
Chociaż ciągle można ułożyć panele horizontal, 2.5 domyślnie sugeruje ułożenie vertical. Idea: niektóre panele naprawdę nie miały szans wyglądać Ok horizontal (np. lista modyfikatorów, selected bones etc.), a niektóre panele wyglądały brzydko (bo były grupowane tak żeby miały sensowną wysokość, zamiast grupować w/g funkcji, patrz e.g. "Editing").
Różne małe ale arcy-miłe drobiazgi:
Animacja: wszystko jest animowalne. W związku z tym: F-curves: ulepszone ipo-curves, Dopesheet: ulepszony Action Editor.
Modyfikatory curves. Szybkie demo noise. Modyfikatory też przejmują np. poprzednie cyclic.
Dowolne particle, soft, cloth mogą być edytowalne (tak jak poprzednio włosy) w "Particle Mode".
Modyfikator Solidify.
Także multiresolution jako modyfikator, i wiele ulepszeń sculpt.
Python:
Materiał typu Volume. See 2.5 release notes o Volume rendering, także dokumentacja.
Projekcja + przeglądanie danych użytych do zrobienia "Elephants Dream" i "Big Buck Bunny". Przy okazji tego drugiego filmiku zerkniemy też na niektóre nowości w Blenderze 2.46 (see release notes dla 2.46).
Krótki plan:
Organizacja katalogów ED (na podstawie readme w środku) — W production/ mamy 8 scen (wygodnie spojrzeć na finalscript). Sceny są podzielone na shots. Każdy shot to plik blend. Shot zawiera zlinkowane dane z production/lib/, wszystko jest linkowane przez relative paths więc działa Ok. W production/lib/ są różne elementy które wygodnie było tworzyć osobno, jak chociażby postacie dwóch bohaterów Emo i Proog. Tekstury są w production/lib/textures/, też linkowane przez relative paths.
Czyli w sumie nic nadzwyczajnego, tylko dobrze zorganizowane dzięki linkowaniu tak żeby można było edytować dowolny kawałek filmu.
live_edit.blend zawiera tylko VSE aby odpowiednio sklejać wyrenderowane shots (zakłada że mamy już gotowe avi dla naszych shots).
Podkatalogi "an" zawierają "animatics", co oznacza (o ile wiem) po prostu "wstępny szkic jakiegoś kawałka animacji". [pokaż kawałek za połową "making of ..."]
[pokaż lib/ducks/jorma] Grupowanie: Ctrl+G, panel "Objects and Links". Grupy pozwalają organizować obiekty niezależnie od zależności parent/child. Obiekty w grupie są zielone w trybie wireframe.
Można stworzyć "instancję grupy": dla dowolnego obiektu można ustawić "DupliGroup" i wpisać nazwę grupy. Albo, prościej: po prostu z menu Add->Group->... dodaje nowy obiekt Empty ustawiony na instancję wybranej grupy. Czyli grupy pozwalają na coś jak "duplicate linked" (alt+d), tyle że dla całej grupy obiektów Blendera.
Można też ograniczać działanie fields do danej grupy (normalnie obiekt jest pod wpływem wszystkich fields z tej samej warstwy). Wygodne kiedy robimy np. włosy przy pomocy różnych sił — wtedy łatwo możemy stwierdzić że mamy zbyt mało warstw żeby odpowiednio odseparować od siebie wszystkie fields.
Grupy działają odpowiednio z linking / appending. Dlatego w ED (prawie?) wszystko jest zorganizowane w grupy, i robiony jest linking grup.
(Raczej nie? Renderują się zbyt długo...) System nodes (materiałów i compositora) został zaimplementowany właśnie w trakcie prac nad ED, i widać że używają go dużo (chociażby różne blury są używane w różnych dynamicznych miejscach, pod koniec filmu kolory są modyfikowane trochę surrealistycznie...).
(Chciałem pokazać jakieś przykładowe ustawienia, ale szczerze mówiąc nawet najprostsze sceny z najprostszymi ustawieniami renderują się zbyt długo).
Fragmenty:
ducks/harmi (note the parent lid from neck1, so it nicely opens)
05_05_simplified: jak otwiera się śluza. Prosty obrót + instance grupy headsnarler. lib/machine/elevator/headsnarler. Każde blade ma kość (armature display option żeby w ogóle zobaczyć tą kość — każda armatura ma jakby w środku swoje własne warstwy). Każda z tych kości ma constraint "copy rotation" ze snarly_controller. Efekt: proste obracanie kością (czyli animacja krzywych Quat kości, jak quaternion) snarly_controller zamyka całą śluzę.
Organizacja BBB: tak jak w ED, podstawą jest scenes/, w nim każdy shot to pojedynczy plik blend. Znowu grupy i linkowanie do grup pozwala rozbić całość na wiele plików blend. Trawa, futro używają mnóstwa particles, więc oglądanie tych scen na normalnym komputerze jest jeszcze bardziej bolesne niż przy ED...
Podkatalog props/ zawiera wiele prostych obiektów Blenderowych. To zostawiam Wam do przeglądnięcia w domu, szczerze mówiąc wiele z nich nadaje się do użytku w innych filmach/grach etc. (a są na CC, więc można czerpać :) ).
Acha, były pytania o robienie napisów do filmu: zerknijmy na scenes/dvd/menu_credits.blend. Jak widać, obiekt Text blendera sprawdza się znakomicie. Krótkie demo obiektu Text. Na panelu edit mamy różne operacje specyficzne dla tekstu, możemy np. wybrać dowolny font ttf, załadować tekst z pliku, wprowadzić dowolny znak z Unicode... więc tekst jak najbardziej może być z polskimi znaczkami, taką czcionką jaką zechcemy.
flyingsquirrel: Armatura jest bardzo rozbudowana, można zerknąć na główne kości na ostatnim display options. Różne kości mają różne constraints, kości jest dużo, więc gdybyśmy widzieli wszystkie kości to w zasadzie nie umielibyśmy w ogóle nic z modelem zrobić...
Szczęśliwie dla nas, zaraz po otwarciu modelu widzimy tylko najważniejsze kości, i to są kości którymi możemy łatwo operować. Niektóre z tych kości nie wyglądają jak normalne kości Blendera, bo mają ustawiony OB — "object that defines custom drawing type for this bone". W pliku jest wiele obiektów o nazwach WIDGT_xxx które właśnie służą tylko do wizualizacji jakiejś kości.
Zerknijmy szybko na shape keys. Dużo. Zwróćmy uwagę na mesh deform — wiewiórkę otacza zewnętrzny mesh, który działa trochę jak lattice ale bardziej swobodne. O tym więcej za chwilę.
Na górze mamy "drivery", jak "mode" ("wings spread" etc.). Wspomniałem o tym bardzo krótko podczas wykładu o podstawach animacji, więcej się tym nie bawiliśmy bo jest to użyteczne dopiero przy naprawdę złożonych modelach, takich jak ten. Działa to łatwo: jakieś property (np. położenie przycisku CTRL_ModeSwitch) kontroluje input krzywej (np. WingsIn, WingsOut na shape).
Jeszcze więcej o materiałach i renderowaniu
...czyli różne ciekawe rzeczy, specjalne efekty etc. na które nie było wcześniej czasu albo "nie byliśmy na nie jeszcze gotowi" (nie znając podstaw materiałów i tekstur). Część tych efektów może przeniesiemy do wykładu o renderowaniu.
Materiał - Halo [docs]
Materiał - Subsurface Scattering [docs]
Vertex painting [docs]
Radiosity [docs - Introduction to Radiosity, Radiosity Rendering, Radiosity Baking]
Worlds & Backgrounds [docs - rozdział z manuala] (trochę bawiliśmy się różnymi przyciskami World przy okazji różnych wykładów i tutoriali).
Zewnętrzne renderery — Yafray, inne? [docs]
Verse: otwarty protokół do komunikacji pomiędzy programami 3D.
(To zapewne zbyt krótkie na wykład, ale warto pokazać przy jakiejś okazji. Być może na pracowni urządzić zabawę tym?)
Nie jest specyficzny dla Blendera, może być (i jest) używany przez inne programy (patrz np. gra Love, Uni-Verse, Crystal Space 3D).
Do czego służy? Przede wszystkim do wspólnego tworzenia światów 3D. Zmiany sceny 3D są natychmiast widoczne przez wszystkie inne osoby połączone z tym samym serwerem Verse (o ile "zasubskrybowały" odpowiedni obiekt). Może też służyć do udostępnienia siły obliczeniowej jednego komputera innym (np. rendering uruchamiany na jednym kliencie jest wykonywany (częściowo?) przez innego klienta), chociaż nie wiem czy jest to możliwe w Blenderze aktualnie (Blender pozwala na rozproszone renderowanie na inne sposoby, chociażby przez użycie zewnętrznego renderera).
Ze strony Verse-Blender można pobrać gotową skompilowaną wersję Blendera z włączonym supportem dla Verse. (Chociaż jest to dość stara wersja Blendera — do "prawdziwej" pracy polecałbym skompilowanie najnowszego Blendera samemu.) Jest też króciutki tutorial, w ciągu 5 minut można nauczyć się co oferuje Verse.
Dokumentacja:
Tutoriale:
Wiele tutoriali do innych programów 3D nadaje się do wykorzystania, np. przy modelowaniu mesha w zasadzie mamy te same operacje w każdym programie.
Oficjalne tutoriale 3ds Maxa - niektóre są niezłe. Szczególnie polecam sekcję o modelowaniu (tutoriale stamtąd przenoszą się dość 1-1 do Blendera), tutoriale jak "Modeling a Chess Set", "Modeling a Low-Poly Character".
Legal disclaimer: Pomijając fakt że nasz Instytut zakupił 3ds Maxa, każdy może też sam ściągnąć te tutoriale instalując wersję trial 3ds Maxa.
Modeling Joan of Arc by Michel Roger — inny tutorial napisany dla 3ds Maxa. Ilustruje bardzo dokładnie modelowanie sylwetki człowieka, ze wszystkimi detalami.
Blueprints, czyli rysunki / obrazki referencyjne (jeżeli znacie inne dobre linki, zgłaszajcie mi!):