エンジン設計追跡(9.1.14.2 f)最近更新:OpenGL ES&tools

21613 ワード

以前は骨格アニメーションのIKを一時的に放送していたが、最近GLESの実現をしている.以前はGLES以外では実現していませんでしたが、Androidのコード移植は完了しました.
[原]プラットフォーム間プログラミングの注意事項(三):windowからandroidへの移植
総じて前回移植の変更は大きくなく、主にDLLと.so間の調整と適合、C++標準関連のコンパイルエラーもある.パケットのロード/初期化/プロファイルとプラグインのロードテストは利用可能であるが、GLESは実現していないため、前回の移植はホスト上を空回りするしかない.
最近暇な時間にGLESの空白を埋めたいと思って、現在インタフェースの調整の差は多くなくて、GLES runtimeは埋めて実現しています.
 
1.Tile Based Rendering GPUの原理と注意事項を簡単に説明する
  • TBR方式は画面空間をいくつかのTileに分け、各tileは画面より小さい、例えば32 x 32である.
  • TBRは、幾何学的データを画面空間ごとにtileに分割する、各Tileをレンダリングする.幾何学的データは多くのtileにまたがる可能性があるため、常に保存する必要があり、drawcallの幾何学的データが多ければ多いほど、消費メモリが大きくなる.
  • TBRのアーキテクチャは、GPU内部にTileに対する高速メモリ(fast memory、しばらくtile cacheと呼びましょう)があり、アクセス速度が速い.しかし、video memoryは、一般的にはカード搭載の物理的なメモリではなく、システムのホストメモリを用いる、video memoryからcacheへの伝送が比較的遅い.
  • Tile Cacheの存在でdepthとcolorを読み書きするのは速い.これは現代PCのGPUとは違います.TBRのblending、depth write/test、multisampleは遅くない.深さの異なる画素については、着色を繰り返すもTile Cache上でのみ行い、最終的にはvideo memoryに書き込まれる.
  • Tile Cacheからvideo memoryへの移行が遅いため、GLESはInvalidateFrameBufferのhintを提供する、このアーキテクチャではcacheとmemory間の追加の転送を回避することができる.
  • GPUにhidden surface removal特性(PVR GPU)がある場合、GPUはこの幾何学的データを並べ替え、Tile Cache上に見える部分だけを描く、pixel負荷はかなり小さい.したがってappは描画時にsolid物体を距離で並べ替える必要はないが、discard/texkillはその特性を失効させる.失効する場合、またはその特性を持たないGPUについては、early z:従来方式のpre-z passを用いる先書き深さを利用することができる.
  • Tile Based GPUの幾何学的負荷(三角形数)は、現代PCのGPUよりもはるかに低い.現代PCの数百万の三角形は小さい意味であるが、Tile basedはこれらの幾何学的データを保存する必要があり、各tileのレンダリングに使用され、メモリと実行コストが比較的大きい.

  •  
    2.GLESとD 3 Dインタフェースの統一
    レンダリングインタフェースは基本的に類似しており、主にshaderインタフェースで等価に実装されています.
    GL/ESはランタイムlinkプログラムで、彼のshaderは中間オブジェクトです.D 3 Dは、一般にオフラインコンパイル後の運転時に直接ロード.
    GLES 3にはglGetProgramBinaryとglProgramBinaryがあり、コンパイル後のshaderを保存してロードすることができる.しかし、コンパイルと保存はtarget deviceで行う.
    Blade以前のインタフェースはIShader=>D 3 D 9 VertexShader:has a IDirect 3 DVertexShader 9
                                        => D3D9FragementShader : has a IDirect3DPixelShader9 
    現在のインタフェースはshaderタイプを統合し、異なるタイプのshaderオブジェクトではなく、1つのshaderにvsやfsなどのオブジェクトが含まれています.
    IShader => D3D9Shader : has a (IDirect3DVertexShader9 & IDirect3DPixelShader9 )
                => GLESShader : has a gl program
    同時にIRenderDevice::setShader(EShaderType,HSHADER&)をsetShader(HSAHDER&)に変更
    GLSL/ESのshaderは、すべてのuniformとvertex input stream(vertex attribute)にsemanticがありません.ユーザ自身が名前に基づいてバインド設定する必要がある.uniformの場合、Bladeのshader resouceは、WORLD_などのエンジンに組み込まれた変数を更新するためにsemantic mapを追加的に保存するためです.MATRIX, EYE_POSなど、uniformのバインドや更新に問題はありません.
    vertex atributeでは、現在の方法では、これらの変数を固定的な名前で置き換える.例えばHLSLのPOSITION 0、対応するGLSL、その変数名はblade_position0.
    これにより、実行時にglBindAttributeLocationをVBOにバインドすることができる.
     
    3.ツール
    パッケージングツールBPKはすでにあり、runtimeもandroidでテストできます.現在必要なツールはshader compiler,texture compressor.
    shader compilerはHLSL 2 GLSLを使用しています.
    Windowsの下にあるshader compilerについてお話しします.
     
    offline:
    HLSL ==(TexShaderSerializer::load) ==>  D3DSoftwareShader : compiled binary == (BinarySerializer::save) ==> binary shader : with semantic map
    runtime:
    binary shader ==(BinarySerializer::load)==> D3DShader
     
    GLESの下ですでに作ったshader compiler:
    offline:
    HLSL ==(TexShaderSerializer::load) ==> D3DSoftwareShader : compiled binary with HLSL text ==(replace with GLSL)==>
    binary with GLSL text ==(HybridShaderSerializer::save)==> hybird shader : text with binary semnatic map
    runtime:
    hybrid shader ==(HybridShaderSerializer::load)==> GLESShader
     
    GLES 3について.0は、起動時にshader(program)をbinary(一度だけ保存)として保存することで、shaderが後でコンパイルすることなく、ロード速度が大幅に速くなる.これはこれからもやります.
    ( https://software.intel.com/en-us/articles/opengl-es-30-precompiled-shaders )
    GLES 2の拡張はglShaderBinaryであるが,リンク後のprogramではなくリンク前のshaderを保存する.
     
    starting up precompile: once and for all
    hybrid shader ==(HybridShaderSerializer::load)==> GLESShader ==(BinaryShaderSerializer::save) ==> binary shader
    runtime:
    binary shader ==(BinaryShaderSerilizer::load) ==> GLESShader
     
    記録が必要なのは、IShaderはレンダリング装置/APIに関するインターフェースであり、そのインターフェースはfoundation libraryに抽象的に位置し、別のDLL/soで実現する.ShaderResourceとすべてのShaderSerializerは多重化可能であり、プラットフォームには関係ない.Graphics Subsystem全体はプラットフォームに関係なく、具体的なプラットフォームに関する最適化(例えばTile Based)はレンダリングプロファイル(このファイルの例.xmlは以前に記録した)で行う必要があり、Blade::IrenderDevice内部のimplementationで対応する処理を行う.
     
    shader compilerは三方ライブラリを使用しているので、現在は完了しており、GLSL ES 3.0に変換することができ、runtime充填プレイを待つことができ、圧縮テクスチャフォーマットがあればテストできる.
     
    texture compressorは、テクスチャをターゲットプラットフォームに圧縮するために使用されるフォーマットである、ここでBladeはETC 2/EACを使用する予定である.これまでbladeはwindows上でリアルタイム圧縮だったが、海外にあるエンジンを見て、pngでディスクに保存するディスク空間を節約することが主な利点で、pngの圧縮比はS 3 TCより高い.しかし、使用中には、大きなマップに対してはロードがやや遅く、移動端に対してはオンライン圧縮も良い方法ではないことが分かった.以降の方式は、先にオフラインで圧縮するマップに変更され、すべてのプラットフォームがこのようなプレ圧縮方式を統一的に使用する.
     
    texture compresstorなら、最近仕事が忙しくて、余暇があまりありません.手書きする時間もないかもしれませんが、三方庫で圧縮します.まだやっていないので、後でやります.また、ターゲットプラットフォームのデータ生成/パッケージングプロセスを整理する.すなわち、shader compiler,texture compressor,BPK packagerを統合し、最終データのbuild/project scriptを一度に生成する.
    他のゲームデータは、プラットフォームにまたがるように設計されており、理論的にはプラットフォームにまたがるべきであり、追加の処理は必要ない.bladeの既存のx 86およびx 64は、いずれも同じデータまたはBPKパケットである.しかしandroidではデバッグが必要になる可能性があります.
     
    最後に、HLSL以前のuniform semantic解析は、ファイルのコメントに含まれています.
     1 //!BladeShaderHeader
    
     2  2 //![VertexShader]
    
     3  3 //!Entry=TerrainVSMain
    
     4  4 //!Profile=vs_3_0
    
     5  5 //![FragmentShader]
    
     6  6 //!Entry=TerrainPSMain
    
     7  7 //!Profile=ps_3_0
    
     8  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 }

     
    ここで注釈の中の声明を抜き、HLSLのフォーマットに変更しました.以前はD 3 DのEffectがuniformを解析するsemanticをサポートしていたので、このフォーマットは.FXはサポートしていますが、D 3 DCompileを直接使うとエラーが発生します.
    しかし、先日試してみたところ、D 3 DCompileはunformのsemanticに間違いを報告しないで、ただそれを無視しただけです.だからすべてこのフォーマットに変更しました. 
    少しコードを追加して手動でsemanticを解析する必要があります.tokenizerでいいです.
     1 //!BladeShaderHeader
    
     2 //![Shader]
    
     3 //!VSEntry=TerrainVSMain
    
     4 //!VSProfile=vs_3_0
    
     5 //!FSEntry=TerrainPSMain
    
     6 //!FSProfile=ps_3_0
    
     7 
    
     8 #include "inc/light.hlsl"
    
     9 #include "inc/common.hlsl"
    
    10 #include "inc/terrain_common.hlsl"
    
    11 
    
    12 
    
    13 void TerrainVSMain(    
    
    14     float2 hpos        : POSITION0,
    
    15     float2 vpos        : POSITION1,
    
    16     float4 normal    : NORMAL0,        //ubyte4-n normal
    
    17 
    
    18  uniform float4x4 wvp_matrix : WORLD_VIEWPROJ_MATRIX, 19  uniform float4 world_translate : WORLD_POSITION, 20     uniform float4 scaleFactor : _SHADER_,        //per shader custom variable: scale
    
    21     uniform float4 UVInfo : _SHADER_,            //per shader custom variable: uv information
    
    22     
    
    23     out    float4 outPos : POSITION,
    
    24     out    float4 outUV  : TEXCOORD0,
    
    25     out float4 outBlendUV : TEXCOORD1,
    
    26     out float3 outWorldPos : TEXCOORD2,
    
    27     out float3 outWorldNormal : TEXCOORD3
    
    28     )
    
    29 {
    
    30     float4 pos = float4(hpos.x, getMorphHeight(vpos, hpos+world_translate.xz, eye_position.xz), hpos.y, 1);
    
    31     pos = pos*scaleFactor;
    
    32 
    
    33     float blendOffset = UVInfo[0];
    
    34     float tileSize = UVInfo[1];
    
    35     float blockSize = UVInfo[2];
    
    36     float blockUVMultiple = UVInfo[3];
    
    37 
    
    38     //normalUV
    
    39     outUV.xy = pos.xz*(tileSize-1)/(tileSize*tileSize) + 0.5/tileSize;
    
    40     //block repeat UV
    
    41     outUV.zw = pos.xz*blockUVMultiple/blockSize;
    
    42     //blendUV
    
    43     outBlendUV.xy = pos.xz*(tileSize-1)/(tileSize*tileSize) + blendOffset/tileSize;
    
    44     outBlendUV.zw = pos.xz/tileSize;
    
    45 
    
    46     //use local normal as world normal, because our terrain has no rotations
    
    47     outWorldNormal = expand_vector(normal).xyz;    //ubytes4 normal ranges 0-1, need convert to [-1,1]
    
    48     
    
    49     //don't use full transform because our terrain has no scale/rotation
    
    50     outWorldPos = pos.xyz+world_translate.xyz;
    
    51 
    
    52     outPos = mul(pos, wvp_matrix);
    
    53 }

    シェーダー変数についてWORLD_VIEWPORJ_MATRIXはbladeのFX frameworkに内蔵された変数であり,「_SHADER_」このsemanticは、この変数がモジュールのカスタムshader変数であることを示すだけで、frameworkには内蔵されておらず、ユーザモジュール(例の地形モジュールなど)は変数の名前に基づいて、直接変数を設定/更新する必要がある.少なくとも1回の設定が必要である、変化がなければ、その値を更新する必要はない.この変数のCPUデータは、material/FX frameworkによって自動的に変数タイプに応じて割り当てるメモリであり、shader/instance/global shader constant tableに保持する.
     
    後ろに暇があったらETC 2/EACのテクスチャ圧縮をします.現在、移植は相対的に仕事量が少なく、適応と最適化に時間がかかる可能性がある.主にプラットフォームに関係のないcore featureが完備していないので、後で集中してこれらをします.そうしないと移植しても意味がありません.core featureとゲームコードさえあれば、新しいプラットフォームを出してもすぐに似合うはずです.もちろんゲームの工程量とエンジンは1つの数量級ではありませんて、後で人と協力する機会があることを望みます.
     
    GLES 3.0はUBOがあり、これも最適化点である.しかし、UBOのインタフェースは露出しないほうがいいと思います.IrenderDeviceのimplementationの中に置いておくと、constant bufferのないAPIにとって、インタフェースに関心を持たなくてもいいと思います.
    もちろんインタフェースを抽象化することもできるが、サポートされていないAPI(例えばDirect 3 D 9)については、Ogreの配列バッファ方式を越えて最後に一度にコミットすることを前提として、いくつかの方法でシミュレーションすることができる.
    この特性は先に置いて、後でDX 11/DX 12を実現する時、総合的に対照して、インタフェースがどのように抽象的に最も良いかを見ることができます.