矩阵
对于XMMATRIX的初始化,可以有多种方法,一种方法是传4个XMVECTOR参数,每个XMVECTOR对应矩阵的一行;第二种方法是直接传递16个浮点数,代表整个矩阵的内容;第三种方法是用一个FLOAT型的数组,代表整个矩阵的内容。当然,这三种方法都有点麻烦,不过在实际中,自己来手动初始化矩阵的地方也不多,了解下其初始化方法即可。其次,XMMATRIX重载了()操作符,用来访问矩阵中的成员,用法跟正常矩阵访问完全一样,即传递两个参数(row, col)即可。 XMMATRIX也重载了*和*=操作符,用途很明显,用来进行矩阵的乘积。
在函数定义中,类型为XMMATRIX的形参必须用CXMMATRIX类型代替。
1、 矩阵相关函数
- XMMATRIX XMMatrixIdentity(); //返回单位矩阵,即对角线全1,其他全0
- BOOL XMMatrixIsIdentity(CXMMATRIX M); //判断一个矩阵是否为单位矩阵
- XMMATRIX XMMatrixMultiply(CXMMATRIX A, CXMMATRIX B); //两矩阵相乘
- XMMATRIX XMMatrixTranspose(CXMMATRIX M); //矩阵转置
- XMVECTOR XMMatrixDeterminant(CXMMATRIX M); //求矩阵对应行列式的值det
- XMMATRIX XMMatrixInverse(XMVECTOR *pDet, CXMMATRIX M); //求矩阵M的逆,*pDet为该矩阵的det
2、 3D中矩阵变换相关函数
- XMMATRIX XMMatrixScaling(FLOAT scaleX, FLOAT scaleY, FLOAT scaleZ); //伸缩变化,指定三个方向上的伸缩比
- XMMATRIX XMMatrixScalingFromVector(FXMVECTOR scale); //通过向量指定三个方向伸缩比,求伸缩变换
- XMMATRIX XMMatrixRotationX(FLOAT angle); //围绕x轴的旋转变换
- XMMATRIX XMMatrixRotationY(FLOAT angle); //围绕y轴的旋转变换
- XMMATRIX XMMatrixRotationZ(FLOAT angle); //围绕z轴的旋转变换
- XMMATRIX XMMatrixRotationAxis(FXMVECTOR axis, FLOAT angle); //围绕任意轴axis的旋转变换
- XMMATRIX XMMatrixTranslation(FLOAT x, FLOAT y, FLOAT z); //平移变换,指定三个方向的平移量
- XMMATRIX XMMatrixTranslationFromVector(FXMVECTOR offset); //通过向量指定三个方向的平移量,求平移变换
- XMVECTOR XMVector3Transform(FXMVECTOR v, CXMMATRIX m); //向量、矩阵相乘
- XMVECTOR XMVector3TransformCoord(FXMVECTOR v, CXMMATRIX m); //向量、矩阵相乘,但向量w=1,因此为点的变换
- XMVECTOR XMVector3TransformNormal(FXMVECTOR v, CXMMATRIX m); //向量、矩阵相乘,但向量w=0,因此为向量的变换
数据格式
D3D应用程序中,无论是纹理图片,还是创建的缓冲区,都有着特定的数据格式。D3D11支持有限的数据格式,以枚举变量形式存在,如下几种:
DXGI_FORMAT_R32G32B32_FLOAT: 3个32位单精度符点数组成,比如用于代表三维空间坐标,以及24位颜色;
DXGI_FORMAT_R16G16B16A16_UNORM: 4个16位数组成,每个成员位于[0,1.0f]之间,UNORM意指:unsigned normalized,即无符号,且归一化的;
DXGI_FORMAT_R32G32_UINT:2个32位数组成,每个成员为无符号整型(unsigned int);
DXGI_FORMAT_R8G8B8A8_UNORM:4个8位数组成,每个成员为[0,1.f]之间;
DXGI_FORMAT_R8G8B8A8_SNORM:4个8位数组成,每个成员为[-1.0f, 1.0f]之间,SNORM意指:signed normalized;
DXGI_FORMAT_R8G8B8A8_SINT:4个8位数组成,每个成员为有符号整型;
此外还有很多其他类型的数据格式,熟悉各部分的意义后对任何类型可以很快从名字中得知其意思,也很容易写出指定意义的数据格式对应的枚举变量。数据格式在程序中使用相当频繁,因此很有必要提前熟悉该枚举类型变量的特点。
多重采样抗锯齿 Multisampling Atialiasing
- typedef struct DXGI_SAMPLE_DESC {
- UINT Count;
- UINT Quality;
- } DXGI_SAMPLE_DESC, *LPDXGI_SAMPLE_DESC;
Count为我们设置的采样的个数,Quality为机器支持的不同的等级,初始化过程中我们会对Quality进行检测。
注意Multisampling区别于super sampling的关键点:不同采样点是分别计算颜色值(super sampling)还是共享同一颜色值(Multisampling)。详细情况有很多参考书介绍。
Direct3D 初始化
Direct3D 初始化
初始化Direct3D,我们需要完成以下四个步骤:
1.定义我们需要检查的设备类型(device types)和特征级别(feature levels)
2.创建Direct3D设备,渲染设备(context)和交换链(swap chain)。
3.创建渲染目标(render target)。
4.设置视口(viewport)
交换链是设备和上下文将要绘制的渲染目标。
DXGI 即DirectX图形学基础,用于Direct3D交换链swap chains和枚举设备适配器
enumeration of deviceadapters的创建。
XInput 是之前版本DirectInput的一个补充,但XInput不支持键盘和鼠标等PC最常见的输入设备,所以涉及到键盘及鼠标消息的处理,还是需要使用DirectInput。
REFERENCED_PARAMETER用于避免变量定义后没在函数体中使用的编译警告
————————————————————————————————————————————————————————————
D3D11的初始化主要有以下几个步骤:
1. 创建设备ID3D11Device和设备上下文ID3D11DeviceContext;
2. 检测多重采样支持的等级:CheckMultisampleQualityLevels
3. 创建交换链
4. 创建RenderTargetView
5. 创建DepthStencilView
6. 把上述两个视图绑定到渲染管线相应的阶段
7. 设置Viewport
********************************************************************************
1 #include <Windows.h> 2 #include <string> 3 #include <D3D11.h> 4 #include <xnamath.h> 5 6 using namespace std; 7 8 //重要的全局变量 9 //在后面学习过程中,这些全局将作为框架类的成员变量存在 10 HINSTANCE g_hInstance(NULL); 11 HWND g_hWnd(NULL); 12 13 wstring g_clsName(L"d3d11"); 14 wstring g_wndTitle(L"D3D11初始化"); 15 16 UINT g_winWidth(640); 17 UINT g_winHeight(480); 18 19 //D3D相关全局变量 20 ID3D11Device *g_device(NULL); 21 ID3D11DeviceContext *g_deviceContext(NULL); 22 IDXGISwapChain *g_swapChain(NULL); 23 24 ID3D11DepthStencilView *g_depthStencilView(NULL); 25 ID3D11RenderTargetView *g_renderTargetView(NULL); 26 27 //初始化 28 BOOL InitWin32(); 29 //初始化D3D 30 BOOL InitD3D(); 31 void Render(); 32 //主循环 33 int Run(); 34 //回收资源 35 void Release(); 36 37 LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); 38 39 //程序入口 40 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR cmdLine, int cmdShow) 41 { 42 g_hInstance = hInstance; 43 44 if(!InitWin32()) 45 return -1; 46 if(!InitD3D()) 47 return -1; 48 49 return Run(); 50 } 51 52 BOOL InitWin32() 53 { 54 //创建窗口类 55 WNDCLASS wndcls; 56 wndcls.cbClsExtra = 0; 57 wndcls.cbWndExtra = 0; 58 wndcls.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH); 59 wndcls.hCursor = LoadCursor(NULL,IDC_ARROW); 60 wndcls.hIcon = LoadIcon(NULL,IDI_APPLICATION); 61 wndcls.hInstance = g_hInstance; 62 wndcls.lpfnWndProc = WinProc; 63 wndcls.lpszClassName = g_clsName.c_str(); 64 wndcls.lpszMenuName = NULL; 65 wndcls.style = CS_HREDRAW | CS_VREDRAW; 66 67 //注册窗口类 68 if(!RegisterClass(&wndcls)) 69 { 70 MessageBox(NULL,L"窗口注册失败!",L"错误",MB_OK); 71 return FALSE; 72 } 73 74 //创建窗口 75 g_hWnd = CreateWindow(g_clsName.c_str(), 76 g_wndTitle.c_str(), 77 WS_OVERLAPPEDWINDOW, 78 CW_USEDEFAULT,CW_USEDEFAULT, 79 g_winWidth,g_winHeight, 80 NULL, 81 NULL, 82 g_hInstance, 83 NULL); 84 if(!g_hWnd) 85 { 86 MessageBox(NULL,L"窗口创建失败!",L"错误",MB_OK); 87 return FALSE; 88 } 89 90 //显示、更新窗口 91 ShowWindow(g_hWnd,SW_SHOW); 92 UpdateWindow(g_hWnd); 93 94 //Win32初始化完毕 95 return TRUE; 96 } 97 98 BOOL InitD3D() 99 { 100 //创建设备及上下文 101 D3D_FEATURE_LEVEL features[3] = {D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_0, D3D_FEATURE_LEVEL_9_3}; 102 D3D_FEATURE_LEVEL myFeatureLevel; 103 HRESULT hr = D3D11CreateDevice(NULL,D3D_DRIVER_TYPE_HARDWARE,0,0,features,3,D3D11_SDK_VERSION,&g_device,&myFeatureLevel,&g_deviceContext); 104 if(FAILED(hr)) 105 { 106 MessageBox(NULL,L"创建d3d11设备失败!",L"错误",MB_OK); 107 return FALSE; 108 } 109 110 //检测4x采样等级 111 UINT msaa4xQuality(0); 112 g_device->CheckMultisampleQualityLevels(DXGI_FORMAT_R8G8B8A8_UNORM,4,&msaa4xQuality); 113 114 //创建交换链 115 //先描述其属性 116 DXGI_SWAP_CHAIN_DESC swapChainDesc = {0}; 117 swapChainDesc.BufferDesc.Width = g_winWidth; //宽、高 118 swapChainDesc.BufferDesc.Height = g_winHeight; 119 swapChainDesc.BufferDesc.RefreshRate.Denominator = 1; //刷新率 120 swapChainDesc.BufferDesc.RefreshRate.Numerator = 60; 121 swapChainDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; //恒定参数,按照这样指明即可 122 swapChainDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED; //同上 123 swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; //数据格式,一个为RGBA四元色格式 124 swapChainDesc.BufferCount = 1; //后缓冲区个数,1个足够 125 swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; //Usage,很好理解 126 swapChainDesc.Flags = 0; 127 swapChainDesc.OutputWindow = g_hWnd; //主窗口句柄 128 swapChainDesc.SampleDesc.Count = 4; //多重采样 129 swapChainDesc.SampleDesc.Quality = msaa4xQuality-1; 130 swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; //交换:绝大多数情况用DISCARD 131 swapChainDesc.Windowed = true; //窗口模式 132 133 //获取IDXGIFactory以创建交换链 134 IDXGIDevice *dxgiDevice(NULL); 135 g_device->QueryInterface(__uuidof(IDXGIDevice),reinterpret_cast<void**>(&dxgiDevice)); 136 IDXGIAdapter *dxgiAdapter(NULL); 137 dxgiDevice->GetParent(__uuidof(IDXGIAdapter),reinterpret_cast<void**>(&dxgiAdapter)); 138 IDXGIFactory *dxgiFactory(NULL); 139 dxgiAdapter->GetParent(__uuidof(IDXGIFactory),reinterpret_cast<void**>(&dxgiFactory)); 140 hr = dxgiFactory->CreateSwapChain(g_device,&swapChainDesc,&g_swapChain); 141 if(FAILED(hr)) 142 { 143 MessageBox(NULL,L"创建d3d11交换链失败!",L"错误",MB_OK); 144 return FALSE; 145 } 146 dxgiFactory->Release(); 147 dxgiAdapter->Release(); 148 dxgiDevice->Release(); 149 150 //创建视图 151 //需要先获得资源 152 ID3D11Texture2D *backBuffer(NULL); 153 g_swapChain->GetBuffer(0,__uuidof(ID3D11Texture2D),reinterpret_cast<void**>(&backBuffer)); 154 hr = g_device->CreateRenderTargetView(backBuffer,NULL,&g_renderTargetView); 155 if(FAILED(hr)) 156 { 157 MessageBox(NULL,L"创建RenderTargetView失败!",L"错误",MB_OK); 158 return FALSE; 159 } 160 backBuffer->Release(); 161 162 //创建深度缓冲区视图 163 //要先创建对应缓冲区 164 //创建缓冲区Texture2D,要先给出描述 165 D3D11_TEXTURE2D_DESC desc = {0}; 166 desc.Width = g_winWidth; 167 desc.Height = g_winHeight; 168 desc.MipLevels = 1; 169 desc.ArraySize = 1; 170 desc.BindFlags = D3D11_BIND_DEPTH_STENCIL; 171 desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; 172 desc.MiscFlags = 0; 173 desc.SampleDesc.Count = 4; 174 desc.SampleDesc.Quality = msaa4xQuality-1; 175 desc.Usage = D3D11_USAGE_DEFAULT; 176 desc.CPUAccessFlags = 0; 177 ID3D11Texture2D *depthStencilBuffer(NULL); 178 hr = g_device->CreateTexture2D(&desc,NULL,&depthStencilBuffer); 179 if(FAILED(hr)) 180 { 181 MessageBox(NULL,L"创建d3d11深度缓冲区失败!",L"错误",MB_OK); 182 return FALSE; 183 } 184 hr = g_device->CreateDepthStencilView(depthStencilBuffer,NULL,&g_depthStencilView); 185 if(FAILED(hr)) 186 { 187 MessageBox(NULL,L"创建DepthStencilView失败!",L"错误",MB_OK); 188 return FALSE; 189 } 190 191 //有了视图要绑定到管线相应阶段 192 g_deviceContext->OMSetRenderTargets(1,&g_renderTargetView,g_depthStencilView); 193 depthStencilBuffer->Release(); 194 195 //最后设置视口 196 D3D11_VIEWPORT viewPort = {0}; 197 viewPort.Width = static_cast<FLOAT>(g_winWidth); 198 viewPort.Height = static_cast<FLOAT>(g_winHeight); 199 viewPort.MinDepth = 0.f; 200 viewPort.MaxDepth = 1.f; 201 viewPort.TopLeftX = 0.f; 202 viewPort.TopLeftY = 0.f; 203 g_deviceContext->RSSetViewports(1,&viewPort); 204 205 return TRUE; 206 } 207 208 void Render() 209 { 210 //渲染一个绿色的窗口 211 XMVECTORF32 color = {0.f, 1.f, 0.f, 1.6f}; 212 g_deviceContext->ClearRenderTargetView(g_renderTargetView,reinterpret_cast<float*>(&color)); 213 g_deviceContext->ClearDepthStencilView(g_depthStencilView,D3D11_CLEAR_DEPTH|D3D11_CLEAR_STENCIL,1.f,0); 214 215 //全部的场景绘制工作在这里面进行..... 216 217 //最后显示 218 g_swapChain->Present(0,0); 219 } 220 221 int Run() 222 { 223 MSG msg = {0}; 224 //主消息循环,也是游戏当中的主循环 225 while(msg.message != WM_QUIT) 226 { 227 if(PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE)) 228 { 229 TranslateMessage(&msg); 230 DispatchMessage(&msg); 231 } 232 else 233 { 234 //在这里做该做的事:渲染 235 Render(); 236 } 237 } 238 239 Release(); 240 241 return msg.wParam; 242 } 243 244 void Release() 245 { 246 g_depthStencilView->Release(); 247 g_renderTargetView->Release(); 248 g_swapChain->Release(); 249 g_deviceContext->Release(); 250 g_device->Release(); 251 } 252 253 LRESULT CALLBACK WinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 254 { 255 switch(msg) 256 { 257 case WM_DESTROY: 258 PostQuitMessage(0); 259 return 0; 260 } 261 262 return DefWindowProc(hwnd,msg,wParam,lParam); 263 }
定时器
3D图形学研究的基本内容,即给定场景的描述,包括各个物体的材质、纹理、坐标等,照相机的位置及朝向,光源等信息,计算其最终在二维的光栅化显示器上对应的显示结果。从最初的场景描述到最终的显示结果,这整个过程就是在3D渲染管线中完成的。
空间 空间变换
Model Space 模型空间
世界空间:World Space
视角空间:View Space
投影、裁剪空间:Projection Clip Space
空间变换:
I. 模型、世界空间变换
从模型空间到世界的变换主要包括:缩放、旋转和平移。缩放和旋转操作通过3X3矩阵及可实现,为了实现平移操作,则需要4X4型矩阵,因此所有的空间变换统一采用4X4矩阵,且顶点坐标也采用相应的[x,y,z,w]型。大多数情况下,w=1,[x,y,z]与顶点本身坐标保持一致。此外,多出的w在投影变换中发挥了至关重要的作用。
II. 世界、视角空间变换
从世界空间到视角空间通过相应的“视角矩阵”实现。为了更好的理解视角矩阵的作用,可以这样理解:
在任意时刻,相机在世界空间都有一个位置坐标[Px,Py,Pz],同时也有相应的朝向,我们可以用三个坐标轴来确定其朝向,即U,V,W,U指向相机右侧,V指定相机上侧,W为相机注视方向。那么视角矩阵的作用,即把相机位置移回到世界坐标系原点,且三个坐标轴U,V,W与世界坐标系的X,Y,Z分别重合。这就是视角矩阵的目的!理解这一点对于自己来实现灵活的照相机非常重要,因为实现照相机最重要的一点即根据任意时刻相机的位置、朝向来计算其视角矩阵。
III. 视角、投影空间变换
从视角空间到投影、裁剪空间依靠“投影矩阵”来实现。投影有两种:正交投影和透明投影,大多数情况下,比如游戏中,用到的投影为透视投影,因为这种投影方式与人观察物体的方式是一样的。
要计算投影矩阵,首先要确定照相机的几项基本参数:近、远平面(n,f),投影平面的宽、高比(r),以及上、下视野角度大小(a)。近、远平面规定照相机能看到的最近和最远的距离。有了这些参数,所有能投影到屏幕上的点组成了如下所示的多面体:
关于投影变换,要注意一点的是,很多人误以为投影即把三维顶点投影到二维平面 上,投影变换后顶点的z坐标即被抛弃,只剩下x,y坐标用于后面的屏幕变换。实际上,投影变换后z坐标并没有消失,位于[0,1]之间。屏幕坐标的变换不再使用z坐标,但z坐标在后面的Output Merger阶段用于深度比较时发挥的关键作用。
整个顶点着色阶段到此结束。
三维物体使用三角形网格进行描述,三角形网格是一个三角形的列表这些三角形组成一个与原来物体形状轮廓相似的三维图形。
虚拟相机的可是范围被设置为一个平截台体,它的范围就是摄像机的可视范围。
三维物体在本地坐标系中定义在进行变换时,集合物体首先被变换到一个世界空间中,为了方便进行摄影,裁剪以及其他操作,物体将被变换到视图空间中。视图空间中摄像机处于坐标系的原点,观察方向为z轴的正方向,几何物体被变换到视图空间后,物体将再次被变换到投影窗口中,最后,视口变换敬爱几何物体从投影窗口变换到视口中,最后通过光栅化,计算是所有独立像素点的颜色值,得到一张描述三维世界的二维图片。
不同点 相同点
FVF与d3d11中的Input Layout是类似的
法线 光照模型
实际上,对于一个顶点的坐标变换A,其对应的法线的正确变换是A的逆矩阵的转置,即。
2. 环境光、漫反射光与全反射光
在3D计算机图形学,对光照计算的处理分为三个部分:环境光、漫反射光和全反射光(或称为高光)。
2.1 环境光(Ambient light)
在现实当中,光照是一个很复杂的物理现象。一个物体所接受的光,除了直接来自光源的部分外,还包括光源经过环境中其他各个物体的反射而来的部分。而在图形学中,我们默认的光照模型为局部光模型,即一个顶点的光照计算只跟该点信息与光源信息有关,而不考虑环境中其他物体的影响,比如阴影等。与局部光照模型相对应的全局光照,这属于高级话题,这里暂时不考虑。为了近似地模拟现实当中来自周围环境的光,在图形学中引入的“环境光”这一概念,即“Ambient Light"。
环境光不需要进行特殊的物理计算,即直接将光源中的环境光部分与材质中的环境光部分相乘,其结果适用于物体上的任一顶点。
2.2 漫反射光(Diffuse light)
光照射在物体表面后,其反射光沿随机方向均匀的分布,即"漫反射”。反射光的强度与光照方向与表面法线的夹角theta相关,满足比例关系:I = Io * cos(theta)。由于反射光方向随机,因此该部分的计算与观察点无关,而只与光线方向与法线相关。
2.3 全反射光(Specular light)
光线照射在光滑物体表面后,在特定方向上会有很强的反射,即发生全反射。全反射光主要集中在一个近似圆锥角的范围内。如下图所示:
纹理
为了表示物体与照射在其表面的光的交互作用,我们需要定义其材质。与光源的三个成分相对应,我们对材质了指定相应的环境光部分、漫反射光部分和全反射光部分,这些属性分别代表光的每一部分在其表面的反射比例。此外,还需要指定物体表面的光滑程度,以用于计算全反射。该值越大,全反射光衰减越迅速。
三种点光源类型
在学习光照计算前,需要先了解3D中常见的几种光源模型。主要分为三种,由简单到复杂分别为:平行光、点光源和聚光灯。
4.1 平行光
平行光是最简单的一种模型,这种光照具有单一的照射方向,且光照强度不随空间位置而变化。现实当中的太阳光就可以认为是这种类型。
4.2 点光源
一个具有点光源特性的典型例子是电灯泡。首先该光源在空间具有一个位置,其次它发出的光以球面形式向四周均匀的传播(尽管实际的电灯光在各个方向上并不均匀,我们此外姑且可以这样理解。)。还有一个重要的特性即光强随着与光源的距离的增大而逐渐减小。理论上光强与距离的平方成反比,即I(d) = I0/(d²)。因此在无穷远处光强接近为0;在光源所在处,光强为无穷大。这样显然不适合在计算机中进行处理。于是在3D图形学中,我们对点光源模型有如下定义:用三个系数A0、A1、A2来控制光强随距离的衰减,分别为常量系数、一次系数和二次系数,这样光强计算公式为:I = I0/(A0+A1*d+A2*d²)。其次,对光照范围有一个限制,超过特定范围后,光照强度定义为0。
4.3 聚光灯
与聚光灯最为接近的现实模型为手电筒。该光源在空间具有一个位置,其次还有一个照射方向,以该方向为中心对称地向周围发散一定的角度,这样光线被限制在一个圆锥内,如下图所示:
我们称这个最大的发散角为theta。给定光源位置与照射点位置,从光源到顶点的射线与光源照射方向的夹角如果位于最大发散角之内,则进行光照计算,否则该点不进行计算。与点光源一样,聚光灯光强也随着的距离的增大而减小,衰减方式完全一样。
内存对齐 HLSL c++
下面通过C++的结构体例子来进一步理解。
考虑如下结构:
- struct Test
- {
- char c1;
- int i1;
- };
该结构中char类型的c1满足对齐要求,int型的i1为了满足4字节对齐,则c1和i1之间会空出3个字节的无用空间。因此,该结构大小sizeof(Test)为8,而不是5!
纹理
RGBA
1.1 高度图
这种纹理的每个元素代表一个高度值。一个常见的用途即地形渲染,地形渲染中用到的雏形是一个平面的网格,然后通过读取高度图来获取网格不同位置的高度信息(大多数情况下,对读取到的高度值,会再乘以一定的系数来满足所需的高度范围)。另一个用途是Displacement Mapping,配合曲面细分技术,可以修改物体表面的顶点位置,从而实现表面的凹凸细节。通过D3D11新增的Tessellation Stage来实现Displacement Mapping在以后会有专门的例子。
当然,纹理的用途不仅仅这些。我们需要知道的是,提到纹理,不能仅仅认为它就是一个贴在物体表面的图片。不过,在这篇文章中,作为一个纹理的简介,我们仅仅考虑纹理最常见的一个用途,其他高级纹理技术在我们后面学到时会详细介绍。
关闭光照的情况下,物体表面的颜色值只由纹理决定;在打开光照的情况下,纹理颜色和光照计算结果通过如下公式得出:
finalColor = texColor * (ambient + diffuse) + specular
finalColor.a = texColor.a * g_material.diffuse.a
即纹理颜色与环境光和漫反射光的和相乘,再加上全反射光。最终的alpha值通过纹理alpha值与材质的漫反射部分的alpha值相乘。
- diffuse = mat.diffuse * L.diffuse * diffFactor * att * spotFactor;
- float3 refLight = reflect(-dir,normal);
- //计算高光系数
- float specFactor = pow(max(dot(refLight,toEye),0.f),mat.specular.w);
- //计算高光
- specular = mat.specular * L.specular * specFactor * att * spotFactor;
模板缓冲区