Tutorial – Hur man använder texturer i OpenEXR-format (.exr) för material i Unreal Engine 4.25

Denna tutorial har det primära syftet att introducera köpare av aifosDesigns materialtexturer till användningen av dessa i Unreal Engine, men det föreslagna arbetsflödet borde kunna appliceras till vilken uppsättning texturer i linjärt (gamma=1.0) OpenEXR-format (.exr) som helst. De exempelmaterial som används är Material – Gräsmatta 2 samt Material – Grus och sand.

Förkunskapströskeln för denna tröskel är avsiktligt ganska låg – detta för att säkerställa att kunder som är relativt nya till Unreal Engine ändå skall kunna använda sig av aifosDesigns materialtexturer – och det inledande avsnittet (som täcker nedladdning av texturfilerna, att skapa ett nytt Unreal Engine-projekt från en av standardmallarna, att avaktivera realtidsuppdatering i arbetsvyn, att skapa mappar, att importera texturerna, samt att ändra budgeten för "Texture Streaming Pool Size") kan upplevas som alltför grundläggande för användare som har viss erfarenhet av Unreal Engine. Om Du önskar hoppa direkt till att välja korrekt "Compression Settings" för de importerade texturerna med hjälp av "Bulk Edit via Property Matrix", innan ett mycket rudimentärt "Master Material" skapas, vänligen klicka här.

De skärmdumpar som inkluderas i denna tutorial är inhämtade från en macOS-version av Unreal Engine 4.25.3, medan själva instruktionerna är formulerade med Windows som "modersmål" – dock torde tutorialen vara tillgänglig för användare av alla UE4-kompatibla plattformar.

Inledningsvis, ladda ned de texturfiler som Du förvärvat. Efter att Du följt länken som förmedlas till Dig vid köp, klicka på knappen Ladda ner alla (eller motsvarande översättning) för att låta Google komprimera alla filer till ett ZIP-arkiv, eller plocka de russin ur kakan som lämpar sig för just Ditt arbetsflöde. Inom ramen för denna tutorial så laddar vi ned alla filer.

En given förutsättning är att Du redan har installerat Unreal Engine på Din dator, och för att stå på samma grund så skapar vi ett nytt projekt utifrån de standardmallar som inkluderas i spelmotorn. Om Du redan har ett projekt som Du vill lägga till texturfilerna i, vänligen gör så i stället. I vilket fall som helst, starta Unreal Engine.

Avseende mallprojektet, så skapar vi ett Game Project...

...och använder mallen First Person Template.

Avseende Project Settings så lämnar vi alla alternativ vid deras standardval och skapar projektet i den mapp där Du helst lagrar Unreal Engine 4-projekt, med ett angivet projektnamn tillräckligt generellt för att vara långsiktigt relevant, snarare än specifikt för stunden (Unreal Engine-projekt är ökänt svåra att senare ändra namn på utan att riskera referensfel,  vilket är skälet till att både Valorant och ARK: Survival Evolved forfarande behåller det interna projektnamnet "ShooterGame" [från den gratis Unreal Engine Learning-mall de båda har sitt ursprung i]).

När det nya projektet har laddat klart och öppnats så kan två små meddelanden ha dykt upp. Det ena informerar om att "New plugins are available" och det andra visar "Compiling Shaders" (vilket innebär att CPU:n beräknar alla implementerade materials s.k. shader-instruktioner). För stunden kan Du avfärda den plugin-relaterade popup:en (märk dock väl att det vanligtvis är rekommenderat att aktivera de plugin:er som Du förväntas använda i projektet så tidigt i arbetet som möjligt, eftersom aktiveringen av vissa plugin:er erfordrar att alla implementerade materials shader-instruktioner behöver kompileras på nytt, vilket är en tidsödande uppgift för CPU:n) och tillåt kompileringen att färdigställas. Medan Du väntar, så kan Du avaktivera realtidsuppdateringen av 3D-arbetsvyn (främst för att minska belastningen på grafikkortet, eftersom den avaktiverade realtidsuppdateringen gör så att arbetsvyn endast uppdateras när Du navigerar i den, medan den senast renderade bildrutan behålles som en stillbild när Du inte aktivt rör Dig i vyn).

Realtidsuppdateringen av arbetsvyn avaktiveras genom att klicka på den nedåtriktade pilen i övre vänstra hörnet av den, och sedan bocka ur Realtime (vid tidtagarurikonen), eller helt enkelt genom att trycka CTRL+R när arbetsvyn är aktiv.

Med mallen First Person Template så är startplatsen i spelmotorns Content Browser (motsvarande Filhanteraren eller Finder) mappen FirstPerson. För att manövrera uppåt i mapphierarkin, klicka på brödsmulan Content, som för alla praktiska ändamål är root-mappen för Ditt projekt. Om Du implementerar innehåll från Unreal Engine Marketplace till Ditt projekt, genom att lägga till dem från Epic Games Launcher-gränssnittet, så är det i Content-mappen de inordnas. Det är rekommenderat att så tidigt som möjligt i ett projekt bestämma en mappstruktur som långsiktigt lämpar sig, eftersom det är mycket enklare att kontinuerligt bibehålla en god mappstruktur som etablerats tidigt, än att försöka omorganisera en salig röra i efterhand.

Om Du skapar en mappstruktur på förhand som är mer förgrenad än vad Du för stunden har filer att befolka mapparna med, märk väl att Unreal Engine efter omstart inte registrerar mappar utan filinnehåll, så se då till att lägga till en enskild provisorisk "dummy"-fil i varje mapp som saknar innehåll (en fil i Content\Environment\Nature\Foliage\ ser till att överordnade mappar också sparas). Dummy-filen kan vara en tom Actor, eller (vilket ordnas på färre klick) ett tomt Particle System (RMB-klicka i mappen och välj det för att lägga till en sådan fil).

Eftersom vi inom ramen för denna tutorial endast skall lägga till ett mindre antal texturer och skapa ett par-tre material, så är det för detta projekt inte överdrivet oorganiserat att helt enkelt skapa en undermapp till mappen Content, namngiven efter källan till de texturer som strax skall importeras, och låta alla filer husera där. Skulle vi veta om att vi hade framför oss att importera massvis med filer till samma mapp, så skulle vi ha ett gott skäl att skapa en mer sofistikerad mappstruktur i förväg. Men för denna tutorial är en gemensam mapp fullt tillräcklig. I en hierarkisk fil-mapp-kedja så bidrar alla mappars namn till den totala sökvägslängden för filer, och i Unreal Engine så får sökvägen inte överstiga 260 tecken. Därför är det av dygd att vara koncis i valet av namn för mappar, och att inte skapa fler undermappar än vad förmågan till översikt kräver, åtminstone inte när distinktion mellan två undermappar inte behövs. Samtidigt är det viktigt att inte offra klarhet och ordning i jakten på en så kort sökväg som möjligt, om kaos och oordning kan undvikas med hjälp av ytterligare ett par undermappar. För att skapa en undermapp i den mapp vi för närvarande befinner oss i (Content) RMB-klicka (högerklicka) och välj New Folder.

Den nyskapade mappen tillåter direkt efter sin tillblivelse att vi ändrar dess namn. Vi namnger mappen efter källan till de texturfiler vi snart skall importera, och trycker ENTER för att bekräfta. Om det blir fel i namngivningen, tryck F2 för att göra markerad fil eller mapp aktiv för namngivning igen.

Vi byter förgrundsprogram från Unreal Engine till Filutforskaren (eller Finder), och navigerar till de nedladdade texturfilerna. Vi markerar de filer vi vill importera, och klick-drar in dem i den Unreal Engine Content Browser-mapp vi just skapat. Importeringen kan ta en stund, beroende på de importerade filernas filstorlek. Inom ramen för denna tutorial så importerar vi alla tillgängliga texturer i 4K-upplösning.

När texturfilerna importerats kan Du mötas av ett rött varningsmeddelande, som deklarerar: TEXTURE STREAMING POOL OVER XXX.XXX MiB BUDGET. Detta har sin huvudsakliga orsak i att texturerna vid importeringen automatiskt blivit tilldelade alldeles för högt uppskruvna Compression Settings, vilket (p.g.a. otillräcklig komprimering) blåser upp filstorlekarna och uppdämmer den budgeterade allokeringen av grafikkortets minne. Den effekt detta får är att material på ett givet betraktningsavstånd då de annars skulle renderas med deras texturer i full upplösning i stället visas i varianter med lägre upplösning (s.k. mip-maps, som automatiskt genereras för texturfiler med tvåpotensupplösning), så att de tar upp mindre resurser av grafikkortets minnesbudget.

Vi skall snart lösa självaste roten till problemet, genom att justera de importerade texturernas Compression Settings till en mer rimlig nivå. Ändock, om problemet skulle kvarstå eller dyka upp igen, så är det enkelt att öka den budgeterade allokering av grafikkortsminne som texturerna använder. Så länge Ditt grafikkort har tillräckligt med dedikerat minne så kan budgeten för Texture Streaming Pool lätt ökas (om Du inte vet hur mycket dedikerat grafikminne du har, Kör [WINDOWS+R] "dxdiag" och undersök värdet för "Display Memory (VRAM)" som visas under Ditt primära grafikkorts Display-flik – säkerställ att Du allokerar färre MB till Texture Streaming Pool, med god marginal, än detta värde, för att undvika att grafikkortsdrivrutinen kraschar.

Om Du klickar på Window\Developer Tools\Output Log så öppnas det som heter Output Log. Medan det är möjligt att ange konsolkommandon i ett direkt-input-gränssnitt via korrekt tangentbordsgenväg (vanligen § tilde-tangenten, men för svensk lokalisering så gäller ej detta som standard), så får man större översikt om man anger det i Output Log-vyn. Där är det enkelt att se effekten av de kommandon som anges, och det är lika enkelt att se vad valfri konsolvariabel har för värde angivet för stunden. Avseende s.k. Boolean-variabler (som bara har två möjliga värde: sant och falskt), så motsvarar 0 False och 1 True.

Syntaxen är väldigt enkel – ange helt enkelt namnet på den variabel Du vill ändra på (utan mellanslag, och med . punkt som hierarkiskt skiljetecken – input-fältet kommer att expandera för att visa matchande variabler utifrån de tecken Du skrivit in, så det fungerar som ett dynamiskt sökfält), lägg till ett mellanslag, och ange sedan det numeriska värde (heltal) som Du önskar att variabeln får som värde. För att se nuvarande värde på en variabel, ange endast namnet på den.

Ange r.Streaming.PoolSize för att kontrollera det nuvarande värdet för variabeln. Ange sedan r.Streaming.PoolSize XXXX, med XXXX ersatt med ett betydligt högre värde än vad som tidigare var aktuellt. Låt Dig vägledas av den budgetövervikt som felmeddelandet informerat Dig om för att ange en betydelsefull förändring (i detta fall så var budgeten överträdd med ungefär 361 MB, och genom att öka variabelns värde från 1000 till 2000 så löses problemet med marginal).

Nu när projektet är initierat och förberett, så är det dags att avgöra vilka Compression Settings som de importerade texturerna bör ha,  och sedan att konstruera ett mycket rudimentärt Master Material.

Eftersom texturerna är sparade i ett förlustfritt komprimerat OpenEXR-format, med inneboende linjär gamma (gamma=1.0) och (half-precision, d.v.s. 16-bitars) floating-point-värden (flyttal), så kommer Unreal Engine att vid import ange som standard för dessa texturer en orimligt (för de allra flesta användningsområden) okomprimerad Compression SettingHDR. Om detta ej korrigeras så kommer texturerna att ta upp oerhört stor plats – både i en kompilerad build av projektet och i grafikkortsminnet vid rendering.

Vi har i denna tutorial importerat alla tillgängliga textures i 4K-upplösning, men vi rekommenderar att Du importerar endast de texturer som är relevanta för just Ditt arbetsflöde (t.ex. texturfilen för Ambient Occlusion-Roughness-Metallic är överflödig när separata texturfiler för Ambient Occlusion, Roughness ochMetallic används, och vice versa). Hur som helst, markera alla importerade texturer, RMB-klicka och välj Asset Actions\Bulk Edit via Property Matrix.

Som synes ovan, så importeras alla OpenEXR-texturer med HDR som standard-Compression setting. Det är alldeles för okomprimerat för de flesta praktiska scenarier. Medan HDR är praktiskt taget utan komprimering, så är den synliga försämringen i visuell kvalitet och trogenhet gentemot originalfilen i jämförelse med en mer aggressivt komprimerad inställning främst synlig när man jämför de två sida vid sida – för de allra flesta naturliga situationer då man påträffar materialet i spelmotorn, så är skillnaden försumbar. Däremot är skillnaden i komprimerad filstorlek oerhörd, vilket redovisas nedan, där alla Texture Compression Settings är listade, tillsammans med det ungefärliga värde som motsvarar deras relativa filstorlek (enligt vår erfarenhet), för en och samma textur komprimerad på olika vis, och med Default-inställningens vikt som referensvärdet 1:

Default: 1
Masks: 1
Alpha: 1
Normalmap: 2
Grayscale: 2
Displacementmap: 2
DistanceFieldFont: 2
BC7: 8
VectorDisplacementmap: 8
UserInterface2D: 16
HDRCompressed: 16
HDR: 16

Utan att försjunka i djupet av vad de olika komprimeringsmetoderna faktiskt gör (om Du önskar en djupare förståelse i detta, vänligen läs denna artikel – den är en källa till våra ställningstaganden), så kan man klart se att det finns mycket att vinna i att välja rätt Compression Setting – man skulle få plats med 16 texturer (av en given upplösning) med inställningen Default/Masks/Alpha på samma mängd grafikkortsminne som en enda textur med inställningen HDR! Det finns ett antal saker att komma ihåg när det kommer till de olika inställningarna, såsom att Alpha är betydligt mindre komprimerad än Masks, och behåller ändå samma filstorlek, men erfordrar att filen är sparad som en enkanalig gråskaletextur. På samma sätt fast i motsatt förhållande tillåter Masks flera olika texturer att packas in i en och samma texturfils olika kanaler, med samma filstorlek som Alpha, men den är jämförelsevis mer komprimerad (vilket sällan är uppenbart, om man inte jämför texturerna sida vid sida). Default tillåter att linjärt sparade texturfiler inläses som sRGB, för att rendera dem i perceptuell färgrymd.

Med de relevanta texturfilerna markerade (CTRL+klicka för att markera flera samtidigt), byt Compression\Compression Setting till Masks för kanalpackade texturer (t.ex. Ambient Occlusion-Roughness-Metallic), till Alpha för separata gråskaletexturer (t.ex. Ambient Occlusion, Roughness, Metallic, Displacement [Height], Opacity [Alpha]), till Default för trekanaliga färgtexturer (Base Colour [Albedo], Emissive, Subsurface Scattering), och till Normalmap för Normal-texturer. Varje byte av inställningar tar en stund, då texturerna omkomprimeras utifrån de nya inställningarna. Om Du föredrar att inte vänta många små stunder, utan i stället en lång stund, så kan Du initialt bocka för alternativet Defer Compression med alla texturer markerade. Detta skjuter upp omkomprimeringen tills texturerna sparas, i stället för varje gång en inställning ändras. Kom ihåg att bocka för sRGB för alla trekanaliga färgtexturer som importerats (i denna tutorial så avses endast Base Colour-texturen). Man skulle kunna invända mot att Displacement-texturen komprimeras med inställningen Alpha i stället för Displacementmap, men vi föredrar personligen en textur komprimerad till halva relativa storleken. Om Displacement-resultatet skulle vara inadekvat (såsom att s.k. stepping eller banding inträffar, när antalet bitar inte räcker till för att återspegla mjuka övergångar i texturen) så kan komprimeringsinställningen för just den texturen justeras i efterhand. När alla texturer har en adekvat Compression Setting tilldelad sig, så kan alla texturer sparas med CTRL+SHIFT+S, vilket sparar alla filer. Sedan kan fönstret för Property Matrix stängas ned.

Nu är tiden kommen att skapa ett Master Material – om än ett mycket rudimentärt sådant. RMB-klicka i en lämplig mapp, och skapa ett nytt Materials & Textures\Material. Namnge detta material som Du anser lämpligt (avseende ett Master Material, så är det rekommenderat att inkludera "Master" i namnet, för att göra det enklare att söka efter när en Material Instance skall få en ny förälder (parent) tilldelad sig.

Öppna materialet Du just skapat. Håll nere T och klicka någonstans i materialets blueprint för att lägga till en Texture Sample-nod. Markera den, och tilldela den en relevant texturfil genom att dra densamma från Content Browser:n till den gult upplysta destinationen för Texture i Texture Sample-nodens Details-vy. Alternativt, markera texturen i Content Browser:n och klicka på den vänsterorienterade pilen vid samma Texture-destination – även detta tilldelar vald texture till Texture Sample-noden. Upprepa proceduren tills alla relevanta texturer för just Ditt arbetsflöde är tilldelade var sin Texture Sample-nod. Det är inte ovanligt att bortse från Ambient Occlusion-texturen om ens projekt skall belysas dynamiskt (eftersom AO-texturer i Unreal Engine endast multipliceras med bakade lightmaps och SkyLights med stationary mobility – om Din SkyLight är moveable inkluderas ändå inte AO-texturen i resultatet; därutöver så avger directional lights ett ljus som inte är applicerbart för AO, eftersom det antingen belyser en triangel eller inte, vilket ändå skulle göra multipliceringen med AO-texturen betydelselös).

När en textur tilldelas till en Texture Sample, så kommer den automatiskt att avgöra vilken Sampler Type som är relevant för angiven textur – utifrån texturens Texture Compression Setting. En textur med kompressionsinställningen Default och sRGB förbockat kommer att inläsas som Color, etc.

Om Du vill använda Displacement (d.v.s. förskjutning av vertexer i vertexens normalriktning [rätvinkligt mot tangenten]), så är det ett förhandskrav att aktivera Tessellation för materialet (för att tillåta att meshens polygoner blir lokalt iterativt uppdelade i mindre polygoner, så att den tessellerade meshens vertexer förskjuts mer troget Displacement-texturen än en icke-tessellerad mesh). Detta görs i Details-vyn för själva materialet, så avmarkera eventuellt markerad nod genom att klicka ut i tomma intet, och skrolla ned till Tessellation. För den allra enklaste implementeringen av tessellering, ändra värdet för D3D11Tessellation till Flat Tessellation, bocka för alternativet Crack Free Displacement (vilket begränsar förskjutna sömmar mellan åtskilda UV-öar), och behåll Adaptive Tessellation förbockat. Detta avsäger användaren kontroll över materialets Tessellation Multiplier, men tillåter spelmotorn att dynamiskt hantera densamma automatiskt. Om Du inte använder en Displacement-textur i Ditt arbetsflöde så finns ingen anledning att aktivera Tessellation.

Avseende denna tutorials rudimentära Master Material, så använder vi den kanalpackade texturfilen för Ambient Occlusion-Roughness-Metallic i stället för separata texturfiler. Detta reducerar mängden grafikkortsminne som materialets texturer upptar, i jämförelse med tre olika s.k. texture lookups som separata Texture Sample-noder ger, men det är bra att komma ihåg att om både AO- och Metallic-texturerna konsekvent bortses ifrån (t.ex. vid användning av dynamiska ljuskällor samt endast material som är helt metalliska eller helt icke-ledande), så uteblir också fördelen med ett färre antal texture lookups, och då är det bättre att endast använda den separata Roughness-texturen i stället (eftersom den är mer troget komprimerad som Alpha, samtidigt som den upptar samma komprimerade filstorlek).

Parentes: om AO och Metallic bortses ifrån, så kan materialets AO-input vara utan nodanslutning, eftersom dess standardvärde är 1 (och multiplikation med 1 saknar aritmetisk effekt), och Metallic-inputen kan antingen vara oansluten likaså – vilket betyder att standardvärdet 0 begränsar möjligheterna att använda detta Master Material till endast dielektriska (icke-metalliska/icke-ledande) material – eller ansluten till en Static Switch Parameter (RMB-klicka i materialets blueprint och börja skriva in dess namn, så kommer sökresultaten snart att smalna av till dess att rätt nod syns i listan), namngiven som "bMetallic" eller liknande ("b" står för "Boolean", och är ett prefix som generellt används för parametrar som bara kan vara sanna eller falska [på eller av]). Med var sin Constant-nod (håll nere 1 och klicka för att skapa en Constant-nod) ansluten till dess input, med värdet 1.0 kopplat till True och värdet 0.0 kopplat till False, så kan alla Material Instances med detta Master Material som förälder (parent) bocka för parametern "bMetallic" för att rendera materialet som metalliskt, och med densamma urbockad för att rendera det som dielektriskt.

Detta mycket enkla Master Material (faktum är att det är så enkelt som det möjligen kan vara, med de givna texturerna involverade) har fyra stycken Texture Samples, och varje Texture Sample har en relevant texturfil tilldelad sig (Base Colour [Albedo], Ambient Occlusion-Roughness-Metallic, Normal and Displacement [Height]). För att se till att Material Instances med detta Master Material som förälder både ärver alla dess egenskaper, men också tillåter att att de angivna texturfilerna kan ändras (vilket är litet av poängen med separata Material Instances som delar ett och samma Master Material som förälder – på så vis behöver bara ett enda materials shader-instruktioner kompileras, medan materialets barn [Material Instances som har Master Material:et som förälder] ärver samma logik men kan gestalta många olika material, genom att byta värde på dess exponerade parametrar), behöver vi konvertera Texture Sample-noderna till parametrar. Detta är tacksamt nog väldigt enkelt: RMB-klicka på valfri Texture Sample, och välj Convert to Parameter. Efter konverteringen, ange ett namn till den nya parametern (t.ex. "T_BaseColour", "BaseColour", eller kort och gott "BC"). Upprepa sedan proceduren för resten av Texture Sample-noderna. Det är av största vikt att komma ihåg att att parametrar med distinka funktioner måste ha unika namn – två parameternoder som delar samma namn kommer att hanteras som instantierade kopior av varandra (vilket reflekteras i att ändringar av en nod överföres till den andra), vilket bör undvikas om så ej är medvetet avsiktligt.

När alla Texture Sample-noder har konverterats till adekvat namngivna parametrar, så kan vi ansluta deras respektive output till lämplig input i självaste materialnoden. För Base Colour och Normal är det mycket enkelt: drag helt enkelt RGB-outputen från vardera till Base Color- respektive Normal-inputen. För den kanalpackade texturen, drag dess Röda output till Ambient Occlusion, dess Gröna till Roughness, och dess Blå till Metallic.

För Displacement-texturen så är det litet mer komplicerat. Inledningsvis, RMB-klicka, ange "VertexNormalWS" och lägg till en sådan nod. Noden hämtar in normalriktingen (d.v.s. den riktning som är positivt rätvinklig till tangenten) hos alla vertexer (tillhörande den mesh som blivit tilldelad materialet) i world space, vilket är nödvändigt för att säkerställa att Displacement-förskjutningen sker rätvinkligt till meshens yta, i stället för att förflytta hela meshen i en generell riktning. Genom att hålla nere M och klicka, lägg till en Multiply-nod (som helt enkelt gör sagd aritmetiska beräkning), och anslut VertexNormalWS-noden till en av Multiply-nodens inputs, och den Gröna outputen från Displacement-texturen till den andra. Detta skulle varit tillräckligt för ett skrattretande rudimentärt Master Material, men effekten av Displacement vore knappt skönjbar, och utan möjlighet att förändra. Därför lägger vi till en Scalar-parameter för att kontrollera Displacement-effektens styrka, och multiplicerar den med den normalorienterade Displacement-effekten tack vare en till Multiply-nod (för att kopiera en nod, markera den och tryck CTRL+W). För att lägga till en Scalar-parameter, antingen RMB-klicka och sök efter den, S+klicka, eller skapa en Constant-nod (genom att hålla nere 1 och klicka) och RMB-klicka på den för att välja Convert to Parameter. Oavsett vilket tillvägagångssätt för att skapa parametern, namnge den adekvat (t.ex. "Displacement_Strength"). Drag produkten av den sista Multiply-noden till materialnodens World Displacement-input.

Som tidigare hävdat så är detta Master Material väldigt rudimentärt och inte mycket att hänga i julgranen. Men vi hoppas att det demonstrerar tillräckligt hur man adekvat implementerar de importerade texturerna i ett Master Material. För att materialet skall bli mer användbart, så skulle behövas åtminstone kontroll över en parameter som avgör graden av rumslig repetition för texturerna. För att uppnå det behöver Du addera en TextureCoordinates-nod (U+klicka), skapa en ny Scalar-parameter (S+klicka) vid namn "Tiling", och multiplicera de två i en ny Multiply-nod (M+klicka), och anslut sedan den multplicerade produkten till UV-inputen hos alla Texture parameter-noder. Det skulle inte skada att även implementera en parameter som kontrollerar intensiteten hos effekten av Normal-texturen, men det är bortom denna tutorials ramar – som söker fokuserar på den adekvata implementeringen av texturerna själva, och inte materialet de implementeras i. Dessutom är konsten att skapa ett Master Material inte en konst att bemästra i en enskild tutorial.

Ytterligare en parentes: varför specifikt använda den gröna kanalen hos en gråskaletextur? Svaret ligger djupt i det dunkla vatten som utgör kompressionsmetodernas logik, och som refererats till ovan: med BC1-kompression, som används för kompressionsinställningarna Default och Masks, så är de röda och blå kanalerna komprimerade ned till 5 bitar, medan den gröna kanalen är komprimerad till 6 bitar, och således är den gröna kanalen mer trogen originalfilen än de övriga vid komprimering. Dock använder kompressionsinställningen Alpha inte BC1-kompression utan BC4, som behåller 8 bitar för alla tre kanaler (men erfordrar att alla kanaler innehåller samma information, d.v.s. en gråskaletextur), så svaret är att det faktiskt inte spelar någon roll huruvida den röda, den gröna eller den blå kanalen används för en gråskaletextur (så länge den är komprimerad som Alpha), men att valet av den gröna kanalen är ett konsekvent ställningstagande som påminner om att det är den som är mest trogna kanalen för de allra mest komprimerade texturerna (vilket är skälet till att Roughness-texturen [som är viktigast av de tre] är lagrad i den gröna kanalen i den kanalpackade texturfilen, som komprimeras som Masks).

Med Master Material:et slutfört, i dess rudimentära form, spara det genom att klicka på Save (eller tryck CTRL+S). När ett material sparas så kommer det automatiskt att kompileras (vilket också kan göras utan att spara materialet genom att klicka på Apply). Med materialet sparat, RMB-klicka på det i Content Browser:n och välj Create Material Instance. Som tidigare sagts, så är en Material Instance hierarkiskt underordnad (som child) det material som är dess parent, och det ärver alla förälderns materialegenskaper och shader-logik, samtidigt som de parametrar som är exponerade hos föräldern kan ändras fritt hos Material Instance:n utan att förändra föräldern, vilket skapar stora möjligheter för individuell utformning genom att helt enkelt ändra värdena på de nedärvda parametrarna. Eftersom föräldramaterialets shader-instruktioner redan har kompilerats, och Material Instance-barnet endast kan ändra värderna på de nedärvda parametrar vars logik redan kompilerats, så kan värdena hos Material Instance:rna ändras fram och tillbaka helt fritt utan att några shader-instruktioner behöver omkompileras – i det praktiska arbetet med Unreal Engine är detta den stora fördelen med Material Instances, eftersom så mycket kompileringstid kan besparas om de används på rätt sätt. Tiden som går åt till kompilering av shaders, vilket utförs på CPU:n och på relativt utdaterade sådana som vår tar mycket tid, kan annars bli ett stort, demoraliserande svart tidshål. Därutöver så uppmuntrar bruket av Material Instances ett mer strömlinjeformat arbetssätt där inte varje material behöver uppfinnas på nytt för varje nytt syfte, utan ett Master Material definieras för att täcka in de parametrar som behöver nedärvas för en viss typ av material, och andra Master Materials för andra, distinkta typer av material. Det är inte ändamålsenligt (som i optimeringsvänligt) att försöka skapa ett Master Material som står redo för varje möjligt material, utan ett för varje grupp material som är tillräckligt lika för att dela samma logik, men där parametrarna tillåter den variation som behövs. Hur som helst, låt oss åter fokusera på den Material Instance vi skapat.

Ge Material Instance:n ett lämpligt namn (t.ex. "MI_NameOfMaterial"). Öppna Material Instance:n genom att dubbelklicka på den.

Med Material Instance:n öppen, bocka för alla de parametrar Du önskar ändra värdet hos. Med ett så rudimentärt Master Material är det inte mycket att ändra förutom att byta ut texturerna, men eftersom de standardtexturer som nedärvts från Master Material:et (som alla hierarkiska barn får som standardvärden att skriva över eller ej) är de som vi avser också för Material Instance:n, så återstår bara att experimentera med värdet för Displacement_Strength, för att se effekten av Displacement-texturen på den tessellerade förhandsgranskningsmeshen.

Om Du har flera Master Materials (t.ex. en med Displacement, en utan, en för bakade texturer, m.fl.), så är det härifrån, under General, som Du kan tilldela en ny Parent (hierarkisk förälder) till aktuell Material Instance. Klicka helt enkelt på namnlisten med den nuvarande föräldern, och ange som söksträng (en del av) namnet på det Master Material som Du avser som ny förälder till Material Instance:n.

För alla ursprungliga syften så skulle tutorialen gott ha kunnat rundas av här, då all nödvändig information om hur man implementerar linjära OpenEXR-texturfiler i Unreal Engine-material redan förmedlats. Tutorialen var nog av störst relevans någonstans kring Bulk Edit via Property Matrix, men har sedan dess rullat nedför en kramsnöbacke (med en sådan tendens etablerad långt dessförinnan), så vi kan likväl fortsätta en bit till.

Med Place Actors-vyn öppen, och Basic-kategorin vald, klick-drag en Sphere ut i nivån.

Med den utplacerade sfärmeshen markerad, tryck END för att låta sfären falla till marken. Detta kommando fungerar för alla mesh-objekt som har korrekt collision konfigurerad (kommandot förflyttar helt enkelt den markerade meshen nedåt i den globala Z-axeln tills meshens collision träffar den collision som någon underliggande mesh besitter). Om sfären inte rör sig, så kan det vara så att den redan är blockerad av en annan mesh (i denna mall så kan det vara så att sfären kolliderat med någon av kuberna, till exempel) – förflytta sfären en bit med XYZ-gizmon, och försök igen. Glöm ej även att om meshen saknar collision, så kommer kommandot inte att fungera alls.

Det finns flera sätt att tilldela en mesh ett material. Det enklaste – så länge mappen där materialet befinner sig i är öppen i Content Browser:n och meshen i fråga är synlig i arbetsvyn – är att helt enkelt klicka och dra Material Instance:n till meshen, och släppa mustangenten. Med Material Instance:n tilldelad till meshen, så kommer alla eventuella förändringar av Material Instance:n (d.v.s. förändringar i de värden som de nedärvda parametrarna gjort anpassningsbara) att omedelbart återges i renderingen av meshen.

För att skapa ytterligare en Material Instance, med samma förälder som den förra, antingen RMB-klicka på Master Material:et och välj Create Material Instance igen, som Du redan gjort, eller RMB-klicka på Material Instance:n och välj Duplicate (alternativelt, tryck CTRL+W med den markerad för att göra samma sak). Ange ett lämpligt namn till denna nya Material Instance, och importera en ny uppsättning texturer, på samma sätt som Du gjort tidigare.

Med den nya Material Instance:n öppen, bocka för de parametrar vars värder Du önskar ändra, och klick-drag-och-släpp de nya texturerna till de relevanta texturparametrarna. Justera Displacement_Strength om så behövs.

Markera den sedan tidigare utplacerade sfären, och håll nere ALT medan Du drar i någon av gizmons axlar för att skapa en dubblett av meshen. Klick-drag-och-släpp den nya Material Instance:n på den duplicerade meshen, och voilà: nu har Du skapat två olika Material Instances med samma Master Material som hierarkisk förälder, och använt dem för att ange material till två olika meshes.

Det är med god anledning som man skulle kunna invända att materialen inte är lika estetiskt tilltalande i renderingen ovan som i förhandsgranskningsrenderingarna som åtföljer produkterna (för exempel, se nedan). Detta bör dock varken förbrylla eller överraska – renderingen av ett material är självfallet intrinsikalt beroende av materialets egenskaper, d.v.s. värdena hos materialtexturerna, men kamerainställningar (exponering, bländaröppning, etc.) och ljussättning är lika viktigt för att fånga en scen på ett estetiskt tilltalande sätt. Detta förhållande görs tydligt av vyn ovan, där Unreal Engines egen tumnagelgenerator presenterar en mycket mer behagfull representation av materialet (se ikonen i Content Browser:n) än vad som visas med standardljussättning i arbetsvyn, fastän de båda hör till samma First Person-mallprojekt.

För materialtexturernas förhandsgranskningsrenderingar så har ett flertal arbetsdagar investerats i insatsen att rendera materialen så estetiskt tilltalande som möjligt. Ett directional light ljussätter scenen primärt, och ackompanjeras av varmare sken från sidan och bakifrån, och även ett svagare underifrån för att matta ut skuggorna längst ned. En HDRI (nämligen HDRI – Stor gräsmatta (sommar, middag)) bidrar till scenens Global Illumination. Den sfäriska meshen har alternativet Cast shadow urbockat, för att skapa illusionen av att sfären flyter i luften. En cinematic camera har använts med väldigt stor bländaröppning, vilket ger det mycket smala fokusområdet, och exponeringen har finjusterats utifrån intensiteten i alla ljuskällor. Unreal Engines Movie Render Queue har använts för att producera de mest högkvalitativa renderingar som vår dator mäktar med.

Även om förhandsgranskningsrenderingarnas sfärmesh har tilldelats Material Instances som hierarkiskt underställts en mer komplex Master Material-förälder än exemplet i denna tutorial, så är värdena som texturerna angivit oförändrade (t.ex. har Base Colour-värdena ej ljusats upp, Roughness-värdena är oförändrade, etc.) och de presenteras som de är. Skillnaden i presentationskvalitet beror inte på skillnader i texturvärden eller materialparametrar, utan på en annan grad av ansträngning med finkalibrering av en cinematic camera, val av ljussättning och renderingsinställningar. Det vore vår glädje att dela med oss av godbitar rörande den kunskapen likaså, men det måste i sådana fall tillfogas en annan tutorial, för denna behöver rundas av.

För transparens skull, så är ovanstående en översikt av det Master Material som vi använt för förhandsgranskningsrenderingarna av materialtexturerna. Även om det ser komplext ut (och också är det), så fungerar det med standardvärden och all valfri tilläggsfunktionalitet avstängd helt jämförbart med denna tutorials rudimentära Master Material. Även om den, tillsammans med mycket mer, har en parameter som möjliggör justering av färgmättnaden i Base Colour-texturen, så ändrar den i standardutförandet den inte alls, exempelvis. Den renderade förnimmelsen av bägge Master Materials är helt beroende av deras identiska materialtexturer.

Att skapa ett Master Material är en konst, och att balansera anpassningsbarhet med prestanda är inte enkelt. Vi har ännu inte färdigställt den uppsättning Master Materials som vi påbörjade arbetet med för två och ett halvt år sedan (!), och som vi aktivt arbetat med under många veckor, men vi hoppas kunna publicera dem på Unreal Engine Marketplace, tillsammans med annat aifosDesign-innehåll, inom en överskådlig framtid.

Om något problem uppstår, lämna gärna en kommentar nedan, så skall vi göra vårt bästa att försöka lösa eventuella problem.

Recommended tutorials to continue with:
Placeholder Tutorial

Om Du vill återvända till översikten över våra tutorials, vänligen klicka här.

Märkt

Lämna ett svar

E-postadressen publiceras inte. Obligatoriska fält är märkta *

Denna webbplats använder Akismet för att minska skräppost. Lär dig hur din kommentardata bearbetas.