• 引擎设计跟踪(九.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>
  • 相关阅读:
    C#与SAP进行数据交互
    自动加减工单结存算法实现
    RDLC报表打印一维码
    调用存储过程通用类
    监听网络状态
    压缩及解压缩文件
    用Go造轮子-管理集群中的配置文件
    2015年总结
    浅析Go语言的Interface机制
    2014年总结
  • 原文地址:https://www.cnblogs.com/crazii/p/3677624.html
Copyright © 2020-2023  润新知