VRath – zewnętrzne obiekty 3D oraz dźwięk

Dzisiaj będzie krótko, ponieważ codzienne obowiązki całkowicie pochłonęły mój czas w tym tygodniu. Krótko ale treściwie, będzie o kolejnych typach zasobów i pewnym problemie.

W ostatnim wpisie projektu w podsumowaniu dałem do zrozumienia, że chciałbym usłyszeć dźwięk podczas rozgrywki, aby nieco ożywić moją scenę. Ponadto chciałem wykorzystać także możliwość wczytywania modeli 3D aby jeszcze bardziej upiększyć strzelnice. Niestety pojawił się pewien problem, który rozwiązałem dosłownie przed chwilą. Manager zewnętrznych zasobów blokował mi możliwość wczytania obiektów o rozszerzeniach takich jak .dae czy .obj, a m.in. w takich formatach są definiowane trójwymiarowe modele. Zastanawiałem się czy to nie problem webpacka i file-loadera, ale sprawcą okazał się sposób zapisu encji managera zasobów. Okazuje się, że twórca aframe-react nie rekomenduje używania zapisu <Entity primitive="a-assets" /> przy definiowaniu managera i sugeruje aby zastosować zapis bezpośrednio z A-Frame’a czyli <a-assets />. Trochę mi to czasu zjadło, ale najważniejsze, że doszedłem co jest problemem. W dalszej części wpisu będę używał zapisu A-Frame’a przy deklarowaniu zasobów.



Niech zabrzmi dźwięk!

Na razie na mojej scenie jest dość cicho, żeby nie powiedzieć za cicho. Zdecydowanie nie można odczuć atmosfery strzelnicy. Brakuje efektu wystrzału oczywiście! Gdzie taki dźwięk można znaleźć? Ja skorzystałem ze strony freesound.org. Można na niej znaleźć sporo fajnych dźwięków do gier i co ważne, znaczna większość jest rozpowszechniana na wolnej licencji i może być używana w komercyjnych projektach. Odpowiedni plik umieszczam w folderze sounds i dopisuję do managera zasobów odpowiedni wpis:

import shotMp3 from "../../sounds/shot.mp3";
...
<audio id="shot" src={shotMp3}></audio>

Pliki dźwiękowe deklarujemy w managerze jako elementy <audio>. Następnie muszę dodać wywołanie tego dźwięku w odpowiednie miejsce w projekcie. Na chwilę obecną mam tylko jedno zdarzenie, jest to kliknięcie na kuli symbolizujące strzał w tarcze. Nie mogę jednak dodać tego w tym miejscu, ponieważ strzelać można wszędzie, nie tylko do tarczy. Przydałoby się więc zaczepić gdzieś w okolicach celownika… a może na celowniku? Wspominałem już, że obiekt kursora emituje zdarzenie click, ale co ciekawe, również na nie nasłuchuje. Natomiast jak dodać dźwięk? A-Frame dysponuje komponentem sound, który posiada właściwość on włączającą dźwięk gdy zajdzie podane zdarzenie. Wydaje się proste i takie właśnie jest, a tak prezentuje się encja mojego kursora wzbogaconego o dźwięk:

<Entity primitive="a-cursor" 
        geometry="primitive: ring; radiusInner: 0.00001; radiusOuter: 0.04" 
        material="src: #crosshairTexture" 
        sound="src: #shot; on: click" />

Gdy zajdzie zdarzenie kliknięcia, dźwięk zostanie uruchomiony. Jest tylko jeden problem. Mogę bardzo szybko klikać natomiast responsywność dźwięku jest mizerna. Brakuje efektu strzelania ciągłego. Na szczęście komponent sound dysponuje właściwością poolSize, która określa maksymalnie ile razy równocześnie ma być odtworzony dźwięk. Myślę, że 10 w zupełności mi wystarczy. Tak wygląda poprawiony kod komponentu:

<Entity primitive="a-cursor" 
        geometry="primitive: ring; radiusInner: 0.00001; radiusOuter: 0.04" 
        material="src: #crosshairTexture" 
        sound="src: #shot; on: click; poolSize: 10" />

Wczytywanie innych obiektów 3D

Moja scena jest dość pusta i choć mógłbym ją wypełnić prostymi obiektami, to jednak nie będzie to ani trochę realistyczne. A-Frame i tym razem przybywa z pomocą, ponieważ umożliwia wczytywanie zewnętrznych obiektów 3D aby urozmaicać swoje animacje. A-Frame obsługuje modele m.in. w formacie Wavefront (.obj, .mtl), Collada (.dae) czy GL Transmission Format (.gltf). Wykorzystam pierwszy format, a swój model pobiorę ze strony clara.io, ponieważ znalazłem to źródło na stronie A-Frame’a i widzę, że oferuje darmowe modele 3D do wykorzystania w swoich projektach, w przeróżnych formatach. Obiektem 3D, który umieszczę na scenie będzie apteczka wojskowa, bo nigdy nie wiadomo czy się nie przyda jak rozgrywka będzie za ostra! 😉 Aby wykorzystać zewnętrzny obiekt 3D, w managerze zasobów należy wykorzystać encję <a-asset-item>.
W przypadku wykorzystywania formatu Wavefront potrzebne są dwa pliki: plik .obj oraz .mtl. Deklaracja użycia w managerze będzie wyglądała więc następująco:

import "../../images/bumpy-olive-green-plastic-texture.jpg";
import "../../images/Lock.png";
import healthPackObj from "../../images/health-pack.obj";
import healthPackMtl from "../../images/health-pack.mtl";
...
<a-asset-item id="healthPackObj" src={healthPackObj}></a-asset-item>
<a-asset-item id="healthPackMtl" src={healthPackMtl}></a-asset-item>

Oprócz wspomnianych przeze mnie plików muszę także zaimportować tekstury, które ten model wykorzystuje, co zrobiłem powyżej. Wykorzystanie modelu w tym formacie odbywa się za pomocą komponentu obj-model, w którym podaje się ścieżkę zarówno do pliku .obj jak i .mtl. Wydzielę osobny plik do szczegółów sceny o nazwie DetailsComponent i umieszczę w nim mój nowy obiekt:

import { Entity } from "aframe-react";
import React from "react";

const DetailsComponent = () => (
    <Entity>
        <Entity obj-model="obj: #healthPackObj; mtl: #healthPackMtl" position="10 -0.5 4" />
    </Entity>
);

export default DetailsComponent;

Na razie umieściłem tą apteczkę przy ścianie po prawej, ale może w finalnej wersji będzie znajdowała się gdzieś zupełnie indziej.

apteczka na scenie

Podsumowanie

Wiem już jak poradzić sobie z dźwiękiem oraz z modelami 3D. Powoli muszę zbierać całość do kupy i zacząć ogarniać naliczanie punktów na tarczy, bo czas leci nieubłaganie. Coś czuje, że szykuje się zarwanie kilku nocek….