3D空間に1ピクセル幅の線を描く


10

カメラからどれだけ離れていても、画面上で常に正確に1ピクセル幅の線を3D空間に描画したいと思います。(単一点についても同じです)。

私がそれをどのように行うことができるかについてのヒントはありますか?

回答:


24

線のレンダリング-方法1(プリミティブ)

3D空間の単純な線の場合、LineListまたはLineStripプリミティブを使用してそれらを描くことができます。以下は、(0,0,0)から(0,0、-50)まで線を引くために空のXNAプロジェクトに追加する必要があるコードの最小量です。カメラがどこにあっても、ラインはほぼ同じ幅で表示されます。

// Inside your Game class
private BasicEffect basicEffect;
private Vector3 startPoint = new Vector3(0, 0, 0);
private Vector3 endPoint = new Vector3(0, 0, -50);

// Inside your Game.LoadContent method
basicEffect = new BasicEffect(GraphicsDevice);
basicEffect.View = Matrix.CreateLookAt(new Vector3(50, 50, 50), new Vector3(0, 0, 0), Vector3.Up);
basicEffect.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45f), GraphicsDevice.Viewport.AspectRatio, 1f, 1000f);

// Inside your Game.Draw method
basicEffect.CurrentTechnique.Passes[0].Apply();
var vertices = new[] { new VertexPositionColor(startPoint, Color.White),  new VertexPositionColor(endPoint, Color.White) };
GraphicsDevice.DrawUserPrimitives(PrimitiveType.LineList, vertices, 0, 1);

基本的BasicEffectには、ビューと投影変換を保持するシンプルなものを作成し、2つの頂点(位置と色を格納する)GraphicsDevice.DrawUserPrimitivesをにレンダリングするメソッドに渡しましたLineList

もちろん、それを最適化する方法はたくさんありますが、そのほとんどは、VertexBufferすべての頂点を保存するためのの作成と、できるだけ多くの行を単一のDraw呼び出しにバッチ処理することですが、これは問題とは関係ありません。


レンダリングポイント-メソッド1(SpriteBatch)

ポイントの描画に関しては、これはポイントスプライトを使用すると簡単でしたが、XNA 4.0から削除されました。ただし、いくつかの選択肢があります。最も簡単な方法は、1x1の白いTexture2Dオブジェクトを作成し、それをSpriteBatch正しい画面位置で使用してレンダリングすることです。これは、Viewport.Projectメソッドを使用して簡単に見つけることができます。

次のTexture2Dように、必要なオブジェクトを作成できます。

Texture2D pixel = new Texture2D(GraphicsDevice, 1, 1);
pixel.SetData(new [] { Color.White });

そして、次のように(x、y、z)の場所にレンダリングします。

// Find screen equivalent of 3D location in world
Vector3 worldLocation = new Vector3(0, 0, 50);
Vector3 screenLocation = GraphicsDevice.Viewport.Project(worldLocation, projectionMatrix, viewMatrix, Matrix.Identity);

// Draw our pixel texture there
spriteBatch.Begin();
spriteBatch.Draw(pixel, new Vector2(screenLocation.X, screenLocation.Y), Color.White);
spriteBatch.End();

線のレンダリング-方法2(SpriteBatch)

または、ここで説明SpriteBatchする手法を使用して、線を描くこともできます。この場合は、3Dラインの両端のスクリーンスペース座標を(もう一度を使用してViewport.Project)見つけ、それらの間に通常のラインを描くだけです。


レンダリングポイント-方法2(プリミティブ付きの小さな線)

コメントで、eBusinessは次の質問を提起しました。

始点と終点が同じ線はどうですか、それで点が生成されませんか?それとも単に目に見えないでしょうか?

私は試してみましたがLineList同じ開始点と終了点を使用してレンダリングすると、も描画されませんでした。私はそれを回避する方法を見つけたので、完全を期すためにここで説明します。

トリックは、同じ始点と終点を使用するのではなく、描画するときに1ピクセルとしてしか表示されないほど細い線を描画することです。だから、正しいエンドポイントを選択するために、私は最初、画面空間にワールド空間の点を投影右1つのピクセルを移動し、画面空間での、そして最終的に戻ってワールド空間にそれを投影しました。それが、ドットのように見えるようにするためのラインの終点です。このようなもの:

Vector3 GetEndPointForDot(Vector3 start)
{
    // Convert start point to screen space
    Vector3 screenPoint = GraphicsDevice.Viewport.Project(start, projection, view, Matrix.Identity);

    // Screen space is defined in pixels so adding (1,0,0) moves it right one pixel
    screenPoint += Vector3.Right;

    // Finally unproject it back into world space
    return GraphicsDevice.Viewport.Unproject(screenPoint, projection, view, Matrix.Identity);
}

その後、通常のラインプリミティブとしてレンダリングします。


デモンストレーション

これは、ラインリストプリミティブを使用して3Dスペースに白い線を描画し、1x1テクスチャとSpriteBatchを使用して線の両端に赤い点を描画したものです。使用したコードは、私が上で書いたものとほぼ同じです。また、ズームインして、幅がちょうど1ピクセルであることを確認します。

ここに画像の説明を入力してください


始点と終点が同じ線はどうですか、それで点が生成されませんか?それとも単に目に見えないでしょうか?
aaaaaaaaaaaa 2012年

@eBusinessいい質問です!私はそれを試してみましたが、実際には何もレンダリングしません。
David Gouveia 2012年

@eBusiness方法を見つけたばかりですが、少しばかげていると思います。とにかく完全にするために追加します。
David Gouveia 2012年

2

これはXNAとしてタグ付けされているので、それがあなたが尋ねていることだと思いますか?

もしそうなら、この記事は行に役立つはずです:

http://msdn.microsoft.com/en-us/library/bb196414(v=xnagamestudio.40).aspx

もちろん、それらの代わりに独自のビュー/投影行列を使用できます。基本的に、PrimitiveType.LineListまたはLineStripGPUレベルで線を描画する方法です。

ポイントについては、PrimitiveType.PointListを使用してXNA 4.0でポイントを描画することはできなくなりました。代わりに、非常に小さな三角形を作成する必要があります。このサンプルは良いベースラインを提供します:

http://create.msdn.com/education/catalog/sample/primitives_3d

以前のバージョンのXNAの場合、それらのいずれかを使用している場合は、先に投稿した記事のXNA 3.0バージョンのポイント部分を読むことができます。

http://msdn.microsoft.com/en-us/library/bb196414(v=xnagamestudio.30).aspx

リンクに注意してください:

graphics.GraphicsDevice.RenderState.PointSize = 10;

明らかにそれをに変更してください1

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.