CGT_2 - Nejjednodušší programy

Tato kapitola uvádí programování v Cg skrze sérii jednoduchých vertexových a fragmentových programů. Kapitola má následujíc čtyři části:

2.1 Jednoduchý vertexový program

Zelená je barva spojená s nezkušeností a růstem, takže Cg program renderující zelený 2D trojúhelník se hodí pro začátek s Cg.

Následující příklad ukazuje kompletní zdrojový kód pro váš první program napsaný v Cg. Zdrojové kódy příkladů v této knize používají modré patkové písmo k označení klíčových slov jazyka Cg a patkové písmo pro věstavěné funkce a věstavěné datové typy. Toto označení vám pomůže odlišit v programech slova která mají speciální význam pro Cg překladač. Navíc, komentáře v kódu jsou označeny zeleným písmem aby se odlišovaly od zbytku kódu. Komentáře v Cg jsou stejné jako v C++: můžete použít /* a */ vymezovače, nebo můžete vytvořit komentáře pomocí dvojice lomítek //.

Pojmenovávací konvence příkladů

Následující vertexový program je docela jednoduchý. Předpona C2E1v použitá v různých částech programu znamená "Kapitola 2, Příklad 1 vertexový program" (Chapter 2, Example 1 vertex program). Používáme toto značení abychom ulehčili hledání příkladů mezi kapitolami a v doprovodném software ke knize. Tato konvence ulehčuje sledování příkladů v knize, ale není to požadavek jazyka Cg samotného a vskutku to není konvence kterou byste museli následovat ve vašich vlastních příkladech.

	struct C2E1v_Output {
		float4 position : POSITION;
		float4 color : COLOR;
	};

	C2E1v_Output C2EV1v_green(float2 position : POSITION) {
		C2E1v_Output out;
		out.position = float4(position, 0, 1);
		out.color = float4(0, 1, 0, 1); // zelená v RGBA
		return out;
	}

Pokud se kamarádíte s C nebo C++, pak si pravděpodobně umíte vydedukovat co program dělá. Program přiřazuje příchozí 2D souřadnice pozice vertexu do 2D souřadnic vertexu na výstupu. Navíc přiřazuje RGBA (červená, zelená, modrá, alfa) konstantu představující zelenou do barvy vertexu na výstupu.

2.1.1 Výstupní struktury

Program C2E1v_green začíná následující deklarací:

	struct C2E1v_Output {
		float4 position : POSITION;
		float4 color : COLOR;
	};

Tato deklarace je pro speciální strukturu známou jako výstupní struktura. Tato struktura obsahuje balík hodnot který představuje výstup (nebo výsledek) daného Cg programu.

Program napsaný v obecném jazyku pro CPU jako C může vykonávat různé úlohy, jako je čtení a zapisování hodnot, zpracovávat uživatelský vstup, tisknout text, zobrazovat grafiku a komunikovat přes síť. Na druhou stranu, Cg programy jsou omezeny na výstup balíku hodnot. Výstupní struktura Cg programu zapouzdřuje potenciální rozsah hodnot daného Cg programu.

Cg deklaruje struktury stejnou syntaxí jaká je použita v C nebo C++. Deklarace struktury začná klíčovým slovem struct, následovaným jménem struktury. Uzavřená ve složených závorkách, definice struktury obsahuje seznam členů struktury, každý se svým jménem a typem.

výstupní struktura se liší od běžné C nebo C++ struktury protože obsahuje i sémantiku každého členu. K tomuto konceptu sémantiky se vrátíme brzy v části 2.1.6.

2.1.2 Identifikátory

Když deklarujete strukturu, poskytujete po klíčovém slově struct identifikátor neboli jméno; to se dělá pro každou strukturu kterou deklarujete. Identiikátor má v Cg ten samý tvar jako v C nebo C++. Identifikátory se skládají ze sekvence jednoho nebo více velkýých nebo malých znaků abecedy, číslic 0 až 9 a znaku podtržítko (_). Platnými identifikátory jsou například Matrix_B a pi2. Identfkiátor nesmí začínat číslicí a nesmí to být klíčové slovo.

Nejenže identifikátory pojmenovávají struktury, ale také pojmenovávají deklarace typů, členy struktur, proměnné, funkce a sémantiky (o těch se zakrátko dozvíte více). Ostatní identifikátory v prvním příkladu jsou tyto:

Cg udržuje prostory jmen založené na kontextu identifikátoru stejným způsobem jako je lze najít v C nebo C++. Například identifikátor position označuje parametr funkce a zároveň člen struktury C2E1v_Output.

Klíčová slova v Cg

Mnoho klíčových slov v Cg jsou také klíčovými slovy v C nebo C++, ale Cg používá některá nová která v C nebo C++ nenajdeme. V průběhu této knihy bude vysvětlena většina klíčových slov. Příloha D obsahuje kompletní seznam klíčových slov v Cg. Stejně jako v C nebo C++, ani v Cg nelze použít klíčová slova jako identifikátory.

2.1.3 Členy struktury

Mezi složenými závorkami deklarace struktury najdete jeden nebo více členů struktury. Každý člen je datový typ s přiděleným jménem.

Ve struktuře C2E1v_Output jsou dva členy: position a color. Oba členy jsou čtyřsložkové vektory s plovoucí desetinnou čárkou, jak naznačuje jejich datový typ float4.

2.1.4 Vektory

Základní datové typy v C nebo C++ jsou skalární veličiny, jako třeba int nebo float. V C nebo C++ neexistuje žádný nativní "vektorový" datový typ, takže vektory jsou typicky reprezentovány jako pole skalárních hodnot. Protože ale vektory jsou nezbytné pro zpracovávání vertexů a fragmentů a protože GPU mají vestavěnou podporu vektorových datových typů, Cg má vektorové datové typy.

Členy (position a color) jsou deklarovány s datovým typem float4. Jméno není v Cg rezervovaným slovem; je to standardní definice typu ve standradní knihovně Cg. Narozdíl od C nebo C++, není potřeba používat direktivy preprocesoru (#include) k vložení deklarací standardní knihovny Cg. Cg místo toho automaticky vkládá deklarace potřebné pro většinu Cg programů.

Měli byste spoléhat na věstavěné vektorové typy, poskytované standardní knihovnou Cg, jako je float2, float3, float4 a ostatní typy abyste zajistili co nejefektivnějšího zpracování vektorů na vaší programovatelné GPU.


Pro pokročilé

Vektorové typy v Cg, jako třeba float3 a float4, nejsou 100 procentně shodné s poli jakéhokoli počtu datového typu float. Například float x[4] není ta samá deklarace jako float4 x. Tyto vektorové typy jsou ve skutečnosti sbalená pole. Sbalená pole, často nazývaná vektory, říkají překladači aby alokoval prvky sbalených polí tak aby vektorové operace s těmito poli byly co nejefektivnější. Pokud jsou dva vstupní vektory uloženy sbalené, programovatelný grafický hardware obvykle provede třísložkové nebo čtyřsložkové matematické operace - jako je násobení, součet a skalární součiny - v jedné instrukci.

Sbalená pole nejsou v běžných programovacích jazycích jako C nebo C++ dostupná. Poslední sady CPU instrukcí , jako SSE2, SSE a MMX od Intelu, 3D Now! od AMD a AltiVec od Motoroly, mají navíc instrukce pro vektory, ale sbalená pole nejsou nativně podporována žádným obecným programovacím jazykem. Avšak Cg poskytuje tuto podporu sbalených polí vektorové veličiny jsou součástí zpracovávání vertexů a fragmentů. Sbalená pole pomáhají překladači Cg využít výhod rychlých vektorových operací na programovatelných GPU.

Stejně jako s ostatními aspekty Cg, i to jak využijete sbalených polí záleží na zvoleném Cg profilu. Například, sbalená pole jsou obvykle omezena na čtyři nebo méně složek. Obvykle jsou extrémně efektivní pro vektorové operace jako je přiřazení, negace, absoutní hodnota, násobení, součet, lineární interpolace, maximum a minimum. Operace skalárního součinu a vektorového sučinu se sbalenými operandy jsou také velmi efektivní.

Na druhou stranu, přistupování ke sbaleným polím s nekonstantním indexem pole je buď neefektivní nebo to vůbec není podporováno. Záleží na profilu. Například:

	int index = 3;
	float scalar;
	scalar = data[3]; // Efektivní
	scalar = data[index]; // Neefektivní nebo nepodporované

Zlatým pravidlem je deklarovat všechny vektory které se skládají ze dvou, tří nrbo čtyř komponentů (jako třeba barvy, pozice, sady souřadnic textur a směry) jako sbalená pole použitím věstavěných datových typů v Cg.


2.1.5 Matice

Cg také, navíc k vektrovým typům, nativně podporuje maticové typy. Zde jsou nějaké příklady deklarací matic v Cg:

	float4x4 matrix1; // Matice 4x4 s 16 prvky
	half3x2 matrix2; // Matice 3x2 s 6 prvky
	fixed2x4 matrix3; // Matice 2x4 s 8 prvky

Můžete deklarovat a inicializovat matici stejným způsobem jako byste inicializovali pole v C nebo C++:

	float2x3 matrix4 = {1.0, 2.0,
			3.0, 4.0,
			5.0, 6.0};

Stejně jako vektory, i matice jsou v Cg sbalené datové typy , takže operace používající standardní maticové typy se na GPU vykonávají velmi efektivně.

2.1.6 Sémantiky

Členy position a color struktury C2E1v_Output následuje dvojtečka a zvláštní slovo známé jako sémantika. Sémanitky jsou, v jistém smyslu, lepidlo které spojuje Cg program se zbytkem grafického potrubí. Sémantiky POSITION a COLOR označují hardwarový zdroj do kterého Cg program navrací odpovídající členy výstupní struktury. Říkají jak se proměnné které je předchazejí napojují na zbytek grafického potrubí.

Sémantika POSITION (v tomto případě se nalézá ve výstupní struktuře používané Cg vertexovým programem) je ořezový bod pro transformovaný vertex. Následující části sestavování primitiv, ořezávaní a rasterizace grafického potrubí použijí výstupní vektor asociovaný s touto sémantikou jako přetransformovaný, ořezový bod vertexu. Do ořezového prostoru budete uvedeni později v této kapitole a hlouběji v kapitole 4. Prozatím můžete uvažovat o 2D pozici bodu v ořezovém prostoru jednoduše jako o pozici v rámci okna.

Sémantika COLOR je v tomto kontextu něco co se v Direct3D nazývá "difúzní barva vertexu" a v OpenGL "primární barva vertexu". Interpolace barev trojúhelníku nebo jiného geometrického primitiva, zálvisí během rasterizace na barvách jednotlivých vertexů.


Nepleťte si jméno členu s jeho sémantikou. V prvním příkladu je člen position asociován se sémantikou POSITION. Avšak to co zapřičiňuje aby rasterizer zacházel s členem position jako s pozicí, je ne jméno členu samotné, ale právě použití sémantiky POSITION. V následujících výstupních strukturách jsou schválně vybrána jména členů jako density a position, aby bylo vidět že Cg používá k navazování sémantiku a ne zavádějící jména:

	struct misleadingButLegal {
		float4 density : POSITION; // Funguje, ale je to zavádějící
		float4 position : COLOR; // Také zavádějící
	};

Budoucí příklady představí i jiné výstupní sémantiky. Ne všechny sémantiky jsou dostupné ve všech profilech, ale v našich příkladech budeme používat sémantiky které jsou široce podporované existujícími profily.

Můžete také vytvářet vlastní sémantiky, ale v této knize se omezíme pouze na příklady se standardní sadou sémantik. Více informací o používání vlastních sémantik lze najít v dokumentu Cg Toolkit User's Manual: A Developer's Guide to Prgrammable Graphics.

2.1.7 Funkce

Deklarování funkcí v Cg funguje stejně jako v C a C++. Určíte naávratový typ funkce (nebo void pokud se nic nenavrací), její jméno a čárkou oddělený seznam parametrů v závorkách. Po deklaraci jsou popsány v těle funkce výpočty prováděné danou funkcí.

Funkce mohou být buď vstupními funkcemi nebo interními funkcemi.

Vstupní funkce

Vstupní funkce definuje vertexový nebo fragmentový program; je analogickí funkci main v C nebo C++. Vykonávání programu začíná právě ve vstupní funkci. V prvním příkladu je definována funkce nazvaná C2E1v_green následovně:

	C2E1v_Output C2E1v_green(float2 position : POSITION)

Tato funkce navrací výstupní strukturu C2E1v_Output popsanou dříve. To znamená že funkce navrací obojí, pozici a barvu. Tyto výstupy mají sémantiku definovánu strukturou.

Funkce také přijímá vstupní parametr nazvaný position. Tento parametr je typu float2, čili jedná se o dvousložkový vektor s plovoucí desetinnou čárkou. Pokud jméno vstupního parametru následuje dvojtečka a jméno sématntiky, znamená to že je tato sémantika s tímto parametrem asociovaná. Když je použita POSITION jako vstupní sémantika, znamená to pro vertexový procesor, aby každý vertex zpracovávaný touto funkcí inicializoval tímto parametrem pozice specifikovaným aplikací.

Vnitřní funkce

Vnitřní funkce jsou pomocné funkce volané vstupními funkcemi nebo jinými vnitřními funkcemi. Můžete použít vnitřní funkce poskytované standardní knihovnou Cg i definovat svoje vlastní interní funkce.

Vnitřní funkce ignorují jakékoliv sémantiky aplikované na jejich vstupní nebo výstupní parametry a výstupní hodnoty; sémantiku používají pouze vstupní funkce.

2.1.8 Vstupní a výstupní sémantiky jsou odlišné

Obrázek níže ukazuje tok vstupních a výstupních sémantik pro vertexový program C2E1v_green.

Vstupní a výstupní sémantiky nejsou to stejné, i když některé mají stejná jména. Například pr vstupní parametr vertexového programu, POSITION se odkazuje na pozici specifikou pozici v aplikací nastavenou aplikací samotnou když posílá vertex do GPU. Avšak prvek výstupní struktury se sémantikou POSITION představuje pozici která prošla ořezávaním a která se posílá do rasterizeru.

Obě sémantiky jsou pojmenovány POSITION, a vskutku, každá je pozicí. Avšak každá sémantika pozice se odkazuje na pozici v různých bodech uvnitř grafického potrubí. Váš vertexový Cg program transformuje vertex poskytnutý aplikací na vertex vhodný ke sestavení primitiv, ořezávání a rasterizaci. V programu C2E1v_green je tato transformace triviální (pozice vertexu je předávána uvntř grafického potrubí beze změn, ale později si ukážeme, například v kapitolách 4 a 5, užitečnější a zajímavější způsoby transformací vertexů.

Tok vstupů a výstupů sémantik v C2E1v_green

Tělo funkce

Podstata funkce C2E1v_green je obsažena v jejím těle:

	C2E1vOutput OUT;
	OUT.position = float4(position, 0, 1);
	OUT.color = float4(0, 1, 0, 1); // RGBA zelená
	return OUT;

Protože návratový typ funkce je C2E1v_Output, musíte deklarovat proměnnou tohoto typu k předání hodnoty kterou funkce vrací. Často nazýváme strukturu navrácenou vstupní funkcí výstupní struktura. Tělo funkce nastavuje oba proměnné prvky této struktury a vrací strukturu (Všimněte si že návratový typ vstupní funkce nemusí mít stejnou předponu jako vstupní funkce, i když my jsme si zvolili ty pro naše příklady identické).

Tečka mezi OUT a position, stejně jako mezi OUT a color je členský operátor a slouží k přístupu k členům struktury. Je to stejný způsob jakým v C a C++ přistupujete k členům struktury. Přemýšlejte o struktuře jako o kontajneru pro více hodnot. Členský operátor vás nechá získat hodnoty obsažené ve struktuře:

	OUT.position = float4(position, 0, 1);
	OUT.color = float4(0, 1, 0, 1); // RGBA zelená

Zaprvé, program přiřazuje vstupní parametr position do OUT.position. Avšak člen výstupní struktury OUT.position je typu float4 (kapitola 4 vysvětluje proč). Výraz float4(position, 0, 1) převádí dvousložkový vektor pozice na čtyřsložkový vektor tak, že nastaví třetí a čtvrtou složku na 0 a 1.

Zadruhé, program přiřazuje RGBA hodonotu pro zelenou barvu do OUT.color. Numerickou hodnotu zelené barvy poskytneme vytvořením čtyřsložkového vektoru. Datový typ členu color je float4 protože barva je specifikována jako RGBA. "A" v RGBA znamená "alfa" a obvykle udává jakou měrou bude daná barva transparentní nebo ne. Alfa hodnota 1 znamená že barva je plně neprůhledná.

Pokud použijete float4 nebo jiný podobný vektorový typ jako funkci (například float4(0, 1, 0, 1)), nazýváme takovou funkci konstruktor. Tento konstruktor vytváří hodnotu typu z hodnot uvedených v závorkách. C++ má konstruktory, ale C ne. Cg poskytuje konstruktory pro vektory a matice.

Syntaxe float4(0, 1, 0, 1) vytváří vektor <0, 1, 0, 1> který je přiřazen členu color typu float4 v OUT. Vektor <0, 1, 0, 1> značí zelenou barvu protože jeho složkami jsou červená, zelená, modrá, alfa (RGBA) se specifikovanou zelenou (a alfa) složkou, ale bez specifikace červené nebo modré složky.

	return OUT;

na konci vací příkaz return výstupní strukturu kterou jste inicializovali. Balík hodnot obsažených v OUT se předá do další části grafického potrubí dle sémantik přiřazených každému z členů.

2.2 Přeložení vašeho příkladu

Běhové prostředí Cg se používá k načítání a přeložení Cg programů. když překládáte program, musíte specifikovat v programu navíc dvě věci:

Jméno vstupní funkce v našem příkladu je C2E1v_green.

C2E1v_green je vertexový program, takže musíte zvolit překlad s vertexovým profilem. Výběr vertexového profilu záleží na programovacím rozhraní které vaše aplikace používá pro vykreslování 3D (OpenGL nebo Direct3D), stejně jako na schopnostech vaší GPU.

Profily vertexových programů

Existuje mnoho vhodných vertexových profilů k přeložení našeho příkladu jak je patrno z tabulky níže. Budoucí GPU budou bezpochyby podporovat schopnější profily.

Váš první příklad je velmi jednoduchý, takže není problém přeložit ho s jakýmkoli z profilů z tabulkz níže, nebo s jakýmkoli budoucím vertexovým profilem pro tento účel. Jak se budete prokousávat knihou, zaznamenáte že některé složitejší Cg programy budou vyžadovat pokročilejší vertexové nebo fragmentové profily. Pokud je potřeba pokročilejší profil, poukážeme na to. Většina příkladů v této knize je napsána tak aby se dala přeložit s širokým spektrem Cg profilů.

Protože asi budete chtít aby se váš příklad C2E1v_green přeložil pro co nejširší spektrum GPU, nejlepšími profily pro váš příklad jsou arbvp1 pro OpenGL a vs_1_1 pro DirectX 8.0. Existuje nějaký důvod vybrat si jiný profil? Ano, pokud chcete použít pokročilejší programování funkcioanlity vertexů, jako je komplexní kontrola toku programu nebo rychlé hardwarové instrukce, které nejsou dostupné v zákadních profilech. Například pokud si vyberete profil vp30, můžete napsat vertexový Cg program který se opakuje libovolně (neurčitě) dlouho.

Jméno profiluProgramovací rozhraníPopis
arbvp1OpenGLVšichni výrobci. Základní programovatelnost vertexů (odpovídá funkcionalitě ARB_vertex_program)
vs_1_1DirectX 8Všichni výrobci. Základní programovatelnost vertexů.
vp20OpenGLnVidia. Základní programovatelnost vertexů (odpovídá funkcionalitě NV_vertex_program
vs_2_0DirectX 9Všichni výrobci. Základní programovatelnost vertexů.
vs_2_xDirectX 9Všichni výrobci. Základní programovatelnost vertexů.
vp30OpenGLnVidia. Základní programovatelnost vertexů (odpovídá funkcionalitě NV_vertex_program2)

Pokud existuje základní profil který postačuje k přeložení vašeho Cg příkladu, použijte ho k získání co nejširší hardwarové podpory. Avšak pokud použijete pokročilejší profil, váš Cg program se může provést efektivněji a můžete ho naprogramovat obecněji.


Takže jaká je vlastně nevýhoda použití pokročilejšího profilu? Může to limitovat váš program pro běh jen na novějších GPU. Abyste získali výhodu obojího - širokou hardwarovou podporu a podporu nejnovějšího hardware, mlžete poskytnout Cg program pro základní profily a pokročilejší Cg program pro pokročilejší profily. Tento přístup zjendodušuje použití CgFX formátu který poskytuje jednotný způsob jak zapouzdřit více implementací daného efektu v Cg do jediného souboru. Příloha C obsahuje více detailů o CgFX.

V příloze B se můžete naučit jak aplikace může využít běhovou knihovnu Cg k načtení a přeložení Cg programů. Obecně stačí zavolat sadu běhových metod Cg které vyžaduje váš kód, vaše vstupní funkce a vámi vybraný profil. Pokud se ve vašem programu vyskytnou nějaké chyby, pak překlad neproběhne. Můžete si vyžádat výpis chyb z překladače abyste si pomohli při opravě svého kódu. Poté co se váš program jednou úspěšně přeloží, jiné běhové metody Cg vám pomohou při konfiguraci vašeho 3D programovacího rozhraní (OpenGL nebo Direct3D) a vykreslení vašeho programu.

Třídy chyb při překladu Cg

Existují dvě třídy chyb překladu pro Cg programy: konvenční a závislé na profilu.

Konvenční chyby jsou způsobeny buď nesprávnou syntaxí, obvykle kvůli překlepům, nebo špatnou sémantikou, jako třeba volání funkce se špatným počtem parametrů.

Tento typ chyb není v základu odlišný od každodenních chyb překladu se kterými se musí potýkat programátoři v C nebo C++.

Chyby závislé na profilu vzchází z použití Cg způsobem který je syntakticky a sémanticky správný ale není podporovaný vaším současným profilem. Můžete mít napsaný platný Cg kód, ale ten se nemusí přeložit díky vámi vybranému profilu. obecné programovací jazyky tento typ chyby nemají.

Chyby závislé na profilu

Chyby závislé na profilu jsou obvykle způsobeny omezeními 3D programovacího rozhraní a hardwarem GPU pro který se snažíte přeložit váš program. Existují tři kategorie chyb závislých na profilu: schopnost, kontext a kapacita.

Schopnost

Všechny současné profily pro fragmentové programy dovolují přístup k texturám, ale žádný profil pro vertexové programy. Důvod je jednoduchý. Programovatelné vertexové procesory v nejnověších GPU nepodporují přístup k texturám. Budoucí vertexové profily by toto měly dovolovat.

Cg vám nedovolí přeložit program který nelze vykonat s daným profilem pro překlad. Pokud vertexový profil nepodporuje přístup k texturám, pak se objeví chyba závislá na schopnosti profilu. Hardware, nebo 3D programovacímu rozhraní chybí schopnost vykonat to co vám Cg program dovolí vyjádřit.

Kontext

Chyba závislá na kontextu profilu je chybou zásadnější, ale méně častou. například, je chybné napsat vertexový program který nevrací přesně jeden parametr který je svázán se sémantikou POSITION. To proto že zybtek grafického potrubí předpokládá že všechny vertexy mají svou pozici.

Stejně tak, fragmetnový profil nemůže navrátit POSITION způsobem jakým ji musí vrátit vertexový profil. Takové chyby jsou způsobeny použitím Cg způsobem který je nekonzistentní s datovým tokem grafického potrubí.

Kapacita

Kapacitní chyby pochází z některých omezených schopností GPU. Některé GPU mají jen čtyři přístupy k texturám v jednom renderovacím cyklu. Jiné GPU mají neomezený počet přístupů v jednom renderovacím cyklu, omezené jen počtem instrukcí ve fragmentovém programu které hardware podporuje. Pokud přistoupíte k více než čtyřem texturám v profilu který nedovoluje přístup k více než čtyřem texturám, obdržíte chybu překročení kapacity.

Kapacitní chyby jsou provděpodobně ty nejvíce frustrující, protože nemusí být zřejmé při pohledu na váš program zda je kapacita překročena. Například, mohli jste překročit maximální možný počet instrukcí vertexového programu pro danou GPU v jediném programu, ale tento fakt pro vás nemusí být ihned zřejmý.

Předcházení chybám

Existují dva způsoby jak předejít těmto frustrujícím chybám. jedním je použít pokročilejší profil. Čím pokročilejší profil, tím menší šance že narazíte na kapacitní omezení nebo omezené schopnosti profilu. Jak se zvyšuje funkcionalita grafického hardware, budete se starat méně a méně o omezení kapacity a schopností.

Jiným řešením je vzdělávat sama sebe o omezeních schopnosti, kontextu a kapacity profilů které použijete ve vaší 3D aplikaci. Pro více informací o omezeních nahlédněte do dokumentace která doprovází Cg Toolkit.

Často můžete získat nějaké ponětí o omezeních závislých na profilu pokud znáte omezeni platná pro 3D programovací rozhraní které používáte. Nahlédněte do dokumentace k OpenGL a Direct3D; pomůže vám to identifikovat ty konstrukce Cg které mohou být předmětem omezení závislých na profilu.

Norma: Vícenásobné vstupní funkce

C a C++ programy začínají svuj běh když operační systém vytvoří instanci programu a zavolá hlavní metodu programu main (nebo WinMain pro programy ve Windows). Náš příklad je kompletní, ale nemá žádnou metodu se jménem main. Proč? Protože místo toho jsme pojmenovali vstupní funkci jako C2E1v_green. V této knize se budeme držet naší pojmenovávací konvence rozlišování příkladů jeden od druhého a jejich snadnějšímu hledání. Ve vaší vlastní 3D aplikaci ale můžete pokmenovat vstupní funkci jak chcete, pokud je její jméno platným identifikátorem.

Obvykle vaše aplikace bude používat kolekci Cg programů, ne jen jeden. Minimálně jeden vertexový a fragmentový program, i když můžete použít neprogramovatelné potrubí pro zpracování vertexů nebo fragmentů nebo bojího pokud si přejete. Komplexní aplikace bude používat stovky Cg programů. Protože Cg programy mohou být přeloženy za běhu, můžete také generovat nové Cg programy tak, že budete text Cg programu procedurálně formátovat.

Samozřejmě můžete stále používat jméno main, což je stnadardní jméno vstupní funkce pro Cg programy pokud nespecifikujete nějaké jiné při překladu Cg zdrojového kódu.


Abyste se vyhnuli zmatkům, vybírejte pro vaše vstupní funkce dostatečně popisná jména. Pokud jsou všechny vaše vstupní funkce pojmenovány main, bude těžké umístit více vstupních funkcí do jednoho zdorjového souboru v Cg - i když je to standardní pojmenování vstupní funkce které běhové prostředí předpokládá.


2.2.5 Stahování a konfigurace vertexových a fragmentových programů

V obecném programovacím jazyce volá operační systém metodu main (nebo WinMain) a program vykoná kód obsažený v metodě main. Když meotda main navrátí, program se ukončí.

AVšak v Cg nevoláte program který běží až do ukončení jak je tomu V C nebo C++. Místo toho Cg překladač přeloží váš program do podoby kterou vaše 3D programovací rozhraní může stáhnout do hardware. Na vaší aplikaci je zavolat nezbytné běhové metody Cg a 3D programovacího rozhraní aby stáhla a nakonfigurovala váš program pro použití v GPU.

Obrázek 2-2 ukazuje jak aplikace překládá Cg program a převádí ho do binárního mikrokódu který vertexový procesor v GPU přímo vykoná když transformuje vertexy.

PO načtení vertexového programu programovatelný vertexový procesor ve vašem GPU spustí program pokaždé, když aplikace pošle nějaký vertex do GPU. Když se renderuje komplexní model s tísíci vertexů, váš aktuální vertexový program zpracovává každý vertex tohoto modelu. Vertexový program se spouští pro každý jeden vertex.

Přeložení a načtení Cg programu do GPU

Do programovatelného vertexového procesoru lze načíst jediný aktuální vertexový program a kdykoli ho vykonat. Avšak je možné, aby vaše aplikace tento vertexový program upravila dle potřeby.

Stejný koncept jediného aktuálního programu platí také pro programovatelný fragmentový procesor vašeho GPU. Ke stažení vašeho programu a navázání ho jako aktuálního fragmetnového programu pro zpracování fragmentů generovaných rasterizerem přeložte Cg fragmetnový program a použijte běhové prostředí Cg spolu s vaším 3D programovacím rozhraním. Poté co je váš fragmentový program navázán, jsou 3D primitiva rasterizována do fragmentů a váš aktuální fragmentový program zpracuje každý generovaný fragment. Fragmentový program se spouští pro každý jeden fragment.

Typicky se 3D aplikace podílí na programování programovatelných vertexových a fragmentových procesorů v GPU aby se dosáhlo určitého vykreslovacího efektu. Tento postup je vlemi účinný díky paralelním a vysoce propojeným programovatelným vertexovým a fragmentovým procesorům v GPU.

2.3 Jednoduchý fragmentový program

Doposud náš příklad obsahuje jen vertexový program, C2E2v_green. Tato sekce uvádí jednoduchý fragmentový program který můžete použít s naším vertexovým programem.

Následující příklad obsahuje kompletní zdrojový kód našeho prvního fragmentového programu.

	struct C2E2f_Output {
		float4 color : cOLOR;
	};

	C2E2f_Output C2E2f_passthrough(float4 color : COLOR)
		C2E2f_Output OUT;
		OUT.color = color;
		return OUT;
	}

Tento program je ještě jednodušší než příklad vertexového programu C2E1v_green. Popravdě ale nedělá téměř nic. Výstupem programu je nezměněná interpolovaná barva přiřazená každému fragmentu který rasterizer vygeneruje. Rastrovací hardware GPU aktualizuje touto barvou snímkovou paměť pokud daný fragment přežije různé restrovací operace jako je ořezávání a testování hloubky.

Zde je výstupní struktura navrácená metodou C2E2f_passthrough:

	struct C2E2f_Output {
		float4 color : COLOR;
	};

Fragmentové programy mají jednodušší výstupní strukturu než ty vertexové. Výstup vertexových programů musí obsahovat pozici a mohou vracet jednu nebo víc barev, sad souřadnic textur a jiné proměnné spojené s vertexy. Avšak fragmentový program musí vše zredukovat na jedinou barvu kterou pak aktualizuje snímkovou paměť (v nektěrých pokročilejších profilech mohou fragmentové programy zapisovat více dat stejně jako hodnotu hloubky). Sémantika COLOR přiřazená členu color ve fragmentovém programu značí že tento člen je barva která bude použita k aktualizaci snímkové paměti.

Deklarace vstupní metody programu C2E2f_passthrough je tato:

	C2E2f_Output C2E2f_passthrough(float4 color : COLOR)

Funkce navrací výstupní strukturu C2E2f_Output s jednou barvou. Funkce přebírá jeden čtyřsložkový vektor, pojmenovaný color, navázaný na vstupní sémantiku COLOR. Vstupní sémantika COLOR fragmentového programu je barva fragmentu interpolovaná rasterizerem, postavená na barvě přiřazené vertexu.

Tělo metody C2E2f_passthrough vypadá takto:

	C2E2f_Output OUT;
	OUT.color = color;
	return OUT;

Po deklaraci proměnné OUT s typem výstupní struktury C2E2f_Output, přiřazuje program interpolovanou barvu fragmentu (jediný vstupní parametr) výsledné barvě fragmentu ve výstupní struktuře. Nakonec program navrací stukturu OUT.

2.3.1 Profily fragmentových programů

Stejně jako jste potřebovali profil k přeložení příkladu C2E1v_green, tak potřebujete profil k přeložení příkladu C2E2f_passthrough. Ovšem profily k přeložení příkladu C2E1v_green byly pro vertexové programy. K překladu C2E2f_passthrough si musíte vybrat odpovídající fragmentový profil.

Následující tabulka obsahuje seznam různých profilů k přeložení fragmentových programů.

stejně jako dřívější příklad vertexovéhp programu, i tento příklad prvního fragmentového programu je tak jednoduchý že můžete příklad C2E2f_passthrough přeložit s jakýmkoli profilem uvedeným v tabulce.

Jméno profiluProgramovací rozhraníPopis
ps_1_1DirectX 8Všichni výrobci. Základní programovatelnost fragmentů
ps_1_2DirectX 8Všichni výrobci. Základní programovatelnost fragmentů
ps_1_3DirectX 8Všichni výrobci. Základní programovatelnost fragmentů
fp_20OpenGLnVidia. Základní programovatelnost fragmentů (odpovídá funkcionalitě NV_texture_shader a NV_register_combiners
arbfp1OpenGLnezávislý na výrobci. Pokročilá programovatelnost fragmentů (odpovídá funkcionalitě ARB_fragment_program)
ps_2_0DirectX 9Nezávislý na výrobci. Pokročilá programovatelnost fragmentů
ps_2_xDirectX 9nezávislý na výrobci. Pokročilá programovatelnost fragmentů
fp30OpenGLnVidia. Pokročilá programovatelnost fragmentů (odpovídá funkcionalitě NV_fragment_program

Cg má přkazový překladač známý jako cgc, což je zkratka pro "Cg compiler". Dynamická kompilace za běhu může být velmi výkonná a velmi se doporučuje. Avšak když píšte Cg programy, musíte si často ověřovat že se přeloží správně bez toho aniž byste spouštěli svou 3D aplikaci. K zjištění chyb z Cg překladače při psaní programů můžete spustit cgc. Ten "zkušebně přeloží" soubor Cg programu použitý vaší aplikací jako součást běžného sestavovacího procesu vaší aplikace. Použití cgc v integrovaném vývojovém prostředí (IDE) jako je Microsoft Visual C++ může urychlit a usnadnit hledání chyb při překladu. Dobré IDE vám také pomůže rychle najít řádek kódu, jehož číslo se objecilo v chybové hlášce, stejně jakbyste psali program v C nebo C++. Obrázek 2-3 ukazuje příklad odlaďování chyb při překladu v Microsoft Visual Studiu.


Cg vývojáři často napíší jeden Cg program který funguje pro OpenGL i Direct3D, i když převážně používají jen jedno nebo druhé programovací rozhraní. Avšak rozsílnost závislé na profilu mohou spočívat mezi tím co je platným programem v souvisejících profilech pro tyto 3D programovací rozhraní. Takže naše doporučení je naučit se překládat vaše Cg programy s cgc dvakrát: jednou pro příslušný OpenGL profil a jednou pro příslušný Direct3D profil.


Hledání řádků s chybami v integrovaném vývojovém prostředí

2.4 Vykreslení vašich příkladů vertexových a fragmentových programů

nyní je čas podívat se na vaše příklady v akci. nočekávejte od toho příliš, protože jsou velmi jednoduché programy. Stále se však můžete mnoho naučit zkoušením jak tyto programy spolupracují - a také se zbytkem grafického potrubí - při vykreslování zeleného trojúhelníku.

Podívejte se na 2D trojúhelník na obrázku 2-4. Ukazuje geometri se kterou fragmentový a vertexový program bude v příkladu pracovat.

2D trojúhleník

2.4.1 Vykreslení trojúhelníku v OpenGL

V OpenGL můžete vykreslit 2D trojúhelník následujícími příkazy:

	glBegin(GL_TRIANGLES);
		glVertex2f(-0.8, 0.8);
		glVertex2f(0.8, 0.8);
		glVertex2f(0.0, -0.8);
	glEnd();
2.4.2 Vykreslení trojúhelníku v Direct3D

V Direct3D můžete vykreslit stejný trojúhelník následujícími příkazy:

	D3DXVECTOR4 vertices[3] = {
		D3DXVECTOR4(-0.8f, 0.8f, 0.f, 1.f),
		D3DXVECTOR4(0.8f, 0.8f, 0.f, 1.f),
		D3DXVECTOR4(0.f, -0.8f, 0.f, 1.f)};

	m_pD3Device->DrawPrimitiveUP(D3DPT_TRIANLGLELIST, 1, vertices, sizeof(D3DXVECTOR4));

Existují jiné, efektivnější způsoby jak zaslat vertexy do GPU pomocí OpenGL nebo Direct3D. Když ke zpracování vertexů použijete Cg programy, nezáleží jak daná aplikace posílá vertexy do GPU.

Získání stejných výsledků

Obrázek 2-5 ukazuje výsledek vykreslování tohoto trojúhelníku vertexovým programem C2E1v_green a fragmentovým programem C2E2f_passtthrough. Výsledek je totožný, ať už použijeme OpenGL nebo Direct3D. I kdzyž to není příliš patrné na pohled, trojúhleník je vykreslen zeleně.

Vykreslování trojúhelníku s C2E1v_green a C2E2f_passthrough

Vertexový program předává určenou pozici každého vertexu ve 2D rasterizeru. Rasterizer očekává tyto pozice definované jako souřadnice v ořezovém prostoru. Ořezový prostor definuje viditelnou část prostoru z aktuálního postu. POkud vertexový program poskytne 2D souřadnice, jako je to v případě obrázku 2-5, kde část priitiva které je vykreslováno je tou částí primitiva kde x a y jsou mezi -1 a +1. Celý trojúhelník se nachází v ořezovém regionu, takže je plně vykreslen.

Obrázek 2-6 ukazuje rasterizaci ořezového prostoru ve 2D.

Primitiva jsou vykreslována do snímkové paměti pokud spadají do šedé oblasti (oblast ořezového prostoru kde jsou x a y mezi -1 a +1). O prostoru se dozvíte více v kapitole 4.

Obrázek 2-7 ukazuje co se stane když použijete vertexový program C2E1v_green a fragmentový program C2E2f_passthrough s 2D geometrií která neleží úplně celá uvnitř viditelné oblasti 2D ořezového prostoru. Pokud hvězdy mají vertexy které mají x-ové a y-ové souřadnice mimo oblast -1 až +1, pak rasterizer ořízne některé zelené hvězdy na okraji viditelné oblasti. Pokud se žádná část primitiva nenachází uvnitř viditelné oblasti, pak rasterizer toto primitivum eliminuje úplně.

2D pohled ořezového prostoru

GPU transformuje ořezový prostor pro rasterizer automaticky (jednoduchou změnou velikosti a sešikmením) do souřadnic okna. GPU zmenší ořezový souřadnice ořeového prostoru dle potřeby pžed rasterizací, aby se shodoval pohled kamery s pozicí okna.

Primitiva vykreslená pomocí C2E1v_green a C2E2f_passthrough. Vyžaduje 2D ořezávání.

Kapitola 4 zobecňuje tuto poznámku o ořezovém prostoru z 2D na 3D prostor, a přidává perspektivu. Ale v této kapitole a v kapitole 3 používají příklady 2D vykreslování pro zachování jednoduchosti.

2.5 Cvičení

  1. Zodpovězte: Jaké GPU profily podporuje váš Cg překladač? Nahlédněte do dokumentace překladače nebo ho spusťte příkazem cgc -help. Které profily jsou vertexové a které fragmentové?

  2. Zkuste sami: Upravte vertexový program C2E1v_green tak, aby obarvil vertexy na červeno místo zeleně.
  3. Zkuste sami: Změňte pozici jednoho vertexu troúhelníku tak aby ležel mimo rozsah [-1, +1]. Příklad spusťte. Je trojúhelník ořezán tak jak jste očekávali?

Další literatura

Najděte si dokumentaci, třeba Cg Toolkit Users Manual: A Developers Guide to Programmable Graphics, která je přiložena k Cg Toolkit.

Také můžete navštívit portál cgshaders.org kde jsou aktuální informace o Cg. Tento portál obsahuje články, fóra kde se můžete ptát a volně dostupné příklady stínovacích programů (pozn. překladatele: Tento portál byl ZRUŠEN).