610 likes | 760 Views
Графични операции в игрите. Какво ще представим?. Показване на сцена, Стъпка по стъпка Текстуриране. Основни принципи Прости модели за осветление Прости светлини Normal Maps. DirectX. EmptyProject в dxsdk samples Използва DXUT – няколко класа, които помагат настройката на устройствата
E N D
Какво ще представим? • Показване на сцена, Стъпка по стъпка • Текстуриране. Основни принципи • Прости модели за осветление • Прости светлини • Normal Maps
DirectX • EmptyProject в dxsdk samples • Използва DXUT – няколко класа, които помагат настройката на устройствата • DXUTSetCallbackD3D9DeviceAcceptable( IsD3D9DeviceAcceptable ); • DXUTSetCallbackD3D9DeviceCreated( OnD3D9CreateDevice ); • DXUTSetCallbackD3D9DeviceReset( OnD3D9ResetDevice ); • DXUTSetCallbackD3D9FrameRender( OnD3D9FrameRender ); • DXUTSetCallbackD3D9DeviceLost( OnD3D9LostDevice ); • DXUTSetCallbackD3D9DeviceDestroyed( OnD3D9DestroyDevice ); • DXUTSetCallbackDeviceChanging( ModifyDeviceSettings ); • DXUTSetCallbackMsgProc( MsgProc ); • DXUTSetCallbackFrameMove( OnFrameMove );
DirectX/ Глобални данни • const D3DXVECTOR3 g_CameraPosition (0.0f,0.0f,-5.0f ) ; • const D3DXVECTOR3 g_CameraUp (0.0f, 1.0f,0.0f) ; • const D3DXVECTOR3 g_CameraLookAt (0.0f,0.f,1.0f) ; • const float g_CameraVx = 4.0f/4.0f; • const float g_CameraVy= 3.0f/4.0f; • const float g_ZMin = 2.0f; • const float g_Zmax= 100.f; • D3DXMATRIX g_WorldMatrix;// само един обект засега • D3DXMATRIX g_CameraMatrix; • D3DXMATRIX g_ProjectionMatrix; • D3DXMATRIX g_WVP;
DirectX OnD3D9CreateDevice() D3DXMatrixLookAtLH (&g_CameraMatrix,&g_CameraPosition,&g_CameraLookAt,&g_CameraUp); D3DXMatrixPerspectiveLH (&g_ProjectionMatrix,g_CameraVx,g_CameraVy,g_ZMin,g_ZMax); Инициализиране g_WorldMatrix, DirectX пази транслацията в най-долния ред. g_WVP = g_WorldMatrix*g_CameraMatrix*g_ProjectionMatrix;
DirectX .x формат { Mesh CubeMesh { 6; -0.500000;-0.500000;0.0;, 0.500000;-0.500000;0.0;, -0.500000;0.500000;0.00000;, 0.500000;0.500000;0.0;, 0.500000;-0.500000;0.0;, -0.500000;0.500000;0.00000;;
DirectX .x формат 2; 3;1,0,2;; 3;3,1,2;; MeshVertexColors { 6; 0;1.0,0.0,0.0,1.0;, 1;0.0,1.0,0.0,1.0;, 2;0.0,0.0,1.0,1.0;, 3;1.0,0.0,0.0,1.0;, 4;1.0,0.0,0.0,1.0;, 5;0.0,0.0,1.0,1.0;; }
DirectX .x формата MeshTextureCoords { 6; 0.0,0.0;, 1.0,0.0;, 0.0,1.0;, 1.0,1.0;, 0.0,0.0;, 0.0,1.0;; }
DirectX Зареждане на Mesh D3DXLoadMeshFromX Чертаене g_Quad->DrawSubset(0); Модифициране на вертексите struct Vertex { float x,y,z; float cx,cy,cz,cw; float tx,ty; }; Vertex* v; g_Quad->LockIndexBuffer( 0, &v);
DirectX • Ефекти • Правят микромениджмънта на shader-ите вместо вас. Разжирение .fx float4x4 g_WVP; // World * View * Projection matrix texture g_txScene; sampler g_samScene = sampler_state { Texture = <g_txScene>; MinFilter = Linear; MagFilter = Linear; MipFilter = Linear; };
DirectX void VertSceneSingle (...) { .... } float4 PixSceneSingle( ...) { .... } technique RenderSceneSingle { pass P0 { VertexShader = compile vs_3_0 VertSceneSingle(); PixelShader = compile ps_3_0 PixSceneSingle(); AlphaBlendEnable = false; ZEnable = false; } }
DirectX • Зареждане ID3DXEffect* g_Effect; • D3DXCreateEffectFromFile (pd3dDevice,”c:/myeffect.fx”,0,0,0,0,&g_Effect,&errors);
DirectX UINT passes; g_Effect->SetTechnique("RenderScene"); g_Effect->Begin(&passes,0); g_Effect->SetMatrix("g_WVP",&g_WVP); g_Effect->SetTexture("g_txScene",g_QuadTexture); g_Effect->CommitChanges(); for (UINT i=0;i<passes;++i) { g_Effect->BeginPass(i); g_Quad->DrawSubset(0); g_Effect->EndPass(); } g_Effect->End();
DirectX UINT passes; g_Effect->SetTechnique("RenderScene"); g_Effect->Begin(&passes,0); g_Effect->SetMatrix("g_WVP",&g_WVP); g_Effect->SetTexture("g_txScene",g_QuadTexture); g_Effect->CommitChanges(); for (UINT i=0;i<passes;++i) { g_Effect->BeginPass(i); g_Quad->DrawSubset(0); g_Effect->EndPass(); } g_Effect->End();
DirectX • Текстуриране • Текстурите имитират геометрия • Изображение от R3 в R2
DirectX • Видове проекции • Сферична • Цилиндрична • Равнинна • Всички проекции по моделите се правят от артисти • Една от най-гадните работи за тях • Трябва да се направи проекцията така, че да може да се рисува върху нея.
DirectX 1.0 Малките триъгълници в синьо 0.0 0.0 1.0
DirectX • Какво правим, когато текстурните координати излизат извън интервала 0;1 MeshTextureCoords { 6; 0.0,0.0;, 2.0,0.0;, 0.0,2.0;, 2.0,2.0;, 0.0,0.0;, 0.0,2.0;; }
DirectX • Какво правим, когато текстурните координати излизат извън интервала 0;1 • Можем да настроим ефектите как да четат от текстурите sampler_state { .... AddressU = Clamp; AddressV = Clamp; };
DirectX AddressU = Wrap; AddressV = Wrap; AddressU = Mirror; AddressV = Mirror; AddressU = Border; AddressV = Border;
DirectX Четене от текстуритев пикселните shader-и: float4 result = tex2D( g_samScene, Tex.xy ); Ако триъгълникът е много голям и трябва да се увеличи текстурата се прави линейно филтриране
DirectX Когато триъгълникът е с много малки размери:
DirectX Когато триъгълникът е с много малки размери: Представлява разстоянието между две mip нива
DirectX • Когато се построяват mip нивата трябва да се има предвид • Ако е за цветови текстури да се внимава с Gamma Space. Иначе по-долните mip нива стават по-тъмни. • Добре е да не се прилага Nearest Neighbour, а Gaussian примерно • Ако пък се правят mip нива за Normal Maps, тогава всяко ниво се генерира отново от геометрията Когато хардуерът чете от текстура с mip нива, построява (u,v,d), Намира d между кои mip нива е, чете билинейно от всяко и после линейно интерполира прочетените стойности с d
DirectX • Без mip map mip map
DirectX • Хардуерни компресии • DXT1/3 – блокова текстура (DDS) за фото реалистични изображения • 3Dc – Разработка на ATI за Normal Maps (текстури, в които вместо цветове има вектори) • DXT5_NM Tangent Space Object Space
DirectX • DXT1 • Изображението се разделя на блокове от 4x4 пиксела • За всеки блок се записват 2 цвята, минимум и максимум от цветовете в блокчето във формат (5:6:5) • След това от правата между двата цвята се избират други два цвята, които са на равно разстояние по правата • Това дава избор от 4 цвята за всеки един от 16-те пиксела • Всеки пиксел се кодира с 2 бита: • 16*2=32 бита общо + 2 * 16 бита = 64 бита за 16 пиксела.или 4 бита за пиксел • DXT1 – прави компресия типично 6:1, защото пикселите са 24 бита иначе • С DXT1 се текстурира по-бързо, защото е по-малка текстура и попадат повече пиксели в текстурните кешове на GPU
DirectX • От Nvidia 1.5 MB 384 kb
DirectX • От Nvidia 1.5 MB 256 kb
DirectX • DXT 5 компресия. За изображения с гладък алфа канал • Използва се за текстури с алфа канал • Цветния канал се компресира като при DXT1, а алфа канала • се разделя на блокове от 4x4 пиксела и се компресира отделно • Избират се две точки от 16-те (може крайните), • Генерират се между тях 6 точки на равни разстояния • И всяка една от другите точки получава 3 битов индекс, коя от 8-те точки приближава • Така за алфа канала се получава : • 2*8 = 16 бита (крайните точки) • 16 * 3 = 48 бита (средните точки)
DirectX • DXT 5 компресия за Normal maps. • Пример за компресия на сигнал в текстура • Normal map съдържа тройки нормализирани вектори • (x,y,z), (x^2+y^2+z^2=1) • Z може да се изчисли от X,Y • Y се компресира като цветови компонент • X се компресира като алфа компонент. • С малко загуба на качеството се постига добра компресия от 4:1 Tangent Space
DirectX • 3DC компресия за Normal maps.(Вече в DirectX 10) • Постига 4:1 компресия като DXT5_NM, но с по-добро качество • Абсолютно аналогична на DXT5, компресира обаче и X и Y все едно са алфа канали на DXT5, в DXT5 Y компонентата е с 6 бита, а тук е с 8 бита
DirectX • Основни принципи за използване на текстури • Да се слагат линейни сигнали или сигнали, които се апроксимират с линейни функции • Ако ще се използва DXТ5 компресия, различните компоненти, трябва да са независими.
DirectX • Нормали Вектор перпендикулярен на равнината определена от трите вертекса с дължина 1.
DirectX • Нормали в • XSI
DirectX • Всяка нормала е зададена в object space MeshNormals { 0.000;-0.793;0.609;, -0.000;0.994;-0.112;, } • И се задава за всеки вертекс. Обикновено автоматично се прави от 3DS Max, XSI, Maya .....
DirectX N V R L Повърхност
DirectX • Дифузна повърхност и светлина само с посока (слънцето) • Intensity=saturate( dot(L,N) ); • DiffuseColor=DiffuseTexture*Intensity; • L и N, могат да са зададени в различни координатни системи. • Тогава чрез World, се минава от едната в другата.
DirectX • Без осветление
DirectX • Само нормали: oPos = mul( Pos, g_WVP ); float4 normal = float4(Normal,1.0f); оIntensity = normal; float4 PixScene( float2 Tex : TEXCOORD0, float4 Intensity : TEXCOORD1 ) : COLOR0 { return Intensity; }
DirectX • Само интензитет на осветлението: float4 normal = float4(Normal,1.0f); float4 objectSpaceLight = normalize(mul(g_InverseWorld, g_Light0 )); oIntensity.xyzw = dot(normal,objectSpaceLight); float4 PixScene( float2 Tex : TEXCOORD0, float4 Intensity : TEXCOORD1 ) : COLOR0 { return Intensity; }
DirectX float4 normal = float4(Normal,1.0f); float4 objectSpaceLight = normalize(mul(g_InverseWorld, g_Light0 )); oIntensity.xyzw = dot(normal,objectSpaceLight); float4 PixScene( float2 Tex : TEXCOORD0, float4 Intensity : TEXCOORD1 ) : COLOR0 { return Intensity*tex2D( g_samScene, Tex ); }
DirectX const D3DXVECTOR4 g_Light0Intensity (0.7f,0.7f,1.0f,1.0f); //Cpp float4 normal = float4(Normal,1.0f); float4 objectSpaceLight = normalize(mul(g_InverseWorld, g_Light0 )); oIntensity = g_Light0Intensity * dot(normal,objectSpaceLight); float4 PixScene( float2 Tex : TEXCOORD0, float4 Intensity : TEXCOORD1 ) : COLOR0 { return Intensity*tex2D( g_samScene, Tex ); }
DirectX Per Pixel Lighting. Как се прави това? Изчисленията се правят във всяка точка. С Normal Maps се имитира геометрия Tangent Space Object Space
DirectX Texture Space C V C B A U B A
DirectX • В DirectX, нормалите се изчисляват с: • D3DXComputeNormals; • тангентите и бинормалите се изчисляват с • D3DXComputeTangentFrameEx • Може да се задава, само тангенти или само бинормали
DirectX void VertScene( float4 Pos : POSITION, float2 Tex : TEXCOORD0, float3 Normal: NORMAL, float3 Tangent: ТANGENT, out float4 oPos: POSITION, out float2 oTex : TEXCOORD0, out float3 oTangent : TEXCOORD1, out float3 oBinormal:TEXCOORD2, out float3 oNormal : TEXCOORD3 ) { oPos = mul( Pos, g_WVP ); oTex = Tex; oTangent = mul(Tangent,g_World); oNormal = mul(Normal,g_World); oBinormal = cross(oTangent,oNormal); }
DirectX float4 PixScene( float2 Tex : TEXCOORD0,float3 Tangent : TEXCOORD1, float3 Binormal : TEXCOORD2, float3 Normal : TEXCOORD3 ) : COLOR0 { float3 tangent = normalize(Tangent); float3 binormal = normalize(Binormal); float4 diffuse = tex2D( g_samScene, Tex ); float3 normal = tex2D( g_samNormalMap, Tex ); normal = 2*normal-1; float3x3 tangentBasis={tangent,binormal, normalize(Normal) }; float3 lightDirection = normalize(g_Light0).xyz; float3 normalInWorldSpace = mul( normal,tangentBasis); float intensity=saturate( dot ( normalInWorldSpace, lightDirection ) ); return diffuse*intensity; }