Tomasz Wozniak´ - dsp.agh.edu.pldydaktyka:tomasz_wozniak_fin_fin.pdf · sa˛ze soba˛ ´sci ´sle...

49
AKADEMIA GÓRNICZO-HUTNICZA IM. STANISLAWA STASZICA W KRAKOWIE Wydzial In ˙ zynierii Mechanicznej i Robotyki PRACA DYPLOMOWA In ˙ zynierska Integracja biblioteki RAYA z silnikiem Unreal Engine 4 Tomasz Wo´ zniak In˙ zynieria Akustyczna 19 stycznia 2016 Promotor pracy: dr in ˙ z. Bartosz Ziólko

Transcript of Tomasz Wozniak´ - dsp.agh.edu.pldydaktyka:tomasz_wozniak_fin_fin.pdf · sa˛ze soba˛ ´sci ´sle...

AKADEMIA GÓRNICZO-HUTNICZA IM.

STANISŁAWA STASZICA W KRAKOWIE

Wydział Inzynierii Mechanicznej i Robotyki

PRACA DYPLOMOWA

Inzynierska

Integracja biblioteki RAYA z silnikiem Unreal Engine 4

Tomasz WozniakInzynieria Akustyczna

19 stycznia 2016

Promotor pracy: dr inz. Bartosz Ziółko

Kraków. dnia.......................

Imię i nazwisko :

Nr albumu :

Kierunek studiów :

Profil dyplomowania :

OŚWIADCZENIE

Uprzedzony o odpowiedzialności karnej na podstawie art. 115 ust 1 i 2 ustawy z dnia 4

lutego 1994 r. o prawie autorskim i prawach pokrewnych (tj. Dz.U.z 2006 r. Nr 90, poz.

631 z późn.zm.) : „Kto przywłaszcza sobie autorstwo albo wprowadza w błąd co do

autorstwa całości lub części cudzego utworu albo artystycznego wykonania, podlega

grzywnie, karze ograniczenia wolności albo pozbawienia wolności do lat 3. Tej samej

karze podlega, kto rozpowszechnia bez podania nazwiska lub pseudonimu twórcy cudzy

utwór w wersji oryginalnej albo w postaci opracowania, artystyczne wykonanie albo

publicznie zniekształca taki utwór, artystyczne wykonanie, fonogram, wideogram lub

nadanie”, a także uprzedzony o odpowiedzialności dyscyplinarnej na podstawie art. 211

ust.1 ustawy z dnia 27 lip[ca 2005 r. Prawo o szkolnictwie wyższym (tj. Dz.U. z 2012 r.

poz. 572, z późn.zm.) „Za naruszenie przepisów obowiązujących w uczelni oraz za czyny

uchybiające godności student ponosi odpowiedzialność dyscyplinarną przed komisją

dyscyplinarną albo przed sądem koleżeńskim samorządu studenckiego, zwanym dalej

„sądem koleżeńskim”, oświadczam, że niniejszą pracę dyplomową wykonałem(-am)

osobiście i samodzielnie i że nie korzystałem (-am) ze źródeł innych niż wymienione w

pracy”.

.....................................................

podpis dyplomanta

Kraków, dn……………..

Imię i nazwisko:

Nr albumu:

Kierunek studiów:

Profil dyplomowania:

OŚWIADCZENIE

Świadomy/a odpowiedzialności karnej za poświadczanie nieprawdy oświadczam,

że niniejszą inżynierską pracę dyplomową wykonałem/łam osobiście i samodzielnie oraz

nie korzystałem/łam ze źródeł innych niż wymienione w pracy.

Jednocześnie oświadczam, że dokumentacja oraz praca nie narusza praw autorskich

w rozumieniu ustawy z dnia 4 lutego 1994 roku o prawie autorskim i prawach pokrewnych

(Dz. U. z 2006 r. Nr 90 poz. 631 z późniejszymi zmianami) oraz dóbr osobistych chronio-

nych prawem cywilnym. Nie zawiera ona również danych i informacji, które uzyska-

łem/łam w sposób niedozwolony. Wersja dokumentacji dołączona przeze mnie na nośniku

elektronicznym jest w pełni zgodna z wydrukiem przedstawionym do recenzji.

Zaświadczam także, że niniejsza inżynierska praca dyplomowa nie była wcześniej

podstawą żadnej innej urzędowej procedury związanej z nadawaniem dyplomów wyższej

uczelni lub tytułów zawodowych.

………………………………..

podpis dyplomanta

Kraków, ……………..

Imię i nazwisko:

Adres korespondencyjny:

Temat pracy dyplomowej inżynierskiej:

Rok ukończenia:

Nr albumu:

Kierunek studiów:

Profil dyplomowania:

OŚWIADCZENIE

Niniejszym oświadczam, że zachowując moje prawa autorskie , udzielam Akademii

Górniczo-Hutniczej im. S. Staszica w Krakowie nieograniczonej w czasie nieodpłatnej

licencji niewyłącznej do korzystania z przedstawionej dokumentacji inżynierskiej pracy

dyplomowej, w zakresie publicznego udostępniania i rozpowszechniania w wersji druko-

wanej i elektronicznej1.

Publikacja ta może nastąpić po ewentualnym zgłoszeniu do ochrony prawnej wyna-

lazków, wzorów użytkowych, wzorów przemysłowych będących wynikiem pracy inży-

nierskiej2.

Kraków, ...............… …………………………….. data podpis dyplomanta

1 Na podstawie Ustawy z dnia 27 lipca 2005 r. Prawo o szkolnictwie wyższym (Dz.U. 2005 nr 164 poz. 1365) Art. 239. oraz Ustawy z dnia 4 lutego 1994 r. o prawie autorskim i prawach pokrewnych (Dz.U. z 2000 r. Nr 80, poz. 904, z późn. zm.) Art. 15a. "Uczelni w rozumieniu przepisów o szkolnictwie wyższym przysługuje pierwszeństwo w opublikowaniu pracy dyplomowej studenta. Jeżeli uczelnia nie opublikowała pracy dyplomowej w ciągu 6 miesięcy od jej obrony, student, który ją przygotował, może ją opublikować, chyba że praca dyplomowa jest czę-ścią utworu zbiorowego." 2 Ustawa z dnia 30 czerwca 2000r. – Prawo własności przemysłowej (Dz.U. z 2003r. Nr 119, poz. 1117 z późniejszymi zmianami) a także rozporządzenie Prezesa Rady Ministrów z dnia 17 września 2001r. w spra-wie dokonywania i rozpatrywania zgłoszeń wynalazków i wzorów użytkowych (Dz.U. nr 102 poz. 1119 oraz z 2005r. Nr 109, poz. 910).

Kraków, dnia

AKADEMIA GÓRNICZO-HUTNICZA WYDZIAŁ INŻYNIERII MECHANICZNEJ I ROBOTYKI

TEMATYKA PRACY DYPLOMOWEJ INŻYNIERSKIEJ dla studenta IV roku studiów stacjonarnych

imię i nazwisko studenta

TEMAT PRACY DYPLOMOWEJ INŻYNIERSKIEJ:

Promotor pracy: [Tytuł, imię i nazwisko Promotora]

Recenzent pracy: [Tytuł, imię i nazwisko Recenzenta] Podpis dziekana:

PLAN PRACY DYPLOMOWEJ (Należy ustalić z Promotorem, np.:) 1. Omówienie tematu pracy i sposobu realizacji z promotorem. 2. Zebranie i opracowanie literatury dotyczącej tematu pracy. 3. Zebranie i opracowanie wyników badań. 4. Analiza wyników badań, ich omówienie i zatwierdzenie przez promotora. 5. Opracowanie redakcyjne.

Kraków, ...............… …………………………….. data podpis dyplomanta

TERMIN ODDANIA DO DZIEKANATU: 20 r.

podpis promotora

Akademia Górniczo-Hutnicza im. Stanisława Staszica Kraków, ................. Wydział Inżynierii Mechanicznej i Robotyki

Kierunek:

Profil dyplomowania:

[imię i nazwisko autora] Praca dyplomowa inżynierska [temat] Opiekun: [stopień naukowy, imię i nazwisko promotora]

STRESZCZENIE [Treść streszczenia, maksymalnie do końca strony, Times New Roman 12 pkt]

AGH University of Science and Technology Kraków, the............ Faculty of Mechanical Engineering and Robotics

Field of Study:

Specialisations:

[First name and family name of the Author] Engineer Diploma Thesis [Title of the project in English] Supervisor: [degree, first name and family name of the Supervisor]

SUMMARY [The summary content, must fit within the page limit Times New Roman 12 pkt]

Serdeczne podziekowania dla mojego promotora

dr inz. Bartosza Ziółko za cenne uwagi odnosnie pracy,

oraz

dla mgr inz. Ireneusza Gawlika za pomoc i inspiracje.

7

Spis tresci

Wstep 10

1 Unreal Engine 4 11

1.1 Wybrane aspekty silnika . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

1.1.1 Edytor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

1.1.2 Architektura, model pamieci . . . . . . . . . . . . . . . . . . . . . . . . . . 11

1.1.3 Aktorzy i komponenty . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

1.1.4 Mechanizm refleksji . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

1.1.5 Serializacja, system asset-ów . . . . . . . . . . . . . . . . . . . . . . . . . . 15

1.2 System audio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

1.2.1 Sound Wave . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

1.2.2 Sound Cue, Sound Node . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

1.2.3 Audio Component . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

1.2.4 Pogłos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

1.2.5 Klasy audio i miksy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

1.3 System wtyczek . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

2 RAYA 20

3 Opis integracji 20

3.1 Załozenia projektowe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

3.2 Ogólny schemat działania . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

3.3 Architekrura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

3.4 RAYA-offline . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

4 Implementacja 25

4.1 Moduł gry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

4.1.1 Asset sceny akustycznej . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

4.1.2 Menadzer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

4.1.3 Komponent odbiornik . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29

4.1.4 Modyfikacja dzwieku w czasie rzeczywistym . . . . . . . . . . . . . . . . . 30

4.2 Moduł edytora . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

4.2.1 Asset materiał akustyczny . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

4.2.2 Komponent materiału akustycznego . . . . . . . . . . . . . . . . . . . . . . 35

8

4.2.3 Konfiguracja RAYA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

4.2.4 Eksport sceny . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38

4.2.5 Wypalenie sceny akustycznej . . . . . . . . . . . . . . . . . . . . . . . . . . 40

4.2.6 Kompresja . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

5 Zakonczenie 45

9

Wstep

Dzwiek, obok obrazu, od zawsze był nierozłaczna czescia wszelkiego rodzaju interaktywnych mul-

timediów, takich jak gry czy symulacje. Mimo tego, ze trudno sobie wyobrazic wciagajaca gre nie

posiadajacej oprawy dzwiekowej, aspekt ten jest, w porównaniu z obrazem, daleko w tyle. Na dzi-

siejszym rynku gier producenci przescigaja sie w oferowaniu w swoich produktach coraz to bardziej

realistycznej grafiki, jednoczesnie nie wprowadzajac zadnych ulepszen w aspekcie audio.

Obecnie, standardowa procedura tworzenia dzwieku w grach jest reczna konfiguracja róznych

jego aspektów i parametrów przez projektanta dzwieku. Pomijane przez to sa naturalne efekty aku-

styczne zwiazane z geometria wirtualnego swiata, takie jak odbicie czy dyfrakcja. W ostatnim okre-

sie, wraz z rozwojem technologii wirtualnej rzeczywistosci, na rynku komercyjnym zaczeły pojawiac

sie wyspecjalizowane aplikacje/biblioteki, których celem jest realistyczne modelowanie dzwieku w

trzech wymiarach w czasie rzeczywistym, np. 3Dception czy Oculus Audio SDK. Mimo, ze oferuja

one integracje z wiekszoscia najpopularniejszych narzedzi do tworzenia gier, korzystaja one z bardzo

uproszczonych modeli geometrycznych zamiast rzeczywistej geometrii sceny.

W niniejszej pracy zaprezentowany jest sposób i implementacja integracji biblioteki programi-

stycznej RAYA z popularnym na rynku gier silnikiem gier, Unreal Engine w wersji 4. Integracja

oznacza w tym przypadku mozliwosc wykorzystania funkcjonalnosci oferowanej przez biblioteke

RAYA z poziomu srodowiska Unreal Engine 4 za pomoca specjalnie napisanej w tym celu wtyczki.

Integracja taka pozwala na rozszerzenie mozliwosci systemu dzwiekowego Unreal Engine 4 o auto-

matyczna zmiane parametrów dzwieku w czasie rzeczywistym na podstawie rzeczywistej geometrii

sceny, materiałów akustycznych i aktualnego połozenia zródeł dzwieku oraz samego gracza.

Praca ta została podzielna na cztery rozdziały. Pierwszy z nich przybliza i opisuje architekture

oraz funkcjonalnosc silnika Unreal Engine 4 i wyjasnia kluczowe z punktu widzenia tej pracy ter-

miny. Drugi rozdział poswiecony jest ogólnemu opisowi zadaniu i mozliwosciach biblioteki RAYA.

W rozdziale trzecim przedstawiony został opis sposobu integracji: załozenia projektowe oraz archi-

tektura wtyczki. Własciwa implementacja została opisana w rozdziale czwartym.

W zwiazku z brakiem materiałów dotyczacych silnika Unreal Engine 4 w jezyku polskim, pod-

czas pisania tej pracy bazowano głównie na artykułach i dokumentacji angielskojezycznej. Tam gdzie

to mozliwe autor starał sie uzywac standardowych tłumaczen terminów. Wszystkie kluczowe sfor-

mułowania podane zostały zawsze z oryginalna wersja angielska.

10

1 Unreal Engine 4

Unreal Engine 4, w skrócie UE4, to wieloplatformowy silnik i srodowisko do tworzenia gier. Unreal

Engine 4 napisany jest wiekszosci w jezyku C/C++. Pierwsza wersja silnika została wydana w 1998

roku1. Obecnie cały kod silnika oraz towarzyszacych mu narzedzi jest open-source.

Ponizej przedstawione zostana wybrane aspekty silnika istotne z punktu widzenia tej pracy. Ze

wzgledu na bardzo złozona i rozbudowana architekture silnika, nie zostały one opisane w sposób

szczegółowy, równiez czesc powiazanych pojec została pominieta. Autor przyłozył jednak wszelkich

staran aby ich ogólny opis był dla czytelnika przejrzysty, a kluczowe zagadnienia zostały odpowiednio

wyjasnione.

1.1 Wybrane aspekty silnika

1.1.1 Edytor

Edytor jest podstawowym narzedziem developera tworzacego gre z uzyciem UE4. To za jego pomoca

tworzone sa poziomy, składajace sie na gre. Z poziomu edytora odbywa sie zarzadzanie własciwie

kazdym aspektem projektu. Tutaj nastepuje m.in. wyswietlanie i edycja sceny, testowanie rozgrywki,

rozmieszczanie i edycja wszelkiego rodzaju obiektów bedacych czescia gry oraz tworzenie animacji.

Innymi słowy, w edytorze zaczyna i konczy sie cały proces twórczy.

Graficzny interfejs edytora Unreal Engine 4 jest stworzony za pomoca platformy programistycznej

stworzonej specjalnie na potrzeby silnika o nazwie Slate.

1.1.2 Architektura, model pamieci

Fundamentalna czescia architektury silnika Unreal Engine 4 jest klasa UObject. Typ ten definiuje

szereg kluczowych funkcjonalnosci oferowanych przez silnik i znajduje sie na szczycie hierarchii

klas wszystkich obiektów. W Unreal Engine 4, własciwie kazdy obiekt bedacy czescia rozgrywki

jest typu dziedziczacego z UObject. Obiekty tej klasy sa m.in. zarzadzane przez odsmiecacz pamieci

(ang. garbage collection), biora udział w serializacji oraz mechanizmie refleksji (1.1.4).

1.1.3 Aktorzy i komponenty

Ponizej przedstawiony zostanie opis dwóch waznych z punktu widzenia tej pracy oraz działania sil-

nika (rozgrywki) terminów: aktor i komponent.1https://pl.wikipedia.org/wiki/Unreal_Engine

11

Rysunek 1: Okno edytora Unreal Engine 4. Zródło [8]

W terminologii Unreal Engine 4 aktor oznacza obiekt, który moze zostac umieszczony na scenie

[4]. Zachowanie i funkcjonalnosc aktora zdefiniowana jest przez komponenty. Komponent to pod-

obiekt aktora definiujacy pewna czesc jego zachowania/funkcjonalnosci [7]. Jak widac, oba te pojecia

sa ze soba scisle zwiazane. Kazdy aktor posiada co najmniej jeden komponent, tzw. komponent (ko-

rzen czy zródłowy?) który definiuje jego 3D-transformacje (połozenie, obrót i skale). Zarówno wiec

z technicznego punktu widzenia jak i uzytkownika, aktor to pewnego rodzaju kontener komponentów,

które wspólnie definiuja jego role w kontekscie gry. W Unreal Engine 4 wystepuje podział aktorów

ze wzgledu na rodzaj komponentu zródłowego: np. aktor reprezentujacy pewna statyczna geometrie,

Static Mesh Actor to aktor z komponentem zródłowym typu Static Mesh Component.

Aktorzy w Unreal Engine 4 posiadaja cykl zycia, który okresla zachowanie aktora od momentu

stworzenia jego instancji (automatycznie przez silnik badz na zadanie przez programiste) do momentu

jego zniszczenia (przez odsmiecanie pamieci). Konkretnie, cykl zycia aktora definiuje kolejnosc

oraz warunki wywoływania przez silnik poszczególnych funkcji interfejsu AActor (klasa bazowa dla

wszystkich aktorów, dziedziczaca z UObject) w zaleznosci od obecnego stanu rozgrywki i obecnego

stanu aktora.

W Unreal Engine 4 istnieja 3 podstawowe elementy hierarchii komponentów. Idac od góry hie-

rarchii (od najbardziej podstawowego) sa to:

• Actor Component (klasa UActorComponent) - baza dla wszystkich komponentów. Definiuje

12

funkcjonalnosc wspólna dla wszystkich komponentów. Komponenty z tej grupy nie posiadaja

transformacji oraz nie moga byc dołaczane do innych komponentów.

• Scene Component (klasa USceneComponent) - komponent posiadajacy transformacje. Kom-

ponenty sceny moga oddziaływac z innymi komponentami oraz byc dołaczane do innych kom-

ponentów w celu tworzenia hierarchii. Komponent zródłowy aktora jest tego typu.

• Primitive Component (klasa UPrimitiveComponent) - komponent posiadajacy graficzna repre-

zentacje w swiecie, na przykład w postaci geometrii (siatki) lub systemu czasteczek.

Wszystkie trzy wyzej wymienione klasy: UActorComponent, USceneComponent oraz UPrimi-

tiveComponent to klasy abstrakcyjne bedace baza dla wielu rodzaju komponentów dostepnych w

UE4. Pełna lista zawiera ponad 50 rodzajów komponentów oferujacych róznorodna funkcjonalnosc,

m.in komponenty systemu fizyki, sztucznej inteligencji, systemów czasteczek, systemu nawigacji,

obiektów na scenie i wiele innych. Naturalnie, istnieje mozliwosc definiowania własnych typów

komponentów z poziomu kodu C++ co zostanie wykorzystane w dalszej czesci pracy.

1.1.4 Mechanizm refleksji

Fundamentalna czescia silnika Unreal Engine 4, jest mechanizm refleksji. Cytujac Wikipedie, mecha-

nizm refleksji to "proces, dzieki któremu program komputerowy moze byc modyfikowany w trakcie

działania w sposób zalezny od własnego kodu oraz od zachowania w trakcie wykonania". Mecha-

nizm refleksji jest wykorzystywany przez wiele aspektów/modułów silnika: wyswietlanie własciwo-

sci obiektu w edytorze, system odsmiecania pamieci czy komunikacje miedzy systemem Blueprints

a kodem C++[3]. W zwiazku z tym, ze Unreal Engine 4 napisany jest w jezyku C++, który standar-

dowo nie wspiera zadnego rodzaju mechanizmu refleksji, Unreal Engine 4 implementuje swój własny

system refleksji, nazwany Unreal Property System [3].

Za proces budowania kodu zródłowego w silniku Unreal 4 odpowiada program Unreal Build Tool

(w skrócie: UBT). Przed rozpoczeciem procesu kompilacji kodu zródłowego przez kompilator C++,

UBT uruchamia tzw. Unreal Header Tool (w skrócie: UHT), którego zadaniem jest parsowanie kodu

zródłowego pod katem metadanych charakterystycznych dla systemu refleksji Unreal i wygenerowa-

nie specjalnego kodu na ich podstawie [12].

Programista chcac aby pisany przez niego kod widoczny był dla systemu refleksji, musi umiescic

w pliku nagłówkowym C++ zawierajacym definicje danego typu dołaczenie specjalnego pliku który

bedzie zawierac kod wygenerowany przez UHT:

# include " FileName . generated .h"

13

Gdzie FileName to nazwa oryginalnego pliku nagłówkowego. Od tego momentu mozliwe staje sie

stosowanie odpowiednich dla systemu refleksji makr w definicjach typów, pól i funkcji.

Z punktu widzenia tej pracy, najwazniejszy jest efekt zastosowania mechanizmu refleksji na wy-

swietlanie i obsługe własciwosci własnych typów przez edytor Unreal 4, dlatego tylko ten aspekt

zostanie tutaj szczegółowo omówiony.

Aby wartosc danego pola klasy/struktury mogła byc edytowana przez uzytkownika z poziomu

edytora, definicja danego pola musi byc poprzedzona makrem UPROPERTY() co spowoduje, ze dane

pole klasy bedzie traktowane przez silnik jako nowy obiekt typu UProperty1. Makro to przyjmuje

szereg opcjonalnych metadanych/specyfikacji definiujacych własnosci i zachowanie tego pola m.in w

edytorze.

Ponizej znajduje sie przykład definicji klasy z zastosowaniem mechanizmu refleksji Unreal Pro-

perty System.

1 UCLASS ( NotPlaceable )

2 class AFoo : public AActor

3 {

4 GENERATED_BODY ()

5

6 UPROPERTY ( EditAnywhere , meta =( ClampMin = "0.0", ClampMax = "1.0"))

7 float someEditableProperty ;

8

9 UPROPERTY ()

10 int someHiddenProperty ;

11

12 bool ordinaryMember ;

13 };

Do poinformowania systemu UHT, ze dana klasa ma brac udział w mechanizmie refleksji słuzy

makro UCLASS([opcjonalna lista specyfikacji]). Analogicznie dla typu strukturalnego, jest to

USTRUCT(...). Opcjonalna lista specyfikacji definiuje zachowanie klasy/struktury wobec róznych

aspektów edytora i silnika. Na przykład, specyfikacja NotPlaceable powoduje, ze obiekt danej klasy

nie moze zostac umieszczony na scenie. Lista dostepnych specyfikacji jest rózna dla struktur i klas

i o wiele krótsza dla tych pierwszych2. Obowiazkowe makro GENERATED_BODY() (linijka 4) ma za

1Typ UProperty jest odpowiednikiem zmiennej w systemie Unreal Property System. Inne odpowiedniki to m.in.UClass (odpowiednik klasy), UStruct (odpowiednik struktury), UFunction (odpowiednik funkcji, metody). Opis zadan ifunkcjonalnosci tych typów wykracza poza ramy tej pracy.

2W Unreal Engine 4 stosowanie struktur ogranicza sie do grupowania powiazanych ze soba danych (zmiennych)- własciwie wszystkie pozostałe typy, które definiuja pewne zachowanie zwiazane z rozgrywka/edytorem musza byc

14

zadanie "wstrzykniecie"dodatkowych funkcji/definicji typów do ciała klasy/struktury wymaganych

do poprawnego działania mechanizmu refleksji. Własnosc klasy someEditableProperty (linijka 7)

moze byc modyfikowane przez uzytkownika w panelu własciwosci w edytorze (specyfikacja Edi-

tAnywhere) i przyjmowac wartosci z zakresu 0-1 (metadane ClampMin oraz ClampMax). Z kolei

własnosc someHiddenProperty (linijka 10) jest niewidoczna w edytorze i modyfikowalna tylko z po-

ziomu kodu. Pole ordinaryMember (linijka 12) jest zwykła zmienna jezyka C++ i niewidoczna dla

systemu refleksji.

USTRUCT ()struct FReverbSettings{

GENERATED_USTRUCT_BODY ()

UPROPERTY ( EditAnywhere , Category =ReverbSettings )

uint32 bApplyReverb :1;

UPROPERTY ( EditAnywhere , Category =ReverbSettings )

class UReverbEffect * ReverbEffect;

UPROPERTY ( EditAnywhere , Category =ReverbSettings )

float Volume ;

UPROPERTY ( EditAnywhere , Category =ReverbSettings )

float FadeTime ;};

(a) (b)

Rysunek 2: Definicja typu (struktury) z widocznymi adnotacjami dla systemu refleksji Unreal Engine4 (a) oraz odpowiadajace mu okno własciwosci obiektu tego typu w edytorze (b)

1.1.5 Serializacja, system asset-ów

Mechanizm Unreal Property System umozliwia zapisanie stanu obiektów na dysk w procesie zwanym

serializacja. W terminologii UE4, taki obiekt bedacy na dysku i mozliwy do ponownego wykorzy-

stania to asset (z ang. asset). W postaci asset-ów przechowywane jest wszystko co moze byc czescia

projektu i gry w UE4: mapy, obiekty graficzne, dzwieki, animacje, materiały, tekstury, efekty i wiele

innych. Asset-y moga byc przenoszone miedzy projektami oraz edytowane w edytorze. W zwiazku

klasami i potomkami klasy bazowej dla wszystkich typów: UObject.

15

z tym developerzy moga sprzedawac i kupowac asset-y do wykorzystania w swoich produkcjach - do

tego celu słuzy sklep internetowy, Unreal Marketplace.

Serializacja, wraz z deserializacja (odtworzenie stanu obiektu na podstawie pliku) jest czescia

funkcjonalnosci oferowanej przez klase UObject. Domyslnie, tylko pola klasy biorace udział w me-

chanizmie refleksji (makro UPROPERTY) sa brane pod uwage podczas serializacji i deserializacji. 1.

W zwiazku z tym, ze asset nic innego niz reprezentacja obiektu (typu dziedziczacego z UObject) w

postaci pliku, w terminologii UE4 czesto uzywa sie tych dwóch pojec wymiennie i tak tez postapiono

na ramach tej pracy. Jest to dodatkowo uzasadnione faktem, iz uzytkownicy UE4 moga nie byc

programistami i nie znac reprezentacji asset-u po stronie kodu a mimo tego dokonywac ich tworzenia

oraz edycji. Autor rozróznia te dwa pojecia tam gdzie jest to istotne.

1.2 System audio

System audio w Unreal Engine 4 daje mozliwosc kontroli wszystkich podstawowych aspektów dzwieku

typowych dla silników gier. Jest wiec mozliwosc kontrolowania m.in głosnosci, wysokosci dzwieku,

tłumienia wraz z odległoscia czy definiowania obszarów w których na dzwiek nałozony zostanie dany

efekt pogłosowy. Oprócz tego, developer ma mozliwosc tworzenia złozonych dzwieków i efektów w

postaci tzw. Sound Cues za pomoca graficznego edytora.

Ponizej przedstawione zostana główne komponenty systemu audio Unreal 4, do których autor

bedzie wielokrotnie odnosic sie w pozostałej czesci pracy.

1.2.1 Sound Wave

Sound Wave reprezentuje plik dzwiekowy w srodowisku Unreal. Jest to asset, który zawiera w so-

bie zaimportowany z pliku sygnał audio o danej czestotliwosci próbkowania i konfiguracji kanałów.

Na ten moment, silnik Unreal 4 wspiera tylko importowanie nieskompresowanych plików 16-bit w

formacie WAV (Waveform Audio File Format). Oprócz podstawowych ustawien takich jak regulacja

głosnosci, wysokosci (pitch) i zapetlenia Unreal pozwala m.in na ustawienie parametrów kompre-

sji, globalnego efektu tłumienia, priorytetu a nawet zdefiniowanie transkrypcji tekstu mówionego

w danym pliku dzwiekowym (wykorzystywane do np. dialogów). Obiekt typu Sound Wave jest

współdzielony w silniku, to znaczy, ze zmiana parametrów wpłynie na wszystkie zródła dzwieku go

wykorzystujace.

1Uzytkownik ma mozliwosc nadpisania domyslnej implementacji serializacji i deserializacji przy tworzeniu własnegotypu.

16

1.2.2 Sound Cue, Sound Node

Sposób odtwarzania dzwieku w Unreal Engine 4 zdefiniowany jest poprzez assety typu Sound Cue.

Najwazniejsza czescia Sound Cue jest tzw. graf audio (ang. Audio Node Graph). Kazdy wezeł tego

grafu reprezentowany jest poprzez obiekt typu Sound Node, który z kolei reprezentuje pewna operacje

na sygnale audio. Kazdy wezeł moze miec rózna ilosc wejsc i wyjsc. Np. wezeł wezeł typu Wave

Player, którego zadaniem jest odtwarzanie dzwieku z assetu Sound Wave bedzie posiadac zero wejsc

i jedno wyjscie. Z kolei wezeł typu Delay (opózniajacy), którego zadaniem jest opóznienie sygnału

dzwiekowego bedzie posiadac jedno wejscie i wyjscie, a wezeł typu Mixer, który dodaje do siebie

sygnały - wiele wejsc i jedno wyjscie [10]. Wezły moga byc łaczone ze soba w rozmaity sposób

pozwalajac na tworzenie złozonych efektów. Warto w tym miejscu zaznaczyc, ze oprócz domyslnej

palety róznego rodzaju podtypów Sound Node, uzytkownik ma mozliwosc definiowania własnych, z

poziomu kodu C++ (wiecej na ten temat w dalszej czesci pracy). Edycji grafu uzytkownik dokonuje

w całosci wizualnie w oknie edytora Sound Cue (patrz Rysunek 3)

Rysunek 3: Okno edytora Sound Cue w Unreal Engine 4 z widocznymi przykładowym połaczeniemmiedzy roznymi rodzajami wezłów Sound Node. Zródło: [9]

1.2.3 Audio Component

Zródło dzwieku na scenie w Unreal Engine 4 reprezentowane jest przez komponent sceny (patrz

1.1.3) typu Audio Component. Zadaniem tego komponentu jest odtwarzanie w czasie rozgrywki

dołaczonego do niego assetu typu Sound Wave badz Sound Cue. Audio Component, jak kazdy inny

komponent w Unreal Engine 4, moze zostac dołaczony do kazdego rodzaju aktora. W zaleznosci od

ustawien i od połozenia komponentu (aktora) wzgledem słuchacza (gracza) bedzie zalezec poziom

17

tłumienia oraz połozenie zródła dzwieku w panoramie.

1.2.4 Pogłos

W Unreal Engine 4, dodanie pogłosu odbywa sie wyłacznie za pomoca tzw. Audio Volumes.Audio

Volume definiuje obszar na scenie (np. szescienny) do którego przypisany jest pewien statyczny efekt

pogłosu, który zostanie nałozony na wszystkie dzwieki w momencie pojawienia sie gracza wewnatrz

tego obszaru. Mechanizm ten pozwala na łatwy i intuicyjny podział swiata gry na obszary o róznym

pogłosie i jest bardzo popularny wsród silników gier - w ten sam sposób funkcjonuja np. Reverb

Zones w silniku Unity 3D 1.

Asset reprezentujacy efekt pogłosu oferuje kontrole szeregu parametrów charakterystycznych dla

wiekszosci cyfrowych procesorów pogłosowych, m.in Density, Diffusion, Decay Time, Reflections

Delay i wiele innych.

Audio Volume, oprócz ustawienia samego efektu pogłosu, umozliwia kontrole czasu przejscia

(ang. transition) pomiedzy dwoma objetosciami oraz zestaw parametrów opisujacych zachowanie

zródeł dzwieku znajdujacych sie poza dana objetoscia (np. wartosc tłumienia, filtr dolnoprzepu-

stowy). Objetosci audio moga nachodzic na siebie - w takim przypadku o koncowym efekcie decy-

duje ich priorytet.

Warto w tym miejscu zaznaczyc, ze zarówno geometria (wymiary, kształt) obiektów Audio Vo-

lume, jak i parametry przypisanego do niego efektu pogłosu, nie sa modyfikowalne w czasie gry, tylko

i wyłacznie w edytorze.

1.2.5 Klasy audio i miksy

Ostatnim wartym uwagi w kontekscie tej pracy komponentem systemu audio Unreal Engine 4 sa tzw.

klasy audio (asset typu Sound Class). Klasa audio to zestaw własciwosci, które moga dodatkowo mo-

dyfikowac dzwiek pochodzacy z asset-u Sound Wave lub Sound Cue. Jedna klasa audio moze zostac

przypisana do wielu asset-ów. Czesc własciwosci klasy audio działa jako mnoznik w stosunku do

tych zdefiniowanych przez Sound Wave/Sound Cue (np. Volume, Pitch) a czesc okresla zachowanie

dzwieku, np. parametr Reverb decyduje o tym czy na dzwieki nalezace do tej klasy moze zostac

nałozony pogłos. Klasy audio moga byc układane w hierarchie.

Do klas audio moga dodatkowo zostac przypisane tzw. miksy (asset typu Sound Mix) które umoz-

liwiaja zastosowanie korekcji barwy. W momencie powstawania tej pracy, Unreal oferuje prosta

3-pasmowa korekcje z regulowanymi czestotliwoscia srodkowa i wzmocnieniem.

1http://docs.unity3d.com/Manual/class-AudioReverbZone.html

18

1.3 System wtyczek

Unreal Engine 4 pozwala na tworzenie wtyczek, które umozliwiaja modyfikacje lub rozszerzenie funk-

cjonalnosci silnika oraz edytora bez koniecznosci edycji ich kodu zródłowego.

Ogólnie rzecz biorac, wtyczka w Unreal Engine 4 to zbiór tzw. modułów napisanych w jezyku

C++ kompilowanych do zewnetrznej biblioteki .dll (.so w systemach Linux). Kazdy moduł to ze-

staw klas definiujacych nowa funkcjonalnosc składajacy sie na pewna samowystarczalna (lub zalezna

od innego modułu) jednostke. Moduły sa ładowane przez silnik automatycznie lub na zadanie, w

zaleznosci od rodzaju (np. moduł moze byc ładowany tylko podczas działania edytora).

Silnik Unreal Engine 4 jest sam w sobie złozony z modułów. Przewazajaca czesc kodu rdzenia

silnika oraz edytora implementuje swoje moduły na podstawie tego samego interfejsu co developer

tworzacy wtyczke. Interfejs, z którego powinny dziedziczyc wszystkie implementacje modułów to

klasa IModuleInterface.

Kazda wtyczka posiada tzw. deskryptor, czyli plik okreslajacy podstawowe cechy wtyczki oraz

liste jego modułów. Plik ten jest wczytywany w momencie uruchomienia silnika w celu wyszukania i

odpowiedniego załadowania bibliotek modułów. Dwie najwazniejsze cechy modułu to jego typ oraz

moment załadowania. Unreal rozróznia nastepujace typu modułów:

• Runtime - moduł tego typu zostanie załadowany zawsze, to znaczy zarówno w grze jak i edy-

torze oraz we wszystkich konfiguracjach gry, równiez w tej przeznaczonej do dystrybucji (ang.

shipping).

• Developer - moduł tego typu zostanie załadowany tylko w developerskich konfiguracjach gry i

edytora.

• Editor - moduł, który zostanie załadowany tylko w edytorze.

Kazdy z tych rodzajów modułów moze dodatkowo definiowac jeden z nastepujacych momentów

załadowania:

• PostConfigInit - moment przed załadowaniem wszystkich podstawowych modułów silnika.

Opcja przydatna w przypadku implementacji modułu modyfikujacego/rozszerzajacego którys z

kluczowych podsystemów.

• PreDefault - moment po załadowaniu wszystkich podstawowych modułów silnika, lecz przed

momentem domyslnym dla wszystkich nie-kluczowych modułów.

• Default - domyslny moment ładowania dla wszystkich modułów.

Wtyczka moze składac sie z modułów róznego typu o roznym momencie załadowania.

19

2 RAYA

RAYA (skrót od ang. Raytracer Audio) jest biblioteka programistyczna, której zadaniem jest odpo-

wiednie przetwarzanie dzwieku w czasie rzeczywistym na podstawie połozenia i ruchu gracza oraz

zródeł dzwieku w wirtualnym swiecie. Biblioteka ta przeznaczona jest przede wszystkim dla develo-

perów gier i symulacji, którzy chca swoja produkcje wzbogacic o realistyczne zjawiska akustyczne

wystepujace w otaczajacym swiecie bez koniecznosci ich manualnego re-kreowania za pomoca do-

stepnych do tej pory komercyjnych narzedzi.

Zasada działania biblioteki RAYA opiera sie na technice sledzenia wiazek (ang. beam tracing)

dzwieku. Na podstawie rzeczywistej geometrii sceny i materiałów akustycznych, trasa przebywana

przez wiazki od zródła do odbiornika (np. gracza) jest rekonstruowana z uwzglednieniem wszystkich

fizycznych efektów akustycznych, takich jak odbicie, dyfrakcja i transmisja. Na tej podstawie wyzna-

czane sa parametry dzwieku, a konkretnie filtr cyfrowy okreslajacy jak zmienia sie dzwiek podczas

swojej drogi od zródła do odbiornika.

Z punktu widzenia uzytkownika, konieczne jest tylko zdefiniowanie geometrii sceny oraz przy-

pisanie odpowiednich materiałów akustycznych. Biblioteka RAYA wspiera szereg parametrów ma-

teriału wpływajacych na jego własciwosci akustyczne, m.in współczynniki pochłaniania, dyfrakcji

czy gestosc materiału. Rozłozenie materiałów na scenie i ich parametry wpływaja na koncowy efekt

dzwiekowy, tak jak ma to miejsce w rzeczywistym swiecie.

Biblioteka RAYA jest przeznaczona do działania w czasie rzeczywistym i umozliwia sledzenie i

jednoczesne przetwarzanie dzwieku pochodzacego z wielu zródeł. W swojej obecnej wersji zoptyma-

lizowana jest na komputery stacjonarne (tzw. PC-ty). Dla zwiekszenia swojej wydajnosci, umozliwia

przeniesienie czesci swoich obliczen na karte graficzna.

3 Opis integracji

3.1 Załozenia projektowe

Ponizej przedstawione zostana wymagania i załozenia projektowe, które wpłyneły na decyzje doty-

czace sposobu implementacji i oferowanej funkcjonalnosci. W zwiazku z faktem, iz, jak juz wcze-

sniej wspomniano, autor nie był jedyna osoba pracujaca nad niniejszym projektem tylko czescia de-

veloperskiego zespołu, czesc wymagan została narzucona odgórnie i nie zostanie przedstawiona ich

argumentacja, tylko wpływ na sposób implementacji.

Pierwszym i kluczowym załozeniem projektu była jego wieloplatformowosc. To znaczy, sposób

20

implementacji powinien byc identyczny dla wszystkich wspieranych platform, bez znaczacych róznic

w kodzie zródłowym. Konkretnie, wymagane było wsparcie dla minimum trzech platform: systemu

Windows oraz konsol Xbox One oraz PlayStation 4. Konsole róznia sie znaczaco pod wzgledem ar-

chitektury i wydajnosci liczonej per procesor w porównaniu do komputerów stacjonarnych. Na tych

drugich, RAYA potrzebuje ok. 10% zasobów procesora (jednego rdzenia)1. W zwiazku z tym, w

swojej obecnej implementacji biblioteka RAYA mogła by zbytnio obciazyc procesor konsoli. W kon-

sekwencji, zdecydowano sie na podejscie, które znaczaco zredukuje obciazenie procesora kosztem

zwiekszonej ilosci wymaganej pamieci: rezygnacje z sledzenia sciezek w czasie rzeczywistym. W

zamian, kalkulacje sciezek i wynikowych efektów akustycznych na podstawie geometrii sceny beda

dokonywane tylko raz, na etapie tworzenia sceny w edytorze UE4. Wyniki tych obliczen beda prze-

chowywane w postaci pliku i wykorzystywane w czasie rozgrywki (szczegółowy opis znajduje sie w

3.3). Podejscie takie prawie w całosci niweluje oryginalny koszt obliczen sprowadzajac go wyłacz-

nie do kosztu ekstrakcji i ewentualnej interpolacji przechowywanych parametrów, kosztem oczywi-

stych wymagan pamieciowych. Mimo to, podejscie to jest duzo łatwiejsze w optymalizacji: jedynym

znaczacym czynnikiem decydujacym o wydajnosci tej implementacji jest ilosc dostepnej pamieci

dyskowej oraz RAM na danym urzadzeniu, a ilosc potrzebnej pamieci moze byc łatwo zmniejszona

(kosztem dokładnosci) przez developera poprzez zmniejszenie gestosci dyskretyzacji sceny.

Drugim waznym wymaganiem projektu była implementacja wtyczki bez koniecznosci edycji

kodu zródłowego silnika UE42. Aby spełnic to wymaganie, trzeba wykorzystac istniejaca funkcjo-

nalnosc silnika audio w Unreal Engine 4 podczas implementacji wtyczki. W tym miejscu pojawił

sie drugi istotny problem: system audio UE4 nie umozliwia dostepu do próbek sygnału audio na

zadnym etapie jego przetwarzania3 w zwiazku z czym nie jest mozliwe zastosowania filtracji filtrami

FIR obliczonymi przez RAYA. Oznacza to, ze konieczna jest konwersja efektu akustycznego zdefi-

niowanego za pomoca odp. impulsowej/widma na w miare mozliwosci podobny efekt uzyskany za

pomoca kontroli parametrów udostepnionych przez silnik audio UE4. Szczegółowy opis rozwiazania

tego problemu i jego implementacji znajduje sie w kolejnych rozdziałach tej pracy.

1Testowane na przecietnym, współczesnym domowym procesorze2Edycja kodu zródłowego silnika UE4 w celu integracji niesie ze soba szereg niedogodnosci i problemów. Najwiek-

szy z nich to brak uniwersalnosci takiego rozwiazania: kazda osoba chcaca wykorzystac wtyczke musiałaby dokonacrekompilacji całego kodu zródłowego silnika.

3Nie w sposób który byłby wieloplatformowy. Istnieje nieudokumentowana mozliwosc dostepu do próbek sygnałuaudio w celu implementowania własnych efektów, ale tylko na platforme Windows w wersji 64-bit.

21

3.2 Ogólny schemat działania

Jak wspomniano w poprzednim rozdziale, sledzenie wiazek i wyliczenie efektów akustycznych nie

bedzie odbywac sie w czasie rzeczywistym. Proces ten bedzie odbywac sie na etapie tworzenia gry

i inicjowany bedzie przez developera z poziomu edytora po przypisaniu materiałów akustycznych

do obiektów na scenie. Wyliczone w ten sposób efekty akustyczne beda nastepnie wykorzystane do

modyfikacji dzwieku w czasie rzeczywistym, juz podczas rozgrywki.

Jako, ze biblioteka RAYA przeznaczona jest do działania w czasie rzeczywistym, bezposrednia

integracja nie jest mozliwa. Jak opisano w 2, obliczenie efektu akustycznego odbywa sie na podstawie

aktualnego połozenia odbiornika i zródeł i geometrii sceny. Natomiast w tym przypadku, czyli poza

rozgrywka, informacje o połozeniu zwyczajnie nie istnieja.

W zwiazku z tym zastosowano podejscie oparte na “dyskretyzacji“ (geometrii) sceny, tzn. gestym

podziale na trójwymiarowe, prostopadłoscienne obszary o tych samych wymiarach, tworzac pewnego

rodzaju siatke. Obszary te beda dalej przez autora nazywane komórkami. Geometryczny srodek

tej komórki wyznacza mozliwe połozenie gracza lub odbiornika. Wyliczenie efektów akustycznych

nastepuje dla kazdej komórki z osobna poprzez "umieszczenie"w jej srodku odbiornika i nastepne

sledzenie wiazek dochodzacych ze zródeł umieszczonych we wszystkich pozostałych komórkach.

Dla kazdej komórki wiec obliczony zostaje zestaw wzglednych efektów akustycznych okreslajacy jak

zmienia sie docierajacy do niej dzwiek z poszczególnych komórek. Oprócz tego, dla kazdej komórki

aproksymowane zostaja czasy pogłosu dla wybranych czestotliwosci.

W nastepnym kroku nastepuje zamiana obliczonych efektów akustycznych (reprezentowanych

przez charakterystyke czestotliwosciowa filtru cyfrowego) na w pewien sposób przyblizajacy dany

efekt zestaw parametrów dzwieku bedacych czescia API silnika Unreal Engine 4. Konkretnie, sa to

trzy parametry: wzmocnienie amplitudy, wzmocnienie najwyzszych czestotliwosci oraz kierunek

dzwieku1. Ostatecznie, wynikowa struktura danych zawiera zestawy ww. parametrów zalezne od

wzglednego połozenia odbiornika i zródła oraz czasy pogłosu zalezne tylko od połozenia odbiornika.

Strukturze tej nadano nazwe wypalona scena akustyczna, a proces jej powstania wypaleniem sceny

akustycznej2.

Wypalona scena akustyczna zostaje nastepnie wykorzystana do modyfikacji dzwieków w czasie

rzeczywistym. Jako ze parametry zmiany dzwieku w wypalonej scenie akustycznej dotycza dyskret-

nych punktów na regularnej siatce, podczas rozgrywki konieczna jest ich interpolacja, na zadanie,

kazdorazowo dla danej pary pozycji zródła i odbiornika.

1Wyjasnienie powodu wyboru konkretnie tych parametrów zostało opisano w rozdziale dot. implementacji 4.1.42Analogicznie do terminu “wypalania“ oswietlenia (ang. light baking) - okreslajacego popularny wsród trójwymia-

rowych aplikacji graficznych (w tym równiez gier) proces wczesniejszego wyliczenia statycznego oswietlenia w celupózniejszego uzycia.

22

Zmiana parametrów dzwieku zalezna od wzglednego połozenia gracza i zródła implementowana

jest poprzez napisany specjalnie w tym celu SoundNode (patrz 1.2.2). Zatem to developer decyduje,

z których zródeł dzwieku dzwiek bedzie modyfikowany. Efekt pogłosu, który jest zalezny tylko od

połozenia gracza, bedzie aplikowany za pomoca obejmujacego cała scene obiektu AudioVolume (patrz

1.2.4).

3.3 Architekrura

Wtyczka podzielona została na dwa moduły:

• Moduł edytora - załadowany tylko wraz z edytorem (patrz 1.3) odpowiedzialny za funkcjonal-

nosc zwiazana z procesem tworzenia gry, czyli praca w edytorze:

– rozszerzenie graficznego interfejsu edytora o kontrolki oraz komunikaty specyficzne dla

wtyczki

– implementacje asset-u reprezentujacego materiał akustyczny wraz z pełna funkcjonalno-

scia w aspekcie tworzenia i edycji przez uzytkownika 4.2.1

– eksport sceny do biblioteki RAYA, tzn. informacji o jej geometrii wraz z rozmieszczeniem

materiałów akustycznych

– zarzadzanie procesem konfiguracji biblioteki RAYA oraz od strony UE4: tworzenia mapy

akustycznej i jej pózniejszej kompresji

• Moduł gry - załadowany zawsze, który odpowiedzialny jest za czesc funkcjonalnosci nieza-

lezna od edytora, czyli ta zwiazana z rozgrywka i samym przetwarzaniem dzwieku, a w szcze-

gólnosci:

– implementacje Sound Node nakładajacego efekt na strumien audio zródła dzwieku w za-

leznosci od pozycji gracza

– sledzenie aktualnej pozycji gracza za pomoca komponentu doczepianego do aktora ka-

mery

– aplikowanie zmiennego efektu pogłosu

Moduł gry definiuje takze dwa typy wykorzystywane przez oba moduły, mianowicie typ re-

prezentujacy asset zawierajacy wypalona scene akustyczna oraz tzw. aktor-menadzer, którego

zadaniem jest m.in. przechowywanie ww. asset-u dla danej sceny (poziomu).

23

W tym miejscu nalezy zaznaczyc, ze powyzszy podział na moduły i zakres ich obowiazków ule-

gał zmianie wielokrotnie w czasie pracy nad projektem. Nadrzednym celem takiego podziału jest

wyizolowanie funkcjonalnosci zaleznej od modułów edytora UE4 i usuniecie jej z modułu gry, co

jest dobra praktyka programistyczna, m.in. poniewaz pozwala na unikniecie stosowania kodu warun-

kowej kompilacji1.

Oba moduły komunikuja sie z zewnetrzna biblioteka, RAYA-offline, stworzona specjalnie na po-

trzeby wtyczki. Biblioteka ta pełni role posrednika miedzy modułami wtyczki a własciwa biblioteka

RAYA i to w niej jest zaimplementowana cała czesc integracji nie zalezna od silnika UE4, w szczegól-

nosci wypalenie sceny akustycznej oraz pózniejsza interpolacja parametrów akustycznych w czasie

rzeczywistym. Szczegółowy opis tej biblioteki znajduje sie w rozdziale 3.4.

BibliotekaRAYA-OFFLINE

Moduł edytora Moduł gry

Wtyczka

geometria

scenyi

rozkładm

ateriałów

wypalona

scena

akustyczna

inte

rpol

owan

epa

ram

etry

pozy

cja

grac

zai

zród

ełdz

wie

ku

Rysunek 4: Schemat komunikacji miedzy modułami wtyczki oraz biblioteka RAYA-offline.

3.4 RAYA-offline

Jak juz wczesniej wspomniano, wewnatrz biblioteki RAYA-offline ma miejsce implementacja algo-

rytmów nie powiazanych z API silnika UE4. Tutaj zaimplementowane zatem sa: wypalanie sceny

akustycznej (dyskretyzacja sceny, aproksymacja efektów akustycznych), interpolacja parametrów

oraz kompresja danych wypalonej sceny akustycznej. Biblioteka ta do swojej implementacji wy-

1Duza czesc kodu UE4 jest warunkowo kompilowana w zaleznosci od edytora (słuza do tego specjalne makra).Pewne klasy i interfejsy sa eksportowane tylko w edytorowych konfiguracjach, tzn. nie beda widoczne dla konsolidatoraw konfiguracjach bez edytora, np. tej przeznaczonej do dystrybucji. Pozostawienie kodu zaleznego od edytora w modulegry, który jest ładowany we wszystkich konfiguracjach oznaczało by koniecznosc otoczenia go makrami warunkowejkompilacji co zmniejsza czytelnosc kodu.

24

korzystuje szereg zewnetrznych bibliotek, w szczególnosci oryginalna biblioteke RAYA. Biblioteka

RAYA-offline jest statycznie linkowana przez moduły wtyczki.

Na wstepie nalezy zaznaczyc, ze implementacja tej biblioteki nie była dziełem autora, za wyjat-

kiem funkcjonalnosci zwiazanej z kompresja i dekompresja wypalonej sceny akustycznej oraz efek-

tem pogłosu.

Biblioteka RAYA-offline komunikuje sie z wtyczka za pomoca dwóch publicznych interfejsów

(klas): AudioOffline i Audio.

Klasa AudioOffline reprezentuje funkcjonalnosc nie zwiazana z przetwarzaniem w czasie rzeczy-

wistym (“offline“). Wykorzystywana jest przez moduł edytora i za jej pomoca przeprowadzana jest

konfiguracja silnika RAYA przed wypaleniem sceny akustycznej, eksport sceny z edytora oraz utwo-

rzenie mapy parametrów akustycznych.

Klasa Audio reprezentuje funkcjonalnosc zwiazana z przetwarzaniem w czasie rzeczywistym i jest

wykorzystywana przez moduł gry wtyczki. Zadaniem obiektu tej klasy jest przekazanie do modułu

gry interpolowanych parametrów modyfikujacych dzwiek i czasów pogłosy na podstawie pozycji

gracza i zródła dzwieku.

4 Implementacja

W rozdziale tym przedstawiona zostanie szczegółowy opis implementacji funkcjonalnosci wtyczki

bedacy dziełem autora tej pracy. W szczególnosci, opisane zostana poszczególne komponenty obu

modułów, ich rola w kontekscie wtyczki oraz sposób działania wraz z argumentacja.

W rozdziale tym pojawiaja sie wycinki rzeczywistego kodu zródłowego implementacji w jezyku

C++ oraz opisy algorytmów za pomoca pseudokodu. Przy implementacji wtyczki stosowano kon-

wencje przyjete w kodzie zródłowym Unreal Engine 4[6], w szczególnosci nazwa typu poprzedzana

jest jedna z trzech liter:

• U - klasa dziedziczaca z UObject

• A - klasa dziedziczaca z AActor

• F - pozostałe typy: klasy oraz struktury

25

4.1 Moduł gry

4.1.1 Asset sceny akustycznej

Dane reprezentujace wypalona scene akustyczna dla danego poziomu, która opisano w 3.2, beda wy-

korzystywane przez oba moduły: edytora i gry. Naturalnie, musza byc one dostepne dla modułu gry

po tzw. spakowaniu gry (ang. packaging), czyli ostatecznym procesie przygotowujacym gre do dys-

trybucji. W zwiazku z tym, konieczne jest przechowanie tych danych w postaci pliku, który zostanie

spakowany wraz z pozostała czescia gry i nastepnie rozpakowany i wczytany w czasie rozgrywki.

Naturalne było wiec wykorzystanie do tego celu systemu asset-ów i ich mechanizmu serializacji i

deserializacji (patrz 1.1.5). Dzieki temu, nie było konieczne programowanie procesu zapisu i od-

czytu danych z dysku - jest to automatyczne implementowane przez mechanizm refleksji silnika i

odpowiednie metody klasy UObject. Reprezentacja za pomoca asset-u pozwala równiez na łatwa

integracje z edytorem, np. w celu intuicyjnego dla uzytkownika przypisywania danych wypalonej

sceny akustycznej do danego poziomu (mapy).

Dane sceny akustycznej wewnatrz asset-u postanowiono przechowywac w postaci zwykłego ciagu

bajtów. Postapiono tak, poniewaz, jak opisano w 3.4, cała implementacja wypalania sceny akustycz-

nej oraz pózniejszej interpolacji znajduje sie w bibliotece RAYA-offline, natomiast mechanizmowi

refleksji podlegaja tylko typy natywne oraz USTRUCT/UCLASS. W zwiazku z tym, aby umozliwic se-

rializacje i deserializacje, konieczne byłoby odzwierciedlenie klas/struktur reprezentujacych scene

akustyczna definiowanych przez RAYA-offline za pomoca odpowiednich klas i struktur oznaczonych

za pomoca makr USTRUCT/UCLASS lub nadpisanie domyslnych metod odpowiedzialnych za serializa-

cje i deserializacje. Wprowadzony w ten sposób dodatkowy poziom abstrakcji byłby zupełnie nie-

potrzebny. O wiele łatwiejsza jest serializacja struktury danych do ciagu (tablicy) bajtów, który jest

typem natywnym.

Bajt w jezyku C++ reprezentowany jest przez typ unsigned char. W UE4, typem reprezentujacy

dynamiczna tablice jest TArray<>. Przechowanie ciagu bajtów za pomoca tej tablicy i oznaczenie pola

poprzez UPROPERTY wystarcza do jego automatycznej serializacji na dysk i deserializacji przez silnik.

Pole to jest domyslnie ukryte przed uzytkownikiem w edytorze. Poniewaz scena akustyczna jest se-

rializowana i deserializowana po stronie biblioteki RAYA-offline, która oczywiscie nie wykorzystuje

typu TArray, lecz odpowiednika z biblioteki standardowej jezyka C++, std::vector, konieczna jest

kazdorazowa konwersja pomiedzy tymi dwoma typami po stronie wtyczki.

Klase reprezentujaca asset wypalonej sceny akustycznej nazwano URAYALevelBakeAsset. Oprócz

zdeserializowanej do ciagu bajtów sceny akustycznej klasa ta zawiera pola dotyczace jej kompresji

opisanej w rozdziale 4.2.6.

26

4.1.2 Menadzer

Jak wspomniano w 4.1.1, kazdy poziom (mapa) musi miec przypisany asset który zostanie załado-

wany przez moduł gry w czasie rozgrywki. Ponadto, uzytkownik musi posiadac mozliwosc zmiany

przypisania asset-u wypalonej sceny akustycznej do danego poziomu. Łatwo sobie wyobrazic sytu-

acje, w której developer wypala scene kilkukrotnie z uzyciem róznych ustawien w celu ich porów-

nania i wybrania najlepszego z nich. Konieczne było wiec zapewnienie uzytkownikowi intuicyjnego

interfejsu, który by taka funkcjonalnosc oferował. Natomiast z technicznego punktu widzenia, takie

przypisanie wypalonej sceny do danego poziomu musi spełniac dwa warunki:

1. Byc jednoznaczne. To znaczy, kazdy poziom musi miec przypisany tylko jeden asset wypalo-

nej sceny akustycznej.

2. W czasie rozgrywki byc łatwo dostepne w momencie załadowania nowego poziomu lub przej-

scia gracza na inny poziom - tak aby moduł gry mógł odpowiednio zareagowac poprzez zmiane

aktualnie wykorzystywanej mapy parametrów akustycznych do modyfikacji dzwieku.

Zadecydowano, ze powyzsze warunki zostana łatwo spełnione poprzez implementacje tzw. obiektu

menadzera reprezentowanego za pomoca specjalnego rodzaju aktora. Aktor ten posiada wskaznik

do instancji obiektu asset-u wypalonej sceny akustycznej odpowiadajacej poziomowi na którym sie

znajduje. Wskaznik ten jest polem objetym systemem refleksji i oznaczonym do edycji z poziomu

edytora (za pomoca makra UPROPERTY(EditAnywhere), patrz 1.1.4) dzieki czemu uzytkownik moze

w łatwy i intuicyjny sposób wybierac i przypisywac asset wypalonej sceny akustycznej w oknie edycji

aktora w edytorze.

Spełnienie warunku 1 osiagnieto w dwóch powiazanych krokach. Pierwszym było całkowite

ukrycie aktora z edytora sceny oraz okna pokazujaca liste wszystkich aktorów na scenie, tzw. scene

outliner. W UE4 dokonac tego mozna ustawiajac specjalne flagi (pola klasy bazowej AActor) w

konstruktorze klasy. Ponizej przedstawiony jest wycinek kodu konstruktora klasy reprezentujacej

aktora-menadzera (nazwanej ARAYAManager) odpowiedzialny za jego niewidocznosc na scenie:

ARAYAManager :: ARAYAManager ()

{

#if WITH_EDITORONLY_DATA

bHiddenEd = true;

bHiddenEdLayer = true;

bHiddenEdLevel = true;

bListedInSceneOutliner = false ;

27

#endif

}

Dzieki temu, ze aktor-menadzer jest niewidoczny na scenie i w edytorze, nie moze on zostac usuniety

lub zreplikowany przez uzytkownika. W zwiazku z faktem iz powyzsze flagi sa zwiazane z edyto-

rem, a aktor-menadzer jest czescia modułu gry, konieczne było otoczenie ich makrem warunkowej

kompilacji WITH_EDITORONLY_DATA, które powoduje, ze kod nie bedzie widoczny dla kompilatora w

konfiguracji bez edytora.

Drugim krokiem podjetym w celu zapewnienia, ze na scenie bedzie tylko jeden aktor-menadzer,

było połaczenie miejsca jego tworzenia z miejscem dostepu do jego instancji z poziomu kodu. Odpo-

wiedzialna jest za to metoda klasy modułu edytora GetManagerForCurrentLevel() której zadaniem

jest odnalezienie aktualnego obiektu menadzera lub, w przypadku gdy taki jeszcze nie istnieje, stwo-

rzenie go:

ARAYAManager * FRAYAEditorModule :: GetManagerForCurrentLevel () const

{

auto World = GetLevelEditorWorld ();

TActorIterator < ARAYAManager > It(World);

if (It)

return *It;

else

return World ->SpawnActor < ARAYAManager >();

}

Dzieki takiej implementacji powyzszej metody, załozenie, ze na scenie bedzie istniec maksymalnie

jeden obiekt aktor-menadzer jest zawsze spełnione (pod warunkiem, ze nie bedzie on tworzony w

zadnym innym miejscu w kodzie). W celu odnalezienia obiektu menadzera, mozna posłuzyc sie

specjalnym typem iteratora, TActorIterator<>, który pozwala na efektywna iteracje po wszystkich

aktorach danego typu znajdujacych sie obecnie na scenie.

Warunek 4.1.2 spełniono wykorzystujac mechanizm cyklu zycia aktora, o którym wspomniano w

1.1.3. W momencie załadowania przez silnik nowego poziomu, silnik wywołuje szereg metod (klasy

bazowej AActor) na obiekcie kazdego aktora nalezacych do tego poziomu w celu jego poprawnego

załadowania i przygotowania. Jedna z nich jest wirtualna metoda BeginPlay(). Postanowiono, ze

za pomoca tej metody aktor-menadzer bedzie “rejestrowac sie“ w instancji modułu gry, przekazujac

siebie jako parametr. Analogicznie, aktor-menadzer bedzie “de-rejestrowac“ wewnatrz analogicznej

metody EndPlay(), która jest wywoływana na aktorze przed jego zniszczeniem (co nastepuje np. w

momencie dany poziom zostaje usuniety z pamieci):

28

void ARAYAManager :: BeginPlay ()

{

IRAYAGameModule :: Get (). ManagerBeginsPlay (this);

}

void ARAYAManager :: EndPlay (const EEndPlayReason :: Type)

{

IRAYAGameModule :: Get (). ManagerEndsPlay (this);

}

Metoda IRAYAGameModule::Get() interfejsu modułu gry zwraca jego instancje. Moduł gry przecho-

wuje wewnatrz liste obecnie zarejestrowanych aktorów-menedzerów. Dzieki temu, ze kazdy z nich

przechowuje wskaznik do asset-u wypalonej sceny akustycznej odpowiadajacej poziomowi (scenie)

której jest czescia, moduł gry moze w kazdym momencie jednoznacznie okreslic, który asset powi-

nien byc w danym momencie “aktualnym“ (opisano w 4.1.3).

Nalezy jeszcze wspomniec, ze klasa reprezentujaca aktora-menadzera (nazwana URAYAManager)

dziedziczy z klasy AInfo - abstrakcyjnej klasy bazowej dla wszystkich aktorów, które w UE4 repre-

zentuja aktorów nie posiadajacych fizycznej manifestacji w swiecie gry i których głównym uzyciem

sa własnie klasy typu "menadzer". Deklaracja klasy AInfo m.in ukrywa wszystkie cechy aktora, które

nie maja sensu aby były wyswietlane w oknie edycji, np. zwiazane z ruchem czy kolizjami.

4.1.3 Komponent odbiornik

Jak wspomniano w 4.1.2, moduł gry zawiera liste aktualnie zarejestrowanych aktorów-menedzerów.

Sa oni rejestrowani i de-rejestrowani wraz z ładowaniem i “od-ładowywaniem“ poziomów przez sil-

nik w czasie rozgrywki. Moduł gry musi byc w kazdym momencie w stanie jednoznacznie okreslic,

który asset wypalonej sceny akustycznej jest tym aktualnym w celu przekazania tej informacji cze-

sciom wtyczki, które przetwarzaja dzwiek na jego podstawie.

Problem z jakim autorowi przyszło sie tutaj zmierzyc jest fakt, iz w danym momencie rozgrywki

moze byc załadowanych kilka poziomów jednoczesnie. Jest to zwiazane z tzw. strumieniowaniem

poziomów (ang. level streaming), tzn. funkcjonalnoscia silnika UE4 umozliwiajaca ich stopniowe

ładowanie i usuwanie z pamieci wraz z przemieszczaniem gracza w celu zapewnienia graczowi nie-

przerwanej rozgrywki oraz odczucia, ze cały swiat gry to jeden, duzy poziom1.

W celu rozwiazania tego problemu i identyfikacji poziomu “wewnatrz“ którego aktualnie znajduje

sie gracz i na tej podstawie własciwego aktora-menadzera (i przypisanego do niego asset-u sceny

1https://docs.unrealengine.com/latest/INT/Engine/LevelStreaming/index.html

29

akustycznej) postanowiono wykorzystac obecna pozycje gracza, czyli odbiornika (słuchacza). Moduł

gry nieustannie sprawdza, wewnatrz, której sceny akustycznej, sposród tych przypisanych do obecnie

zarejestrowanych menedzerów aktualnie znajduje sie gracz. Sprawdzenie to odbywa sie poprzez

prosty test czy punkt (pozycja gracza) w przestrzeni trójwymiarowej znajduje sie wewnatrz objetosci

obejmujacej dana scene akustyczna. Wymiary tej objetosci, tzw. z ang. bounding-box zawarte sa

wewnatrz obiektu URayaLevelBakeAsset i zdefiniowane w momencie wypalenia sceny na podstawie

jej geometrii.

Moduł gry jednak nie posiada informacji o pozycji “gracza“ gdyz z technicznego punktu widzenia

jest to pojecie czysto abstrakcyjne. Postanowiono wiec wprowadzic komponent odbiornik, którego

zadaniem bedzie przekazywanie modułowi gry swojej pozycji. Uzytkownik doczepiajac ten kom-

ponent np. do aktora-kamery na scenie definiuje, ze to jest obiekt, który ma byc traktowany jako

odbiornik dzwieku przez moduł gry.

Klase reprezentujaca komponent-odbiornik nazwano URAYAListenerComponent. Implementacja

tego komponentu do przekazania swojej pozycji do instancji moduły gry nadpisuje metode wirtualna

TickComponent() klasy bazowej komponentu aktora (UActorComponent). Metoda ta jest wywoły-

wana przez silnik co klatke. Ponizej przedstawiony jest wycinek kodu zródłowego implementacji:

void URAYAListenerComponent :: TickComponent ( float DeltaTime , ELevelTick

TickType , FActorComponentTickFunction * ThisTickFunction )

{

FVector Position = GetOwner () ->ActorToWorld (). GetLocation ();

IRAYAGameModule :: Get (). UpdateListenerPosition ( Position );

// pozostała część ciała metody

}

Nastepnie, moduł gry wewnatrz metody UpdateListenerPosition(), iterujac po kolekcji zareje-

strowanych aktorów-menedzerów, sprawdza dla kazdego, czy przekazane współrzedne znajduja sie

wewnatrz przypisanej do niego sceny akustycznej i na tej podstawie ustawia wskaznik na aktualnego

menadzera. W przypadku gdy komponent-odbiornik znajduje sie poza granicami wszystkich obecnie

załadowanych scen akustycznych, wskaznik reprezentujacy aktualnego menedzera ustawiany jest na

wartosc NULL.

4.1.4 Modyfikacja dzwieku w czasie rzeczywistym

Jak wspominano w 3.2, modyfikacja sygnału akustycznego w zaleznosci od połozenia gracza wzgle-

dem zródła dzwieku zaimplementowana została poprzez napisanie klasy rozszerzajacej interfejs So-

30

undNode, bedacy czescia API silnika UE4 (patrz 1.2.2). Klasa ta została nazwana URAYASoundNode. Z

kolei nałozenie zmiennego w czasie rzeczywistym efektu pogłosu odbywa sie za pomoca manipulacji

parametrami przypisanego do obiektu Audio Volume efektu pogłosu (patrz 1.2.4).

RAYA Sound Node

Implementacja własnego podtypu SoundNode sprowadza sie do nadpisania metody wirtualnej USo-

undNode::ParseNodes(). Głównym zadaniem tej metody jest modyfikacja przekazanej do niej jako

parametr struktury zawierajacej zestaw parametrów nakładanych na sygnał audio, FSoundParseParameters

. To własnie modyfikacja tych parametrów definiuje efekt implementowany przez dany Sound Node.

Silnik, podczas tzw. ewaluacji grafu audio, czyli, w tym przypadku przechodzenia go od ostatniego

wierzchołka do pierwszego, wywołuje metode ParseNodes() na kazdym aktywnym wierzchołku kaz-

dorazowo przekazujac ta sama instancje struktury FSoundParseParameters.

Jak juz wspomniano wczesniej w 3.2, opisana tutaj implementacja modyfikuje tylko trzy parame-

try: wzmocnienie amplitudy, wzmocnienie najwyzszych czestotliwosci oraz wzgledna transformacje

zródła dzwieku. Jest tak, poniewaz sa to jedyne parametry struktury FSoundParseParameters, które

moga byc zalezne od wzglednego połozenia gracza1. Parametry te reprezentowane sa kolejno przez

pola:VolumeMultiplier, HighFrequencyGain i Transform.

Jak opisano w 3.4, wypalona scena akustyczna przechowywana jest wewnatrz obiektu klasy Au-

dio bedacej czescia API biblioteki RAYA-offline. Aktualny w danym momencie obiekt tej klasy

uzyskiwany jest za pomoca metody interfejsu modułu gry GetCurrentAudio()2.

Algorytm wewnatrz metody ParseNodes() pobiera od modułu gry wskaznik do aktualnego obiektu

Audio, a nastepnie, za pomoca odpowiedniej metody tej klasy pobiera zestaw ww. parametrów mo-

dyfikujacych dzwiek przekazujac do niej współrzedne odbiornika oraz zródła sygnału audio. Obie

współrzedne przekazywane sa do metody ParseNodes() jako parametry. Ostatecznie, modyfikowane

sa odpowiednie pola struktury FSoundParseParameters.

Pogłos

W rozdziale 1.2.4 opisano pokrótce w jaki sposób implementowany jest mechanizm efektu pogłosu

w silniku Unreal Engine 4. Developer (projektant dzwieku) definiuje obszary na scenie poprzez

rozstawianie specjalnych aktorów typu Audio Volume przypisujac do kazdego z nich statyczne efekty

1Fakt ten jest prawdziwy równiez dla najnowszej wersji silnika w momencie pisania tej pracy - 4.10. Dokumentacjastruktury FSoundParseParameters: https://docs.unrealengine.com/latest/INT/API/Runtime/Engine/FSoundParseParameters/index.html

2W implementacji modułu gry, kazdy zarejestrowany aktor-menedzer posiada odpowiadajacy mu obiekt klasy Audio.Jak opisano w 4.1.3, moduł gry przechowuje i uaktualnia wskaznik na aktualnego obecnie aktora-menedzera.

31

Rysunek 5: Obiekt RAYASoundNode w oknie edycji SoundCue.

pogłosu, reprezentowane przez obiekt (asset) typu UReverbEffect.

Z punktu widzenia przedstawionej tutaj implementacji wazne jest, ze zmiana parametrów instancji

obiektu UReverbEffect nie spowoduje uaktualnienia efektu pogłosu aplikowanego przez silnik audio.

Silnik audio UE4 działa w ten sposób, ze co klatke, na podstawie aktualnej pozycji gracza, przy-

gotowywana jest lista wszystkich obszarów Audio Volume wewnatrz których aktualnie znajduje sie

gracz. Sposród nich nastepnie wybierany jest ten o najwyzszym priorytecie i nastepuje sprawdzenie

czy przypisana do niego instancja klasy UReverbEffect jest inna niz w poprzedniej klatce. Jezeli tak,

nastepuje interpolacja do nowego efektu1.

Do implementacji zmiany efektu pogłosu w czasie rzeczywistym wystarczy wiec podmiana co

klatke przypisanego obiektu UReverbEffect do obejmujacego obszar całej sceny akustycznej aktora

Audio Volume.

Za ustawienie obiektu Audio Volume na scenie odpowiedzialny jest aktor-menedzer. Jak wspo-

mniano w 1.2.4, nie jest mozliwe utworzenie obiektu Audio Volume w czasie rozgrywki - musi sie to

odbyc przy załadowanym edytorze.

W momencie gdy uzytkownik w edytorze zmieni przypisany do aktora-menedzera asset wypalo-

nej sceny akustycznej, tworzy on nowa instancje Audio Volume o prostopadłosciennym kształcie i wy-

miarach obejmujacych cała scene akustyczna. Silnik UE4, a konkretnie mechanizm refleksji umoz-

liwia wykrycie momentu zmiany wartosci pola klasy oznaczonego przez makro UPROPETY. Słuzy do

tego metoda wirtualna metoda klasy UObject, PostEditChangeProperty(). Ponizej przedstawiona

jest implementacja tej metody wewnatrz klasy aktora-menadzera:

void ARAYAManager :: PostEditChangeProperty ( struct FPropertyChangedEvent

1Algorytm opisano na podstawie analizy kodu zródłowego silnika.

32

& PropertyChangedEvent )

{

auto PropertyName = ( PropertyChangedEvent . Property ) ?

PropertyChangedEvent .Property -> GetFName () : NAME_None ;

if ( PropertyName == GET_MEMBER_NAME_CHECKED ( ARAYAManager , BakeAsset )

)

{

if ( RayaAudioVolume )

{

RayaAudioVolume -> Destroy ();

}

SpawnRayaAudioVolume ();

}

}

Najpierw sprawdzane jest czy zmienione zostało pole BakeAsset, czyli wskaznik na asset sceny aku-

stycznej (słuzy do tego makro bedace czescia API UE4 GET_MEMBER_NAME_CHECKED). Jezeli tak, to

w przypadku gdy na scenie znajduje sie juz obiekt Audio Volume, zostaje on uprzednio zniszczony.

Ostatecznie, metoda SpawnRayaAudioVolume() tworzy nowy taki obiekt o wymiarach zdefiniowa-

nych przez bounding-box sceny akustycznej, czyli obejmujacy cała scene.

Za utworzenie efektów pogłosu (obiektów UReverbEffect) i ich podmiany w stworzonym w po-

wyzszy sposób obiekcie Audio Volume odpowiada komponent-odbiornik (opisany w 4.1.3). Dokonuje

tego wewnatrz opisanej juz wczesniej metody TickComponent().

W obecnej implementacji, biblioteka RAYA-Offline oferuje algorytm do aproksymacji czasu po-

głosu tylko dla dwóch czestotliwosci: 0Hz oraz czestotliwosci Nyquista, czyli czestotliwosci równej

połowie czestotliwosci próbkowania zatem tylko te dwa czasy pogłosu sa zawarte w danych wypa-

lonej scenie akustycznej. Na podstawie tych dwóch czasów, wyrazonych w sekundach, autor po-

stanowił dokonac wyznaczenia wartosci dwóch parametrów bedacych czescia struktury UReverbEf-

fect: DecayHFRatio oraz RTAt1Khz. Pierwszy z nich to, według dokumentacji, stosunek szybkosci

zanikania wysokich czestotliwosci w stosunku do czestotliwosci niskich. Postanowiono zatem wy-

znaczyc go jako iloraz czasu pogłosu dla czestotliwosci Nyquista i czasu pogłosu dla czestotliwosci

0Hz: DecayHFRatio = rtNyquist/rtDC. Drugi parametr, RTAt1Khz, czyli czas pogłosu wyrazony w

sekundach dla czestotliwosci 1kHz, obliczany jest za pomoca logarytmicznej interpolacji.

33

4.2 Moduł edytora

4.2.1 Asset materiał akustyczny

W celu umozliwienia uzytkownikowi przypisywania materiałów akustycznych do obiektów na scenie

zaimplementowano dwa elementy. Pierwszym z nich jest asset reprezentujacy materiał akustyczny,

czyli zestaw parametrów definiujacych własciwosci akustyczne danego materiału. Drugim elemen-

tem jest komponent sceny, który po podpieciu do aktora reprezentujacego pewna geometrie umozliwi

przypisanie do niego asset-u reprezentujacego materiał akustyczny. Teoretycznie, sam komponent

zawierajacy w sobie liste własciwosci materiału wystarczałby do tego aby uzytkownik mógł okreslac

własciwosci akustyczne obiektów na scenie. Jednakze implementacja specjalnego asset-u reprezentu-

jacego materiał akustyczny pozwala na intuicyjne tworzenie i edytowanie materiałów akustycznych w

taki sam sposób jak innych rodzajów materiałów w Unreal Engine 4. Taka funkcjonalnosc umozliwia

dodatkowo np. łatwe stworzenie biblioteki materiałów akustycznych.

Biblioteka RAYA udostepnia szereg parametrów okreslajacych lub wpływajacych na własciwosci

akustyczne materiału. Sa to m.in: współczynnik pochłaniania i rozpraszania (w 8 pasmach czestotli-

wosci), predkosc dzwieku w materiale, gestosc, grubosc, moduł Younga czy współczynnik Poissona.

Wszystkie te parametry powinny znalezc odzwierciedlenie w typie asset reprezentujacych materiał

akustyczny. Zdecydowano, ze dla prostoty implementacji wystarczy tylko aby klasa definiujaca as-

set zawierała pola odpowiadajace kolejnym parametrom materiału. Kazde z pól jest typu zmienno-

przecinkowego pojedynczej precyzji float, tak jak odpowiadajace im pola w typie reprezentujacym

materiał akustyczny w bibliotece RAYA. Zastosowano równiez takie samo nazewnictwo wszystkich

parametrów.

Klasa reprezentujaca materiał akustyczny nazwana została URAYAMaterial. Ponizej podany jest

wycinek kodu jej definicji:

UCLASS ()

class URAYAMaterial : public UObject

{

GENERATED_BODY ()

public :

UPROPERTY ( EditAnywhere )

float AbsorptionCoefficients [8];

// pozostałe pola reprezentujące właściwości akustyczne

};

34

Wszystkie pola klasy poprzedzone sa makrem UPROPERTY(EditAnywhere) aby uzytkownik miał

mozliwosc ich edycji z poziomu edytora.

Aby uzytkownik posiadał mozliwosc tworzenia asset-u z poziomu okna przegladarki asset-ów

wewnatrz edytora, nalezało dodatkowo zaimplementowac interfejs tzw. fabryki, UFactory, którego

zadaniem jest stworzenie nowej instancji danego asset-u. Do implementacji wystarczy nadpisac me-

tode wytwórcza UFactory::FactoryCreateNew() zwracajaca wskaznik do nowej instancji obiektu,

w tym przypadku typu URAYAMaterial. Ponizej podany jest kod implementacji tej metody wewnatrz

klasy URAYAMaterialFactory:

UObject * URAYAMaterialFactory :: FactoryCreateNew ( UClass * Class , UObject

* InParent , FName Name , EObjectFlags Flags , UObject *,

FFeedbackContext *)

{

return NewObject < URAYAMaterial >( InParent , Class , Name , Flags);

}

Rysunek 6: Materiał RAYA w menu tworze-nia nowego asset-u.

Rysunek 7: Okno edycji materiału RAYA.

4.2.2 Komponent materiału akustycznego

Zadaniem komponentu materiału akustycznego jest przypisanie asset-u URAYAMaterial do aktora na

scenie reprezentujacego pewien statyczny obiekt geometryczny (obiekt ten nie powinien byc dyna-

miczny, czyli posiadac mozliwosc zmiany transformacji podczas gry, poniewaz mapa parametrów

akustycznych jest z definicji statyczna). Podstawowym i najczesciej uzywanym typem obiektu w

UE4, który posiada geometrie, jest komponent sceny Static Mesh Component lub aktor typu Sta-

35

tic Mesh Actor, który posiada taki komponent jako komponent zródłowy (patrz 1.1.3). Geometria

tych obiektów zdefiniowana jest poprzez trójwymiarowa siatke (ang. mesh) trójkatów. Słowo Static

oznacza, ze siatka ta jest statyczna, czyli jej geometria nie moze sie zmieniac w czasie gry.

W zwiazku z tym, ze uzytkownik moze tworzyc hierarchie komponentów typu Static Mesh w

celu tworzenia złozonych geometrii i chciec przypisac inny materiał do kazdego z nich, komponent

reprezentujacy materiał akustyczny musi posiadac mozliwosc bycia doczepianym do innych kompo-

nentów, czyli dziedziczyc co najmniej z typu komponentu sceny, USceneComponent. (1.1.3).

Komponent materiału akustycznego reprezentowany jest przez klase URAYAMaterialComponent.

Klasa ta zawiera tylko jedno pole, którym jest wskaznik do aktualnej instancji asset-u materiału:

UCLASS (...)

class URAYAMaterialComponent : public USceneComponent

{

// ...

UPROPERTY ( EditAnywhere )

class URAYAMaterial * Material ;

};

Autor dodatkowo postanowił uniemozliwic uzytkownikowi mozliwosci doczepiania innych kom-

ponentów do komponentu materiału, gdyz, z logicznego punktu widzenia nie miało by to zadnego

sensu. Do tego celu posłuzyła metoda wirtualna CanAttachAsChild() w klasie USceneComponent,

która jest wywoływana przez silnik w momencie gdy uzytkownik próbuje dołaczyc jakis komponent

do danego. Metoda ta przyjmuje dołaczany komponent oraz jego nazwe jako parametry i zwraca

wartosc logiczna okreslajaca czy takie dołaczenie jest mozliwe (bazowa implementacja zwraca za-

wsze wartosc true). W zwiazku z tym, ze do komponentu materiału akustycznego nie powinien byc

dołaczany zaden typ komponentu, wystarczy, ze zwrócona zostanie zawsze wartosc logiczna false:

bool URAYAMaterialComponent :: CanAttachAsChild ( USceneComponent *, FName)

const

{

return false;

}

Ponadto, autor postanowił zakomunikowac uzytkownikowi, w przypadku gry ten próbuje doła-

czyc komponent materiału akustycznego do komponentu innego niz typu StaticMeshComponent lub

komponentu, który nie jest statyczny. Do tego celu posłuzyła wirtualna metoda komponentu sceny,

OnAttachmentChanged(), która wywoływana jest przez silnik na komponencie w momencie gdy

36

zmianie ulega komponent do którego jest dołaczony. W ponizszej implementacji nastepuje sprawdze-

nie czy oba powyzsze warunki sa spełnione i jezeli nie, w konsoli wyswietlony zostaje odpowiedni

komunikat:

void URAYAMaterialComponent :: OnAttachmentChanged ()

{

if ( AttachParent && ( AttachParent -> Mobility != EComponentMobility ::

Static || Cast < UStaticMeshComponent >( AttachParent ) == nullptr ))

{

UE_LOG ( LogRayavEditorModule , Warning , TEXT(" RAYAMaterial

components should only be attached to Static Mesh components

with static mobility "));

}

}

To czy transformacja danego komponentu moze sie zmieniac w trakcie rozgrywki reprezentowane

jest przez aktualna wartosc pola Mobility komponentu sceny. Wartosc typu EComponentMobility::

Static oznacza, ze dany komponent jest statyczny, czyli nie moze zmienic swojej transformacji.

4.2.3 Konfiguracja RAYA

Przed rozpoczeciem procesu wypalenia sceny akustycznej, konieczna jest konfiguracja silnika RAYA.

Celem tej konfiguracji jest odpowiednie przygotowanie lub zmiana domyslnych ustawien modułów

bioracych udział w procesie symulacji propagacji wiazek, w szczególnosci modułu geometrii. Czesc

konfiguracji jest obowiazkowa, np. podanie odpowiednich sciezek do plików wykorzystywanych

przez silnik, a czesc dotyczy parametrów, które bezposrednia wpływaja na jakosc i dokładnosc symu-

lacji, np. właczenie/wyłaczenie symulacji efektu dyfrakcji.

Konfiguracja silnika RAYA moze nastapic z pliku badz z poziomu kodu. W tym przypadku

konfiguracja nastepuje z poziomu kodu, na podstawie ustawien zawartych w obiekcie menadzera

(typ URAYAManager) otrzymanego za pomoca metody GetManagerForCurrentLevel() modułu edy-

tora (patrz 4.1.2]).

Parametry konfiguracyjne w bibliotece RAYA maja postac pary [nazwa parametru, wartosc] gdzie

nazwa parametru jest łancuchem znakowym, a wartosc moze byc róznego typu. Interfejs AudioOffline

biblioteki RAYA-offline oferuje zestaw przeładowanych metod dla róznych typów parametrów.

Ponizej przedstawiony jest wycinek kodu funkcji wewnatrz modułu edytora wtyczki SetRayaConfig

odpowiedzialnej za skonfigurowanie silnika RAYA z wykorzystaniem parametrów ustawionych przez

uzytkownika zawartych w strukturze typu FRAYAConfiguration bedacej czescia klasy menadzera

37

(4.1.2):

void SetRayaConfig ( raya_offline :: AudioOffline & AudioOffline , const

FRAYAConfiguration & RayaConfiguration )

{

AudioOffline . setConfig ("max beam generation ", RayaConfiguration .

MaxBeamGeneration );

AudioOffline . setConfig ("use varying beam accuracy ",

RayaConfiguration . bUseVaryingBeamAccuracy );

// pozostała część konfiguracji

}

Rysunek 8: Okno edycji aktora-menadzera wewnatrz edytora słuzace do konfiguracji ustawien dlaobecnie edytowanego poziomu.

4.2.4 Eksport sceny

W celu symulacji propagacji wiazek i na tej podstawie utworzenia mapy parametrów dzwiekowych

przez biblioteke RAYA-offline konieczne jest uprzednie przekazanie do niej informacji o geometrii

38

sceny i rozkładzie materiałów akustycznych. Proces ten w kontekscie niniejszej wtyczki nazwany

został eksportem sceny.

Eksport sceny sprowadza sie do zbudowania sceny akustycznej korzystajac z interfejsu biblio-

teki RAYA-offline na podstawie sceny akustycznej w Unreal Engine 4. W tym przypadku, na scene

akustyczna składaja sie tylko aktorzy (komponenty) typu Static Mesh wraz z ew. materiałem aku-

stycznym (asset RAYAMaterial) (patrz 4.2.2).

W celu zbudowania sceny, biblioteka RAYA-offline udostepnia interfejs SceneBuilder. Schemat

korzystania z tego interfejsu jest bardzo prosty: po zarejestrowaniu materiałów akustycznych uzyt-

kownik po prostu dodaje kolejne trójkaty składajace sie na dana siatke jednoczesnie podajac indeks

materiału akustycznego otrzymany przy jego rejestracji.

Problem eksportu sceny ogranicza sie zatem do ekstrakcji informacji o trójkatach z komponentu

Static Mesh. Na szczescie, interfejs tego komponentu umozliwia dostep do listy trójkatów składa-

jacych sie na jego siatke. W tym miejscu nalezy zaznaczyc, ze siatka w UE4 złozona jest z tzw.

“pod-siatek“ o róznej gestosci (szczegółowosci), w jez. ang. LOD (Level of Detail). Kazda z tych

pod-siatek posiada osobna liste trójkatów. Siatki o róznym poziomie szczegółowosci wykorzysty-

wane sa przez silnik w celu poprawy wydajnosci - wraz z oddalaniem sie kamery od obiektu ren-

derowana zostaje coraz mniej szczegółowa siatka. Z punktu widzenia eksportu sceny akustycznej,

interesujaca jest tylko siatka o najmniejszym stopniu szczegółowosci.

Ponizej przedstawiony jest uproszczony pseudokod algorytmu eksportu sceny:

SceneBuilder : rozpocznij budowe sceny

dla kazdego aktora AStaticMeshActor na scenie :

dla kazdego statycznego komponentu UStaticMeshComponent tego aktora :

jezeli posiada podpiety material URAYAMaterial :

SceneBuilder : zarejestruj material akustyczny jezeli nie

zarejestrowany

w przeciwnym wypadku , uzyj domyslny

SceneBuilder : rozpocznij nowa siatke

sposrod pod - siatek komponentu znajdz siatke o najmniejszej

szczegolowosci

dla kazdego trojkata tej siatki :

SceneBuilder : dodaj trojkat

SceneBuilder : zakoncz siatke

SceneBuilder : zakoncz budowe sceny

W implementacji załozono, ze wszystkie komponenty Static Mesh znajdujace sie na scenie beda

39

czescia aktora typu Static Mesh Actor. Autor zdecydował sie na takie załozenie, poniewaz wydaje

sie mało prawdopodobne aby uzytkownik dołaczał komponenty typu Static Mesh do aktorów innego

rodzaju1 W przeciwnym wypadku, konieczna byłaby iteracja po wszystkich obiektach na scenie (któ-

rych moze byc tysiace) w celu znalezienia komponentów typu statycznej siatki.

4.2.5 Wypalenie sceny akustycznej

Rozpoczecie procesu wypalania sceny akustycznej inicjowane jest przez uzytkownika z poziomu edy-

tora. Jego wynikiem jest utworzenie sceny akustycznej i zapisanie jej do reprezentujacego ja asset-u

klasy RAYALevelBakeAsset (4.1.1). Jak wspomniano w 3.3, za zarzadzanie tym procesem odpowie-

dzialny jest moduł edytora.

Po stworzeniu nowego obiektu klasy AudioOffline, konfiguracji silnika RAYA (patrz 4.2.3) i eks-

porcie sceny (4.2.4) nastepuje rozpoczecie wypalenie sceny akustycznej, inicjowane przez wywołanie

odpowiedniej metody klasy AudioOffline.

W zwiazku z tym, ze proces wypalania sceny akustycznej moze potrwac od kilku minut do kilku

godzin konieczne jest aby odbywał sie asynchronicznie, czyli na watku innym niz watek interfejsu

uzytkownika. W przeciwnym razie, uzytkownik po kliknieciu przycisku inicjujacego wypalenie sceny

nie bedzie mógł korzystac w tym czasie z edytora.

W celu zarzadzania procesem wypalania sceny zaimplementowano obiekt menedzera, reprezento-

wany przez klase FRAYABakeManager. Zadaniem obiektu tej klasy jest stworzenie nowego watku, tzw.

roboczego z którego rozpoczynany bedzie proces wypalania sceny oraz utworzenie asset-u wypalonej

sceny po zakonczeniu procesu wypalania. Oprócz tego, obiekt tej klasy pełni role posrednika pomie-

dzy interfejsem uzytkownika a watkiem roboczym: do jego zadan nalezy wyswietlanie komunikatów

informujacych uzytkownika o obecnym stanie wypalania oraz ew. zatrzymanie watku roboczego na

zadanie uzytkownika.

W projekcie załozono, ze nie bedzie mozliwosci jednoczesnego wypalania kilku scen akustycz-

nych. W zwiazku z tym klasa FRAYABakeManager zaimplementowana jest jako tzw. signgleton. Sin-

gleton to kreacyjny wzorzec projektowy, który ogranicza mozliwosc tworzenia wiecej niz jednej in-

stancji danego obiektu oraz umozliwia globalny dostep do tego obiektu.

Klasa reprezentujaca tzw. obiekt robotnik (ang. worker), nazwana została FRAYABakeWorker.

Klasa ta dziedziczy z klasy bazowej FRunnable bedacej czescia API Unreal Engine 4, która reprezen-

tuje obiekt wykonujacy pewna “prace“ na pewnym watku. Kluczowymi elementami tego interfejsu

1Wniosek ten wysnuty został na podstawie studiowania kodu zródłowego silnika oraz oficjalnej dokumentacji, wktórej panuje powszechne załozenie, ze obiekty o statycznej geometrii reprezentowane sa poprzez aktora typu StaticMesh Actor [11]

40

sa trzy wirtualne metody: Init(), Run() i Exit(), wywoływane w tej kolejnosci. W metodzie Init()

obiekt robotnik powinien dokonac swojej inicjalizacji, w Exit() zwolnic wszystkie uzywane zasoby

natomiast własciwa praca powinna odbyc sie w metodzie Run(). W tym przypadku w metodzie Run()

odbywa sie wywołanie metody rozpoczynajacej wypalanie sceny.

Aby uzytkownik posiadał mozliwosc sledzenia postepu wypalania sceny (jak juz wczesniej wspo-

mniano proces ten moze trwac bardzo długo), w tym czasie na ekranie wyswietlone zostaja komuni-

katy, w postaci nieinwazyjnych, małych okienek (przedstawione na rysunku 9). Okna te sa czescia

standardowego systemu notyfikacji wykorzystywanego przez silnik do wyswietlania postepu długo

trwajacych procesów, np. wypalania statycznego oswietlenia.

W celu implementacji tej funkcjonalnosci obiekt klasy FRAYABakeWorker wykorzystuje tzw. obiekty

delegujace (ang. delegate). W skrócie, zadaniem delegatów jest oddelegowanie pewnego zadania do

innej czesci programu. Odbywa sie to poprzez tzw. powiazanie (ang. binding) metody/funkcji z

obiektem delegata. Obiekt delegata nie wie co dana funkcja lub metoda robi, jego przeznaczeniem

jest tylko jej wywołanie. W tym przypadku, obiekt klasy FRAYABakeWorker przechowuje dwa obiekty

delegujace: jeden odpowiedzialny za oddelegowanie w momencie zwiekszenia postepu (procento-

wego) wypalania sceny akustycznej, drugi za oddelegowanie w momencie zakonczenia sukcesem.

Obiekt menedzera, w momencie tworzenia obiektu robotnika wiaze swoje metody odpowiedzialne za

wyswietlanie notyfikacji z odpowiednimi delegatami.

Ponizej przedstawiony jest kod metody Run() klasy FRAYABakeWorker:

uint32 FRAYABakeWorker :: Run ()

{

// Utworzenie funkcji anonimowej wywoływanej podczas zmiany postępu

// Progress - procentowa wartość postępu

auto ProgressCallback = [&]( unsigned int Progress )

{

auto OldValue = PercentCompleted .Set( Progress );

// Jeżeli z delegatem powiązana jest jakaś funkcja, oddeleguj

if (( int32) Progress > OldValue && OnBakeProgressDelegate . IsBound ()

)

OnBakeProgressDelegate . Execute ();

};

// Rozpocznij wypalanie sceny

AudioOffline ->bake (* BakeSettings , *BakeOutput , ProgressCallback );

41

// Jeżeli użytkownik nie anulował i z delegatem reprezentującym pomyślne

// zakończenie wypalania powiązana jest jakaś funkcja, oddeleguj

if (! Canceled && OnBakeCompletedDelegate . IsBound ())

OnBakeCompletedDelegate . Execute ();

IsFinished = true;

return 0;

}

Metoda bake() klasy AudioOffline przyjmuje jako parametr strukture zawierajaca parametry konfi-

guracyjne procesu wypalania, wektor (dynamiczna tablice) do którego zapisany zostanie ciag bajtów

reprezentujacy zdeserializowany obiekt wypalonej sceny akustycznej oraz anonimowa funkcje (tzw.

lambda) która jest wywoływana w momencie zwiekszenia postepu procesu wypalania sceny aku-

stycznej.

Proces rozpoczecia wypalania sceny akustycznej inicjowany jest przez wywołanie na obiekcie

menedzera FRAYABakeManager metody StartBake() która przyjmuje instancje obiektu AudioOffline

jako parametr. Wewnatrz metody tej nastepuje utworzenie nowego obiektu roboczego, pobranie pa-

rametrów dot. konfiguracji samego procesu wypalania (liczba watków oraz długosc boku komórki

determinujaca gestosc dyskretyzacji sceny) z obiektu aktora-menedzera oraz powiazanie odpowied-

nich delegatów.

Po zakonczeniu procesu wypalenia sceny akustycznej, czyli powrocie z metody bake(), wywo-

ływany jest delegat OnBakeCompletedDelegate. Z tym delegatem powiazana jest metoda obiektu

FRAYABakeManager odpowiedzialna za utworzenie i zapisanie asset-u wypalonej sceny akustycznej

oraz wyswietlenie okienka notyfikacji informujacego o pozytywnie zakonczonym procesie wypala-

nia.

Rysunek 9: Notyfikacje o postepie procesu wypalania sceny akustycznej wyswietlane wewnatrz edy-tora.

42

4.2.6 Kompresja

Duzym problemem zwiazanym z wypalona scena akustyczna była ilosc zajmowana przez nia pa-

mieci. Jak juz wspomniano w 3.2, parametry wzgledne zmiany dzwieku, mianowicie wzmocnie-

nie amplitudy, wzmocnienie najwyzszych czestotliwosci oraz kierunek dzwieku przechowywane we-

wnatrz struktury sceny akustycznej zaleza od dwóch zmiennych: komórki odbiornika i komórki zró-

dła dzwieku. Oznacza to wiec, ze ilosc pamieci potrzebna do ich przechowania jest wprost propor-

cjonalna do kwadratu liczby komórek na które podzielona została scena.

Przykładowo, gry poczatkowo parametry te przechowywano jako typ dwu-bajtowy ze znakiem1 to

ilosc pamieci potrzebna do reprezentacji jednego zestawu tych parametrów wynosiła 2+2+(2 ·3) =

10 bajtów (kierunek reprezentowany jest przez wektor trzech współrzednych). Zatem, dla przykłado-

wej, “małej“ sceny o wymiarach 30mx30mx5m i długosci boku pojedynczej komórki równej 1 metra,

ilosc komórek na które zostanie podzielona scena wynosi 30 · 30 · 5 = 4500. Ostatecznie wiec, ilosc

pamieci potrzebna w tym przypadku do przechowania ww. parametrów to 45002 · 10 bajtów, czyli

≈ 193MB. Łatwo sobie wyobrazic, ze w przypadku gdy developer bedzie chciec dokonac gestszego

podziału sceny lub scena bedzie wieksza (podane powyzej rozmiary sceny sa stosunkowo małe na

dzisiejsze standardy gier) to ilosc pamieci zajmowanej na dysku/wczytanej do RAM przez wypalona

scene akustyczna moze byc rzedu gigabajtów. Nalezy równiez wsiasc pod uwage, ze typowa gra

składa sie z wielu poziomów (scen), rzedu kilkunastu. Przy takiej implementacji same pliki wypalo-

nej sceny akustycznej mogłyby przerosnac swoim rozmiarem pozostała czesc gry.

W celu rozwiazania tego problemu postanowiono zastosowac kompresje tych danych. Kazdy z

wyzej wymienionych parametrów wzglednej zmiany dzwieku mozna przedstawic w postaci macie-

rzy, gdzie kolumny/wiersze odpowiadaja komórkom odbiornika/zródła. W zwiazku z tym, zastoso-

wana metoda kompresji bedzie pewnym rodzajem kompresji macierzy. Istnieje wiele algorytmów

kompresji macierzy, dotycza one jednak tzw. macierzy rzadkich, czyli takich, których wiekszosc

elementów jest zerowa. W przypadku macierzy parametrów wzglednej zmiany dzwieku miedzy ko-

mórkami, zdecydowana wiekszosc elementów nie bedzie zerowa, poniewaz dzwiek z jednej komórki

dociera do wiekszosci, a nawet wszystkich pozostałych. Zatem zastosowany algorytm kompresji

musiał byc rodzajem kompresji macierzy gestej.

Popularna i zarazem łatwa metoda kompresji macierzy gestych, szczególnie stosowanej w dzie-

dzinie przetwarzania obrazów jest kompresja z wykorzystaniem rozkładu na według wartosci oso-

bliwych (ang. Singular value decomposition, w skrócie SVD). SVD to rozkład macierzy na iloczyn

trzech specyficznych macierzy. Zgodnie z teoria, kazda macierz o wartosciach rzeczywistych lub

1Docelowo parametry te w API silnika UE4 sa typu zmiennoprzecinkowego pojedynczej precyzji (4 bajty).

43

zespolonych mozna przedstawic za pomoca rozkładu SVD. Zakładajac rzeczywista macierz M o wy-

miarach m x n, jej rozkład według wartosci osobliwych dany jest przez

M = USV∗

gdzie

• U - macierz ortogonalna o wymiarach m x m

• S - macierz diagonalna o wymiarach m x n

• V - macierz ortogonalna o wymiarach n x n

Wartosci na przekatnej macierzy S nazywane sa wartosciami osobliwymi macierzy M. Jezeli

posortowane one sa według malejacych wartosci, to poprzez eliminacje kolejnych (od najmniejszych)

wartosci osobliwych i odpowiadajacych im kolumn/wierszy z macierzy U i V otrzymywana zostanie

coraz gorsza, według kryterium błedu srednio-kwadratowego, aproksymacja oryginalnej macierzy M.

Fakt ten jest istota metody kompresji za pomoca SVD.

Algorytm obliczenia SVD nie jest istotny z punktu widzenia tej pracy, poniewaz dostepne sa bi-

blioteki programistyczne do algebry liniowej obliczajace SVD. Autor do implementacji kompresji

sceny akustycznej zdecydował sie skorzystac z biblioteki Eigen1. Jest to popularna i ceniona biblio-

teka w jezyku C++ do algebry liniowej. Jej zaleta jest fakt, iz jest w całosci szablonowa, czyli w celu

jej dołaczenia do projektu wystarczy załaczenie pliku nagłówkowych. Waznym aspektem przy wybo-

rze tej biblioteki była tez jej licencja - biblioteka Eigen jest obecnie na licencji MPL22, która pozwala

na uzywanie jej w komercyjnych aplikacjach bez koniecznosci dystrybucji kodu zródłowego.

Natura algorytmów do obliczania SVD jest wspieranie tylko macierzy o wartosciach typu zmien-

noprzecinkowego. Algorytm biblioteki Eigen nie jest tutaj wyjatkiem. Zatem aby mozliwe było za-

stosowanie kompresji konieczna była uprzednia zamiana parametrów z reprezentacji stałoprzecinko-

wej (dwu-bajtowej) na zmiennoprzecinkowa pojedynczej precyzji. Warto w tym miejscu zaznaczyc,

ze kompresji podlegaja tylko dwa parametry: wzmocnienie amplitudy i najwyzszych czestotliwosci.

Zrezygnowano z kompresji informacji o kierunku ze wzgledu na wyraznie słyszalne błedy kompresji.

Implementacja algorytmu kompresji odbywa sie w bibliotece RAYA-offline. Kompresja doko-

nywana jest po wypaleniu sceny akustycznej. Aby umozliwic uzytkownikowi intuicyjna kompresje

asset-u wypalonej sceny akustycznej z poziomu edytora, stworzono do tego celu specjalna klase ak-

tora. Aktor ten, podobnie jak aktor-menedzer (patrz 4.1.2 nie jest ustawiany na scenie, jest tylko wy-

1http://eigen.tuxfamily.org/index.php?title=Main_Page2https://www.mozilla.org/en-US/MPL/2.0/

44

swietlany w oknie edycji aktora. Posiada on tylko trzy pola: wskaznik (typu URAYALevelBakeAsset*)

do asset-u nie-skompresowanej sceny akustycznej, wskaznik na asset do którego zostanie zapisana

skompresowana scena akustyczna oraz pole reprezentujace stopien kompresji, przyjmujace wartosci

od 0 (brak kompresji) do 1 (maksymalna kompresja). W momencie gdy uzytkownik zmienia ten

parametr, implementacja wywołuje odpowiednia metode wewnatrz biblioteki RAYA-offline, która

dokonuje rozkładu za pomoca SVD usuwajac odpowiednia ilosc wartosci osobliwych. Ilosc usunie-

tych wartosci osobliwych jest wprost proporcjonalna do ww. stopnia kompresji. Klase reprezentujacy

obiekt słuzacy do kompresji sceny akustycznej nazwano ARAYABakeAssetCompressor.

Rysunek 10: Okno edycji obiektu klasy ARAYABakeAssetCompressor wewnatrz edytora.

5 Zakonczenie

W pracy tej przedstawiono sposób i mozliwosci integracji biblioteki RAYA z silnikiem Unreal En-

gine 4. Za pomoca integracji tej udało sie rozszerzyc funkcjonalnosc silnika w aspekcie kreowania

dzwieku o automatyczna zmiane niektórych parametrów dzwieku na podstawie rzeczywistej geome-

trii sceny i materiałów akustycznych na biezaco podczas rozgrywki.

Integracji dokonano za pomoca systemu wtyczek Unreal Engine 4 pozwalajacy na rozszerzenie

funkcjonalnosci edytora i silnika bez koniecznosci edycji kodu zródłowego. Dzieki temu projektant

dzwieku chcac wykorzystac funkcjonalnosc biblioteki RAYA w swoim projekcie nie musi porzucac

ani zmieniac znanego mu srodowiska pracy.

Oprócz samej funkcjonalnosci zwiazanej z automatyczna zmiana dzwieku, zaimplementowano

system pozwalajacy uzytkownikowi na utworzenie i zarzadzanie biblioteka materiałów akustycznych

z poziomu edytora poprzez integracje z systemem asset-ów Unreal Engine 4.

W zwiazku z przyjetymi załozeniami, duzym problemem podczas implementacji była znaczna

ilosc pamieci potrzebna do przechowania informacji na temat parametrów dzwiekowych wykorzy-

45

stywanych do modyfikacji dzwieku w czasie rozgrywki. Problem ten rozwiazano za pomoca metody

kompresji z wykorzystaniem rozkładu na wartosci osobliwe.

Do propozycji dalszej pracy mozna by zaliczyc m.in przetestowanie wydajnosci obecnej imple-

mentacji przy jednoczesnej obecnosci duzej ilosci zródeł dzwieku oraz ulepszenie implementacji

zmiennego efektu pogłosu poprzez kontrole wiekszej ilosci parametrów. Istotnym rozszerzeniem

obecnej funkcjonalnosci mogłoby byc równiez uwzglednianie geometrii obiektów reprezentujacych

krajobraz w scenie akustycznej.

46

Bibliografia

[1] B. Ziółko, T. Pedzimaz, Sz. Pałka, I. Gawlik, B. Miga , P. Bugiel. „Real-time 3D Audio Simu-

lation in Video Games with RAYAV”. W: Making Games vol.1 (2015).

[2] B.Miga, B.Ziółko. „Real-time acoustic phenomena modelling for computer games audio en-

gine”. W: Archives of Acoustics (IF) vol. 2 (2015).

[3] Michael Noland. Unreal Property System (Reflection). Dostep: 18.01.2016. URL: https://

www.unrealengine.com/blog/unreal-property-system-reflection.

[4] Unreal Engine 4 Documentation, Actors. Dostep: 18.01.2016. URL: https://docs.unrealengine.

com/latest/INT/Programming/UnrealArchitecture/Actors/index.html.

[5] Unreal Engine 4 Documentation, Audio System Overview. Dostep: 18.01.2016. URL: https:

//docs.unrealengine.com/latest/INT/Engine/Audio/Overview/index.html.

[6] Unreal Engine 4 Documentation, Coding Standard, Naming Conventions. Dostep: 18.01.2016.

URL: https://docs.unrealengine.com/latest/INT/Programming/Development/

CodingStandard/index.html#namingconventions.

[7] Unreal Engine 4 Documentation, Components. Dostep: 18.01.2016. URL: https://docs.

unrealengine.com/latest/INT/Programming/UnrealArchitecture/Actors/Components/

index.html.

[8] Unreal Engine 4 Documentation, Level Editor. Dostep: 18.01.2016. URL: https://docs.

unrealengine.com/latest/INT/Engine/UI/LevelEditor/index.html.

[9] Unreal Engine 4 Documentation, Sound Cue Editor. Dostep: 18.01.2016. URL: https : / /

docs.unrealengine.com/latest/INT/Engine/Audio/SoundCues/Editor/index.

html.

[10] Unreal Engine 4 Documentation, Sound Cue Reference. Dostep: 18.01.2016. URL: https:

//docs.unrealengine.com/latest/INT/Engine/Audio/SoundCues/NodeReference/

index.html.

[11] Unreal Engine 4 Documentation, Static Mesh Actors. Dostep: 18.01.2016. URL: https://

docs.unrealengine.com/latest/INT/Engine/Actors/StaticMeshActor/index.

html.

[12] Unreal Engine 4 Documentation, Unreal Build System. Dostep: 18.01.2016. URL: https :

//docs.unrealengine.com/latest/INT/Programming/UnrealBuildSystem/index.

html.

47

[13] I. Gawlik, T. Pedzimaz, Sz. Pałka, B. Ziółko. „Efficient Vectorized Architecture for Feedback

Delay Network Reverberator with Policy Based Design”. W: SPA Conference, Poznan, 2015.

[14] Sz. Pałka, B. Głut, B Ziółko. „Visibility determination in beam tracing with application to

real-time sound simulation”. W: Computer Science, AGH vol.15.2 (2014).

48