DirectX Kartezyen Koordinat Sistemi ve Camera Alt Yapısı
Bu makalede 3 boyutlu şekiller çizmek için gerekli olan 3 boyutlu koordinatları göstermek için gerekli olan kartezyen koordinat sistemini, bu sistem üzerinde rahatça işlem yapmak için sağ ve sol el kuramını inceleyeceğiz. İncelediğimiz yapı üzerinden hareketle uygun koordinat noktaları vererek bir küp tasarlayacağınız. Daha sonra küp üzerinde transform işlemler yaparak küpümüzü 3 boyutlu olarak ekran üzerinde hareket ettireceğiz.
Koordinat uzayı ve Sağ El Kuramı 3 boyutlu uzay X-Y ve Z koordinatlarından oluşur. Ekran üzerinde tasarım yaparken ekranı 3 boyutlu uzay olarak düşünmemiz gerekmektedir. Kartezyen koordinat sisteminde uzay içerisindeki tüm noktaları X;Y;Z değerlerini vererek tanımlanır. Örnek olarak X;Y;Z (0;0;0) bizim başlangıç noktamızdır. DirectX ile yarattığımız form üzerinde bu nokta formun sol üst noktasıdır. Z ekranı 3 boyutu kazandıran derinliktir. Görüntü kullanıcıya yaklaştığında Z değeri sol veya sağ el kuramını kullanmamıza göre büyür ya da küçülür. Koordinat sistemi üzerinde yatay olarak X, dikey olarak Y, ve derinlik için Z kullanılmasına rağmen directX de bu yapıya uymaz, directX üzerinde X ve Y koordinatları formun sol üst köşesinde 0 iken formun sağına ve altına gittikçe bu değerler artar. DirectX'de dikeyde X yatayda Y kullanılmaktadır. Aslında her iki sistem de aynı sistemi kullanmaktadır. Bunu anlamak için fizikte ve elektromanyetik alan hesaplarında kullanılan sağ ve sol el kuramı kullanılır. Sağ el şekildeki gibi tutulduğunda işaret parmağı X eksenini, orta parmak Y eksenini ve baş parmak ise Z eksenini göstermektedir. Elinizi bu şekilde tutup başparmağı size doğru döndürürseniz directX'in sağ el için kullandığı koordinat yapısına ulaşmış olursunuz. Bu koordinat yapısında işaret parmağı formun altına doğru artmakta yani aşağı göstermekte, Orta parmağınız form üzerinde yatay olarak sağa gidildiğinda artmakta, Z ekseni ise nesne size yaklaştıkça azalmaktadır(işareti - olacaktır). Sağ el kuramını kullanırsanız eğer 3 boyutlu çizimler çizerken noktaların koordinatlarını belirlerken çok rahatlıkla hesap yapabilirsiniz. Sol el kuramında ise, sağ eliniz yerine sol elinizi kullanıyorsunuz. Bu sefer Z ekseni derinlik arttıkça azalacaktır. Hayattan bir örnek vermek gerekirse sağ el kuramı ile bir vidayı hangi yöne hareket ettirmek istiyorsanız orta parmağınızı o yöne getirin(örnek vidayı çıkartmak istiyorsunuz orta parmağınız size bakacaktır). Bu durumda vidayı baş parmağınızın gösterdiği yöne(sağ taraf) vidayı çevirirseniz vida size doğru hareket edecektir. Gördüğünüz gibi directX ile program yaparken sadece yazılımsal bilgileriniz değil geometrik ve matematiksel bilgilerinizi de kullanmanız gerekmektedir. Bu bilgiler hayatla iç içedir. Bu yapıya göre küpümüzü tasarlarsak, bir küp 8 noktadan oluşur. Küpü 6 kare, 12 üçgen ile tanımlayabiliriz. 12 üçgende toplam 36 tane nokta vardır. Bu noktaları uygun şekilde tanımlama yapmamız gerekmektedir. Aşağıda sol el ve sağ el kuramına göre kuramına göre noktaların tanımlanışı vardır
Sağ el kuramına göre küpü tanımladığımız noktalar.
//Ön Yüz verts[0] = new CustomVertex.PositionColored(-1.0f, 1.0f, -1.0f, Color.Red.ToArgb()); verts[1] = new CustomVertex.PositionColored(-1.0f, -1.0f, -1.0f, Color.Red.ToArgb()); verts[2] = new CustomVertex.PositionColored(1.0f, 1.0f, -1.0f, Color.Red.ToArgb()); verts[3] = new CustomVertex.PositionColored(-1.0f, -1.0f, -1.0f, Color.Red.ToArgb()); verts[4] = new CustomVertex.PositionColored(1.0f, -1.0f, -1.0f, Color.Red.ToArgb()); verts[5] = new CustomVertex.PositionColored(1.0f, 1.0f, -1.0f, Color.Red.ToArgb());
// Arka Yüz verts[6] = new CustomVertex.PositionColored(-1.0f, 1.0f, 1.0f, Color.Blue.ToArgb()); verts[7] = new CustomVertex.PositionColored(1.0f, 1.0f, 1.0f, Color.Blue.ToArgb()); verts[8] = new CustomVertex.PositionColored(-1.0f, -1.0f, 1.0f, Color.Blue.ToArgb()); verts[9] = new CustomVertex.PositionColored(-1.0f, -1.0f, 1.0f, Color.Blue.ToArgb()); verts[10] = new CustomVertex.PositionColored(1.0f, 1.0f, 1.0f, Color.Blue.ToArgb()); verts[11] = new CustomVertex.PositionColored(1.0f, -1.0f, 1.0f, Color.Blue.ToArgb()); //Üst Yüz verts[12] = new CustomVertex.PositionColored(-1.0f, 1.0f, -1.0f, Color.Yellow.ToArgb()); verts[13] = new CustomVertex.PositionColored(1.0f, 1.0f, 1.0f, Color.Yellow.ToArgb()); verts[14] = new CustomVertex.PositionColored(-1.0f, 1.0f, 1.0f, Color.Yellow.ToArgb()); verts[15] = new CustomVertex.PositionColored(-1.0f, 1.0f, -1.0f, Color.Yellow.ToArgb()); verts[16] = new CustomVertex.PositionColored(1.0f, 1.0f, -1.0f, Color.Yellow.ToArgb()); verts[17] = new CustomVertex.PositionColored(1.0f, 1.0f, 1.0f, Color.Yellow.ToArgb()); // Alt Yüz verts[18] = new CustomVertex.PositionColored(-1.0f, -1.0f, -1.0f, System.Drawing.Color.Black.ToArgb()); verts[19] = new CustomVertex.PositionColored(-1.0f, -1.0f, 1.0f, Color.Black.ToArgb()); verts[20] = new CustomVertex.PositionColored(1.0f, -1.0f, 1.0f, Color.Black.ToArgb()); verts[21] = new CustomVertex.PositionColored(-1.0f, -1.0f, -1.0f, Color.Black.ToArgb()); verts[22] = new CustomVertex.PositionColored(1.0f, -1.0f, 1.0f, Color.Black.ToArgb()); verts[23] = new CustomVertex.PositionColored(1.0f, -1.0f, -1.0f, Color.Black.ToArgb()); // Sol Yüz verts[24] = new CustomVertex.PositionColored(-1.0f, 1.0f, -1.0f, Color.Gray.ToArgb()); verts[25] = new CustomVertex.PositionColored(-1.0f, -1.0f, 1.0f, Color.Gray.ToArgb()); verts[26] = new CustomVertex.PositionColored(-1.0f, -1.0f, -1.0f, Color.Gray.ToArgb()); verts[27] = new CustomVertex.PositionColored(-1.0f, 1.0f, 1.0f, Color.Gray.ToArgb()); verts[28] = new CustomVertex.PositionColored(-1.0f, -1.0f, 1.0f, Color.Gray.ToArgb()); verts[29] = new CustomVertex.PositionColored(-1.0f, 1.0f, -1.0f, Color.Gray.ToArgb());
//Sağ Yüz verts[30] = new CustomVertex.PositionColored(1.0f, 1.0f, -1.0f, Color.Green.ToArgb()); verts[31] = new CustomVertex.PositionColored(1.0f, -1.0f, -1.0f, Color.Green.ToArgb()); verts[32] = new CustomVertex.PositionColored(1.0f, -1.0f, 1.0f, Color.Green.ToArgb()); verts[33] = new CustomVertex.PositionColored(1.0f, 1.0f, 1.0f, Color.Green.ToArgb()); verts[34] = new CustomVertex.PositionColored(1.0f, 1.0f, -1.0f, Color.Green.ToArgb()); verts[35] = new CustomVertex.PositionColored(1.0f, -1.0f, 1.0f, Color.Green.ToArgb());
Sol el kuramına göre noktaları hesaplarken sağ el kuramından fark olarak Z ekseni işaret değiştirir.
//Ön Yüz verts[0] = new CustomVertex.PositionColored(-1.0f, 1.0f, 1.0f, Color.Red.ToArgb()); verts[1] = new CustomVertex.PositionColored(-1.0f, -1.0f, 1.0f, Color.Red.ToArgb()); verts[2] = new CustomVertex.PositionColored(1.0f, 1.0f, 1.0f, Color.Red.ToArgb()); verts[3] = new CustomVertex.PositionColored(-1.0f, -1.0f, 1.0f, Color.Red.ToArgb()); verts[4] = new CustomVertex.PositionColored(1.0f, -1.0f, 1.0f, Color.Red.ToArgb()); verts[5] = new CustomVertex.PositionColored(1.0f, 1.0f, 1.0f, Color.Red.ToArgb()); // Arka Yüz verts[6] = new CustomVertex.PositionColored(-1.0f, 1.0f, -1.0f, Color.Blue.ToArgb()); verts[7] = new CustomVertex.PositionColored(1.0f, 1.0f, -1.0f, Color.Blue.ToArgb()); verts[8] = new CustomVertex.PositionColored(-1.0f, -1.0f, -1.0f, Color.Blue.ToArgb()); verts[9] = new CustomVertex.PositionColored(-1.0f, -1.0f, -1.0f, Color.Blue.ToArgb()); verts[10] = new CustomVertex.PositionColored(1.0f, 1.0f, -1.0f, Color.Blue.ToArgb()); verts[11] = new CustomVertex.PositionColored(1.0f, -1.0f, -1.0f, Color.Blue.ToArgb()); //Üst Yüz verts[12] = new CustomVertex.PositionColored(-1.0f, 1.0f, 1.0f, Color.Yellow.ToArgb()); verts[13] = new CustomVertex.PositionColored(1.0f, 1.0f, -1.0f, Color.Yellow.ToArgb()); verts[14] = new CustomVertex.PositionColored(-1.0f, 1.0f, -1.0f, Color.Yellow.ToArgb()); verts[15] = new CustomVertex.PositionColored(-1.0f, 1.0f, 1.0f, Color.Yellow.ToArgb()); verts[16] = new CustomVertex.PositionColored(1.0f, 1.0f, 1.0f, Color.Yellow.ToArgb()); verts[17] = new CustomVertex.PositionColored(1.0f, 1.0f, -1.0f, Color.Yellow.ToArgb()); // Alt Yüz verts[18] = new CustomVertex.PositionColored(-1.0f, -1.0f, 1.0f, System.Drawing.Color.Black.ToArgb()); verts[19] = new CustomVertex.PositionColored(-1.0f, -1.0f, -1.0f, Color.Black.ToArgb()); verts[20] = new CustomVertex.PositionColored(1.0f, -1.0f, -1.0f, Color.Black.ToArgb()); verts[21] = new CustomVertex.PositionColored(-1.0f, -1.0f, 1.0f, Color.Black.ToArgb()); verts[22] = new CustomVertex.PositionColored(1.0f, -1.0f, -1.0f, Color.Black.ToArgb()); verts[23] = new CustomVertex.PositionColored(1.0f, -1.0f, 1.0f, Color.Black.ToArgb()); // Sol Yüz verts[24] = new CustomVertex.PositionColored(-1.0f, 1.0f, 1.0f, Color.Gray.ToArgb()); verts[25] = new CustomVertex.PositionColored(-1.0f, -1.0f, -1.0f, Color.Gray.ToArgb()); verts[26] = new CustomVertex.PositionColored(-1.0f, -1.0f, 1.0f, Color.Gray.ToArgb()); verts[27] = new CustomVertex.PositionColored(-1.0f, 1.0f, -1.0f, Color.Gray.ToArgb()); verts[28] = new CustomVertex.PositionColored(-1.0f, -1.0f, -1.0f, Color.Gray.ToArgb()); verts[29] = new CustomVertex.PositionColored(-1.0f, 1.0f, 1.0f, Color.Gray.ToArgb()); //Sağ Yüz verts[30] = new CustomVertex.PositionColored(1.0f, 1.0f, 1.0f, Color.Green.ToArgb()); verts[31] = new CustomVertex.PositionColored(1.0f, -1.0f, 1.0f, Color.Green.ToArgb()); verts[32] = new CustomVertex.PositionColored(1.0f, -1.0f, -1.0f, Color.Green.ToArgb()); verts[33] = new CustomVertex.PositionColored(1.0f, 1.0f, -1.0f, Color.Green.ToArgb()); verts[34] = new CustomVertex.PositionColored(1.0f, 1.0f, 1.0f, Color.Green.ToArgb()); verts[35] = new CustomVertex.PositionColored(1.0f, -1.0f, -1.0f, Color.Green.ToArgb());
Küpümüzü oluşturduktan sonra küpümüzü hareket etirmek için Device.Transform objesini kullanacağız. Device.Transform objesi, üzerinde çalıştığımız Direct3D aygıtının görünüşünü ve nesnelerin hareketleri için kullanılan bir sınıftır. Device.Transform.View ise nesneye hangi yönden bakacağımızı belirlediğimiz yapıdır. Device.Transform.Projeksiyon ile baktığımız nesneye hangi açıdan nasıl baktığımızı belirteceğiz. Sağ ve sol el kuramını kullanmamıza göre çalıştırdığımız fonksiyon isimleri değişecektir. Yani aşağıdaki fonksiyonlar Matrix.LookAtLH ve Matrix.PerspectiveOffCenterLH şeklinde olacaktı. Matrix.LookAtRH fonksiyonu 3 tane vektör almaktadır. Bu vektörler X,Y,Z koordinatlarını veren birer noktadır. Matrix.LookAtRH ile nesneye nasıl bakacağımızı yani formun bakış kamerası koordinatlarını belirtiriz. İlk nokta ile kameranın uzayda durduğu koordinatı belirtiriz, ikinci nokta ile kamaranın bakacağı noktayı belirleriz son olarak ise kamaranın yükseklik koordinatını veririz. PerspectiveOffCenterRH fonksiyonu ile projeksiyon matrisi elde edilir. Bu fonksiyonun birinci parametresi görüş açısını, ikinci parametresi olarak pencerenin yatay/düsey oranını (aspectRatio) alır. 3 ve 4. parametreler ise znearPlane ve zfarPlane olarak geçer yani kameranın(ekranın) hangi derinliğine baktığını bilgisini alır. Eğer znearPlane ve zfarPlane değeri arasında olmayan tanımlanmış nesneler varsa bunlar kamera üzerinde görülmeyecektir. Aygıtınızın nasıl bir eksende döneceğinizi aygıtınızın Transform.World değerini vererek belirtebilirsiniz. Aygıtınızı X,Y veya karışık modda döndürebilirsiniz. burada angle değişkeni radyan cinsinden açıdır. Ayrıca formunuz üzerinde herhangi bir ışık kaynağı tanımlamadığınız için device.RenderState.Lighting = false; yapmanız gerekmektedir. Eğer bu işlemi yapmazsanız küpün tüm yüzleri siyah çıkacaktır. Aşağıdaki koddan farklı olarak device.Transform.World=Matrix.RotationX(angle); ile X ekseni üzerinde, device.Transform.World=Matrix.RotationY(angle); ile Y ekseni üzerinde hareket işlemini yapar.
device
X,Y hareket
Y Ekseni üzerinde küpü hareket ettirme
X Ekseni üzerinde hareket ettirme
Makalede ya da kodlarda bulunan hatalar ya da sorularınız için mehmetaliecer@gmail.com adresinden bana ulaşabilirsiniz. İyi çalışmalar. Mehmet Ali ECER
www.mehmetaliecer.com
using
namespace
{
static class Program
public class Form1 : System.Windows.Forms.Form
private Device device = null;
private VertexBuffer vb = null;
private System.ComponentModel.Container components = null;
private float angle = 0.0f;
public Form1()
InitializeComponent();
this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque, true);
}
public void InitializeGraphics()
PresentParameters presentParams = new PresentParameters();
presentParams.Windowed = true;
presentParams.SwapEffect = SwapEffect.Discard;
device = new Device(0, DeviceType.Hardware, this, CreateFlags.SoftwareVertexProcessing, presentParams);
vb = new VertexBuffer(typeof(CustomVertex.PositionColored), 36, device, Usage.Dynamic | Usage.WriteOnly, CustomVertex.PositionColored.Format, Pool.Default);
vb.Created += new EventHandler(this.OnVertexBufferCreate);
OnVertexBufferCreate(vb, null);
private void OnVertexBufferCreate(object sender, EventArgs e)
VertexBuffer buffer = (VertexBuffer)sender;
CustomVertex.PositionColored[] verts = new CustomVertex.PositionColored[36];
verts[0] = new CustomVertex.PositionColored(-1.0f, 1.0f, -1.0f, Color.Red.ToArgb());
verts[1] = new CustomVertex.PositionColored(-1.0f, -1.0f, -1.0f, Color.Red.ToArgb());
verts[2] = new CustomVertex.PositionColored(1.0f, 1.0f, -1.0f, Color.Red.ToArgb());
verts[3] = new CustomVertex.PositionColored(-1.0f, -1.0f, -1.0f, Color.Red.ToArgb());
verts[4] = new CustomVertex.PositionColored(1.0f, -1.0f, -1.0f, Color.Red.ToArgb());
verts[5] = new CustomVertex.PositionColored(1.0f, 1.0f, -1.0f, Color.Red.ToArgb());
verts[6] = new CustomVertex.PositionColored(-1.0f, 1.0f, 1.0f, Color.Blue.ToArgb());
verts[7] = new CustomVertex.PositionColored(1.0f, 1.0f, 1.0f, Color.Blue.ToArgb());
verts[8] = new CustomVertex.PositionColored(-1.0f, -1.0f, 1.0f, Color.Blue.ToArgb());
verts[9] = new CustomVertex.PositionColored(-1.0f, -1.0f, 1.0f, Color.Blue.ToArgb());
verts[10] = new CustomVertex.PositionColored(1.0f, 1.0f, 1.0f, Color.Blue.ToArgb());
verts[11] = new CustomVertex.PositionColored(1.0f, -1.0f, 1.0f, Color.Blue.ToArgb());
verts[12] = new CustomVertex.PositionColored(-1.0f, 1.0f, -1.0f, Color.Yellow.ToArgb());
verts[13] = new CustomVertex.PositionColored(1.0f, 1.0f, 1.0f, Color.Yellow.ToArgb());
verts[14] = new CustomVertex.PositionColored(-1.0f, 1.0f, 1.0f, Color.Yellow.ToArgb());
verts[15] = new CustomVertex.PositionColored(-1.0f, 1.0f, -1.0f, Color.Yellow.ToArgb());
verts[16] = new CustomVertex.PositionColored(1.0f, 1.0f, -1.0f, Color.Yellow.ToArgb());
verts[17] = new CustomVertex.PositionColored(1.0f, 1.0f, 1.0f, Color.Yellow.ToArgb());
verts[18] = new CustomVertex.PositionColored(-1.0f, -1.0f, -1.0f, System.Drawing.Color.Black.ToArgb());
verts[19] = new CustomVertex.PositionColored(-1.0f, -1.0f, 1.0f, Color.Black.ToArgb());
verts[20] = new CustomVertex.PositionColored(1.0f, -1.0f, 1.0f, Color.Black.ToArgb());
verts[21] = new CustomVertex.PositionColored(-1.0f, -1.0f, -1.0f, Color.Black.ToArgb());
verts[22] = new CustomVertex.PositionColored(1.0f, -1.0f, 1.0f, Color.Black.ToArgb());
verts[23] = new CustomVertex.PositionColored(1.0f, -1.0f, -1.0f, Color.Black.ToArgb());
verts[24] = new CustomVertex.PositionColored(-1.0f, 1.0f, -1.0f, Color.Gray.ToArgb());
verts[25] = new CustomVertex.PositionColored(-1.0f, -1.0f, 1.0f, Color.Gray.ToArgb());
verts[26] = new CustomVertex.PositionColored(-1.0f, -1.0f, -1.0f, Color.Gray.ToArgb());
verts[27] = new CustomVertex.PositionColored(-1.0f, 1.0f, 1.0f, Color.Gray.ToArgb());
verts[28] = new CustomVertex.PositionColored(-1.0f, -1.0f, 1.0f, Color.Gray.ToArgb());
verts[29] = new CustomVertex.PositionColored(-1.0f, 1.0f, -1.0f, Color.Gray.ToArgb());
verts[30] = new CustomVertex.PositionColored(1.0f, 1.0f, -1.0f, Color.Green.ToArgb());
verts[31] = new CustomVertex.PositionColored(1.0f, -1.0f, -1.0f, Color.Green.ToArgb());
verts[32] = new CustomVertex.PositionColored(1.0f, -1.0f, 1.0f, Color.Green.ToArgb());
verts[33] = new CustomVertex.PositionColored(1.0f, 1.0f, 1.0f, Color.Green.ToArgb());
verts[34] = new CustomVertex.PositionColored(1.0f, 1.0f, -1.0f, Color.Green.ToArgb());
verts[35] = new CustomVertex.PositionColored(1.0f, -1.0f, 1.0f, Color.Green.ToArgb());
buffer.SetData(verts, 0, LockFlags.None);
private void SetupCamera()
device.RenderState.Lighting = false;
angle = angle + 0.01f;
device.Transform.World=Matrix.RotationYawPitchRoll(angle,angle,angle);
device.Transform.View = Matrix.LookAtRH( new Vector3(0.0f, 0.0f, -5.0f), new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0.0f, 1.0f, 0.0f));
device.Transform.Projection = Matrix.PerspectiveOffCenterRH(-1.0f * (float)this.Width /(float)this.Height, 1.0f * (float)this.Width / (float)this.Height, -1.0f, 1.0f, 1.0f, 100.0f);
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
device.Clear(ClearFlags.Target, Color.CornflowerBlue, 1.0f, 0);
SetupCamera();
device.BeginScene();
device.VertexFormat = CustomVertex.PositionColored.Format;
device.SetStreamSource(0, vb, 0);
device.DrawPrimitives(PrimitiveType.TriangleList,0, 12);
device.EndScene();
device.Present();
this.Invalidate();
protected override void Dispose(bool disposing){
if (disposing){
if (components != null)
components.Dispose();
base.Dispose(disposing);
#region Windows Form Designer generated code
private void InitializeComponent()
this.components = new System.ComponentModel.Container();
this.Size = new Size(800, 600);
this.WindowState= FormWindowState.Maximized;
this.Text = "mehmet ali ecer";
ShowInTaskbar = false;
this.ShowIcon=false;
this.TopMost=true;
#endregion
static void Main()
using (Form1 frm = new Form1())
frm.Show();
frm.InitializeGraphics();
Application.Run(frm);
}}
}}}