Jarosław Maciejewski
Minecraft w FrameVR.io
Ważne informacje
Obecnie pisany artykuł działa z Minecraft 1.16
Obecnie Mineways nie eksportuje i nie widzi następujących rzeczy [nie umieszczaj ich na swojej mapie w grze Minecraft]:
- napisy na tablicach
- książkę na podeście
- świeczki [candles, *_candle] [dodane w MC 1.17]
- łódka
- minecart
- spore_bloosom
- hanging_roots
- glow_lichen
- *amethyst*
- *dripstone*
- big_dripleaf
- moss_carpet
- azalea
- oxidized_copper
- waxed_cut_copper
- waxed_cooper_block
- oxidized_cut_copper_stairs
- raw_iron_block
- raw_copper_block
- raw_gold_block
Wstęp
FrameVR.io jest projektem internetowym, który pozwala na zwiedzanie wirtualnego świata, głównie przy użyciu okularów VR, chociaż można także zwiedzać przy użyciu komputera czy smartfona. Oferuje m.in. możliwość udostępniania swojego ekranu, rozmów głosowych, zabezpieczania swojej scenerii hasłem, załadowania własnej scenerii, dodania różnych zasobów do scenerii: obrazków, sfer 360°, filmów 360°, PDFy, filmy, dźwięków czy modeli. Tych opcji jest naprawdę dużo.
Ja postanowiłem, że jedna z moich scenerii w FrameVR będzie bazowana na znanym świecie z gry Minecraft, który jest dostępny publicznie pod adresem: https://framevr.io/nitro. Okazało się, że wiele osób jest zachwyconych moim pomysłem na scenerię w FrameVR (co jest mi bardzo miło) i zaczęło pytać mnie jak tego dokonałem.
Zatem w tym artykule chcę przedstawić opis od tworzenia świata w Minecraft do eksportu do FrameVR.
Oto na początku krótka lista moich uwag:
- powinieneś mieć zainstalowaną na komputerze grę Minecraft,
- powinieneś mieć podstawowe umiejętności posługiwania się programem Blender,
- powinieneś mieć zainstalowany node.js, który powinien być dodany do ścieżki systemowej,
- wszystko wykonuje na systemie Windows, ale bez problemu powinieneś wykonać na innym systemie.
Krok pierwszy: Minecraft
Naszą przygodę zaczniemy od Minecraft, ale zanim uruchomimy grę, to warto najpierw nakreślić sobie na kartce albo w głowie podglądowy plan naszego świata. Wówczas będziemy wiedzieli co mamy zrobić w Minecraft i zaoszczędzimy sobie czasu na niepotrzebne rozmyślanie co jeszcze dodać do scenerii. Nasz świat nie powinien być duży, wszystkie elementy rozmieszczone w miarę racjonalnie, tak, aby zmieścić się w limicie narzuconym przez FrameVR dla środowiska, który obecnie wynosi 15 MB.
Zanim uruchomisz Minecraft to polecam zainstalować następujące wtyczki:
- Fabric API – podstawa API dla większości innych wtyczek,
- Fabric Mod – wtyczka, która “podłącza” powyższe API dla innych wtyczek (przy Fabric API jest ona wymagana),
- Warp Mod Fabric – wtyczka, która pozwala na zarządzanie i poruszanie się po zapisanej liście miejsc,
- World Edit – znana wtyczka, która pozwala na łatwiejsze wykonanie niektórych operacji.
Powyższe wtyczki są zalecane, ale nie wymagane, jednakże warto sobie ułatwić pracę z Minecraft.
Jeżeli jesteśmy gotowi, mamy plan, wiemy co chcemy zrobić, to uruchamiamy Minecraft (z oryginalnej instancji w najnowszej wersji lub instancji Fabric), przechodzimy do trybu pojedynczego gracza, tworzymy nowy świat.
Podczas tworzenia nowego świata wybieramy następujące opcje (są one moimi zaleceniami):
- tryb gry: kreatywny – dostęp do wszystkich opcji,
- poziom trudności: pokojowy – wszystkie moby są dla nas miłe,
- zezwolaj na polecenia: włączony – włączamy możliwość wpisywania komend na czacie,
- w Zasady gry:
- Aktualizacje świata:
- Włącz cykl i dnia: wyłączony – wyłączamy automatyczną zmianę pory dnia,
- Cykl pogodowy: wyłączony – wyłączamy automatyczną zmianę pogody,
- Tempo losowych ticków: 1000 – trochę przyśpieszamy czas gry,
- Łupy – tutaj wszystko dajemy na wyłączony,
- Odradzanie – tutaj wszystko dajemy na wyłączony,
- Aktualizacje świata:
- Więcej opcji świata…
- Generuj struktury: włączony/wyłączony – od nas zależy, czy chcemy generować dodatkowe struktury, np. wioski,
- Bonusowa skrzynia: wyłączony – niepotrzebne nam to,
- Typ świata: od nas zależy rodzaj mapy, ja pracuję na superpłaskim.
Jeżeli wszystko ustawiliśmy w opcjach jak chcieliśmy, to tworzymy świat i do niego wchodzimy.
Od razu na czacie wpisujemy dwa polecenia, tj. niebo jest zawsze bezchmurne i zawsze mamy południe:
/weather clear
/time set noon
Tworząc nasz świat, pamiętamy o następujących wskazówkach:
- nie ma potrzeby umieszczania napisów na tabliczkach, ponieważ nie zostaną one wyeksportowane.
Ogólnie mój świat w Minecraft wygląda tak:
Uwagę przykuwa charakterystyczny prostokąt zrobiony z bloków rudy złota. W moim świecie wyznacza on granice do których ma być zbudowany zaplanowany pomysł.
Jeżeli nasza praca w Minecraft jest gotowa, to wychodzimy ze świata i gry.
Krok drugi: Mineways
Kolejnym krokiem jest wyeksportowanie naszego świata z Minecraft do pliku OBJ, który z łatwością zostanie odczytany przez program Blender. W tym celu do zrealizowania tego punktu docelowego potrzebujemy program Mineways, który ściągamy ze strony, rozpakowujemy archiwum ZIP i uruchamiamy. Pomimo, że opis programu w tym wątku jest dość obszerny to sam program jest prosty w obsłudze. Zalecam przed eksportem do zamknięcia innych pamięciożernych programów, ponieważ podczas eksportu możemy dostać komunikać, że program nie mógł zarezerwować odpowiednią ilość pamięci.
Nasze kroki w tym programie zaczynamy od wczytania naszego świata do programu.
Robimy to przez kliknęcie na ‘File’ w górnym pasku programu i wybrania ‘Open World’. Zobaczymy tutaj listę z nazwami światów z Minecraft, a więc wybieramy z niej nasz docelowy, w którym mamy zrobiony nasz świat.
Nasz świat zostanie wczytany do programu. Widzimy wszystko z góry.
Obsługa programu za pomocą klawiatury i myszki jest bardzo prosta:
- -/+ lub przesuwanie kółka myszy – powiększanie mapy,
- trzymanie lewego przycisku myszy – przesuwanie mapy,
- trzymanie prawego przycisku myszy – zaznaczanie obszaru, który ma być wyeksportowany.
Pojawi się komunikat, który poinformuje, że poziom głębokości został ustalony przez program i zostanie zmieniony. Klikamy na OK.
Na mapie widzimy wycinek naszego świata, który jest otoczony charakterystycznymi żółtymi liniami, które są tak naprawdę blokami z rudy złota.
Powiększamy mapę i za pomocą trzymania prawego przycisku myszy robimy odpowiedni prostokąt, który obejmie obszar, który chcemy wyeksportować. Ten obszar możemy poprawić, wystarczy, że powiększymy mapę, przesuniemy ją do wybranej granicy i za pomocą kursora myszy (powinien zostać zmieniony na ikonkę zmiany wymiaru pionowego) zmienić granice obszaru fioletowego.
Należy pamiętać, aby podczas zaznaczania obszaru nie zaznaczyć żółtych linii.
W górnej części okna programu znajdziemy dwa paski:
- Height – maksymalna wysokość to 255 i na taką jest ustawiony pasek. Do tej wysokości program będzie uwzględniał ustawione bloki.
- Depth – jest to minimalna wysokość od której będą uwzględnione bloki.
Teraz zdecydujemy jakie tekstury mają być nałożone na poszczególne bloki z Minecraft.
Aby to zmienić klikamy na ‘File’ => ‘Choose Terrain File’. Mamy tutaj listę z nazwami zasobów tektur, które są w folderze programu Mineways.
Domyślnie używaną paczką jest ‘terrainExt.png’, więc jeżeli chcemy skorzystać wyłącznie z tekstur bloków z Minecraft, to nic tutaj nie musimy zmieniać. Inaczej możemy wybrać inną paczkę z listy. Wygląd poszczególnych paczek tekstur znajdziemy na stronie Mineways (Documentation => Textures), gdzie są odnośniki do projektów do strony Sketchfab oraz inne podglądowe obrazki.
Ja używam paczki terrainExt_JG-RTX256, która zawiera inne tekstury o wyższej rozdzielczości i które są miłe dla oka, zwłaszcza, że FrameVR jest dedykowany dla osób, które będa się poruszać po scenerii w okularach VR.
Do folderu Mineways można dodać własne zasoby tekstur. Na stronie tego programu znajdziemy instrukcję jak przekonwertować do pojedynczego pliku, gdzie w zasadzie sprowadza się do wydania dwóch poleceń w wierszu poleceń.
Z menu ‘File’ wybieramy opcję ‘Export for Rendering’ i w nowym oknie dialogowym wybieramy lokalizację oraz nazwę pliku, gdzie będziemy chcieli zapisać nasz plik OBJ z zaznaczonym wycinkiem naszej pracy z Minecrafta. Jako typ pliku upewnijmy się, że jest wybrana opcja: ‘Wavefront OBJ, absolute (*.obj)’.
Po kliknięciu na ‘Zapisz’ pojawi się inne okno dialogowe z szerszymi opcjami do wyboru.
W oknie tym w zasadzie zaznaczamy dwie opcje:
- ‘Export tiles for textures to’
- ‘Export separate types’
- ‘Split by block type’
I na wszelki wypadek sprawdzamy czy dla ‘Make each block’ jest ustawiona wartość 1000.
Najlepiej porównać swoje okno z obrazkiem. Pomijamy wartości dla ‘World coordinates selection volume’, które będą różne przy zaznaczaniu obszaru w programie.
Opcja ‘Export separate types’ połączona z ‘Split by block type’ pozwala na zmniejszenie rozmiaru pliku wynikowego o ponad 50% (w przeciwieństwie do opcji ‘Export individuals blocks’), ponieważ program łączy te same bloki, które są do siebie “przyklejone” w jeden blok, usuwa ściany bloków, które nie są widoczne dla odbiorcy. A więc możemy spokojnie budować pełne struktury w Minecraft, ponieważ i tak zostaną uproszczone podczas eksportu do pliku.
Jeżeli wszystko się zgadza to klikamy na ‘OK’. Program wyeksportuje nasz świat do pliku OBJ.
Kiedy zakończy się cały proces, to wyświetli się komunikat, który pokazuje statystyki oraz zapytanie, czy ma się pojawiać za każdym razem przy eksporcie do pliku dopóki nie zamkniemy całkowicie programu. Klikamy na ‘Nie’ i zamykamy program.
W lokalizacji zapisu pliku OBJ powinny pojawić się dodatkowe 3 elementy: plik .obj, plik .mtl i folder textures.
Krok trzeci: Blender
W Blenderze obrobimy nasz model bardziej szczegółowo, dodamy inne obiekty i wyeksportujemy do pliku GLB, który jest obsługiwany przez FrameVR.
Zatem uruchamiamy program Blender, kasujemy obecną zawartość obszaru roboczego, importujemy nasz model OBJ do Blendera. W tym celu z menu wybieramy ‘File’ => ‘Import’ => ‘Wavefront (.obj)’, wybieramy lokalizację, gdzie znajduje się nasz model OBJ, klikamy na przycisk ‘Import OBJ’ (nie ma potrzeby zmiany ustawień po prawej stronie okna). Nasz model zostanie zaimportowany do Blendera.
Zmieniamy sposób wyświetlania tekstur (klawisz [Z], a potem [2]) – ‘Viewport shading’ na ‘Material Preview’. Dzięki temu widzimy model ze wszystkimi teksturami bez względu na oświetlenie.
Przesuwamy nasz obiekt tak, aby wyznaczyć punkt startowy dla awatarów na powierzchni bloku. W Blenderze jest to łatwe, gdyż punktem startowym będzie punkt ‘World Origin’ wskazywany przez dwa wyraźnie przecinające się linie: czerwoną i zieloną. Początkowo ten punkt także jest wskazywany przez kursora lokalizacji, przesuwania i transformacji. Ustawmy też odpowiednią wysokość – przy świecie ‘superpłaskim’ obniżamy obiekt.
Na karcie ‘Object Properties’ w części ‘Transform’, gdzie mamy podaną lokalizację obiektu zadbajmy, aby X, Y i Z zawierały wyłącznie całkowite liczby.
Jeżeli spojrzymy na nasz świat to zauważymy pewne niedoskonałości, np. wiata tramwajowa zbudowana ze szkła nie jest przezroczysta, woda jest zbyt niebieska, wokół kwiatów są czarne obwódki. Nieciekawie to wygląda.
Aby naprawić ten problem, to dla tych tekstur należy ustawić ‘Alpha’ jako obraz odnoszący się do ‘Base color’ oraz ‘Blend Mode’ ustawić na: ‘Alpha Clip’ albo ‘Alpha Blend’.
Jeżeli mamy dużo tekstur to jest to dość czasochłonne zadanie.
Dlatego przychodzę z pewną pomocą – do naprawy tego problemu wykorzystamy mój skrypt napisany w Pythonie. W tym celu przechodzimy do zakładki ‘Scripting’, tworzymy nowe okno. W oknie tym wklej mój skrypt i go uruchom.
import bpy
import re
from mathutils import *
from math import *
for material in bpy.data.materials:
material.shadow_method = 'NONE'
#When method=BLEND
arrayMaterials = [".*water_still.*", ".*water_flow.*", ".*glass.*", ".*sunflower_back.*", ".*sunflower_front.*", ".*trapdoor.*"]
for am in arrayMaterials:
if re.match(am, material.name):
links = material.node_tree.links
nodes = material.node_tree.nodes
material.blend_method = 'BLEND'
links.new(nodes['Principled BSDF'].inputs['Alpha'], nodes['Image Texture'].outputs['Alpha'])
#When method=CLIP
arrayMaterials = [".*leaves.*", ".*fern.*", ".*dandelion.*", ".*blue_orchid.*", ".*allium.*", ".*azure_bluet.*", ".*tulip.*", ".*oxeye_daisy.*", ".*cornflower.*", ".*lily_.*", ".*torch.*", ".*vine.*", ".*sunflower_top.*", ".*lilac.*", ".*peony.*", ".*campfire_fire.*", ".*campfire_log.*", ".*soul_campfire.*", ".*grass.*", ".*sunflower_bottom.*", ".*MW_bed.*", ".*bamboo_small_leaves.*", ".*bamboo_large_leaves.*", ".*ladder.*", ".*stonecutter.*", ".*bell.*", ".*cobweb.*", ".*_door_.*", ".*rail.*", ".*rose.*", ".*poppy.*", ".*scaffolding.*", "sugar_cane", "sea_pickle", ".*fungus.*", ".*coral.*", ".*kelp.*", ".*mushroom.*", "crimson_roots", "warped_roots", "nether_sprouts", "iron_bars", "chain", ".*lantern.*"]
for am in arrayMaterials:
if re.match(am, material.name):
links = material.node_tree.links
nodes = material.node_tree.nodes
material.blend_method = 'CLIP'
links.new(nodes['Principled BSDF'].inputs['Alpha'], nodes['Image Texture'].outputs['Alpha'])
#Show backface
arrayMaterials = [".*water_still.*", ".*water_flow.*", ".*sunflower_back.*", ".*sunflower_front.*"]
for am in arrayMaterials:
material.show_transparent_back = False
if re.match(am, material.name):
material.show_transparent_back = True
Kod ten naprawia wspominane błędy z przezroczystością obiektów, wyłącza cienie.
Jeżeli znowu przejdziesz do widoku ‘Layout’ to zobaczysz, że problemy znikną.
Zachęcam jednak Ciebie, abyś wykorzystał ‘Fly Navigation’ i przeleciał się po całym obiekcie, wyszukując takie dziwne błędy związane z niepoprawnym wyświetlaniem się tekstur i ręczne ich naprawie. Jeżeli coś takiego zobaczysz, to dodaj to do skryptu wyżej, ale starałem się, aby wszystkie znane tekstury bloków były w tym skrypcie podane.
Ten skrypt wykonaj tylko kiedy skasujesz stary obiekt i dodasz nowy obiekt wyeksportowany z programu Mineways.
Jeżeli mamy naprawione błędy związane z obiektem, to do naszego projektu w Blenderze możemy dodać inne obiekty, np. u mnie są nimi awatar Alex, awatar Steve, Golem, kot.
Jeżeli w FrameVR nasz awatar nie może wejść, np. po schodach to dodajmy przezroczysty ‘plane’ jako deskę do wchodzenia umieszczoną pod pewnym kątem (0-60°).
Jeżeli dodaliśmy obiekty, odpowiednio je ustawiliśmy na scenerii, itd., to musimy wykonać jeszcze jedną operację. Kiedy dodamy taką scenerię do FrameVR.io to zauważyć można w niektórych miejscach czarne plamy, które pojawiają się od spodu obiektów.
Aby rozwiązać ten problem, należy do każdego materiału dodać oryginalny obraz materiału jako ‘Emission’, oraz ustawić ‘Emission Strength’ na wartość 0.3.
Przy wielu materiałach i wielu obiektach jest to dość czasochłonne zadanie, dlatego ponownie przychodzę z pomocą własnego skryptu (Skrypt 2), który szybko zrealizuje ten cel.
Zatem ponownie przełączamy się na zakładkę: ‘Scripting’, kasujemy poprzednią zawartość, wklejamy poniższą zawartość i uruchamiamy:
import bpy
from mathutils import *
from math import *
for objects in bpy.data.objects:
for materialSlots in objects.material_slots:
if not materialSlots.name:
continue
material = bpy.data.materials[materialSlots.name]
material.shadow_method = 'NONE'
material.show_transparent_back = False
if hasattr(material.node_tree, 'nodes'):
nodes = material.node_tree.nodes
if "Image Texture" in nodes:
links = bpy.data.materials[materialSlots.name].node_tree.links
links.new(nodes['Principled BSDF'].inputs['Emission'], nodes['Image Texture'].outputs['Color'])
nodes['Principled BSDF'].inputs['Emission Strength'].default_value = 0.3
Ten kod możemy wykonywać za każdym razem, kiedy dodamy nowy obiekt do naszego projektu.
Jeżeli nasz projekt w Blenderze jest gotowy to warto zapisać go w formacie Blendera, aby mieć gotowy projekt do edycji. Nie zapomnijmy przed zapisaem o włączenie sobie opcji pakowania wszystkiego do jednego pliku (‘File’ => ‘External Data’ => ‘Automatically Pack Into .blend’).
Sam eksport do pliku GLB wygląda następująco:
- w menu ‘File’ wybieramy: ‘Export’, a następnie: gITF 2.0 (.glb/.gltf),
- W nowym oknie wskazujemy lokalizację, gdzie plik ma być zapisany,
- Upewniamy się, że po prawej stronie w ‘Format’ mamy wybraną opcję ‘gITF Binary (.glb),
- Klikamy na przycisk ‘Export gITF 2.0’,
- Nasz projekt zostanie zapisany do pojedynczego pliku GLB.
Krok czwarty: Kompresja pliku GLB
Maksymalny rozmiar pliku GLB jaki możemy załadować jako środowisko na FrameVR wynosi 15 MB. Jeżeli nasz plik ma większy rozmiar to albo zmniejszamy ilość elementów na mapie Minecraft i w Blenderze albo możemy spróbować zmniejszyć rozmiar oryginalnego GLB za pomocą algorytmu kompresji stworzonego przez Google. Z pomocą przychodzi nakładka na
algorytm Draco, która jest wykonywana jako skrypt Node.js o nazwie gltf-pipeline.
Otwórz wiersz poleceń w folderze, gdzie znajduje się plik GLB i wpisz polecenie, aby zainstalować dostępnym w całym systemie projekt gltf-pipeline:
npm install -g gltf-pipeline
Następnie wpisujemy i zatwierdzamy następujące polecenie:
for /L %i in (0,1,10) do gltf-pipeline -i minecraft.glb -o output_draco_%i.glb -d --draco.compressionLevel %i
gdzie:
- minecraft.glb – nazwa pliku wejściowego, który musi być taki sam jak tego wyeksportowanego za pomocą programu Blender.
- output_draco_%i.glb – nazwa pliku wyjściowego, %i służy tutaj za informację jaki poziom kompresji zastosowano.
Czekamy, aż polecenie się wykona.
Na przykładowym wyżej obrazku widzimy oryginalny wyeksportowany plik GLB z programu Blender oraz 11 innych dodatkowych plików, które są plikami wyjściowymi z zastosowaniem kompresji Draco. Na końcu każdej nazwy jest podany stopień kompresji w zakresie 0-10.
Widać już, że przy kompresji na poziomie 0, Draco zmniejsza oryginalny plik GLB prawie o 50%, potem do poziomu 2 uzyskujemy jeszcze mniejsze pliki lekko ponad 50%. Jednakże od poziomu 3 do 10 kompresja już nie ma takiego znaczenia.
Dlatego polecam nawet zmodyfikować powyższe polecenie, aby generowało GLB z kompresją Draco na poziomie 0-2 [zmiana z (0,1,10) na (0,1,2)].
Jeżeli nawet po kompresji z zastosowaniem algorytmu Draco nasz plik GLB jest za duży, to rozważmy zmiany w projekcie w Blenderze, które doprowadzą do zmniejszenia rozmiaru pliku GLB.
Załączniki
Artykuł jest wersją poprawioną pierwszego artykułu znajdującego się na zenodo.org