はじめに
多数の要素を含む複雑なグラフィックシーンは、描画が遅くなることがあります。この場合、動的なグラフィック要素 (カーソル、グリップ/スナップ点、選択矩形、ユーザーインターフェース要素など) も描画が遅くなります。これは、グラフィックシーンと動的なグラフィック要素を正しく組み合わせるために、レンダラーがすべての基になるシーン要素を再描画する必要があるためです。この問題は、メインのレンダリングされたシーンと動的なグラフィック要素を別々のバッファに描画するオーバーレイバッファを使用することで解決できます。変更されたジオメトリを含むバッファのみが再描画され、最終的に画面出力時に変更されていないバッファと結合されます。
ベクトル化モジュールがサポートしている場合、グラフィックシステムによってオーバーレイバッファが呼び出されることがあります。現在、オーバーレイバッファは WinGLES2.txv Teigha ベクトル化モジュールのみでサポートされています。
使用例
最も頻繁に使用される動的なグラフィック要素の 1 つがコマンドトラッカーであるため、この使用例ではコマンドトラッカーの簡単な実装を示します。コマンドトラッカーは、Teigha コマンド内で追加の視覚情報を提供するために使用できるシンプルなカスタム描画可能オブジェクトです。まずトラッカーの全リストを示し、その後でコードの最も重要な部分について説明します。
コマンドトラッカーのコードリスト
class ExRectFrame : public OdEdPointDefTracker, public OdGiDrawableImpl<>
{
OdGsModelPtr m_pModel; // Overlay model.
mutable OdGePoint3d m_pts[4];
virtual OdUInt32 subSetAttributes(OdGiDrawableTraits* ) const ODRX_OVERRIDE
{
return kDrawableIsAnEntity;
}
virtual bool subWorldDraw(OdGiWorldDraw* pWd) const ODRX_OVERRIDE
{
return false;
}
virtual void subViewportDraw(OdGiViewportDraw* pVd) const ODRX_OVERRIDE
{
const OdGiViewport& vp = pVd->viewport();
OdGeMatrix3d x = vp.getWorldToEyeTransform();
OdGePoint3d p0 = x * m_pts[0];
OdGePoint3d p2 = x * m_pts[2];
m_pts[1].x = p0.x; m_pts[3].x = p2.x;
m_pts[1].y = p2.y; m_pts[3].y = p0.y;
m_pts[1].z = m_pts[3].z = p2.z;
x = vp.getEyeToWorldTransform();
m_pts[1].transformBy(x);
m_pts[3].transformBy(x);
OdGiDrawFlagsHelper _dfh(pVd->subEntityTraits(), OdGiSubEntityTraits::kDrawNoPlotstyle);
pVd->subEntityTraits().setFillType(kOdGiFillAlways);
pVd->subEntityTraits().setTransparency(OdCmTransparency(0.5));
if (m_pts[3].x < m_pts[1].x)
pVd->subEntityTraits().setColor(3);
else
pVd->subEntityTraits().setColor(5);
pVd->geometry().polygon(4, m_pts);
}
OdGePoint3d basePoint() const
{
return m_pts[0];
}
public:
static OdEdPointTrackerPtr create(const OdGePoint3d& base)
{
OdEdPointTrackerPtr pRes = OdRxObjectImpl<ExRectFrame, OdEdPointTracker>::createObject();
static_cast<ExRectFrame*>(pRes.get())->m_pts[0] = base;
return pRes;
}
void setValue(const OdGePoint3d& p)
{
m_pts[2] = p;
if (!m_pModel.isNull())
{ // Update drawable cache.
OdGiDrawable* pParent = NULL;
m_pModel->onModified(this, pParent);
}
}
int addDrawables(OdGsView* pView)
{
m_pModel = pView->device()->createModel();
if (!m_pModel.isNull()) // Setup model overlay.
m_pModel->setRenderType(OdGsModel::kDirect);
pView->add(this, m_pModel);
return 1;
}
void removeDrawables(OdGsView* pView)
{
pView->erase(this);
}
};
カスタム描画可能オブジェクトのオーバーレイバッファ使用を有効にする
まず、個別のグラフィックシステムモデルオブジェクトを作成します。
m_pModel = pView->device()->createModel();
この個別のモデルオブジェクトは、個別のオーバーレイバッファを有効にするために必要です。
if (!m_pModel.isNull()) // Setup model overlay.
m_pModel->setRenderType(OdGsModel::kDirect);
メインシーンは通常、「kMain」オーバーレイバッファにレンダリングされます。各オーバーレイタイプには独自の特性があり、さまざまな目的に使用できます。
- kUserBg1 - メインシーンの下に、デプスバッファを使用せずにレンダリングします。背景のレンダリングに便利です。
- kUserBg2 - メインシーンの下に、独自のデプスバッファを使用してレンダリングします。メインシーンの下にスプライトや3Dオブジェクトをレンダリングするのに便利です。
- kUserBg3 - メインシーンの下に、メインのデプスバッファを使用してレンダリングします。グリッドのレンダリングに便利です。
- kMain - メインのグラフィックシーンオーバーレイ。
- kSprite - メインシーンの上に、独自のデプスバッファを使用してレンダリングします。メインシーンの上にスプライトや3Dオブジェクトをレンダリングするのに便利です。
- kDirect - メインシーンの上に直接レンダリングします。
- kHighlight - メインシーンの上に、デプスバッファを使用せずに直接レンダリングします。
- kHighlightSelection - メインシーンの上に、デプスバッファを使用せずに直接レンダリングしますが、ハイライトスタイルを使用します。
- kDirectTopmost - メインシーンの上に、デプスバッファを使用せずにレンダリングします。
- kContrast - メインシーンの上に、デプスバッファを使用せずにレンダリングしますが、コントラストスタイルを使用します。UI要素に便利です。
- kUserFg1 - メインシーンの上に、メインのデプスバッファを使用してレンダリングします。
- kUserFg2 - メインシーンの上に、独自のデプスバッファを使用してレンダリングします。
- kUserFg3 - 他のすべてのオーバーレイの上に、デプスバッファを使用せずにレンダリングします。
オーバーレイバッファは、テーブルで指定された順序でレンダリングされるため、類似のプロパティを持つ異なるオーバーレイを使用してカスタム要素のレンダリング順序を選択できます。オーバーレイがデプスバッファを呼び出さない場合、ジオメトリのZ座標が考慮されないため、オーバーレイ内の要素のレンダリング順序が重要になります。メインのデプスバッファを呼び出すオーバーレイバッファは、同じオーバーレイに描画されたものと同様に結合されます(マージ中にシーンのデプス情報が考慮されます)。独自のデプスバッファを持つオーバーレイは、メインのグラフィックシーンの上または下に視覚的に描画される3Dオブジェクトをレンダリングするのに便利です。以下の表は、特定のオーバーレイプロパティをより分かりやすい方法で示しています。
|
オーバーレイタイプ |
描画順序 |
デプスバッファ |
ダイレクトレンダリング |
ハイライトスタイル |
コントラストスタイル |
|
kUserBg1 |
1 |
- |
- |
- |
- |
|
kUserBg2 |
2 |
独自 |
- |
- |
- |
|
kUserBg3 |
3 |
メイン |
- |
- |
- |
|
kMain |
4 |
メイン |
- |
- |
- |
|
kSprite |
5 |
独自 |
- |
- |
- |
|
kDirect |
6 |
- |
+ |
- |
- |
|
kHighlight |
7 |
- |
+ |
- |
- |
|
kHighlightSelection |
8 |
- |
+ |
+ |
- |
|
kDirectTopmost |
9 |
- |
- |
- |
- |
|
kContrast |
10 |
- |
- |
- |
+ |
|
kUserFg1 |
11 |
メイン |
- |
- |
- |
|
kUserFg2 |
12 |
独自 |
- |
- |
- |
|
kUserFg3 |
13 |
- |
- |
- |
- |
「ダイレクトレンダリング」機能がマークされたオーバーレイバッファは、このモードがサポートされている場合、レンダラーによって画面に直接描画できます(中間バッファキャッシュをスキップします)。
グラフィックスシステムモデルの作成と設定後、レンダリング可能なオブジェクト(描画可能オブジェクト)は、設定されたモデルとともにグラフィックスシステムビューに追加できます。
pView->add(this, m_pModel);
グラフィックスシステムモデルポインタとともにビューに追加された場合、この描画可能オブジェクトのグラフィックスキャッシュが作成されることを忘れないでください。描画可能オブジェクトの状態が変更され、再描画が必要な場合は、この描画可能オブジェクトのグラフィックスキャッシュを更新する必要があることをグラフィックスシステムに手動で通知してください。
if (!m_pModel.isNull())
{ // Update drawable cache.
OdGiDrawable* pParent = NULL;
m_pModel->onModified(this, pParent);
}
カスタムトラッカーレンダリングの確認
カスタムトラッカーのレンダリングを確認するには、マウス入力とユーザーコマンドコンテキストをサポートする任意のグラフィック例を使用してください。
bool OdExEditorObject::OnMouseLeftButtonClick(int x, int y)
{
OdGePoint3d pt = toEyeToWorld(x, y);
OdDbUserIO* pIO = m_pCmdCtx->dbUserIO();
try
{
OdEdPointTrackerPtr pTracker = ExRectFrame::create(pt);
OdGePoint3d pts[2] = {
pt,
pIO->getPoint(OD_T("Specify opposite corner:"), OdEd::kGptNoLimCheck|OdEd::kGptNoUCS, NULL, OdString::kEmpty, pTracker)
};
}
catch( const OdError& )
{
return false;
}
catch( ... )
{
throw;
}
return true;
}
以下の例では、データベースコマンドコンテキストを呼び出して入力矩形を取得するだけです。トラッカーは、2番目の入力点が最初の入力点の左側に配置されている場合は透明な緑色の矩形を描画し、それ以外の場合は透明な青色の矩形を描画します。
レンダリング速度を確認するには、多数の要素を含む大規模な描画を使用します。以下の画像は、100万本のカラーラインを含むファイルで生成されました。まず、グラフィックシステムモデルなしで、またはメインシーンオーバーレイバッファ用に構成されたグラフィックシステムモデルでトラッカーを呼び出してみてください。
矩形の再描画速度は視覚的に遅いため、大きなファイルを扱うのは困難です。別のオーバーレイの使用を有効にしてください。
オーバーレイバッファが有効で、ベクトル化モジュールによってサポートされている場合、矩形の再描画時間は高速になります。これは、エディタアプリケーションにおいて、動的に変更可能なグラフィック要素のほとんどをオーバーレイバッファに移動させることで、大規模な描画を編集する際のアプリケーションの使いやすさを向上させるために推奨されます。
非互換なベクトル化モジュールでのオーバーレイ動作
ベクトル化モジュールがオーバーレイバッファをサポートしていない場合でも、異なるレンダリングタイプを持つ個別のグラフィックシステムモデルを使用することで、レンダリング結果に影響を与える可能性があります。まず、グラフィックシステムは描画可能なものをオーバーレイ順にソートします。これは、オーバーレイモデルを使用してレンダリング順序を変更できることを意味します。たとえば、メインシーンの上にレンダリングする必要があるグリップポイントやその他の要素は、kMainレンダリングタイプよりも大きいレンダリングタイプを持つモデルに配置できます。セカンダリベクトル化モジュールは、それを必要とするオーバーレイのデプスバッファの使用を無効にすることができます。これは、たとえばkDirectレンダリングタイプを持つモデルに配置された描画可能なものが、メインシーングラフィックの下に空間的に配置されていても、メインシーングラフィックの上に描画されることを意味します。
結論
レンダリング要素の順序を設定する前に、アプリケーションは、基になるOdGsViewに指定されたものと同様のパラメータを持つ個別のOdGsViewオブジェクトを作成し、それらを複製されたOdGsViewの上または下に描画することができました。このメカニズムはうまく機能しますが、オーバーレイに必要なものよりも多くのソースコードを必要とします。しかし、オーバーレイバッファの主な利点は、メイングラフィックシーンの上または下で動的に変更可能なジオメトリを高速にレンダリングできることです。
この機能は、コマンドトラッカー、カーソル、ユーザーインターフェイス要素、グリップ/スナップポイントだけでなく、高速なハイライト表示(またはホバー)やアニメーションシーン要素にも役立ちます。WinGLES2.txvベクトル化モジュールは、GPU OpenGLフレームバッファを呼び出してオーバーレイバッファ機能を完全にサポートするため、どんなビデオカード(非常に古いものでも)でもサポートされます。全体として、オーバーレイバッファ機能は、クリエイティブなユーザーインターフェイスを備えた最新の編集アプリケーションに役立つでしょう。