引擎設計跟蹤(九.12) 圖形系統設計


Blade引擎的shader/FX系統

相對來說非常簡單,使用XML定義材質:technique、pass,包含renderstates和自定義的semantic 。shader目前用hlsl,受到doxygen的啟發,將引擎自定義的部分寫在注釋部分,這樣可以保證hlsl可以不做任何預處理而被正常編譯。注釋部分(//!)會被單獨提取出來作為一個ini被parse。貼一個VS的sample吧。

 1 //!BladeShaderHeader
 2 //![VertexShader]
 3 //!Entry=TerrainVSMain
 4 //!Profile=vs_3_0
 5 //![FragmentShader]
 6 //!Entry=TerrainPSMain
 7 //!Profile=ps_3_0
 8 
 9 #include "inc/light.hlsl"
10 #include "inc/common.hlsl"
11 #include "inc/terrain_common.hlsl"
12 
13 //![Semantics]
14 //!wvp_matrix = WORLD_VIEWPROJ_MATRIX
15 //!world_translate = WORLD_POSITION
16 
17 
18 void TerrainVSMain(    
19     float2 hpos        : POSITION0,
20     float2 vpos        : POSITION1,
21     float4 normal    : NORMAL0,        //ubyte4-n normal
22 
23     uniform float4x4 wvp_matrix,
24     uniform float4 world_translate,
25     uniform float4 scaleFactor,        //scale
26     uniform float4 UVInfo,            //uv information
27     
28     out    float4 outPos : POSITION,
29     out    float4 outUV  : TEXCOORD0,
30     out float4 outBlendUV : TEXCOORD1,
31     out float3 outWorldPos : TEXCOORD2,
32     out float3 outWorldNormal : TEXCOORD3
33     )
34 {
35     float4 pos = float4(hpos.x, getMorphHeight(vpos, hpos+world_translate.xz, eye_position.xz), hpos.y, 1);
36     pos = pos*scaleFactor;
37 
38     float blendOffset = UVInfo[0];
39     float tileSize = UVInfo[1];
40     float blockSize = UVInfo[2];
41     float blockUVMultiple = UVInfo[3];
42 
43     //normalUV
44     outUV.xy = pos.xz*(tileSize-1)/(tileSize*tileSize) + 0.5/tileSize;
45     //block repeat UV
46     outUV.zw = pos.xz*blockUVMultiple/blockSize;
47     //blendUV
48     outBlendUV.xy = pos.xz*(tileSize-1)/(tileSize*tileSize) + blendOffset/tileSize;
49     outBlendUV.zw = pos.xz/tileSize;
50 
51     //use local normal as world normal, because our terrain has no scale/rotations
52     outWorldNormal = expand_vector(normal).xyz;    //ubytes4 normal ranges 0-1, need convert to [-1,1]
53     
54     //don't use full transform because our terrain has no scale/rotation
55     outWorldPos = pos.xyz+world_translate.xyz;
56 
57     outPos = mul(pos, wvp_matrix);
58 }

 

目前支持自定義的semantic,不支持annotation。由於沒有使用d3dx的FX框架,而dx9的shader不支持自定義的senmatic,所以沒有使用DX11的風格,而是寫在注釋里。senmatic可以寫在shader注釋里面,也可以寫在材質腳本(XML)里面,兩種都可以。

 

關於shader cosntant的優化。很早在OpenGPU提問過。首先shader constant可以分為global和per-instance。
global的就是在同一幀中不會變化的,比如light(DS),camera pos,view和projection, time 等等。

per-instance的通常是跟每個對象有關,比如world matrix, world_view_projection, instance color等等。

對於DX和GL, 對於所有的shader, 可以將global constant都使用相同的寄存器來保存,比如(c0), 這樣在同一幀, 這些數據只需要更新一次。由於使用相同的寄存器,同一幀內后續的繪制不需要更新這些變量。

不過目前好像GLES2.0還不支持指定寄存器索引。

這種方式Blade還沒有使用,后期優化會考慮,一開始已經將這兩種變量類型的update分開,所以優化起來不難。

另外DX9也可以一次性更新一組變量,以減少SetShaderConstant的調用次數, 比如OGRE中就有,不過Blade還沒有做。這個應該不算太難,只要render device(引擎的render API抽象層)內部維護一個CPU constant array,用來批量update就可以了。猜測與DX11相差應該不大。比如DX11可能使用兩個或者多個constant buffer,將同一幀內頻繁修改的cbuffer與不頻繁的分開。由於還沒用過dx11,所以不瞎猜了。

 

渲染管線(render pipeline)與空間管理(space management)

既然提到render API抽象層,再簡單說下引擎的graphics system的組織。由於細節太多,就簡單說一下。

 

render device (render API abstraction:dx9,dx11,gl,gles)

  |                 

  |                 

render piple line (FX framework, render queue)         ----           camera、view      ----  space (scene management/ space partition)

 

render device 是對渲染狀態設置和draw call的抽象,它與render target、texture, vertex、index buffer, shader等組成了render API抽象層。這層抽象位於foundation library,只有抽象,有專門的device library來實現對應的API。

 

space主要負責圖形scene management、culling,通過預定義的接口,可以有具體的實現方案。比如可以是quadtree,octree, 也可以是no space partition(最簡模式),甚至(partition+)Software Occlusion。

 

render pipline 主要是渲染的組織,FX框架的runtime 和 render queue的sorting等,包含了各種phase,每個phase可以有自己的input buffer和output buffer。

借鑒了nebula引擎,一個pipeline是可配置的,下面是forward shading 的配置。目前pipeline runtime和配置系統還不完善。

使用配置文件的目的是保證管線足夠靈活,並且期望其支持FS、DS、DL, 並能方便集成各種PostEffect等等。

  1 <?xml version="1.0" encoding="utf-8"?> 
  2  
  3 <!-- technique is the technique name for all render types' materials -->
  4 <render_scheme name="Forward Shading" technique="default" >
  5 
  6     <!-- render buffer definition, the default final output is not needed, as it is controlled by program -->
  7     <!-- pre-defined buffers are "FINAL", "EMPTY" -->
  8     <render_buffers>
  9         <!-- FINAL color buffer : the final buffer created by app. it doesn't have any depthstencil buffer attached -->
 10         <!--
 11             attributes:
 12             width/height: set the target dimension. example "1280" or "50%" or "50%+256".
 13                             "P%" means the dimension is decided relatively to the size of final buffer.
 14             format:       the pixel format that to be used.
 15             type:           buffer type: either to be "color" or "depth"
 16             access:       graphics device access. could be "read", "write", or "read_write"
 17             
 18         -->
 19         <buffer name="depth_buffer" width="100%" height="100%" type="depth" format="D24S8" />
 20     </render_buffers>
 21     
 22     <!-- types definition -->
 23     <render_types>
 24         <type name="Terrain"/>
 25         <type name="Static Mesh"/>
 26         <type name="Skinned Mesh"/>
 27         <type name="Atmosphere"/>
 28         <type name="Effect"/>
 29     <type name="AABB"/>
 30     <type name="Gizmo Helper"/>
 31     </render_types>
 32     
 33     <!-- pre-z pass -->
 34     
 35     <!-- shadow pass -->
 36 
 37     <!-- foward pass -->
 38     <render_output name="Forward Shading" target="FINAL" target_depth="depth_buffer" enable="true" >
 39     
 40         <!-- view definition available options are :
 41         reference = 
 42         "FINAL" - use the app specific view,
 43         "NONE" - default value. use a new view object , with its default values already being set properly
 44         
 45         or create new view with attributes as follows
 46         <view [reference="NONE"] left="10+20T" top="5+10%" right="20+10%" bottom="100%">
 47             <clear color="NONE / (0,0,0,0)" depth="NONE / 1.0f" stencil="NONE / <uint16_val>" />
 48         </view>
 49         -->
 50         <view reference="FINAL" />
 51         
 52         <!-- camera definition 
 53         "reference" options  are:
 54         "MAIN" - use the app speicified main camera
 55         "MAIN_LIGHT" - use the main directional light bounded camera
 56         "$NAME" - use the camera which has the name "$NAME", created by app
 57     unlike view object, camera must have a reference, to use the reference camera's space geometry data (rotation/position)
 58     but it can be customized.
 59 
 60     attributes:
 61     custom:       enable customized attributes. use "disable" to disable the following custom attributes, "enable" to enable them. default value: "disable"
 62     custom attributes:
 63     type:         projection mode. PERSPECTIVE/ORTHOGRAPHIC. default value: same as referenced target.
 64     near/far:     near/far clip plane. default value: same as referenced target.
 65     horiz_fov:    horizontal field of view. default vallue: same as referenced target.
 66     aspect:       aspect ratio. default vallue: same as referenced target.
 67     width/height: project size in orthographic mode. P% means using value relative view' width/height.
 68                   "default" of width/height equals 100%. default vallue: same as referenced target.
 69 
 70     note: custom camera params does not affect scene/space culling, it is just used for rendering only
 71     example:
 72         <camera reference="MAIN" custom="enable/disable" static="disable" type="PERSPECTIVE" horiz_fov="90" /> 
 73         
 74         -->
 75         <camera reference="MAIN" />
 76     
 77         <render_step type="Atmosphere" enable="true" pass="default" />
 78 
 79         <render_step type="Terrain" enable="true" pass="default" />
 80 
 81         <render_step type="Static Mesh" enable="true" pass="default" />
 82         
 83         <render_step type="Effect" enable="true" pass="default"/>
 84 
 85         <render_step type="AABB" enable="true" pass="default"/>
 86 
 87         <render_step type="Gizmo Helper" enable="true" pass="default" />
 88     </render_output>
 89 
 90   <!-- !if you want draw a single object, 
 91   then you'd better put the object and the referenced camera into a separated space,
 92   so that this object will not be affetcting or affected by the rest of the entire scene -->
 93   
 94   <!-- !important: better to put 2D objects in a spearated space -->
 95   <render_output name="2D" target="FINAL" target_depth="depth_buffer" enable="true" >
 96     
 97     <view reference="NONE">
 98       <!-- default value for clear: no clear - color=”NONE“, depth="NONE" -->
 99       <clear/>
100     </view>
101 
102     <camera type="ORTHOGRAPHIC" custom="enable" near="0.1" far="1000" />
103   </render_output>
104     
105 </render_scheme>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM