Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 2 - XNA a HLSL - Textury

Posledně, XNA a HLSL - První shader, jsme si vytvořili jednoduchý shader.

Zatím jsme vykreslovali konstantní barvu, proto si přidáme texturu. Pojďme na to.

Texturujeme

Nejprve budeme ale potřebovat texturu získat. Každý model, když ho nahrajeme, tak obsahuje svou instanci třídy BasicEffectu a právě v ní se textura nalézá. To máme první problém, už nám jen zbývá do shaderu přidat příslušný kód. Jak jsme si řekli ve třetím díle, textury mají svůj vlastní souřadnicový systém. Těmto souřadnicím se říká také UV. Přidáme si je do struktury, která do shaderu vstupuje:

struct VertexShaderInput{
  float4 Position : POSITION0;
  float2 UV:TEXCOORD0;
};

Jméno složky je jen a jenom na nás, ale název UV se mi zdá poměrně dobrý. Je to vektor pro dvě čísla a jeho význam je souřadnice pro textury. To máme druhou sémantiku, o které je dobré vědět. To samé přidáme i do výstupní struktury z vertex shaderu:

struct VertexShaderOutput{
  float4 Position : POSITION0;
  float2 UV:TEXCOORD0;
};

Budeme potřebovat souřadnice přeposlat i do pixel shaderu, kde budeme texturování provádět. Proto do vertex shaderu doplníme:

output.UV=input.UV;

Máme vše připravené pro samotné texturování. Můžeme si vyzkoušet, zda-li se nám souřadnice do pixel shaderu dostávají. Postačí, když si je pouze převedeme na výstup:

return float4(input.UV.x,input.UV.y,0,1);

Pokud uvidíte něco jako na tomto obrázku:

Výstupní souřadnice textury v XNA - Tvorba shaderů v HLSL

Tak je vše v pořádku a můžeme pokračovat s přidáním textury. Prvně přidáme texturu do efektu:

Texture Texture;

První Texture je jméno datového typu a druhé je až identifikátor, ten může být libovolný. Textury se nanášejí přes takzvané samplery. Proto si taky jeden musíme vytvořit:

sampler TextureSampler = sampler_state {
  texture = <Texture>;
};

Sampler se jmenuje TextureSampler a má přiřazenou texturu, kterou bude nanášet. Můžeme zde nastavit také další parametry, o těch se zmíníme později. Už zbývá jen a pouze texturu pomocí sampleru nanést. To provedeme v pixel shaderu. Máme na to funkci tex2D. Do té předáváme dva parametry, jeden je náš sampler a druhý jsou souřadnice.

float4 tex=tex2D(TextureSampler,input.UV);

Vrací se vektor o 4 složkách 3 barvy a jeden alfa kanál. A právě tuto barvu pouze vrátíme jako výsledek pixel shaderu.

return tex;

Shader je hotový. Teď už jen zbývá jeho obsluha. V metodě LoadContent si nastavíme texturu:

foreach (ModelMesh mesh in model.Meshes){
  foreach (ModelMeshPart part in mesh.MeshParts){
    BasicEffect ef = part.Effect as BasicEffect;
    effect.Parameters["Texture"].SetValue(ef.Texture);
    part.Effect = effect;
  }
}

A je tak hotovo vše, co bylo potřeba. Pokud nyní program spustíme uvidíte otexturovaný koberec:

Otexturovaný model v C# XNA - Tvorba shaderů v HLSL

Ještě by se hodilo povolovat/zakazovat používání textury. Proto přidáme do shaderu nový parametr:

bool TextureEnabled=false;

Můžeme přímo ve shaderu nastavovat implicitní hodnotu, pro jistotu zde dáme false. Pak už jen do pixel shaderu přidáme podmínku i ty můžeme ve shaderech používat:

if(TextureEnabled)return tex2D(TextureSampler,input.UV);
else return float4(1, 0, 0, 1);

Pak ještě v metodě LoadContent nastavíme tento nový parametr na true:

effect.Parameters["TextureEnabled"].SetValue(true);

A opět uvidíme otexturovaný koberec. Shader máme pro tuto chvíli hotový.

AddressMode

Už výše jsme se zmínil i o dalších parametrech, které můžeme samplerům nastavovat. Prvním z nich je adresní mód. Ten nám říká, jak se má sampler zachovat, pokud nejsou souřadnice v rozmezí 0 – 1. Grafická karta zná tři možnosti, jak se s tím vypořádat:

  • wrap: nanese do oněch částí texturu jakoby byla v rozmezí 0 – 1, lze tak udělat opekování
  • clamp: na část která je v rozsahu nanese texturu normálně ale na zbývající místa roztáhne její okraje
  • mirror: provede zrcadlení, viz obrázek
Adresní módy textur shaderu v XNA - Tvorba shaderů v HLSL

Na obrázku vidíte všechny tři možné adresní módy. Lze je dokonce pro každou osu nastavit zvlášť. Defaultně je nastaven režim wrap. Nastavování můžeme dělat buď přímo v sampleru nebo také prostřednictvím XNA. Pojďme se podívat na první možnost tu děláme uvnitř sampleru:

sampler TextureSampler = sampler_state {
  texture = <Texture>;
  AddressU=clamp;
  AddressV=clamp;
};

A uvnitř XNA pak máme ve třídě GraphicsDevice kolekci SamplerStates, kde můžeme jednotlivé stavy nastavovat. Kupříkladu:

GraphicsDevice.SamplerStates[0] = SamplerState.LinearWrap;

a pro režim mirror se musíme uchýlit k menší lsti:

GraphicsDevice.SamplerStates[0] = new SamplerState(){
  AddressU=TextureAddressMode.Mirror,
  AddressV=TextureAddressMode.Mirror
};

Nastavení předávané z XNA přepisuje nastavení zapsané ve shaderu.

Filtrování

Samplery mají také ještě jeden důležitý parametr a tím je filtrování. K filtrování dochází tehdy, pokud se na požadovaných souřadnicích textury netrefíme na střed pixelu ale někam jinam. Pak grafická karta použije nastavený filtr. Máme k dispozici tyto filtry:

  • point – hodnota je zaokrouhlena na nejbližší pixel
  • linear – lineární interpolace
  • anisotropic – jiná interpolace

Na následujícím obrázku je patrný rozdíl mezi filtrováním na body a zbytkem:

Filtrování v XNA - Tvorba shaderů v HLSL

Máme k dispozici tři možnosti nastavení filtrů. Jeden filtr pro situace, když je textura zmenšována, jeden když je textura naopak zvětšována. Třetí filtr můžeme nastavit pro takzvané mipmapování. Mip mapping je technika, při které nepoužíváme jen jednu velikost textury, ale také její zmenšené kopie a podle texturované plochy si grafická karta vybere příslušnou velikost textury, která se nejlépe hodí. Můžeme XNA přikázat, aby je generovalo a to v nastavení textury, jak je patrné na následujícím obrázku:

Mip mapy v XNA - Tvorba shaderů v HLSL

Pojďme se podívat jak filtry nastavit skrze HLSL:

sampler TextureSampler = sampler_state {
    texture = <Texture>;
    MinFilter=Point;
    MagFilter=Point;
    MipFilter=Point;
};

V XNA můžeme použít opět předpřipravených nastavení samplerů nebo si nadefinovat vlastní, obdobně jako jsme to udělali výše. Filtry mají některá omezení. Nejsou vhodné pro úplně všechny formáty textur. Ale pro naše skromné účely na ně zatím nenarazíme.

To by bylo pro dnešní díl vše. Ve zdrojových kódech naleznete také oba projekty se čtverci.

Příště, XNA a HLSL - Světla podruhé, si přidáme další světla, konkrétně ambientní a směrové.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 136x (1.77 MB)
Aplikace je včetně zdrojových kódů v jazyce C# .NET

 

Předchozí článek
XNA a HLSL - První shader
Všechny články v sekci
Tvorba shaderů v HLSL
Přeskočit článek
(nedoporučujeme)
XNA a HLSL - Světla podruhé
Článek pro vás napsal vodacek
Avatar
Uživatelské hodnocení:
5 hlasů
Vodáček dělá že umí C#, naplno se již pět let angažuje v projektu ŽvB. Nyní studuje na FEI Upa informatiku, ikdyž si připadá spíš na ekonomice. Není mu také cizí PHP a SQL. Naopak cizí mu je Java a Python.
Aktivity