HLSL-高级着色语言简介【转】
HLSL-High Level Shader Language
优点
用来书写Vertex Shader和Pixel Shader程序的代码,语法类似于C/C++,在DirectX 8.x的时代,Shader程序都是用低级Shader汇编语言编写的,姑且称之为LLSL吧,HLSL与之相比具有以下优点:
- 更高的生产力,使用HLSL编程更快更容易,使我们有更多的时间关注与算法而不是编码
- 更好的可读性,使用HLSH编写的程序更易读,易调试及维护
- 编译器将生成更加高效的汇编代码
- 可以将同一份代码编译成任何可用的Shader版本,但是用LLSL则必须按不同版本编写代码
如果你的显卡不支持Shader的话,那么可以使用REF Device模拟,这样可以得到正确的结果,但是速度非常慢
编写Shader代码
你可以将Shader代码写入到你的程序中,但是为了更方便,更模块化,通常将Shader程序放在单独的文件里,比如记事本,然后使用D3DXCompileShaderFromFile函数来编译它,使用记事本写Shader程序可能不太方便,以前微软提供编写Shader的工具,在DirectX SDK当中,但是现在不支持了,大家可以用AMD的RenderMonkey来编写。
一般的Shader程序包含以下几个部分
- 全局变量-viewprojmatrix, color等
- 输入结构和输出结构-VS_INPUT, VS_OUTPUT
- 入口函数-Main, note the name is not mandatory, you can used any valid function name
常量表
每个Shader程序都有一个常量表来存储它的变量。可以用ID3DXConstantTable接口访问长量表,可以设置Shader程序中的全局变量值
实战-一个简单的Shader程序
下面我们就来看看如何编写一个Shader程序,我们还以茶壶为例,看看如何用Shader绘制一个蓝色的茶壶,学习如何用Shader处理颜色,这个例子简单的不能再简单,但是,它确实能反映如何使用Shader。首先用VS建立一个Win32工程,添加必要的框架代码,主要是创建窗口,简单的消息处理以及初始化D3D等,如下
1 #include <d3dx9.h>
2
3 LPDIRECT3D9 g_pD3D = NULL ; // Used to create the D3DDevice
4 LPDIRECT3DDEVICE9 g_pd3dDevice = NULL ; // Our rendering device
5
6 HRESULT InitD3D( HWND hWnd )
7 {
8 // Create the D3D object, which is needed to create the D3DDevice.
9 if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
10 return E_FAIL;
11
12 D3DPRESENT_PARAMETERS d3dpp;
13 ZeroMemory( &d3dpp, sizeof(d3dpp) );
14 d3dpp.Windowed = TRUE;
15 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
16 d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
17
18 // Create device
19 if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
20 D3DCREATE_SOFTWARE_VERTEXPROCESSING,
21 &d3dpp, &g_pd3dDevice ) ) )
22 {
23 return E_FAIL;
24 }
25
26 return S_OK;
27 }
28
29 VOID Cleanup()
30 {
31 if( g_pd3dDevice != NULL)
32 g_pd3dDevice->Release();
33
34 if( g_pD3D != NULL)
35 g_pD3D->Release();
36 }
37
38 VOID Render()
39 {
40 if( NULL == g_pd3dDevice )
41 return;
42
43 // Clear the back-buffer to a RED color
44 g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );
45
46 // Begin the scene
47 if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
48 {
49 // Rendering of scene objects can happen here
50
51 // End the scene
52 g_pd3dDevice->EndScene();
53 }
54
55 // Present the back-buffer contents to the display
56 g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
57 }
58
59 LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
60 {
61 switch( msg )
62 {
63 case WM_KEYDOWN:
64 {
65 switch( wParam )
66 {
67 case VK_ESCAPE:
68 SendMessage( hWnd, WM_CLOSE, 0, 0 );
69 break ;
70 default:
71 break ;
72 }
73 }
74 break ;
75
76 case WM_DESTROY:
77 Cleanup();
78 PostQuitMessage( 0 );
79 return 0;
80 }
81
82 return DefWindowProc( hWnd, msg, wParam, lParam );
83 }
84
85 INT WINAPI wWinMain( HINSTANCE hInst, HINSTANCE, LPWSTR, INT )
86 {
87 // Register the window class
88 WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
89 GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
90 L"D3D Tutorial", NULL };
91 RegisterClassEx( &wc );
92
93 // Create the application's window
94 HWND hWnd = CreateWindow( L"D3D Tutorial", L"D3D Tutorial 01: CreateDevice",
95 WS_OVERLAPPEDWINDOW , 0, 0, 800, 600,
96 NULL, NULL, wc.hInstance, NULL );
97
98 // Initialize Direct3D
99 if( SUCCEEDED( InitD3D( hWnd ) ) )
100 {
101 // Show the window
102 ShowWindow( hWnd, SW_SHOWDEFAULT );
103 UpdateWindow( hWnd );
104
105 // Enter the message loop
106 MSG msg ;
107 ZeroMemory( &msg, sizeof(msg) );
108 PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE );
109
110 while (msg.message != WM_QUIT)
111 {
112 if( PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE) != 0)
113 {
114 TranslateMessage (&msg) ;
115 DispatchMessage (&msg) ;
116 }
117 else // Render the game if no message to process
118 {
119 Render() ;
120 }
121 }
122 }
123
124 UnregisterClass( L"D3D Tutorial", wc.hInstance );
125 return 0;
126 }
然后按照下面的步骤绘制一个茶壶
1.在程序头部添加茶壶对应的全局变量
1 ID3DXMesh* g_pMesh = NULL ;
2.在InitD3D函数尾部(返回语句之前)创建绘制茶壶的代码
1 D3DXCreateTeapot(g_pd3dDevice, &g_pMesh, NULL) ;
2
3. 在Render函数中添加绘制茶壶的代码,位于BeginScene和EndScene之间
1 g_pMesh->DrawSubset(0) ;
4.在Cleanup函数中清除茶壶对应的mesh
1 if(g_pMesh != NULL)
2 g_pMesh->Release() ;
3
下面编写Shader程序,打开记事本,输入如下代码,代码很简单-略加解释,ViewProjMatrix对应是view matrix和projection matrix的乘积,Blue是顶点颜色,input只包含一个信息,顶点位置,output包含两个信息,顶点的位置和颜色,在main函数中,将顶点的位置由local坐标系变换到投影空间,将颜色设置为蓝色,就这么简单。
1
2 matrix ViewProjMatrix;
3 vector Blue = {0.0f, 0.0f, 1.0f, 0.0f} ;
4
5 struct VS_INPUT
6 {
7 vector position : POSITION;
8 };
9
10 struct VS_OUTPUT
11 {
12 vector position : POSITION;
13 vector diffuse : COLOR;
14 };
15
16
17 VS_OUTPUT Main(VS_INPUT input)
18 {
19 VS_OUTPUT output = (VS_OUTPUT)0;
20
21 output.position = mul(input.position, ViewProjMatrix);
22
23 output.diffuse = Blue ;
24
25 return output;
26 }
27
28
回到主程序中,添加全局变量g_pVertexShader用来保存创建的shader
1 IDirect3DVertexShader9* g_pVertexShader = NULL ;
添加全局变量g_pConstantTable用来保存Shader对应的常量表,有了常量表就可以存取和修改shader中的变量
1 ID3DXConstantTable* g_pConstantTable = NULL ;
添加一个变量句柄来存取shader中对应的ViewProjMatrix
1 D3DXHANDLE ViewProjMatrixHanle = 0 ;
添加函数PrepareShader,这个函数负责从文件编译shader,创建shader,设置shader中的变量等
1 bool PrepareShader()
2 {
3 ID3DXBuffer *shader ;
4 ID3DXBuffer *errorBuffer ;
5
6 // Compile shader from file
7 HRESULT hr = D3DXCompileShaderFromFileA("Shader.txt", 0, 0, "Main", "vs_1_1",
8 D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY, &shader, &errorBuffer, &g_pConstantTable) ;
9
10 // error handling
11 // output compile error message
12 if( errorBuffer )
13 {
14 MessageBoxA(0, (char*)errorBuffer->GetBufferPointer(), 0, 0);
15 errorBuffer->Release() ;
16 }
17
18 // compile failed
19 if(FAILED(hr))
20 {
21 MessageBox(0, L"D3DXCompileShaderFromFile() - FAILED", 0, 0);
22 return false;
23 }
24
25 // Create shader
26 hr = g_pd3dDevice->CreateVertexShader((DWORD*)shader->GetBufferPointer(), &g_pVertexShader) ;
27
28 // create failed
29 if(FAILED(hr))
30 {
31 MessageBox(0, L"CreateVertexShader - FAILED", 0, 0);
32 return false;
33 }
34
35 shader->Release() ;
36
37 // map handle to variable in shader
38 ViewProjMatrixHanle = g_pConstantTable->GetConstantByName(0, "ViewProjMatrix") ;
39 }
40
最后一行将shader中的变量ViewProjMatrix与ViewProjMatrixHandle相关联,这样接下来就可以用ViewProjMatrixHandle来存取和设置ViewProjMatrix了。注意,GetConstantByName函数的第二个参数是一个字符串,用来表示要获取的变量名字,这个名字必须与Shader文件中指定的名字一样才行,否则的话不起作用,也就是说Shader文件中一定有一个名为ViewProjectMatrix的变量。
添加函数SetupMatrix
这个函数负责设置view matrix, projection matrix, 并将二者的乘积赋值给shader中的ViewProjMatrix以便完成shader中的运算
1 void SetupMatrix()
2 {
3 // set view
4 D3DXVECTOR3 eyePt(0.0f, 0.0f, -10.0f) ;
5 D3DXVECTOR3 upVec(0.0f, 1.0f, 0.0f) ;
6 D3DXVECTOR3 lookCenter(0.0f, 0.0f, 0.0f) ;
7
8 D3DXMATRIX view ;
9 D3DXMatrixLookAtLH(&view, &eyePt, &lookCenter, &upVec) ;
10
11 // set projection
12 D3DXMATRIX proj ;
13 D3DXMatrixPerspectiveFovLH(&proj, D3DX_PI / 4, 1.0f, 1.0f, 1000.0f) ;
14
15 D3DXMATRIX viewproj = view * proj ;
16 g_pConstantTable->SetMatrix(g_pd3dDevice, ViewProjMatrixHanle, &viewproj) ;
17
18 // this line is mandatory
19 g_pConstantTable->SetDefaults(g_pd3dDevice);
20 }
注意最后一行很重要,他是用来设置常量表中所有变量的默认值的,很多时候如果不加这一句,窗口中将看不到任何东西!还有要在InitD3D函数中禁用光照效果,因为我们是自己设置颜色
1 g_pd3dDevice->SetRenderState( D3DRS_LIGHTING , FALSE );
最后,也是最重要的,在Render函数中设置shader,只有这样,它才能生效
1 g_pd3dDevice->SetVertexShader(g_pVertexShader) ;
程序结束后,在Cleanup函数中清除常量表和shader
1 if(g_pConstantTable != NULL)
2 g_pConstantTable->Release() ;
3
4 if(g_pVertexShader != NULL)
5 g_pVertexShader->Release() ;
6
好了,大功告成,现在编译并运行这个程序,你将看到一个蓝色的茶壶!
完整源代码
1 #include <d3dx9.h>
2
3 LPDIRECT3D9 g_pD3D = NULL ; // Used to create the D3DDevice
4 LPDIRECT3DDEVICE9 g_pd3dDevice = NULL ; // Our rendering device
5 ID3DXMesh* g_pMesh = NULL ; // Hold the teapot
6 IDirect3DVertexShader9* g_pVertexShader = NULL ; // vertext shader
7 ID3DXConstantTable* g_pConstantTable = NULL ; // shader constant table
8
9 // variable handle in shader file
10 D3DXHANDLE ViewProjMatrixHanle = 0 ;
11
12 HRESULT InitD3D( HWND hWnd )
13 {
14 // Create the D3D object, which is needed to create the D3DDevice.
15 if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
16 return E_FAIL;
17
18 D3DPRESENT_PARAMETERS d3dpp;
19 ZeroMemory( &d3dpp, sizeof(d3dpp) );
20 d3dpp.Windowed = TRUE;
21 d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
22 d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
23
24 // Create device
25 if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
26 D3DCREATE_SOFTWARE_VERTEXPROCESSING,
27 &d3dpp, &g_pd3dDevice ) ) )
28 {
29 return E_FAIL;
30 }
31
32 //g_pd3dDevice->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
33 g_pd3dDevice->SetRenderState( D3DRS_LIGHTING , FALSE );
34
35 D3DXCreateTeapot(g_pd3dDevice, &g_pMesh, NULL) ;
36
37 return S_OK;
38 }
39
40 VOID Cleanup()
41 {
42 if( g_pd3dDevice != NULL)
43 g_pd3dDevice->Release();
44
45 if( g_pD3D != NULL)
46 g_pD3D->Release();
47
48 if(g_pMesh != NULL)
49 g_pMesh->Release() ;
50
51 if(g_pConstantTable != NULL)
52 g_pConstantTable->Release() ;
53
54 if(g_pVertexShader != NULL)
55 g_pVertexShader->Release() ;
56 }
57
58 bool PrepareShader()
59 {
60 ID3DXBuffer *shader ;
61 ID3DXBuffer *errorBuffer ;
62
63 // Compile shader from file
64 HRESULT hr = D3DXCompileShaderFromFileA("Shader.txt", 0, 0, "Main", "vs_1_1",
65 D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY, &shader, &errorBuffer, &g_pConstantTable) ;
66
67 // error handling
68 // output compile error message
69 if( errorBuffer )
70 {
71 MessageBoxA(0, (char*)errorBuffer->GetBufferPointer(), 0, 0);
72 errorBuffer->Release() ;
73 }
74
75 // compile failed
76 if(FAILED(hr))
77 {
78 MessageBox(0, L"D3DXCompileShaderFromFile() - FAILED", 0, 0);
79 return false;
80 }
81
82 // Create shader
83 hr = g_pd3dDevice->CreateVertexShader((DWORD*)shader->GetBufferPointer(), &g_pVertexShader) ;
84
85 // create failed
86 if(FAILED(hr))
87 {
88 MessageBox(0, L"CreateVertexShader - FAILED", 0, 0);
89 return false;
90 }
91
92 shader->Release() ;
93
94 // map handle to variable in shader
95 ViewProjMatrixHanle = g_pConstantTable->GetConstantByName(0, "ViewProjMatrix") ;
96 }
97
98 void SetupMatrix()
99 {
100 // set view
101 D3DXVECTOR3 eyePt(0.0f, 0.0f, -10.0f) ;
102 D3DXVECTOR3 upVec(0.0f, 1.0f, 0.0f) ;
103 D3DXVECTOR3 lookCenter(0.0f, 0.0f, 0.0f) ;
104
105 D3DXMATRIX view ;
106 D3DXMatrixLookAtLH(&view, &eyePt, &lookCenter, &upVec) ;
107
108 // set projection
109 D3DXMATRIX proj ;
110 D3DXMatrixPerspectiveFovLH(&proj, D3DX_PI / 4, 1.0f, 1.0f, 1000.0f) ;
111
112 D3DXMATRIX viewproj = view * proj ;
113 g_pConstantTable->SetMatrix(g_pd3dDevice, ViewProjMatrixHanle, &viewproj) ;
114
115 // this line is mandatory
116 g_pConstantTable->SetDefaults(g_pd3dDevice);
117 }
118
119 VOID Render()
120 {
121 if(!PrepareShader())
122 return ;
123
124 SetupMatrix() ;
125
126 // Clear the back-buffer to a RED color
127 g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );
128
129 // Begin the scene
130 if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
131 {
132 // Rendering of scene objects can happen here
133 g_pd3dDevice->SetVertexShader(g_pVertexShader) ;
134
135 g_pMesh->DrawSubset(0) ;
136 // End the scene
137 g_pd3dDevice->EndScene();
138 }
139
140 // Present the back-buffer contents to the display
141 g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
142 }
143
144 LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
145 {
146 switch( msg )
147 {
148 case WM_KEYDOWN:
149 {
150 switch( wParam )
151 {
152 case VK_ESCAPE:
153 SendMessage( hWnd, WM_CLOSE, 0, 0 );
154 break ;
155 default:
156 break ;
157 }
158 }
159 break ;
160
161 case WM_DESTROY:
162 Cleanup();
163 PostQuitMessage( 0 );
164 return 0;
165 }
166
167 return DefWindowProc( hWnd, msg, wParam, lParam );
168 }
169
170 INT WINAPI wWinMain( HINSTANCE hInst, HINSTANCE, LPWSTR, INT )
171 {
172 // Register the window class
173 WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
174 GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
175 L"D3D Tutorial", NULL };
176 RegisterClassEx( &wc );
177
178 // Create the application's window
179 HWND hWnd = CreateWindow( L"D3D Tutorial", L"Simple shader",
180 WS_OVERLAPPEDWINDOW , 0, 0, 600, 600,
181 NULL, NULL, wc.hInstance, NULL );
182
183 // Initialize Direct3D
184 if( SUCCEEDED( InitD3D( hWnd ) ) )
185 {
186 // Show the window
187 ShowWindow( hWnd, SW_SHOWDEFAULT );
188 UpdateWindow( hWnd );
189
190 // Enter the message loop
191 MSG msg ;
192 ZeroMemory( &msg, sizeof(msg) );
193 PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE );
194
195 while (msg.message != WM_QUIT)
196 {
197 if( PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE) != 0)
198 {
199 TranslateMessage (&msg) ;
200 DispatchMessage (&msg) ;
201 }
202 else // Render the game if no message to process
203 {
204 Render() ;
205 }
206 }
207 }
208
209 UnregisterClass( L"D3D Tutorial", wc.hInstance );
210 return 0;
211 }
212
213
214
215
happy coding!
HLSL-高级着色语言简介【转】的更多相关文章
- DirectX9:高级着色语言(HLSL)
一.简介 高级着色语言(High)可以编写顶点着色器和像素着色器,取代固定功能流水线中的部分功能,在图形卡的GPU(Graphics Processing Unit,图形处理单元)中执行 注意:如果图 ...
- 有关OpenGL着色语言(一)
刚接触OpenGL着色语言...,不定期增加内容 1.OpenGL着色语言(GLSL)是什么? 用于OpenGL的面向过程的高级着色语言,是近年来图形编程领域中出现的最重要的新型开发技术,使用Open ...
- Obj模型功能完善(物体材质,光照,法线贴图).Cg着色语言+OpenTK+F#实现.
这篇文章给大家讲Obj模型里一些基本功能的完善,包含Cg着色语言,矩阵转换,光照,多重纹理,法线贴图的运用. 在上篇中,我们用GLSL实现了基本的phong光照,这里用Cg着色语言来实现另一钟Blin ...
- WPF 像素着色器入门:使用 Shazzam Shader Editor 编写 HLSL 像素着色器代码
原文:WPF 像素着色器入门:使用 Shazzam Shader Editor 编写 HLSL 像素着色器代码 HLSL,High Level Shader Language,高级着色器语言,是 Di ...
- 计算机程序和C++语言简介
C++程序设计 第一章 计算机程序和C++语言简介 1.计算机是一台能够存储并处理数据的电子设备,包含硬件和软件两部分. 2.计算机硬件由: 1)中央处理单元(Central Processing U ...
- GO 语言简介(网摘)
GO 语言简介 原文出处:[陈皓 coolshell] Hello World 文件名 HELLO.GO package main //声明本文件的package名 import "fmt& ...
- 第一章 Python程序语言简介
第一节 Python概述 1. 什么是Python Python是一种 解释型.面向对象.动态数据类型 的高级程序设计语言.由Guido van Rossum与1989年发明,第一个公开发行版本发行于 ...
- Python 语言简介
Python是一种计算机程序设计语言.你可能已经听说过很多种流行的编程语言,比如非常难学的C语言,非常流行的Java语言,适合初学者的Basic语言,适合网页编程的JavaScript语言等等. 那P ...
- Go 语言简介(下)— 特性
希望你看到这篇文章的时候还是在公交车和地铁上正在上下班的时间,我希望我的这篇文章可以让你利用这段时间了解一门语言.当然,希望你不会因为看我的文章而错过站.呵呵. 如果你还不了解Go语言的语法,还请你移 ...
随机推荐
- SVN客户端的安装和使用
----------------------siwuxie095 SVN 客户端的安装 1.SVN 客户端,选择 TortoiseSVN,下载链接: https://tortoisesvn.net/d ...
- Apache Cordova vs Adobe PhoneGap: the differences and which one to use
http://www.makehybridapps.com/2014/06/09/cordova-vs-phonegap-the-differences-and-which-one-to-use/
- instanceof用法及本质:
import static java.lang.System.*; public class InstanceofTest{ public static void main(String[] args ...
- iOS.ObjC.Basic-Knowledge
1. ObjC的基础 2. ObjC2.0中的编译指令 3. ObjC Runtime 4. ObjC Object Model 5. ObjC的新语法 6. FQA 1. ObjC的基础 2. Ob ...
- python编辑excel
转: http://www.cnblogs.com/lhj588/archive/2012/01/06/2314181.html
- Alluxio/Tachyon如何发挥lineage的作用?
在Spark的RDD中引入过lineage这一概念.指的是RDD之间的依赖.而Alluxio则使用lineage来表示文件之间的依赖.在代码层面,指的是fileID之间的依赖. 代码中的注释指出: * ...
- 我的UI启蒙之路
为什么叫UI启蒙之路呢? 我没有学过美术,也不懂设计,但是有的时候也许就是一种命中注定吧,让我知道了UI,并且一发不可收拾的爱上了它. 具体情况是这样的: 我毕业于电力学校,是一名不折不扣的工科生,专 ...
- laravel使用$errors提取错误信息
1.控制器 2.模板
- Laravel 5.4+Vue.js 初体验:Laravel下配置运行Vue.js
生产材料PHP:PHP 5.6+Laravel 5.4:https://github.com/laravel/laravel/releases/Composer:http://getcomposer. ...
- 低配NOSQL
东西写的太简单了 都不好意思说是NOSQL 其实就是STL 的map容器记录了写入的信息 解析了下数据仅此. 分析的时候想了很多 比如学习redis的自写hash,动态调整hash表容量. 比如右值或 ...