ケース スタディの性能の異なるデバイス間でスケーリング DatascapeCase study - Scaling Datascape across devices with different performance

Datascape は、社内で開発されたマイクロソフトの地形のデータの上に気象データを表示する処理に重点を置いた Windows Mixed Reality アプリケーションです。Datascape is a Windows Mixed Reality application developed internally at Microsoft where we focused on displaying weather data on top of terrain data. アプリケーションは、holographic のデータの視覚化を持つユーザーで囲むと、複合現実でデータを検出からのユーザーが独自の洞察を説明します。The application explores the unique insights users gain from discovering data in mixed reality by surrounding the user with holographic data visualization.

Datascape まで Windows Mixed Reality のイマーシブ ヘッドセットを Microsoft HoloLens とハイエンド GPU を搭載した最新の Pc に低電力の Pc から別のハードウェア機能を備えたさまざまなプラットフォームを対象とする場合。For Datascape we wanted to target a variety of platforms with different hardware capabilities ranging from Microsoft HoloLens to Windows Mixed Reality immersive headsets, and from lower-powered PCs to the very latest PCs with high-end GPU. 主な課題は、高のフレーム レートでの実行中に視覚に訴える必要に応じてまったく異なるグラフィックス機能を備えたデバイス上で、シーンを表示でした。The main challenge was rendering our scene in a visually appealing matter on devices with wildly different graphics capabilities while executing at a high framerate.

このケース スタディは、プロセスおよびより多くの GPU 集中システムが発生しました。 問題とその克服する方法を説明するを作成するために使用する手法について説明します。This case study will walk through the process and techniques used to create some of our more GPU-intensive systems, describing the problems we encountered and how we overcame them.

透明度を描画できますとTransparency and overdraw

透過性は、GPU で高価なできるため、メインのレンダリングの問題は、透明度を処理します。Our main rendering struggles dealt with transparency, since transparency can be expensive on a GPU.

ソリッド ジオメトリには、そのピクセルは破棄されてからの背後にある将来の (ピクセル) を停止、深度バッファーへの書き込み中にバックアップする前を表示できます。Solid geometry can be rendered front to back while writing to the depth buffer, stopping any future pixels located behind that pixel from being discarded. これは非表示のピクセルがピクセル シェーダーは、プロセスを大幅に高速化を実行することを防ぎます。This prevents hidden pixels from executing the pixel shader, speeding up the process significantly. Geometry が最適に並べ替えられる場合、画面上の各ピクセルは 1 回だけ描画されます。If geometry is sorted optimally, each pixel on the screen will be drawn only once.

並べ替えられるジオメトリの透過的なニーズの前面にバックアップし、描画画面上の現在のピクセルをピクセル シェーダーの出力に依存しています。Transparent geometry needs to be sorted back to front and relies on blending the output of the pixel shader to the current pixel on the screen. これは、結果、描画されているを複数回描画できますと呼ばれる、フレームごとに、画面上の各ピクセル。This can result in each pixel on the screen being drawn to multiple times per frame, referred to as overdraw.

HoloLens とメインの Pc では、画面のみ入力できる回数は、いくつか問題のあるレンダリング透過的です。For HoloLens and mainstream PCs, the screen can only be filled a handful of times, making transparent rendering problematic.

Datascape シーンのコンポーネントの概要Introduction to Datascape scene components

今回のシーンを 3 つの主要なコンポーネントがありましたUI マップ、および気象します。We had three major components to our scene; the UI, the map, and the weather. わかって早い段階で、UI と、アルファブレンディングを削減する方法で地形を意図的に設計するために、天気の効果ができる、すべての GPU 時間に必要なことです。We knew early on that our weather effects would require all the GPU time it could get, so we purposely designed the UI and terrain in a way that would reduce any overdraw.

UI を複数回に手直しを最小限に抑えるの量に描画できますが生成されます。We reworked the UI several times to minimize the amount of overdraw it would produce. 発光ボタンとマップの概要などのコンポーネントの互いの上にオーバーレイの透明なアートではなくより複雑なジオメトリの横にあるであったします。We erred on the side of more complex geometry rather than overlaying transparent art on top of each other for components like glowing buttons and map overviews.

マップのカスタムのシェーダーは影や複雑なライティングなどの標準の Unity 機能を削除する単純な単一 sun の照明モデルとカスタム霧計算で置き換えることを使用します。For the map, we used a custom shader that would strip out standard Unity features such as shadows and complex lighting, replacing them with a simple single sun lighting model and a custom fog calculation. これは、簡単なピクセル シェーダーを作成し、GPU のサイクルを解放します。This produced a simple pixel shader and free up GPU cycles.

取得する、UI と、マップの表示に予算が不要だった; ハードウェアに応じてそれらへの変更の管理ただし、特にクラウド レンダリング、天気、視覚エフェクトは大きな課題であることが!We managed to get both the UI and the map to rendering at budget where we did not need any changes to them depending on the hardware; however, the weather visualization, in particular the cloud rendering, proved to be more of a challenge!

クラウドのデータの背景Background on cloud data

NOAA サーバーからダウンロードされたクラウド データ (http://nomads.ncep.noaa.gov/) 3 つの独立した 2D 層で、それぞれ、グリッドのセルごとに、クラウドの密度と同様に、クラウドの上端と下端の高さに付属していたとします。Our cloud data was downloaded from NOAA servers (http://nomads.ncep.noaa.gov/) and came to us in three distinct 2D layers, each with the top and bottom height of the cloud, as well as the density of the cloud for each cell of the grid. データは、GPU 上で簡単にアクセスのテクスチャの赤、緑、および青のコンポーネントで各コンポーネントが格納されているクラウド情報テクスチャに処理があります。The data got processed into a cloud info texture where each component was stored in the red, green, and blue component of the texture for easy access on the GPU.

ジオメトリのクラウドGeometry clouds

低電力コンピューターで開始することにしました、クラウドを表示できるかどうかを確認するには、を最小限に抑えるソリッド ジオメトリを使用するアプローチを描画できます。To make sure our lower-powered machines could render our clouds we decided to start with an approach that would use solid geometry to minimize overdraw.

クラウド情報テクスチャ頂点ごとの radius を使用して、図形を生成する各レイヤーの solid 高さマップのメッシュを生成することによってクラウドの作成を最初にしようとしました。We first tried producing clouds by generating a solid heightmap mesh for each layer using the radius of the cloud info texture per vertex to generate the shape. ジオメトリ シェーダーは、両方にしっかりとしたクラウドの図形を生成する、クラウドの上下の頂点を生成するために使用しました。We used a geometry shader to produce the vertices both at the top and the bottom of the cloud generating solid cloud shapes. 暗い色の詳細の密度の高いクラウドでのクラウドの色、テクスチャから density の値を使用しました。We used the density value from the texture to color the cloud with darker colors for more dense clouds.

頂点を作成するためのシェーダー:Shader for creating the vertices:

v2g vert (appdata v)
{
    v2g o;
    o.height = tex2Dlod(_MainTex, float4(v.uv, 0, 0)).x;
    o.vertex = v.vertex;
    return o;
}
 
g2f GetOutput(v2g input, float heightDirection)
{
    g2f ret;
    float4 newBaseVert = input.vertex;
    newBaseVert.y += input.height * heightDirection * _HeigthScale;
    ret.vertex = UnityObjectToClipPos(newBaseVert);
    ret.height = input.height;
    return ret;
}
 
[maxvertexcount(6)]
void geo(triangle v2g p[3], inout TriangleStream<g2f> triStream)
{
    float heightTotal = p[0].height + p[1].height + p[2].height;
    if (heightTotal > 0)
    {
        triStream.Append(GetOutput(p[0], 1));
        triStream.Append(GetOutput(p[1], 1));
        triStream.Append(GetOutput(p[2], 1));
 
        triStream.RestartStrip();
 
        triStream.Append(GetOutput(p[2], -1));
        triStream.Append(GetOutput(p[1], -1));
        triStream.Append(GetOutput(p[0], -1));
    }
}
fixed4 frag (g2f i) : SV_Target
{
    clip(i.height - 0.1f);
 
    float3 finalColor = lerp(_LowColor, _HighColor, i.height);
    return float4(finalColor, 1);
}

実際のデータの上に詳細情報を表示する小さなノイズ パターンが導入されています。We introduced a small noise pattern to get more detail on top of the real data. Round クラウドの端を生成するためにクリップ ピクセル ピクセル シェーダー補間の半径の値をゼロに近い値を破棄のしきい値にヒットしたとき。To produce round cloud edges, we clipped the pixels in the pixel shader when the interpolated radius value hit a threshold to discard near-zero values.

ジオメトリのクラウド

クラウドは、信頼性の高い geometry であるため、地形のフレーム レートをさらに向上させるために下にある高価なマップ (ピクセル) を非表示にする前に、表示できます。Since the clouds are solid geometry, they can be rendered before the terrain to hide any expensive map pixels underneath to further improve framerate. このソリューションは、ソリッド ジオメトリのレンダリング方法が原因と、HoloLens、ハイエンドなグラフィックス カードに min 仕様からすべてのグラフィックス カードでもを実行します。This solution ran well on all graphics cards from min-spec to high-end graphics cards, as well as on HoloLens, because of the solid geometry rendering approach.

Solid パーティクル クラウドSolid particle clouds

今すぐ、当社のクラウド データの適切な表現を生成し、"wow"要素で少し悩みの種でしたが、ハイエンドのマシンに帯域幅消費型の外観は与えられませんでしたするバックアップ ソリューションがありました。We now had a backup solution that produced a decent representation of our cloud data, but was a bit lackluster in the “wow” factor and did not convey the volumetric feel that we wanted for our high-end machines.

次の手順をより自然で帯域幅消費型の参照を生成するために約 10万台のパーティクルを表すことによって、クラウドの作成されました。Our next step was creating the clouds by representing them with approximately 100,000 particles to produce a more organic and volumetric look.

パーティクルが常に純前から後ろを並べ替える場合引き続き利用できるレンダリングされた以前のパーティクルの背後にあるピクセルの深度バッファー カリング、アルファブレンディングを減らすこと。If particles stay solid and sort front-to-back, we can still benefit from depth buffer culling of the pixels behind previously rendered particles, reducing the overdraw. また、パーティクル ベースのソリューションでは、別のハードウェアをターゲットに使用されるパーティクルの量を変更しましたできます。Also, with a particle-based solution, we can alter the amount of particles used to target different hardware. ただし、すべてのピクセルでは、深度テスト、追加のオーバーヘッドで結果にする必要があります。However, all pixels still need to be depth tested, which results in some additional overhead.

最初の起動時に、エクスペリエンスの中心点を中心粒子の位置を作成します。First, we created particle positions around the center point of the experience at startup. 密度を中心パーティクルを配布しましたの距離は小さいためです。We distributed the particles more densely around the center and less so in the distance. 最も近いパーティクルは最初に表示されるように、センターからのすべてのパーティクルを背面へ移動事前並べ替えます。We pre-sorted all particles from the center to the back so that the closest particles would render first.

計算シェーダーに適切な高さと、密度をに基づいて色を各粒子の位置にクラウド情報テクスチャ サンプリングを行います。A compute shader would sample the cloud info texture to position each particle at a correct height and color it based on the density.

使用してDrawProceduralパーティクル データの GPU 上で常にすべてのパーティクルごとのクアッドを表示するためにタイムアウトします。We used DrawProcedural to render a quad per particle allowing the particle data to stay on the GPU at all times.

各パーティクルには、半径と高さの両方が含まれています。Each particle contained both a height and a radius. 高さは、クラウドのデータをクラウド情報テクスチャからサンプリングに基づきますが、半径は、その最も近い隣接ノードを水平方向の距離を格納する計算は最初の配布に基づいていた。The height was based on the cloud data sampled from the cloud info texture, and the radius was based on the initial distribution where it would be calculated to store the horizontal distance to its closest neighbor. このデータ、四角形は自体とユーザーから見ても水平方向にように高さによって角度の回転を使用して、高さに表示されるとその近隣ノード間の領域を対象には、上から下にあるユーザーを検索する場合。The quads would use this data to orient itself angled by the height so that when users look at it horizontally, the height would be shown, and when users looked at it top-down, the area between its neighbors would be covered.

パーティクルの図形

シェーダーの分布を示すコード。Shader code showing the distribution:

ComputeBuffer cloudPointBuffer = new ComputeBuffer(6, quadPointsStride);
cloudPointBuffer.SetData(new[]
{
    new Vector2(-.5f, .5f),
    new Vector2(.5f, .5f),
    new Vector2(.5f, -.5f),
    new Vector2(.5f, -.5f),
    new Vector2(-.5f, -.5f),
    new Vector2(-.5f, .5f)
});
 
StructuredBuffer<float2> quadPoints;
StructuredBuffer<float3> particlePositions;
v2f vert(uint id : SV_VertexID, uint inst : SV_InstanceID)
{
    // Find the center of the quad, from local to world space
    float4 centerPoint = mul(unity_ObjectToWorld, float4(particlePositions[inst], 1));
 
    // Calculate y offset for each quad point
    float3 cameraForward = normalize(centerPoint - _WorldSpaceCameraPos);
    float y = dot(quadPoints[id].xy, cameraForward.xz);
 
    // Read out the particle data
    float radius = ...;
    float height = ...;
 
    // Set the position of the vert
    float4 finalPos = centerPoint + float4(quadPoints[id].x, y * height, quadPoints[id].y, 0) * radius;
    o.pos = mul(UNITY_MATRIX_VP, float4(finalPos.xyz, 1));
    o.uv = quadPoints[id].xy + 0.5;
 
    return o;
}

背面へ--正面にあるパーティクルを並べ替えて、クリップ (blend ではない) の透明なピクセル solid スタイル シェーダーを引き続き使用しましたので、この手法は驚くほどパーティクル、低電力コンピューター上であってもコストがかかるの過剰な描画を回避するを処理します。Since we sort the particles front-to-back and we still used a solid style shader to clip (not blend) transparent pixels, this technique handles a surprising amount of particles, avoiding costly over-draw even on the lower-powered machines.

透過的なパーティクルのクラウドTransparent particle clouds

Solid のパーティクルを適切な動きが、クラウドの図形にはまだクラウドの fluffiness を販売するために必要な。The solid particles provided a good organic feel to the shape of the clouds but still needed something to sell the fluffiness of clouds. 透明度を導入できるハイエンドなグラフィックス カードのカスタム ソリューションを試すことにしました。We decided to try a custom solution for the high-end graphics cards where we can introduce transparency.

これを行うにパーティクルの初期の並べ替え順序を切り替えるし、テクスチャ アルファを使用するシェーダーを変更します。To do this we simply switched the initial sorting order of the particles and changed the shader to use the textures alpha.

Fluffy クラウド

発生数百回の画面上の各ピクセルをレンダリングするための最も困難なマシンでもが重すぎるなることが判明しましたすばらしい!It looked great but proved to be too heavy for even the toughest machines since it would result in rendering each pixel on the screen hundreds of times!

低解像度でオフスクリーン レンダリングします。Render off-screen with lower resolution

四半期の解像度のバッファー (画面と比較して) でのレンダリングを開始した、クラウドでレンダリングされるピクセルの数を減らすためには、し、すべてのパーティクルが描画された後、画面上をバックアップ、最終的な結果を拡大します。To reduce the number of pixels rendered by the clouds, we started rendering them in a quarter resolution buffer (compared to the screen) and stretching the end result back up onto the screen after all the particles had been drawn. これは、当社が約 4 倍の高速化が、いくつかの注意事項に付属しています。This gave us roughly a 4x speedup, but came with a couple of caveats.

オフスクリーン レンダリングするコード:Code for rendering off-screen:

cloudBlendingCommand = new CommandBuffer();
Camera.main.AddCommandBuffer(whenToComposite, cloudBlendingCommand);
 
cloudCamera.CopyFrom(Camera.main);
cloudCamera.rect = new Rect(0, 0, 1, 1);    //Adaptive rendering can set the main camera to a smaller rect
cloudCamera.clearFlags = CameraClearFlags.Color;
cloudCamera.backgroundColor = new Color(0, 0, 0, 1);
 
currentCloudTexture = RenderTexture.GetTemporary(Camera.main.pixelWidth / 2, Camera.main.pixelHeight / 2, 0);
cloudCamera.targetTexture = currentCloudTexture;
 
// Render clouds to the offscreen buffer
cloudCamera.Render();
cloudCamera.targetTexture = null;
 
// Blend low-res clouds to the main target
cloudBlendingCommand.Blit(currentCloudTexture, new RenderTargetIdentifier(BuiltinRenderTextureType.CurrentActive), blitMaterial);

最初に、オフスクリーン バッファーにデータを表示するとき情報が失われたすべての深さ、メインのシーンから山の背後にあるパーティクル山の上にレンダリングになります。First, when rendering into an off-screen buffer, we lost all depth information from our main scene, resulting in particles behind mountains rendering on top of the mountain.

次に、解像度の変更が顕著なクラウドの端に成果物を導入、バッファーを拡張します。Second, stretching the buffer also introduced artifacts on the edges of our clouds where the resolution change was noticeable. 次の 2 つのセクションでは、これらの問題を解決した方法について説明します。The next two sections talk about how we resolved these issues.

パーティクル深度バッファーParticle depth buffer

Mountain またはオブジェクトがその背後にあるパーティクルをカバーでしたをするために、環境内ジオメトリと共存パーティクルをメインのシーンのジオメトリを含む深度バッファーによってオフスクリーン バッファーが設定されます。To make the particles co-exist with the world geometry where a mountain or object could cover particles behind it, we populated the off-screen buffer with a depth buffer containing the geometry of the main scene. このような深度バッファーを作成するを作成し、2 つ目のカメラ、実線のジオメトリとシーンの深さをレンダリングします。To produce such depth buffer, we created a second camera, rendering only the solid geometry and depth of the scene.

使用して新しいテクスチャで、クラウドのピクセル シェーダーがピクセルです。We then used the new texture in the pixel shader of the clouds to occlude pixels. 同じテクスチャを使用して、クラウドのピクセルの背後にあるジオメトリの距離を計算しました。We used the same texture to calculate the distance to the geometry behind a cloud pixel. その距離を使用して、ピクセルのアルファに適用することで、効果のパーティクルと地形を満たすクラウドと、地形の近くにフェードアウト、任意のハード傷口を削除するようになりましたが。By using that distance and applying it to the alpha of the pixel, we now had the effect of clouds fading out as they get close to terrain, removing any hard cuts where particles and terrain meet.

クラウドの地形にブレンド

エッジがシャープSharpening the edges

伸縮をクラウドでは、パーティクルの中央に通常のサイズのクラウドとほぼ同じ検索またはクラウドの端にある一部のアイテムが示しましたの重なっている場合。The stretched-up clouds looked almost identical to the normal size clouds at the center of the particles or where they overlapped, but showed some artifacts at the cloud edges. それ以外の場合鋭いエッジがぼやけてし、エイリアス効果は、カメラの移動時に導入されました。Otherwise sharp edges would appear blurry and alias effects were introduced when the camera moved.

これを解決しました大きな変化 (1) が発生した一方をオフスクリーン バッファーで単純なシェーダーを実行しています。We solved this by running a simple shader on the off-screen buffer to determine where big changes in contrast occurred (1). 新しいステンシル バッファー (2) に大きな変更でピクセルを格納します。We put the pixels with big changes into a new stencil buffer (2). 使用してマスクにステンシル バッファーこれらハイ コントラストの領域をオフスクリーン バッファーを画面に適用する場合、クラウド (3) の周囲の穴にします。We then used the stencil buffer to mask out these high contrast areas when applying the off-screen buffer back to the screen, resulting in holes in and around the clouds (3).

ここに表示されるすべてのパーティクルもう一度全画面表示モードで、今度は、すべての情報をマスクするステンシル バッファーを使用がピクセルの最小限のセットでその結果、エッジは、(4) をであっても。We then rendered all the particles again in full-screen mode, but this time used the stencil buffer to mask out everything but the edges, resulting in a minimal set of pixels touched (4). コマンド バッファーは、パーティクルを既に作成されてからもう一度新しいカメラにレンダリングすると、単に必要があります。Since the command buffer was already created for the particles, we simply had to render it again to the new camera.

クラウドの端のレンダリングの進行状況

最終的な結果は、低コスト センターのセクションでは、クラウドのエッジをシャープでした。The end result was sharp edges with cheap center sections of the clouds.

これがレンダリングよりもはるかに高速ですべてのパーティクルが画面を完全なコストが膨大な量の範囲もようにに対して、ステンシル バッファーのピクセルのテストに関連するコストが付属してまだがあります。While this was much faster than rendering all particles in full screen, there is still a cost associated with testing a pixel against the stencil buffer, so a massive amount of overdraw still came with a cost.

パーティクルを選別していますCulling particles

風効果風の多くの wisp を作成する、世界では、計算シェーダーの三角形ストリップ時間の長いを生成しました。For our wind effect, we generated long triangle strips in a compute shader, creating many wisps of wind in the world. 風の効果が生成される幅の狭いストリップのためのフィル レートの負荷は高くでないときに、何百もの何千もの頂点、頂点シェーダーの結果として負荷が生成されます。While the wind effect was not heavy on fill rate due to skinny strips generated, it produced many hundreds of thousands of vertices resulting in a heavy load for the vertex shader.

紹介を描画する風のストリップのサブセットをフィードする計算シェーダーのバッファーを追加します。We introduced append buffers on the compute shader to feed a subset of the wind strips to be drawn. ロジックを含むいくつか単純なビューの視錐台カリング計算シェーダーで、ストリップがカメラ ビュー外かどうかを判断でしたし、プッシュ バッファーに追加されないようにします。With some simple view frustum culling logic in the compute shader, we could determine if a strip was outside of camera view and prevent it from being added to the push buffer. これは、ストリップの量を大幅に削減、GPU 上でいくつか必要なサイクルを解放します。This reduced the amount of strips significantly, freeing up some needed cycles on the GPU.

コードは、追加のバッファーのデモ:Code demonstrating an append buffer:

計算シェーダー。Compute shader:

AppendStructuredBuffer<int> culledParticleIdx;
 
if (show)
    culledParticleIdx.Append(id.x);

C#コード:C# code:

protected void Awake() 
{
    // Create an append buffer, setting the maximum size and the contents stride length
    culledParticlesIdxBuffer = new ComputeBuffer(ParticleCount, sizeof(int), ComputeBufferType.Append);
 
    // Set up Args Buffer for Draw Procedural Indirect
    argsBuffer = new ComputeBuffer(4, sizeof(int), ComputeBufferType.IndirectArguments);
    argsBuffer.SetData(new int[] { DataVertCount, 0, 0, 0 });
}
 
protected void Update()
{
    // Reset the append buffer, and dispatch the compute shader normally
    culledParticlesIdxBuffer.SetCounterValue(0);
 
    computer.Dispatch(...)
 
    // Copy the append buffer count into the args buffer used by the Draw Procedural Indirect call
    ComputeBuffer.CopyCount(culledParticlesIdxBuffer, argsBuffer, dstOffset: 1);
    ribbonRenderCommand.DrawProceduralIndirect(Matrix4x4.identity, renderMaterial, 0, MeshTopology.Triangles, dataBuffer);
}

計算シェーダーでそれらの数を減らしますあり、のみ表示される表示のパーティクルをプッシュしましたが、クラウド パーティクルで同じ手法を使用してみました。We tried using the same technique on the cloud particles, where we would cull them on the compute shader and only push the visible particles to be rendered. この手法実際に保存していない私たち GPU にあまりにおける最大のボトルネックが、画面と頂点の計算コストいないにレンダリングされる量ピクセルであったためです。This technique actually did not save us much on the GPU since the biggest bottleneck was the amount pixels rendered on the screen, and not the cost of calculating the vertices.

この方法では、他の問題は、その性質上に並列化されたコンピューティング rted されていない、ちらつきのクラウドのパーティクルにする並べ替えられたパーティクルの原因、パーティクルのランダムな順序で追加のバッファーが設定されているでした。The other problem with this technique was that the append buffer populated in random order due to its parallelized nature of computing the particles, causing the sorted particles to be un-sorted, resulting in flickering cloud particles.

プッシュ バッファーを並べ替える方法はありますが、いないこの最適化を追求することにしましたは限られた量のパーティクルをカリングから入手したパフォーマンス向上のための追加の並べ替えをオフセットするは可能性があります。There are techniques to sort the push buffer, but the limited amount of performance gain we got out of culling particles would likely be offset with an additional sort, so we decided to not pursue this optimization.

アダプティブ レンダリングAdaptive rendering

曇り vs などの条件を明確に表示のレンダリングをさまざまなアプリで安定したフレーム レートが確実に、アプリにアダプティブ レンダリングを導入しました。To ensure a steady framerate on an app with varying rendering conditions like a cloudy vs a clear view, we introduced adaptive rendering to our app.

アダプティブ レンダリングの最初の手順では、GPU を測定します。The first step of adaptive rendering is to measure GPU. 先頭と末尾のレンダリングされたフレームの GPU コマンド バッファーにカスタム コードを挿入することで、これを行った、両方をキャプチャ左と右目の画面時間。We did this by inserting custom code into the GPU command buffer at the beginning and the end of a rendered frame, capturing both the left and right eye screen time.

測定することによってレンダリングと比較して、必要な更新レートでしたフレームの欠落を閉じる方法を把握できましたにかかった時間。By measuring the time spent rendering and comparing it to our desired refresh-rate we got a sense of how close we were to dropping frames.

フレームを削除するには、近い場合は、レンダリング時間を短縮適合させます。When close to dropping frames, we adapt our rendering to make it faster. 適合させる 1 つの簡単な方法は、描画するには、小さいピクセルを必要とする、画面のビューポートのサイズに変更されます。One simple way of adapting is changing the viewport size of the screen, requiring less pixels to get rendered.

使用してUnityEngine.XR.XRSettings.renderViewportScaleシステムは、対象のビューポートの縮小し、サイズに合わせて画面へのバックアップ結果を自動的に拡大します。By using UnityEngine.XR.XRSettings.renderViewportScale the system shrinks the targeted viewport and automatically stretches the result back up to fit the screen. スケールをわずかに変更が環境内のジオメトリにかろうじて気付くと 0.7 のスケール ファクターがレンダリングされるピクセルの大きさの半分が必要です。A small change in scale is barely noticeable on world geometry, and a scale factor of 0.7 requires half the amount of pixels to be rendered.

70% のスケール、半分のピクセル

固定の数値で小数点以下桁数を削減し、向上させるフレームのドロップしようとしていることを検出したとき、十分な速さをもう一度実行しているときにバックアップします。When we detect that we are about to drop frames we lower the scale by a fixed number, and increase it back when we are running fast enough again.

時間がないを使用するには、どのようなクラウド手法では、起動時に、ハードウェアの機能をグラフィックスに基づいたしました、システムが時間が長く、低解像度に滞在するを防ぐために、GPU の測定値からデータを基にすることができますが、これは、 Datascape で調査します。While we decided what cloud technique to use based on graphics capabilities of the hardware at startup, it is possible to base it on data from the GPU measurement to prevent the system from staying at low resolution for a long time, but this is something we did not have time to explore in Datascape.

まとめFinal thoughts

さまざまなハードウェアを対象とするが困難にし、計画を立てる必要があります。Targeting a variety of hardware is challenging and requires some planning.

問題の領域に慣れるし、すべてのマシンで実行されるバックアップ ソリューションを開発する低電力コンピューターを対象とする機能を開始することをお勧めします。We recommend that you start targeting lower-powered machines to get familiar with the problem space and develop a backup solution that will run on all your machines. ピクセルは、最も貴重なリソースになるために念頭に置いてのフィル レートでソリューションを設計します。Design your solution with fill rate in mind, since pixels will be your most precious resource. 透過性経由でターゲット ソリッド ジオメトリ。Target solid geometry over transparency.

バックアップ ソリューションでは、ハイ エンド マシン複雑で階層化を開始したり、おそらくだけバックアップ ソリューションの解像度を向上できます。With a backup solution, you can then start layering in more complexity for high end machines or maybe just enhance resolution of your backup solution.

、最悪のシナリオを設計し、おそらくアダプティブ レンダリングを使用して、負荷の高い状況を検討します。Design for worst case scenarios, and maybe consider using adaptive rendering for heavy situations.

著者についてAbout the authors

Picture of Robert Ferrese Robert FerreseRobert Ferrese
ソフトウェア エンジニア @MicrosoftSoftware engineer @Microsoft
Picture of Dan Andersson Dan AnderssonDan Andersson
ソフトウェア エンジニア @MicrosoftSoftware engineer @Microsoft

関連項目See also