Is it possible to use normal maps on Android with unity?

Normal Maps på Android med Unity: Guide

08/06/2022

Rating: 4.36 (3368 votes)
Indholdsfortegnelse

Normal Maps på Android med Unity: En Omfattende Vejledning

Som erfaren iOS-udvikler, der begiver sig ud i Android-verdenen gennem Unity, kan overgangen være fyldt med nye udfordringer. En af de mest almindelige og frustrerende er at få normal maps til at fungere korrekt på Android-enheder. Mens de kan se fejlfri ud i Unity-simulatoren på din computer, kan de pludselig se helt forkerte eller slet ikke blive gengivet, når de bygges til en fysisk Android-enhed som en Samsung Galaxy S8+. Dette er et velkendt problem i Unity-fællesskabet, og årsagen ligger ofte i en kombination af teksturimportindstillinger, shader-kompatibilitet og enhedsspecifikke begrænsninger.

Hvad er Normal Maps, og hvorfor er de Vigtige?

Før vi dykker ned i de tekniske detaljer, er det vigtigt at forstå, hvad normal maps er, og hvorfor de er så værdifulde i 3D-grafik. Et normal map er en tekstur, der lagrer retningsinformation for overfladens detaljer, i stedet for selve detaljerne. Ved at bruge et normal map kan udviklere simulere komplekse overfladestrukturer – som f.eks. ujævnheder, ridser eller mønstre – uden at skulle tilføje yderligere polygoner til 3D-modellen. Dette er essentielt for at opnå realistiske og visuelt tiltalende grafikker, især på mobile enheder, hvor ydeevne og ressourceforbrug er kritiske faktorer.

Almindelige Problemer med Normal Maps på Android

Den primære årsag til, at normal maps fejler på Android-enheder, når de fungerer i simulatoren, skyldes ofte, hvordan Android-enheder behandler teksturer, især i forhold til komprimering og farveformater. Mange mobile GPU'er har specifikke krav eller begrænsninger, der kan påvirke, hvordan normal maps fortolkes.

Teksturimportindstillinger: Nøglen til Succes

Den mest citerede løsning på dette problem er at justere teksturimportindstillingerne i Unity. Som brugeren nævner, er det ofte foreslået at tvinge teksturen til "Truecolor" (RGBA 32 Bit). Dette sikrer, at teksturen importeres med den mest præcise farveinformation, hvilket kan være afgørende for korrekt fortolkning af normal maps.

Her er de vigtigste indstillinger, du bør overveje:

1. Format:Under teksturimportindstillingerne i Unity Inspector skal du sørge for, at formatet er sat til noget, der bevarer alle farvekanaler og præcision. "RGBA 32 bit" (eller "Truecolor") er ofte den bedste indstilling. Undgå komprimerede formater som ETC eller ASTC, medmindre du har testet dem grundigt og sikret kompatibilitet.

2. Alpha is Transparency:For normal maps, der bruger den blå kanal til at gemme en del af normalinformationen, skal du deaktivere "Alpha is Transparency". Normal maps bruger typisk RGB-kanalerne til at kode retningsinformation, og alfa-kanalen kan enten være ubrugt eller indeholde yderligere data, men den skal ikke fortolkes som gennemsigtighed.

3. Generate Mip Maps:Mens Mip Maps kan forbedre ydeevnen og reducere aliasing ved objekter langt fra kameraet, kan de nogle gange forårsage problemer med normal maps på mobile enheder. Det er værd at prøve at deaktivere "Generate Mip Maps" for dine normal map-teksturer for at se, om det løser problemet.

4. Compression:Som nævnt bør du generelt undgå komprimering for normal maps på Android, medmindre du er sikker på, at det understøttes korrekt. "Don't Override" er ofte et godt udgangspunkt, men hvis det ikke virker, kan det være nødvendigt at eksperimentere med specifikke komprimeringsformater, der er kendt for at være kompatible med din målplatform.

Shader-kode og `UnpackNormal()`

Brugerens shader-kode indeholder funktionen `UnpackNormal(n)`. Denne funktion er standard i Unitys standard shaders til at konvertere normal maps fra den typiske tangent-space til den korrekt orienterede normal-vektor, der bruges i rendering. Selvom det er standard, kan der være subtile forskelle i, hvordan denne funktion implementeres eller fortolkes på tværs af forskellige platforme og hardware.

Shader-koden ser således ud:

void surf (Input IN, inout SurfaceOutputStandard o) { half4 d = tex2D (_MainTex, IN.uv_MainTex); half4 n = tex2D (_BumpMap, IN.uv_BumpMap); o.Albedo = d.rgb; o.Normal = UnpackNormal(n); o.Metallic = 0.0; o.Smoothness = 0.0; }

Hvis `UnpackNormal()` giver problemer, kan du prøve en alternativ implementering, der er mere eksplicit. Mange mobile shaders bruger denne version:

// Alternativ UnpackNormal funktion half3 UnpackNormalAlternative(half4 tex) { #if defined(UNITY_UV_STARTS_AT_TOP) && !defined(UNITY_COMPILER_GLSL) tex.y = 1.0 - tex.y; #endif tex.x = tex.x * 2.0 - 1.0; tex.y = tex.y * 2.0 - 1.0; tex.z = tex.z * 2.0 - 1.0; return UnpackNormal(tex); } void surf (Input IN, inout SurfaceOutputStandard o) { half4 d = tex2D (_MainTex, IN.uv_MainTex); half4 n = tex2D (_BumpMap, IN.uv_BumpMap); o.Albedo = d.rgb; o.Normal = UnpackNormalAlternative(n); o.Metallic = 0.0; o.Smoothness = 0.0; }

Denne alternative funktion håndterer potentielle forskelle i UV-koordinatretningen og sikrer, at normal dataen er korrekt skaleres og forskudt.

Programmatisk Oprettelse af Normal Maps

Brugerens forsøg på at generere normal maps programmatisk fra en grayscale heightmap er et godt skridt til at isolere problemet. Koden:

public Texture2D NormalMap(Texture2D source, float strength = 10.0f) { Texture2D normalTexture; float xLeft; float xRight; float yUp; float yDown; float yDelta; float xDelta; normalTexture = new Texture2D (source.width, source.height, TextureFormat.RGBA32, false, true); for (int y=0; y

Selvom denne kode fungerer i simulatoren, er der et par ting at bemærke:

  • Ydeevne: `GetPixel` og `SetPixel` er meget langsomme operationer. At køre dette på enheder, især med store teksturer, kan føre til alvorlige ydeevneproblemer eller endda frysninger. Det er generelt bedre at udføre denne type operation på computeren ved hjælp af Unitys tekstur-pipeline eller et eksternt værktøj.
  • Kant-effekter: Koden forsøger at tilgå pixels uden for teksturens grænser (f.eks. `x - 1` når `x` er 0). Unitys `GetPixel` vil returnere (0,0,0,0) for pixels uden for grænserne, men dette kan føre til uventede resultater. Det er bedst at håndtere kanttilfældene eksplicit eller bruge en tekstur-samplingmetode, der håndterer dette korrekt (f.eks. ved at indstille teksturens wrap mode).
  • Farveformat: Selvom du bruger `TextureFormat.RGBA32`, kan der stadig være problemer med den interne repræsentation på Android, især hvis teksturen ikke er markeret som "normal map" i importindstillingerne.

Fejlfindingstrin og Anbefalinger

Baseret på de almindelige problemer og brugerens erfaringer, her er en struktureret tilgang til fejlfinding:

  1. Verificer Teksturimportindstillinger:
    • Sæt Format til "RGBA 32 bit" eller "Default (RGBA 32 bit)".
    • Sørg for, at sRGB (Color Texture) er aktiveret for almindelige farveteksturer, men deaktiveret for normal maps. Unity har ofte en specifik indstilling til "Normal Map" der automatisk håndterer dette, men hvis du importerer som en almindelig tekstur, skal du være opmærksom.
    • Deaktiver Generate Mip Maps.
    • Undgå Texture Compression, især i starten. Vælg "Don't Override" eller et format som "RGBA 32 bit" direkte.
    • Tjek om Alpha is Transparency er deaktiveret.
  2. Test Shader-koden:
    • Prøv den alternative `UnpackNormalAlternative` funktion for at udelukke kompatibilitetsproblemer med standardfunktionen.
    • Hvis du bruger en brugerdefineret shader, skal du sikre dig, at den er kompatibel med den rendering pipeline, du bruger (Built-in, URP, HDRP).
  3. Undersøg Teksturdata:
    • Brug et billedredigeringsprogram (som Photoshop eller GIMP) til at åbne din normal map-tekstur og inspicere dens kanaler. Normal maps bruger typisk X-aksen til rød, Y-aksen til grøn, og Z-aksen til blå. Den forventede farve er ofte en lilla-blå nuance.
    • Tjek farveformatet og dybden af teksturen.
  4. Enhedsspecifikke Overvejelser:
    • Nogle ældre eller lavere-end Android-enheder kan have begrænset understøttelse af bestemte teksturformater eller shader-funktioner.
    • Overvej at teste på flere forskellige Android-enheder for at se, om problemet er specifikt for din S8+ eller mere generelt.
  5. Brug Unitys Standard Normal Map Shader: Hvis du ikke har brug for en fuldstændig brugerdefineret shader, kan du prøve at bruge Unitys indbyggede "Standard" eller "Standard (Specular setup)" shader og blot tildele din normal map til "Normal Map"-slotten. Dette kan hjælpe med at identificere, om problemet ligger i din brugerdefinerede shader-opsætning.

Sammenligning af Teksturindstillinger

Her er en tabel, der opsummerer de vigtigste teksturimportindstillinger for normal maps på Android:

IndstillingAnbefalet for Normal Maps (Android)Bemærkninger
FormatRGBA 32 bit / TruecolorBevarer præcision, undgå komprimering i starten.
sRGB (Color Texture)DeaktiveretNormal maps koder normalvektorer, ikke farver.
Generate Mip MapsDeaktiveretKan forårsage problemer med præcision på mobile enheder.
Alpha is TransparencyDeaktiveretAlfa-kanalen bruges ikke til gennemsigtighed i normal maps.
Texture CompressionDon't Override / NoneKomprimering kan introducere fejl i normal data.

Ofte Stillede Spørgsmål (FAQ)

Q: Hvorfor ser mine normal maps lilla ud på Android?
A: Dette skyldes sandsynligvis, at normal map-teksturen enten ikke er korrekt konfigureret i Unitys importindstillinger (f.eks. sRGB er aktiveret), eller at shaderen fortolker dataen forkert.

Q: Er der en performance-omkostning ved at bruge RGBA 32 bit teksturer?
A: Ja, RGBA 32 bit teksturer bruger mere hukommelse og båndbredde end komprimerede formater. På mobile enheder er det vigtigt at afbalancere visuel kvalitet med ydeevne. Overvej at bruge mere effektive komprimeringsformater som ASTC, hvis det er muligt og testet.

Q: Kan jeg bruge normal maps med URP (Universal Render Pipeline) eller HDRP (High Definition Render Pipeline) på Android?
A: Ja, URP og HDRP understøtter normal maps på Android. Dog kan der være specifikke shader-opsætninger eller indstillinger, der skal tilpasses for disse pipelines. URP er generelt designet med mobil i tankerne og tilbyder god ydeevne.

Q: Hvad hvis ingen af disse løsninger virker?
A: Hvis du har prøvet alle de foreslåede trin og stadig oplever problemer, kan det være en god idé at simplificere dit projekt yderligere. Prøv at importere en standard normal map-tekstur fra Unity Asset Store og brug den med en standard shader for at se, om den fungerer. Dette kan hjælpe med at isolere, om problemet ligger i dine specifikke aktiver eller i din generelle projektopsætning.

Konklusion

At få normal maps til at fungere korrekt på Android med Unity kræver ofte omhyggelig opmærksomhed på detaljer, især med hensyn til teksturimportindstillinger og shader-kompatibilitet. Ved at følge ovenstående trin, verificere dine indstillinger og eksperimentere med alternative shader-implementeringer, kan du forbedre dine chancer for succes markant. Husk, at mobiludvikling ofte indebærer en balancegang mellem visuel kvalitet og ydeevne, så test grundigt på din målplatform for at opnå de bedste resultater.

Hvis du vil læse andre artikler, der ligner Normal Maps på Android med Unity: Guide, kan du besøge kategorien Mobil.

Go up