Saya ingin menggambar garis dalam ruang 3D yang selalu persis selebar satu piksel di layar, tidak peduli seberapa jauh dari kamera itu. (Dan hal yang sama untuk poin tunggal juga).
Adakah petunjuk tentang bagaimana saya bisa melakukan itu?
Garis Rendering - Metode 1 (Primitif)
Untuk garis-garis sederhana dalam ruang 3D, Anda dapat menggambarnya menggunakan a LineList
atau LineStrip
primitif. Berikut jumlah minimal kode yang harus Anda tambahkan ke proyek XNA kosong agar dapat menarik garis dari (0,0,0) hingga (0,0, -50). Garis tersebut seharusnya memiliki lebar yang kira-kira sama di mana pun kamera berada.
// 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);
Saya pada dasarnya membuat sederhana BasicEffect
untuk menahan pandangan saya dan transformasi proyeksi, dan melewati dua simpul (menyimpan posisi dan warna) ke GraphicsDevice.DrawUserPrimitives
metode yang akan diterjemahkan sebagai LineList
.
Tentu saja ada banyak cara untuk mengoptimalkannya, yang sebagian besar melibatkan pembuatan a VertexBuffer
untuk menyimpan semua simpul, dan mengelompokkan sebanyak mungkin garis ke dalam satu panggilan Draw tunggal tetapi itu tidak relevan dengan pertanyaan.
Poin Rendering - Metode 1 (SpriteBatch)
Adapun untuk menggambar poin, ini dulunya mudah menggunakan sprite titik tetapi mereka dihapus dari XNA 4.0 . Ada beberapa alternatif. Cara termudah adalah membuat Texture2D
objek putih 1x1 , dan membuatnya menggunakan SpriteBatch
di lokasi layar yang benar, yang dapat Anda temukan dengan mudah menggunakan metode Viewport.Project .
Anda dapat membuat Texture2D
objek yang diperlukan seperti ini:
Texture2D pixel = new Texture2D(GraphicsDevice, 1, 1);
pixel.SetData(new [] { Color.White });
Dan render di lokasi (x, y, z) seperti ini:
// 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();
Garis Rendering - Metode 2 (SpriteBatch)
Atau, Anda juga dapat menggambar garis menggunakan SpriteBatch
menggunakan teknik yang dijelaskan di sini . Dalam hal ini, Anda hanya perlu menemukan koordinat ruang layar untuk kedua ujung garis 3D (sekali lagi menggunakan Viewport.Project
) dan kemudian menggambar garis biasa di antara mereka.
Poin Rendering - Metode 2 (Garis Kecil dengan Primitif)
Dalam komentar, eBusiness mengangkat pertanyaan berikut:
Bagaimana dengan garis dengan titik awal dan akhir yang sama, bukankah itu menghasilkan titik? Atau apakah itu tidak akan terlihat?
Aku mencoba memberikannya dan render sebuah LineList
menggunakan yang sama awal dan akhir mengakibatkan tidak ditarik. Saya menemukan cara mengatasinya jadi saya akan menjelaskannya di sini untuk kelengkapan.
Triknya adalah tidak menggunakan titik awal dan akhir yang sama, melainkan menggambar garis yang sangat kecil, sehingga hanya muncul sebagai satu piksel saat digambar. Jadi, untuk memilih titik akhir yang benar, saya pertama-tama memproyeksikan titik ruang dunia ke ruang layar, memindahkannya satu pixel ke ruang layar , dan akhirnya memproyeksikannya kembali ke ruang dunia. Itulah titik akhir dari garis Anda agar terlihat seperti titik. Sesuatu seperti ini:
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);
}
Diikuti dengan menjadikannya sebagai garis normal primitif.
Demonstrasi
Inilah yang saya dapatkan menggambar garis putih dalam ruang 3D menggunakan daftar garis primitif, dan titik-titik merah di kedua ujung garis menggunakan tekstur 1x1 dan SpriteBatch. Kode yang digunakan cukup banyak seperti yang saya tulis di atas. Saya juga telah memperbesar sehingga Anda dapat mengonfirmasi bahwa mereka persis selebar satu piksel:
Ini ditandai sebagai XNA jadi saya berasumsi itu yang Anda tanyakan?
Jika demikian, artikel ini akan bermanfaat untuk baris:
http://msdn.microsoft.com/en-us/library/bb196414(v=xnagamestudio.40).aspx
Tentu saja Anda dapat menggunakan matriks tampilan / proyeksi Anda sendiri, bukan dari matriks mereka. Pada dasarnya,
PrimitiveType.LineList
atauLineStrip
bagaimana cara menggambar garis pada level GPU.Adapun poin, Anda tidak bisa lagi menggunakan PrimitiveType.PointList untuk menggambar poin lagi di XNA 4.0. Sebaliknya Anda harus membuat segitiga yang sangat kecil. Sampel ini memberikan garis dasar yang baik:
http://create.msdn.com/education/catalog/sample/primitive_3d
Untuk versi XNA sebelumnya, jika Anda menggunakan salah satu dari itu, Anda dapat melanjutkan dan membaca bagian Poin dari versi XNA 3.0 dari artikel yang diposting di atas:
http://msdn.microsoft.com/en-us/library/bb196414(v=xnagamestudio.30).aspx
Perhatikan bahwa tautannya memiliki:
Jelas mengubahnya menjadi
1
.sumber