Çarşamba, Nisan 30, 2008

Microsoft Üniversite Lansmanlarının Sonuncusu Ktü 'de Gerçekleştirildi

30 Nisan 2008 Çarşamba günü Karadeniz Teknik Üniversitesi Atatürk Kültür Merkezinde Microsoft yazılım geliştirme platformuna ilişkin lansman yapıldı. Tüm dünyada "Heroes Happen Here", ülkemizde ise "Bilişim kahramanları Aramızda" slogunuyla gerçekleştirilen, Microsoft'un 2008 de piyasaya sundugu en yeni ürünleri olan Microsoft Server 2008, SQL Server 2008, Visual Studio 2008 ürünlerinin tanıtıldığı üniversite lansmanlarının sonuncusu, KTÜ 'de gerçekleşti.

Bu güzel etkinliğin KTÜ gerçekleşmesinde en büyük çalışmayı ise MSP Ahmet KAKICI üstlendi. Kendisi gecesini gündüzüne katarak çok güzel bir organizasyon sundu bizlere. Ben ve diğer arkadaşlarımızda elimizden geldiğince kendisine yardım etmeye çalıştık. Bu güzel etkinlik için kendisine buradan da sonsuz teşekkürlerimi sunuyorum ve sunuyoruz...

Etkinlik sonrası katılımcılara doldurdukları formlar karşılığında Bilişim kahramanları aramızda kupalarından hediye edildi. Umarım arkadaşlarımız bu ufak hediyeleri beğenmişlerdir.

Not: Dağıtmış olduğumuz kupalara öğrenci arkadaşlarımızın dışında KTÜ personeli ve üst düzey akademisyenlerin oldukça garipsediğim davranışları oldukça ilginçti. Öğrencilere dağıtılacak olan bardaklardan yaklaiık 6 kolisine bir şekilde sahip oldular. Böyle bir davranış olmasaydı biz zaten kendilerine birer tane dağıtacaktık. Ama kişi başı kupa sayısı arttıkça öğrencilerin hakkının yendiğini düşündüm. Bu da seminerin üzücü yüzüydü.

Ama her ne olursa olsun öğrenci arkadaşlarımız ve MSP Ahmet KAKICI için iyi bir etkinlik oldu. Seminer öncesinden güzel bir resmi aşağıda bulabilirsiniz. Ben ve Ahmet 'teki yorgunluk ifadeleri 25 koli hediye taşıdığımız için oluşmuştur. :)

Etkinlik...

Ortamızdaki arkadaşımız Bilgisayar Mühendisliği 3. sınıf öğrencisi Mustafa YAZICI 'dır...

Cumartesi, Nisan 26, 2008

Controlling the Distribution of Silverlight Updates in the Enterprise

If you're a systems administrator, one of the aspects of Silverlight that concerns you is probably controlling the distribution of updates. In general, enterprises like to control their desktop and laptop environments to ensure no sudden surprises are caused (for example, by a runtime update that breaks a commonly used application). So some people may wish to dial down the update settings that are optimized for end-users when Silverlight is running in a corporate environment.

Silverlight supports enterprise rollout via WSUS and we provide guidance on how to roll it out across an enterprise via other means such as Group Policy (using the EXE-based installer). Silverlight is installed via a normal MSI plus an MSP-based patch which can be chained through a variety of means. Updating Silverlight to the latest revision can be done automatically or manually (by pushing out the latest MSP).

There are two different knobs an enterprise administrator can turn to control how updates are applied to the runtime:

  • Firstly, if the enterprise sets the UpdateMode DWORD registry value under the HKLM\Software\Microsoft\Silverlight key to 2 then the Silverlight auto-updater will be disabled (i.e. it won't automatically check for updates or try to install them). This is the equivalent to an end-user choosing the Silverlight Configuration dialog and manually disabling auto-updates from the Updates tab.
  • Second, the feature that allows a non-admin to patch Silverlight on Windows Vista without requiring admin elevation is not a Silverlight feature: it's a feature of Windows Installer which can be disabled if the admin wants to do so (and is indeed off-by-default in Windows Server 2008). You can switch this off using Group Policy by setting the DisableLUAPatching property. More information on UAC Patching can be found on MSDN.

If an enterprise disables the LUA patching feature in MSI and does not give their users administrative access to machines then users will not be able to install, remove or patch Silverlight. Only the enterprise administrator could touch the files. Obviously, it's important that someone is actively monitoring and distributing patches; as with any runtime for any operating system, without any means to fix potential security vulnerabilities, users' machines are at risk.

Configuring a Web Server to Host Silverlight Content

Deploying Silverlight content to a production web server is a pretty easy process. Despite occasional misconception, Silverlight doesn't require a Microsoft-based web server: Apache can host up Silverlight content just as happily as IIS.

But there's one little gotcha: web servers are typically configured to only serve up a limited set of known file extensions as static content. That's all well and good, but Silverlight introduces two new file extensions (.xaml for loose XAML files and .xap for the zip-based binary packaging format). As a result, you need to add the MIME types for those file extensions to your web server so that it recognizes Silverlight content appropriately. Here are the MIME types you need to add to the server configuration:

Extension - MIME Type

.xaml - application/xaml+xml

.xap - application/x-silverlight-app

That's all you have to do. Unfortunately, it's not possible to provide generic instructions for how to add MIME types, as it varies from server to server, but here are some links for various common web servers:

While you're updating the list of MIME types served, you might want to also add the relevant types to your web server to support WPF and ClickOnce applications. Here are the additional items you'll need:

Extension - MIME Type

.manifest - application/manifest

.application - application/x-ms-application

.xbap - application/x-ms-xbap

.deploy - application/octet-stream

.xps - application/vnd.ms-xpsdocument

But what if you're hosting your Silverlight application on a shared hosting service and your hoster doesn't give you access to change these settings? The good news is that there are two options available to you. Obviously, you could take advantage of Silverlight Streaming, our free hosting service for up to 10GB of Silverlight content.

Alternatively, you can "cheat" the web server by renaming the XAP file extension to a compatible MIME type. The XAP container is ZIP-based, so you can simply rename the output file from .xap to .zip and change the source param within the object tag contained in the HTML file to point to the new file location. Click on this hyperlink to see the technique in action - it's a plain HTML file that points to a ZIP file (containing the Silverlight content).

One last piece of good news: IIS 7, included in Windows Server 2008, already includes all the relevant MIME types for both WPF and Silverlight, including both .xap and .xaml extensions, so if you're using Windows Server 2008, you're all set. (The same applies to a clean install of Windows Vista SP1, although if you upgrade from the RTM to the SP1 release, your settings will remain unchanged until you uninstall and reinstall the IIS feature).

What does Windows Vista SP1 Mean for Developers?

Aside from the inevitable bug fixes and enhancements to support new hardware types, one of the underlying changes is that SP1 brings the Windows Vista and Windows Server 2008 codebases together.WV-SP1_h_rgb_3

This is a big deal, but it's surprising how few people have noted it: this is the first time we've ever had a common codebase for Windows that goes all the way from a budget consumer PC right up to a mainframe-class datacenter server. Internally to Microsoft, this makes it easier for us to provide sustained engineering on the product: if we want or need to update a system component, we only have to produce two binaries (x86 and x64) for all languages and product editions. Compare that to the days of Windows XP/2003, when we had maybe 25 different language editions and x86 and x64 variants for both client and server OS releases, and you can see how the testing matrix has become a lot simpler! Externally, the benefit is of course that simply by updating to SP1, you get the benefit of a kernel that has been through an extensive server-hardening process. (Check out this Channel 9 video I recorded last year with Eric Hanson to get just a small flavor of the stress testing work that we do with every build.)

Beyond the kernel and subsystem improvements, Windows Vista SP1 brings major improvements to IIS 7. Comparing the original Windows Vista "RTM" version against that shipped with SP1 is like comparing the basic and premium models of a car - the SP1 version of IIS contains all the features added to create the server-strength edition (with the caveat that Windows Vista SP1 is obviously not licensed for use as a commercial-scale production Internet web server). As a crude measure, compare the two screenshots of the administration console below - the left image is of Windows Vista RTM, the right is of SP1:

IISComparison_4

You'll see other changes to Windows Vista that affect certain relatively niche groups of developers. Direct3D receives a minor update to 10.1; there are new APIs to control the Data Execution Protection and Kernel Patch Protection features; and there are new cryptographic and random number generation algorithms available for developer use. As ever, more information about these features can be found in the Windows SDK.

image_7

As a .NET developer, you'll notice that Vista SP1 updates the installed .NET components to .NET Framework 3.0 Service Pack 1. The good news is that many of the enhancements from .NET Framework 3.5 are included in 3.0 SP1 - for example, everything apart from System.AddIn and the Firefox XBAP support is included in Windows Vista SP1. This is a little bit confusing, but it probably helps to know that each of the last .NET Framework releases have built on top of each other, rather than existing side-by-side. The diagram to the right demonstrates this.

As a result, all the CLR and class library enhancements that were made to existing assemblies in 3.5 are incorporated in 3.0 SP1 (mscorlib.dll is updated from 2.0.50727.312 to 2.0.50727.1434); the binaries are identical to those shipped with .NET Framework 3.5. The only difference between 3.0 SP1 and 3.5 is that 3.0 SP1 doesn't have any of the new assemblies ("green bits") added in 3.5 for new capabilities like LINQ. Of course, if you've already installed .NET Framework 3.5 on your Windows Vista machine prior to installing SP1, you'll still have the full 3.5 release on your machine afterwards.

The many other nice features in SP1 for end-users and IT Professionals are outside of the scope of this entry, but suffice it to say that some of the major peeves have been addressed: UAC is less aggressive, file copy performance has been greatly improved (and it takes less time to "estimate"!), application compatibility is better, resuming from standby is faster, and over a thousand bugs have been fixed. For more detail on all these items, check out the main Windows Vista Service Pack 1 site.

It's worth noting in closing that many of the above fixes at least have been delivered via Windows Update over the last twelve months. We're moving away from the old-school approach where service packs were the main way that fixes were delivered to a more agile model where patches are available via Windows Update (or its enterprise equivalent, WSUS) and then rolled into a service update at a later stage. The goal is to reduce the gap between us fixing something and you seeing the results of that fix.

Well, what are you waiting for? Go install Windows Vista Service Pack 1!

Thanks, Tim Sneath...

yazgelistir.com Silverlight Bölüm Editörlüğü

Bugün güzel bir gelişme oldu ve yazgelistir.com ' da Silverlight bölümünün editörü oldum. Buradan tüm YazGeliştir ekibine ve özellikle Işıl Orhanel 'e ilgisi ve çalışması için teşekkür ediyorum. Artık bir YazGelistir yazarı olarak Silverlight makalelerimi yazdıktan sonra bir YazGelistir editörü olarak da kendi makalelerimi onaylayabileceğim. Güzel bir duygu olacak sanırım.

MakaleGonder Yazgelistir

Silverlight 2.0 - İlk Uygulamamız

Silverlight ‘ı ilk olarak WPF/E olarak tanımıştık. Zaman ilerledikten sonra kod adını bir kenara atarak Microsoft Silverlight adını almıştır. Silverlight ile geliştirdiğimiz ilk uygulamalar XAML ve JavaScript bileşiminden oluşuyordu. Silverlight ‘ın 1.0 sürümü biraz önce bahsettiğimiz birleşim ile uygulama geliştirmek istediğimizde yapacak olduğumuz bir çok işlemi JavaScript ler ile yapmamız gerekiyordu. Örneğin, farenin sağ tuşuna tıklanması sonucu gerçekleşecek olan bir olayı ilk olarak JavaScript ‘te bir fonksiyon olarak tanımlarız ve sonrasında da XAML kod tarafında kullanacak olduğumuz kontrole ekleriz. Fakat bu kontroller üzerinde istediğimiz düzeyde müdahale yapabilmemiz mümkün olmuyordu.

Zamanlar ilerledi ve Silverlight 1.1 sürümü karşımıza çıktı. Bu sürümde ise bir nebzede olsa form kontrolleri kullanılmaya başlanmış ve XAML kod tarafından web formların yönetilebilirliği arttırılmıştır.

Silverlight ‘ın ilk duyurulduğu 2007 Nisan ayından bu yana gerçekleşen gelişmeler bu şekildeydi. 2008 yılına girdiğimizde ise Silverlight 2.0 ‘ın beta1 sürümü duyuruldu. Artık Silverlight ile geliştirmiş olduğumuz web form uygulamalarında Silverlight için yeniden elden geçirilmiş olan kontrolleri kullanabileceğiz.

Silverlight 2.0 Beta1 ile gelen yenilikleri, kurulum esnasında sorun yaşarsak nasıl çözebileceğimizi ve bir önceki sürümlerine oranla mimari anlamda ne tür değişiklikler yapıldığını daha önceki yazılarımızda incelemiştik. Bu yazımızda ise, programcılık tekniğinin ilk adımı olan Merhaba dünya uygulamasını Silverlight 2.0 Beta1 ile gerçekleştirmeye çalışacağız. Bu yazımızı takiben yayınlayacak olduğumuz yazılarda ise WPF ile sıklıkla kullanmaya başladığımız birçok kontrolü sınırlıda olsa Silverlight 2.0 Beta1 ile nasıl kullanabileceğimize değinmeye çalışıyor olacağız.

İlk olarak Silverlight ’ı bilgisayarımıza kurmamız gerekmektedir. Bunu daha önceki makalelerimizde açıklamaya çalışmıştık, bu sebepten ötürü sadece yüklü olan programlarımız tarafında hangi bileşenlerinin kurulu olarak gözüktüğüne dair ekran görüntüsünü vereceğiz.


Sistemimizde bu üç parçanın kurulu olması gerekmektedir.

Yukarıdaki bileşenler sistemimizde kurulu olduğuna göre Silverlight uygulamamızı geliştirmeye başlayabiliriz.

Uygulamamızı Visual Studio 2008 ile geliştirebilmemizin yanında Expression Blend ile de geliştirebilmemiz mümkündür. Ufak bir notu da sizlere iletmek isterim. Silverlight 2.0 Beta1 .Net IDE ‘lerin den yalnızca Visual Studio 2008 ’e kurulabilmektedir.

Visual Studio ile ilk uygulamamızı geliştirmeye başlarken New->Project yolunu izleyerek C# tarafından Silverlight tagının üzerine tıklayarak geliştirecek olduğumuz Silverlight uygulamasının türünü ve adını seçiyoruz.


Uygulamamızın ismini yazdıktan sonra “OK” diyerek oluşturmasını istiyoruz. Daha sonrasında çıkan ekran bu uygulamayı web sayfasında kullanacağımız için bir sonraki ekranda çıkan mesaja tamam dedikten sonra ilk Silverlight 2.0 Beta1 uygulamamızı oluşturmuş oluyoruz.

Uygulamamız oluşturulduğu zaman karşımıza iki farklı uygulama oluşturulmuş gibi bir görünüm çıkıyor. ASP.net uygulamasında Client-Server ‘ı kullanabilmemiz için oluşturuluyor. Bu oluşturulan bölümde statik sayfa oluşturuluyor. Bu statik sayfayı mümkün olduğunca birçok sunucuda kullanabilmemize olanak tanınmaktadır.

Oluşturulmuş olan uygulamadaki dosyanın ekran görüntüsü aşağıdaki gibi gözükmektedir.


Silverlight Projesinde oluşan dosyaların ne olduğunu anlamaya çalışalım.

Silverlight uygulamasını oluşturulduğumuz proje tarafında oluşturulan App.xaml ve Page.xaml dosyaları ve bu dosyalara kod ekleyebilmemize olanak tanıyan sınıfları yer almaktadır. Bu sınıflar C#, VB, Rubby, Pyhton dilleri ile kodlanabilmektedir.


App.xaml dosyasının içerisinde uygulamaya ait stil ve brush nesneleri yer alırken kod tarafında ise hangi sayfanın ilk açılış sayfası olacağı(Application_Startup ) , hangi sayfanın çıkış sayfası olabileceği (Application_Exit) ve hata alınması durumunda (Application_UnhandledException) hangi sayfaya gidileceği gibi olaylar yer almaktadır.

Page.xaml ‘in WPF uygulamalarında kullanım biçimindeki en büyük farkı, WPF ‘de Page.xaml ‘de başlangıç formunu belirlerken Silverlight ‘ta Page.xaml ‘e ait olan kod sınıfının içerisinde belirlenmektedir.

Uygulamamızda gerçekleşebilecek olayları Page.xaml dosyasına ait olan sınıfta tanımlayabilmemiz mümkündür.

Oluşturmuş olduğumuz Silverlight uygulamasını derlediğimiz zaman ClientBin dosyasının içerisinde TurhalDigi.xap .Net Assembly dosyasının oluştuğunu göreceksiniz.


*.xap ‘ta (okunuşu = zap) standart sıkıştırma algoritması kullanılarak minimize edilmiştir. Bu sayede kullanıcı tarafında bir istek geldiğinde hızlıca isteğe cevap verilemesine olanak tanınacaktır.

Silverlight 2 uygulamalarında taglarının içerisinde standart HTML kodları kullanılabilmektedir. *.xap dosyalarını belirtirken javascript leri HTML sayfaya tanıttığımız gibi tanıtmamız gerekmemektedir. Ayrıca Silverlight 2 ‘nin en güzel özelliklerinden birisi cross browser (ie, Firefox ve safari) ve cross systems (Windows, Linux, mac, v.d.) sorunsuzca çalışabilmesidir.

Silverlight uygulamamızı herhangi bir değişiklik yapmadan derlemek istediğimizde TestPage.aspx web sayfasının ilk açılan sayfa olduğunu ve bu sayfanın her tamamıyla Silverlight ile oluşturulduğunu göreceksiniz.

Silverlight kontrollünü ve bu kontrole ait el ile işlem olaylarını öğreniyoruz

Silverlight 2 Beta1 ‘in diğer Silverlight sürümlerinden en büyük değişikliğinin form kontrollerini kullanabiliyor olmamız olduğundan bahsetmiştik. Şimdi bu kontrolleri uygulamalarımızda nasıl kullanabileceğimize değinmeye çalışalım.

Form kontrollerini eklerken Page.xaml dosyasından yararlanıyoruz.


Dikkat edeceğiniz üzere diğer Silverlight sürümlerine oranla daha başarılı bir intellisence bulunuyor. İstersek Silverlight kontrollerinde istediğimizi App.xaml dosyasının içeriğine ekleyerek kullanabiliriz. Biz Button kontrolünün kod tarafında kullanılabilmesi için adını dugme olarak belirliyoruz. Bu özelliğinin dışında üzerinde yazacak olan yazısını, genişliğini ve yüksekliğini de belirtiyoruz. Silverlight 2 Beta1 ‘de henüz özellikler bölümünü aktif olarak çalışamamaktadır.


Button kontrolümüze eklemiş olduğumuz özellikler sonucunda nasıl bir form görüntüsüne kavuştuğuna göz atalım.


Oldukça güzel bir görüntüye sahip Silverlight formumuz oluştu. Fakat biz butona tıkladığımız zaman herhangi bir işlem yapmamaktadır. Şimdi butona tıklanması olayını nasıl yapacağımıza değinmeye çalışalım.

Buttonumuzun özelliklerine göz attığımızda Click olayına da verebileceğimiz özelliklerin olduğunu görürüz. İşte biz bu özelliğe tıklanması esnasında kod tarafında çağırılması için bir olay kontrolcüsü tanımayacağız.


Butonun tıklanması olayına vereceğimiz kontrol ise,


Biz bu tıklanma olayına vereceğimiz ismi kendi inisiyatifimize göre verebilirken, istersek VS IDE ‘sine de otomatik olarak oluşturtabiliyoruz. Biz IDE ‘ye oluşturtuyoruz ve aşağıdaki bir isim tanımlıyor.


Buttona tıklanma olayları Page.xaml.cs sınıfının içerisine oluşturulmaktadır. Oluşturulan bu tıklanması olayı masaüstü uygulamalardan özelliklede Windows Presentation Foundation ‘dan alıştığımız biçimde oluşmaktadır.


Butonumuza tıklandığı zaman içeriğine istediğimiz mesajı yazdırabiliyoruz. Şimdi bu küçük uygulamamız derleyerek nasıl bir sonuç alacağımıza göz atabiliriz.


Evet, uygulamamız başarılı bir şekilde derlendi ve istediğimiz işlemi yaparak butona tıkladığımızda “Dugmeye basildi…” yazısını üzerinde gösterdi. Ayrıca uygulamamızı derlerken Cross browser özelliğini de değinebilmek için Apple Safari tarayıcısında derleyerek test ettik. Sonuç ise Internet Explorer ‘da olduğu gibidir.

Bu yazımızda Silverlight 2.0 uygulamalarına ilk adımımızı atmış oluyoruz. Temel olarak Silverlight 2.0 ‘ı tanıdık ve ilk uygulamamızı geliştirdik. Bir sonraki yazımızda TurhalDigi projemizin üzerinden web form ‘umuzun ekranını nasıl kontrol edebileceğimizi incelemeye çalışıyor olacağız.

Umarım yararlı olmuştur.

Yazımızda değinmiş olduğumuz uygulamanın kaynak kodlarına linkten erişebilirsiniz.

Turhal Temizer

Pazar, Nisan 20, 2008

WPF – Uygulamalara Video Kontrolleri Eklemek

2005 yılında Windows Presentation Foundation ile ilgili söylentiler ortaya atıldığında, Adobe Flash ile yapabildiğimiz bütün işlemleri ve daha fazlasını masaüstü ve web uygulamalarında yapabileceğimizden söz edilmişti. Daha sonra .Net Framework 3.0 ‘ın ilk sürümleri olarak .Net FX bizlere sunulduğundan bu söylentilerin gerçekleşebileceği düşünceleri zihnimizde canlanmaya başlamış ve özellikle masaüstü uygulamalarda devrim niteliği taşıyabileceğini düşünmeye başlamıştık. Belirli zaman geçtikten sonra WPF ‘i yalnızca masaüstü uygulamalar için kullanılacağına ve web uygulamalarının isminin de Microsoft Silverlight olacağını gözlemlemiş olduk. WPF ile de web uygulamaları yayınlamak hala mümkün olmakta ve bu tür uygulamalara da XBAP uygulamalar denilmiştir. Web tarafında Silverlight ‘ın estirdiği fırtınayı masaüstü uygulamalarında da WPF gerçekleştirmeye başlamıştı.

WPF ile gelen ve dünya da en çok kullanılan ürünler ile Windows Vista, Office System 2007 ve Windows Live Messenger 8.0 ve sonrası olmuştur. Karşımıza gelen bu ürünlerin ortak özellikleri tasarımlarının bir önceki sürümlerine oranla inanılmaz değişikler gösterebilmiş olmasıdır. Özelliklere kısaca örnek vermek gerekirse, Windows Vista ile izleyeceğimiz bir videoyu herhangi bir oynatıcı açmadan izleyebiliyor olmamızdır. Bu ve bunun gibi birçok işlemin ana özelliği uygulamalarımızda yer alan kontrolleri dinamik bir biçimde kullanabiliyor olmamızdır.



Windows Vista ile nasıl video kontrollerini kullanıldığını yukarıdaki ekran görüntüsünden bakabiliriz. Son kullanıcılar bu tür kontrolleri kullandıkça bizlerden geliştirmemizi istedikleri uygulamalarda bu tür kullanım kolaylıklarının olmasını istemektedirler. Bizlerde bu tür istekleri uygulamamızın performansını da düşünerek gerçekleştirmeye çalışırız.

Windows kontrollerinin daha iyileştirilmiş ve yeni nesil sistemler ile uyumlu olabilmesi açısından WPF ile geliştirmek bizler için her daim ayrıcalıklı bir durum olacaktır. Ayrıcalıklı durumdan kastımız, uygulamalarımızda ne kadar en son teknoloji kullanırsak son kullanıcılar tarafında o kadar coşku uyandırırız. Müşteri memnuniyetine dayalı bir dünyada yaşadığımız içinde bu bize çok daha fazlası ile katma değer olarak geri dönecektir.

Kısaca neden yeni kontrolleri kullanmamız gerektiğini ve bu kontrollerden video kontrolünün Windows Vista işletim sistemi ile nasıl gözüktüğüne göz attıktan sonra bu makalemizde değinecek olduğumuz WPF uygulamalarına Media kontrollerinin eklenmesi konusunu incelemeye başlayabiliriz.

Win32 uygulamalarımızı dijital Media kontrollerinin eklemenin iki yolu vardır. Bunlardan birincisi animasyon işlemlerini daha canlı göstermek ve video kontrollerini uygulamalarımızda kullanmak için başvurduğumuz DirectShow Api leridir. Bir diğeri ise Windows Media Player ActiveX kontrolüdür. Bu iki kontrolü de uygulamamıza gömülü bir biçimde uygulamalarımızda kullanabiliyoruz.

“Peki, bu iki kontrol varken neden WPF ‘te kullanılmakta olan kontrollerin bizlere sunulduğu” sorusunun cevabını araştırmaya çalışalım. DirectShow ile geliştiricilere Media uygulamaları için inanılmaz fazlalıkla imkânlar sağlanmaktadır. Tabii bu imkânları kullanabilmemiz için bu api hakkında geniş bir bilgi yelpazesine sahip olmamız gerekiyordu. Uygulamalarımızda yalnızca tek bir video göstermek içinde geliştiricilere bu api hakkında geniş bilgi düzeyine sahip olmalarını istemek geliştiriciler için oldukça sıkıcı bir durum oluyordu.

WPF ‘de ise DirectShow api lerinde yer alan kontrollerinin benzerlerini .Net Framework 3.0 ile birlikte gelen özellikler ile rahatlıkla gerçekleştirebilmemiz mümkündür. WPF ile gelen kontrolleri de Win32 uygulamalarında sorunsuzca kullanabiliriz.

Media oynatmak içinde Windows Media Player ActiveX kontrolüne ait özelliklere hâkim olmamız gerekmektedir. Yine geliştiricilere ekstra bir şeyler öğrenmeye zorlamak yerine WPF ile .Net Framework yapısına eklenen MediaElement kontrolü yardımı ile bu işlemleri de sorunsuzca gerçekleştirebilmemiz mümkündür. Kullandığımız bu kontrol yardımı ile videolarımızı 3D yüzeylerdeymiş gibi de kullanabilmemiz mümkündür.

Ses ve Media kontrollerini geliştiriciler kullanmak istediğinde WPF ile sunulan Media özellikleri olduğundan bahsetmiştik. Bu Media özelliklerini kullanmak istediğimizde arka planda Media Player işlemini başlatarak işlemlerimizi gerçekleştirebilmemize olanak sağlanmaktadır. WPF uygulaması açıldıktan sonra Media uygulaması olan sayfada yer alan Media dosyası yüklendikten sonra Media Player ‘ın açabileceği bir format olup olmadığını kontrol ediyor. Eğer bu formatlar dışında bir dosya açmak istiyorsak uygulama bizden codec yüklememizi istemektedir.

Media uygulamaları olan uygulamalarımızdaki dosyalar gösterilirken arka planda dosyalarımızın yüklenmesine devam edilmektedir. Bu yüklenme işlemi biz video ‘yu duraklatsak bile yüklemeye devam edecektir. Video ‘nın yüklenmesini engellemek için yapmamız gereken işlem tamamen durdurmak olacaktır. Ayrıca, ses dosyalarını çaldırabilmemiz için System.Media.SoundPlayer sınıfını da kullanabilmemiz mümkündür.

MediaElement Kontrolünün Kullanılması

Windows Presentation Foundation ile Media dosyalarını göstermenin oldukça kolay olduğundan ve bu tür işlemleri yapabilmek içinde MediaElement kontrolünün gerekli olduğundan üst paragraflarda bahsetmiştik. Bu kontrolü XAML kod tarafında ekleyebileceğimiz gibi C# veya VB.Net kod tarafında MediaElement kontrolünü aktifleştirerek kullanabilmemiz mümkündür. MediaElement kontrolünü uygulamalarımızda kullanırken ya bağımsız olarak kontrollerimizden aldığımı değeler yönetiriz ya da sistem saatinden alarak işlemlerimizi yapmamıza olanak tanıyacaktır.

Bağımsız durumda Media elementi nasıl kullanacağımıza göz atalım;

XAML
<MediaElement Source="Forza.wmv" Width="320" Height="240" LoadedBehavior="Play" />

XAML kod bloğunu uygulamamıza yazıp derlediğimiz zaman uygulamamızın içerisinde videomuzun görüntülendiğine tanık olacağız.

Not: Eğer videonuzun yolunu doğru bir şekilde belirttiğiniz halde gözükmediyse muhakkak projenizin oluştuğu klasörün altında yer alan Debug dizininin altında izlettireceğiniz videonun yer almasına dikkat ediniz.

MediaElement kontrolünün performans açısından çok daha fazla olanaklarının olduğundan ve diğer Api lere oranla işlemciyi daha az yoracağından bahsetmiştik. Şimdi bu söylemlerimizi doğrular nitelikteki ekran görüntülerini veriyoruz. Bu ekran görüntüsünde MediaElement yardımı ile oluşturduğumuz videonun yanında görev yöneticisi yer almaktadır.



MediaElement kontrolümüzü kullanarak çok basit anlamda bir uygulama geliştirdik ve bu uygulamamızı görüntüledik. Şimdi yapacağımız örnekte ise başlat, duraklat, bitir sessiz butonlarının olduğu bir örnek olacaktır. Bu örneğimizde kontrolleri XAML kod tarafında hazırlarken kontrollere verilecek olan görevleri C# kod tarafında oluşturuyor olacağız. Ayrıca kontrollerimizin kullanıcılar tarafından kullanıldığından videoyu kontrol edebilmesi için LoadBehavior özelliğine Manual ‘i atayacağız.

XAML
<Window x:Class="WpfMedia.Window1"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   Title="MediaElement Makale" Height="800" Width="600">
   <Grid>
      <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
         <MediaElement Name="MediaMakale" Source="Forza.wmv"
            LoadedBehavior="Manual" Width="320" Height="240" />
         <StackPanel Orientation="Horizontal" Margin="0,10,0,0">
            <Button Content="Oynat" Margin="0,0,10,0"
               Padding="5" Click="mediaOynat" />
            <Button Content="Duraklat" Margin="0,0,10,0"
               Padding="5" Click="mediaDuraklat" />
            <Button x:Name="sessizButton" Content="Sessiz"
               Padding="5" Click="Sessiz" />
         </StackPanel>
      </StackPanel>
   </Grid>
</Window>

C#
susing System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace WpfMedia
{
   public partial class Window1 : System.Windows.Window
   {
      public Window1()
      {
         InitializeComponent();
         mediaMakale.Volume = 100;
         mediaMakale.Play();
      }

      void mediaOynat(Object sender, EventArgs e)
      {
         mediaMakale.Play();
      }

      void mediaDuraklat(Object sender, EventArgs e)
      {
         mediaMakale.Pause();
      }

      void mediaMute(Object sender, EventArgs e)
      {
         if (mediaMakale.Volume == 100)
         {
            mediaMakale.Volume = 0;
            sessizButton.Content = "Sesli";
         }
         else
         {
            mediaMakale.Volume = 100;
            sessizButton.Content = "Sessiz";
         }
      }
   }
}



MediaElement, zaman durumuna bağlı olarak Windows Presentation Foundation ‘ta yer alan animasyon mimarisine bağlı olarak ta kullanılabiliyor. Zaman durumunu aktifleştirdiğimizde MediaElement ‘in özelliklerinden olan MediaTimeline ve MediaClock özelliklerine başlangıç ve ilerleme değerleri aktararak kullanabiliyoruz. Uygulamalarımızda başlangıç zamanı ve hangi zaman aralıkları ile ilerleyeceği ile ilgili özellikler Windows Presentation Foundation ‘da animasyon işlemlerini yaparken kullandığımız StoryBoard üyesine benzemektedir. Bu üyeyi de kullanırken belirli bir başlangıç zamanı, ilerleme zamanı ve sonlanma zamanı belirtebiliyorduk. Şimdi bu tür zamana bağlı kontrolleri kullanmak istediğimizde uygulamamızda ne tür bir kod bloğu kullanabileceğimize değinmeye çalışalım.

XAML
<MediaElement Name="mediaMakale" Width="320" Height="240" />
   <Grid.Triggers>
      <EventTrigger RoutedEvent="Grid.Loaded">
         <EventTrigger.Actions>
            <BeginStoryboard>
               <Storyboard Storyboard.TargetName="mediaMakale">
                  <MediaTimeline Source="Forza.wmv"
                     BeginTime="00:00:00" Duration="00:05:00" />
               </Storyboard>
            </BeginStoryboard>
         </EventTrigger.Actions>
      </EventTrigger>
   </Grid.Triggers>

Uygulamalarımızda MediaTimeline özelliğini kullanmak yerine MediaElement kontrolünü kullanmak ileride gerçekleşebilecek sorunları ortadan kaldırmak açısından çok daha yararlı olacaktır. Çünkü MediaTimeline ile uygulamalarımızı çalıştırmak istediğimizde arkada MediaElement kontrolü oluşturulmak istenecek ve istek sonrasından belirli zaman aralıklarında önbelleğe alacaktır. Sürekli çağırılan video dosyaları uygulamalarımızı web tabanlı yaptığımız durumlarda performans kaybına uğrayabilmekte ya da Windows tabanlı olarak geliştirdiğimiz uygulamalarda çok büyük dosyalı uygulamaları göstermek istediğimizde hatalar verebilecektir. Fakat aklımıza başka bir soru takılabilir. “O da çok büyük boyutlu bir videoyu birden önbelleğe aldırarak oynat dediğimizde performans kaybı yaşamayacak mıyız?” olacaktır. İşte bu sorunu engellememiz için MediaElement kontrolü içerisinde video dosyalarımızı oynatıyoruz. MediaElement kontrolünün Media dosyalarını çalıştırma mantığı minimum sistem zorlaması ile maksimum performans alabilmektedir. Diğer durumlarda biz yönetmeye çalışırsak, WPF öncesi durumlarda olduğu gibi oldukça zprlanabilir ve işlemlerimizi yaparken büyük sorunlar yaşabiliriz.

MediaPlayer Sınıfının Kullanılması

MediaElement kontrolünün özelliklerinde çok fonksiyonlu özellikler yani, yeniden oynatma, çalma listesi gibi özellikler yer almamaktadır. MediaElement üzerinde yer alan kontrollerimize daha çok fonksiyonellik kazandırmak istediğimizde MediaPlayer sınıfını kullanabiliriz. MediaElement ile video ve benzeri Media dosyaları oynatmak istediğimizde arka planda Media Player işleminin başlatıldığından ve bu işlemler üzerinden videomuzu oynattığından bahsetmiştik. İşte bu sebepten ötürü uygulamalarımızda MediaPlayer sınıfını kullanmak performans kaybı yerine son kullanıcıya sunacağımız birçok özelliği kolaylıkla sunabilme olanağı tanımaktadır.

MediaPlayer sınıfını kullanmamız için uygulamamızda System.Windows.Media isim alanının kullanılıyor olmasına dikkat etmemiz gerekmektedir. Şimdi ise C# ile Media Player sınıfını nasıl kullanabileceğimize ilişkin bir örnek vereceğiz.

C#
MediaPlayer mp = new MediaPlayer();
   Try {
      mp.Open(new Uri("mediaMakale.wmv"));
      }
     catch(Exception ex) {
    MessageBox.Show(ex.Message);
}

Media Player sınıfı ile kullanabildiğimiz özellikler ve üyeler MediaElement kontrolünün içerisinde kullanılabilmektedir. MediaElement ve Media Player uyumu ile gerçekleştirdiğimiz uygulamalarda yalnızca HD videoların gösterilmesinde sorunlar çıkmaktadır. Bu sorunlarda sistem özelliklerimizden olduğu düşünülmektedir. Çünkü ekran kartı iyi bir sistem ile uygulamamızı çalıştırdığımızda herhangi bir sorun ile karşılaşmazken, daha düşük özellikleri sistemlerde denediğimizde hatalar verebilmektedir. Media Player sınıfı videolarımızı çalıştırırken VideoDrawing sınıfı yardımı ile bu işlemleri yapmaktadır. 3D yüzeylerde de video izlemek istediğimizde Media Player sınıfı yine VideoDrawing sınıfı yardımı ile kolaylıkla video dosyalarını gösterebilmektedir.

Media Player sınıfında MediaElement kontrolünde olduğu gibi direk yolu gösterebilmek yerine uri özelliği ile yolunu uygulamamızın içerisindeki yolunu belirtiyoruz.

WPF Kontrollerinde Gömülü Videoların Kullanımı

MediaElement kontrolü System.Windows.UIElement sınıfından miraslanarak oluşturulmaktadır. Miraslamadan ötürü bir kontrolü başka bir kontrolün içerisinde de kullanabilmemize olanak tanınmıştır. Bizde bu özelliği test edebilmek için Button kontrolünün içerisinden MediaElement kontrolünü çalıştırmayı deneyeceğiz. Bunun için XAML kod tarafına aşağıdaki kodları ekliyoruz.

XAML
<Button Name="videoButton" Click="videoButton_Click"
   Width="320" Height="240">
   <MediaElement Name="forzaVid" Source="Forza.wmv"
       LoadedBehavior="Play" Width="320" Height="240" />
</Button>



Bu uygulamamızı derlediğimiz anda video oynamaya başlamaktadır. Bunun sebebi LoadedBehavior özelliğine Play değerini atmamızdan kaynaklanmaktadır. Eğer ki biz uygulama başlar başlamaz değil de Butona tıklandığı zaman videoyu başlatmak istersek Button_onClick özelliğine MediaElement ‘e vermiş olduğumuz isim ile forzaVid.Play(); kodunu eklememiz yeterli olacaktır. Bu değişiklik sonrasında uygulamamız butona tıklandığı anda, buton içerisinde video gösteren bir hal almış olacaktır. Bu tür ince detaylar son kullanıcılara sunulacak olan uygulama kullanım zevkini maksimuma çıkaracağı kaçınılmaz bir gerçektir.

Islak Zemin Yansıması Teknikleri

Uygulamalarımızda suda ya da camda karşılaştığımız yansıma işlemlerini yapmaya çalışırken fazlaca zaman kaybına uğrardık. WPF ile bu işlemleri yapmak istediğimizde ise VisualBrush üyesine MediaElement ‘i bağlamamız yeterli olacaktır. Daha sonrasında ise, VisualBrush içerisinden yapacağımız ince detaylar ile yansıma işlemini gerçekleştirebiliriz.

Yansıma işlemlerini nasıl yaptığımız konusunda kafanızda herhangi bir soru işareti oluşursa daha önceki WPF makalelerimizi okuyabilirsiniz.

Şimdi ise ıslak zemin yansıma efektine benzeyen uygulamamızı yapmamıza yarayacak olan kodlarımızı verelim.

XAML
<Window x:Class="WpfMedia.Window3"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   Title="WPF Makale" Height="340" Width="350">
      <Grid x:Name="Grid">
         <StackPanel VerticalAlignment="Center">
            <MediaElement Name="Vid" Source="Forza.wmv"
               LoadedBehavior="Play" Width="320" Height="240" />
            <Rectangle Width="320" Height="240">
               <Rectangle.Fill>
                  <VisualBrush Visual="{Binding ElementName=Vid}" />
               </Rectangle.Fill>
               <Rectangle.OpacityMask>
                  <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                     <GradientStop Color="#AA000000" Offset="1" />
                     <GradientStop Color="#00000000" Offset="0" />
                  </LinearGradientBrush>
               </Rectangle.OpacityMask>
            <Rectangle.RenderTransform>
         <TransformGroup>
         <ScaleTransform ScaleY="-1" />
         <TranslateTransform Y="242" />
      </TransformGroup>
   </Rectangle.RenderTransform>
</Rectangle>
</StackPanel>
</Grid>
</Window>



Bu uygulamamızı da basitçe yapmış oluyoruz.

Uyumlu Ses Dosyalarının WPF Uygulamalarına Eklenmesi

WPF uygulamalarımıza MediaElement kontrolü yardımı ile birçok video ekledik ve eklediğimiz bu videoları form kontrollerinin içerisine bile ekleyebildik. Fakat dijital dünya sadece görüntüden ibaret değildir. Birde bu dünyada sesler yer almaktadır. Şimdi de ses dosyalarını nasıl WPF uygulamalarımıza ekleyebileceğimize değineceğiz.

Ses dosyalarımızı uygulamalarımızda kullanabilmemiz için System.Windows.Media isim alanı altında tanımlı olan sound Player sınıfını kullanacağız. Bu sınıfta Media Player ile çalabildiğimiz ses dosyalarımızı WPF uygulamalarımız da çalabilmemiz mümkündür. Ayrıca Media Player için varsayılan ses formatı olan WAV ‘ı da sorunsuzca çalıştırabilmektedir.

SoundPlayer sınıfını kullanırken bu sınıfın metotlarından olan SoundPlayer.Play(); metodu yardımı ile de ses dosyalarını yürütebilmemiz mümkündür. Tabii yürütebilme özelliği ile birlikte duraklatma ve sonlandırma metotları da yer almaktadır.

Şimdi uygulamalarımızda SoundPlayer özelliğini kullanabileceğimiz örnek için gerekli olan kod parçacığına göz atalım.

XAML
<EventTrigger RoutedEvent="Button.MouseEnter" SourceName="Button">
   <EventTrigger.Actions>
      <SoundPlayerAction Source="ses/lake.wav"/>
   </EventTrigger.Actions>
</EventTrigger>

Uygulamamızı derlediğimizde ses dosyamız sorunsuz bir biçimde çalacaktır.

Bu yazımızda nelere değindiğimizi toparlamak gerekirse, ilk olarak WPF ile geliştirilmiş ve günümüzde en çok kullanılan uygulamalara değindik ve bu uygulamalardan Windows Vista ‘da MediaElement kontrolünü nerede kullanıldığına göz attık. Sonrasında ise MediaElement kontrolü kullanılarak yapılmış farklı uygulamaları incelemeye çalıştık.

Sonuç olarak en temel anlamda MediaElement kontrolünü kullanarak video dosyalarını nasıl kullanabileceğimize incelemeye çalıştık.

Umarım yararlı olmuştur.

Yazımızda değinmiş olduğumuz uygulamanın kaynak kodlarına linkten erişebilirsiniz.

turhal.temizer@csharpnedir.com

Pazartesi, Nisan 14, 2008

WPF - 2D, 3D ve Yüzey (Topoloji) Uygulamaları

Windows Presentation Foundation ile yapılmış profesyonel projeleri incelediğimizde genellikle 3D işlemlerinin uygulandığını görüyoruz. Geliştiriciler uygulamalarında 3D ‘yi tercih etmelerinin sebeplerinin başında WPF ‘in grafik kartlarını başarılı bir şekilde kullanabilmesi gelmektedir. Bu başarıyı sağlayan en büyük etmen ise Windows Vista işletim sistemli bilgisayarlarda grafik kartını çok daha performanslı bir şekilde kullanabilmesidir. Vista işletim sisteminde animasyonların bir çoğunun WPF ‘te kullanılan sınıflar ile yapıldığını düşünürsek neden 3D işlemlere daha fazla yer verildiğini anlayabiliriz.

Günümüzde hazırlanan ve hazırlanmakta olan uygulamaları göz önüne alarak bizlerde uygulamalarımızda 3D işlemleri uygulamamız, yeni teknolojileri yakalamak açısından yararlı olacaktır.

Bu ve diğer bir çok sebebi düşünerek bu makalemizde Windows Presentation Foundation ile 3D uygulamalarını nasıl geliştireceğimizi ayrıntılı bir biçimde incelemeye çalışacağız.

Daha önceleri ayrıntılı bir 3D uygulaması geliştirmek istiyorsak yönetilebilir 3D programlama yapısını, vektörsel 2D programlama yapısını bilmemiz gerekiyordu. Tabii bu bilgileri bilmememiz durumunda uzunca bir süre bunları öğrenmek ile zaman kaybettikten sonra uygulamalarımızı geliştirmeye başlayabiliyorduk. Fakat çok daha ileri düzey uygulama geliştirmek istediğimizde harcayacağımız zaman aralığı oldukça artacak ve belki de hazırlayacak olduğumuz uygulama sonlandığında çalıştığımız sistemler güncelliğini kaybedecektir.

Fakat .net 3.0 yapısı ile bizlere sağlanan kolaylıkları kullanarak biraz önce bahsettiğimiz o zorlu 3D uygulamalarını rahatlıkla yapabilmemize olanak tanınmaktadır. Biz bu makalemizde 3D işlemlerimizi bir tutorial gibi en temelden ele alarak eğitsel bir biçimde inceleyeceğiz.

3D Grafik Teorisi

WPF ile 3D programlamaya başlarken nasıl yapacağı konusunda herhangi bir fikri olmayanlar için açıklamaya başlarsak, 3D modelleme ve çizim işlemlerini yaparken Mesh (ağ topluluğu) içerisine noktalarımızı yerleştirmeli, üçgen (triangle) ve doğrusal (normal) çizimler ile de istediğimiz şekli çizmeliyiz. Bu karmaşık gelen işlemleri çok az 3D modelleme bilgisi ile WPF ‘de çabucak işlemlerimizi yapabilmemiz mümkündür. Bu işlemleri yapmaya başlarken biraz önce saydığımız üç özelliği incelemek çok daha yararlı olacaktır.

Mesh Nedir?

Mesh, yüzeyi yeniden göstermek olarak kısaca tanımlayabiliriz. Çizimlerimizi yaparken köşe noktalarımızı belirler, en yüksek ve en alçak yükseltilerini belirleyerek basitçe çizim yapabiliriz.

Peki, “biz daha önceden mesh ‘i kullanmak isteseydik kullanamaz mıydık?” diye bir soru kafanıza takılırsa bunun cevabı evet olurdu. .net Framework 2.0 dan beri mobile uygulamalarda DirectX kütüphanesinde Direct3D nesnesini kullanabilmemiz mümkündür. Eğer ki mobile uygulamalarınızda mesh sınıfını kullanmayı düşünüyorsanız bu sınıf .net 3.5 ile de yapıda yer almıştır.

Mesh ‘i WPF üzerinden incelemeye devam edelim. Yüzey yüksekliğini minimum olarak belirlersek bizim karşımıza yalnızca düz bir yüzey çıkacaktır. Bu yüzeyde en basit anlamda bir üçgene benzer fakat yükseklikleri ve farklı koordinat noktalarını belirttiğimiz zamanda karşımıza küp görünümlü bir ekran görüntüsü alabiliriz. Biraz daha farklı düşünürsek, tek bir yükseklik değil de birden fazla düşünmemiz durumunda ise tümsekli bir yeryüzü yapısı elde edebilmemiz mümkündür.

Mesh ile çizim işlemlerimiz aşağıdaki üçlü sayesinde oluşturulabilmektedir.
Mesh pozisyonu
Triangle Indices
Üçgen standartları

Mesh Pozisyonu

Mesh pozisyonu, çalışacağımız yüzeyde belirlediğimiz noktalar sayesinde hangi alanda çalışacağımızı belirlememize yarar.

Triangle Indices

Mesh ile çalışırken temel olarak 3 nokta üzerinde çalışıp üçgen ‘e benzer çizim işlemleri yapabilmemiz mümkündür. Fakat biz bu üç noktadan daha fazla çalışmak istersek farklı köşegen noktaları belirlememiz gerekecektir.

WPF ile çalışırken ise bizden mesh ‘imizin koordinat noktalarını girmemiz istenir. Bizde bu noktaları diziye benzer bir şekilde uygulamamıza ekleriz. Örneğin, beş tane koordinat noktası eklemek istediğimizde {n0,n1,n2,n3,n4} biçiminde ekleyebiliriz. Burada n0..5 ile belirlediğimiz koordinatlar uygulamada point2d veya point3d koordinat noktalarına karşılık gelecek olan noktalardır. Eğer biz bu girdiğimiz koordinat noktaları ile bir üçgen çizmek istiyorsak bu noktalardan üçünü kullanmamız yeterli olacaktır veya koordinat noktalarına girdiğimiz değerler diziye girdiğimiz sırayla değil, bu durumda ise bu koordinat noktalarını istediğimiz şekilde değiştirebilmemiz mümkündür. {n2,n1,n4,n0,n3} Daha sonra biz bu noktaları uygulamamızda çağırırken 4. nokta diye belirteceğiz. Biz kod içerisinde 4. nokta dediğimizde o n0 ‘ı algılayacaktır. Aynı şekilde diğer noktaları da bu şekilde çağırabilmemiz mümkündür.

Biraz önce bahsettiğimiz koordinat noktalarının uygulamada çağırılma işlemi esnasında bizler bu noktaların içerisine girdiğimiz değerleri dışarıdan da alarak şekillerimizin X, Y, Z koordinatlarında şekillenmesine olanak tanıyabiliriz.

Ayrıca doğru çizimlerini yaparken unutmamamız gereken bir önemli noktada bu doğruları uygulamada belirtirken saat yönünün tersinde belirtmemiz gerektiğidir. Yani bunu kısaca örneklemek gerekirse, sağ elini kullananlar kâğıt üzerinde çizim yaparken ilk olarak en sağdaki noktayı çizer ve daha sonra sola doğru çizim yaparlar. İşte WPF ‘de çizim işlemlerini yaparken bu mantıkla çalışmaktadır. Yani bizler WPF ile çizim yaparken ilk olarak en sağ noktasını belirtip daha sonra en sol noktaya kadar olan noktaları belirterek işlemlerimizi yapabilmemiz mümkündür.

Peki, neden sağ el ile çizim örneğini verdik. Hemen isterseniz elinize bir kâğıt ve kalem alıp deneyin (Örneğimiz sağ elini kullananlar içindir). Bir sağdan sola, birde sağdan sola doğru çizim yapmayı deneyin. Dikkat edeceksiniz ki sağdan sola doğru yaptığınız çizim diğer koordinatlarda yaptığınız çizim işlemlerine göre çok daha düzgün olacaktır. Dünyada ki insanların büyük bir çoğunluğu da sağ ellerini kullandıkları için bilinçaltında kabul edilmiş çizim mantığının dışına çıkılmaması için böyle bir düşünce içerisine girilmiş.

Üçgen Standartları

Hepimizin ilkokuldan bildiği bir bilgi üçgenler üç noktadan oluşur. Bu üç noktaları bilgisayar ortamında çizmeye çalıştığımızda üç noktaya karşılık 6 koordinat noktaları verir ve çizimlerimizi yapardık. Daha önceden bilgisayar grafikleri ile uğraşamamış olan arkadaşlar için neden altı koordinat noktası girilmesi gerektiğinden kısaca bahsedeyim. Bilindiği üzere uygulamamızın formunun üzerinden işaretlenen bir noktanın ayrıntılarını incelediğimizde X ve Y noktalarından oluştuğunu ve bu bilgilerin tutulduğu gözlenir. Bizlerde üçgen oluşturmak istediğimizde A noktası için (X1 ve Y1), B noktası için (X2 ve Y2) ve son olarak ta C noktası içinde (X3 ve Y3) koordinatlarının bilgilerini tutar. Son olarak ta bu üç noktayı üçgen oluşturma kurallarına aykırı olmadığı takdirde birleştirdiğimiz zaman bir üçgen oluşacaktır.

Çizim işlemlerimizi yaparken birden fazla yöntem izleyebiliriz. Bunlar ABxAC, BCxBA veya CBxCA noktalarını ele alarak çizim işlemlerimizi yapabiliriz.




Üç basit doğru ile bir üçgen çizebildik. Bu noktaları arttırıp, açı değerlerini aralarında 90 derece olacak şekilde ayarlayıp koordinat noktalarını belirmemiz durumunda ise küp çizebilmemiz mümkündür.

Buraya kadar çizimin nasıl yapılacağına değinmeye çalıştık. Şimdi bu edindiğimiz bilgilerin daha kalıcı olabilmesi için örnek uygulamalar yapacağız.

Uygulama Geliştirmeye Başlarken

Yapacağımız örneğin daha anlaşılır olabilmesi için ilk başta bir kullanıcı arayüzü hazırlayacağız. Hem de uygulamamızı kullanacak olan son kullanıcılar için daha hoş bir görünüm sunulacaktır. Hazırladığımız kullanıcı arayüzünde 3D nesnelerin gözükebilmesi için viewport3D kontrolü kullanılmıştır.

<Grid>
<DockPanel
Width="Auto"
VerticalAlignment="Stretch"
Height="Auto"
HorizontalAlignment="Stretch"
Grid.ColumnSpan="1"
Grid.Column="0"
Grid.Row="0"
Margin="0,0,0,0"
Grid.RowSpan="1">
<StackPanel>
<StackPanel.Background>
<LinearGradientBrush>
<GradientStop Color="White" Offset="0"/>
<GradientStop Color="DarkGoldenrod" Offset=".3"/>
<GradientStop Color="DarkGoldenrod" Offset=".7"/>
<GradientStop Color="White" Offset="1"/>
</LinearGradientBrush>
</StackPanel.Background>
<StackPanel Margin="10">
<Button
Name="buton"
Click="butonClick">Ucgen</Button>
</StackPanel>
</StackPanel>
<Viewport3D Name="anaGoruntuleme" ClipToBounds="True">
<Viewport3D.Camera>
<PerspectiveCamera
FarPlaneDistance="100"
LookDirection="-11,-10,-9"
UpDirection="0,1,0"
NearPlaneDistance="1"
Position="11,10,9"
FieldOfView="70" />
</Viewport3D.Camera>
<ModelVisual3D>
<ModelVisual3D.Content>
<DirectionalLight
Color="White"
Direction="-2,-3,-1" />
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D>
</DockPanel>
</Grid>

3D alanımızı basit bir biçimde Viewport3D kontrollerini kullanarak oluşturuyoruz. Viewport3D kontrollerini kullanmamızın sebebi üç boyut işlemlerini çok daha performanslı gerçekleştirebilmesinden ötürüdür. Viewport3D kontrolünün özelliklerini MSDN ‘de incelerseniz size not olarak “eğer 3D işlemlerini kullanacaksanız Viewport3D kontrolünün içerisinden kullanmanız uygulamanızın performansı açısından daha yararlı olacaktır” ile karşılaşacağız. Normalde form kontrolleri 2D işlemlerini çok performanslı gerçekleştirirken 3D işlemlerinde zaman kaybına uğradığı bilinmektedir. Bu zaman kaybının önlemek içinde Viewport3D kontrolünün kullanılması daha mantıklıdır.

Ayrıca daha sonradan kullanıcılara görüntümüzü farklı açılar üzerinden göstermeyi amaçladığımız için PerspectiveCamera özelliğini ekliyoruz. PerspectiveCamera Viewport3D kontrollünün alt özelliklerinden biridir. Varsayılan olarak kamera açısı {0, 0, 0} olarak bizlere sunulmaktadır.

DirectionalLight, yine Viewport3D kontrollerinden birisidir. Bu özellik uygulamamızdaki nesnemize belirli bir açı ile ışık geliyormuş hissi verir. Sanki gerçek hayatta nesnelerin üzerine güneş ışığının çarpması sonrasında belirli bir parlaklık alması gibi algılayabiliriz.

Hazırlamış olduğumuz kullanıcı kontrolü aşağıdaki gibi oluşmuştur.



Daha önceki WPF makalelerimizi incelediyseniz uygulamalarımızı genellikle XAML kod tarafında hazırlardık. Bu sefer ise C# kod tarafında da kod yazacağız. Bu sayede uygulamamızda yönetilebilir kodda kullanılmış olacak.

Kod tarafına geçtiğimizde isteklerimize karşılık verilebilmesi için butonun tıklanması olayına dayanarak işlemlerimizi yapacağız. Kullanıcı arayüzümüzü tasarlarken bir de ekrana buton eklemiştik. Bu eklediğimizi butonun name özelliğine istediğimiz ismi verebilmemiz mümkündür. Ben bu yazımız için buton veriyorum. Butona ismi verdikten sonra tıklanması sonrasında olayların gerçekleştirilebilmesi için kod tarafında butonu belirtmemiz gerekmektedir. Bu işlem esnasında ister XAML ile oluşturduğumuz butonun üstüne çift tıklar otomatik oluşturturuz ya da kendimiz nesne özellikleri ve yönlendirmesini belirterek biz oluştururuz.

İşlemi gerçekleştirdiğimizde karşımıza aşağıdaki bir kod oluşmalıdır.

private void butonClick(object sender, RoutedEventArgs e)
{
}

Basit Bir Çizim Modeli Oluşturulması

Viewport3D kontrollünün içerisinde kullanabileceğimiz tipleri ve 3D sınıfları kısaca tanımlayalım.

GeometryModel3D: .net3.0 ile gelmiştir. Mesh (MeshGeometry3D) ile 3 boyutlu çizim nesneler oluşturabilmemize olanak tanır.
MeshGeometry3D: .net3.0 ile gelmiştir. Bünyesinde nesnemizin pozisyonlarını, koordinatlarını ve normal çizgileri tutar.
Point3D: .net3.0 ile gelmiştir. Çizeceğimiz nesnelerin koordinat noktalarını tutar.
Vector3D: .net3.0 ile gelmiştir. Normal çizgileri oluşturur.
DiffuseMetarial: .net3.0 ile gelmiştir. Oluşturduğumuz modele renginin ve üzerinde tasarım var ise o özelliklerini vermemize olanak tanır.
DirectionalLight: .net3.0 ile gelmiştir. Nesnemizi aydınlatabilmemize olanak tanır.
Ayrıca bu özellikleri kullanabilmemize olanak tanıyan isim alanı System.Windows.Media.Media3D ‘dır. Bu sınıfa ait özellikleri yeri geldikçe inceleyeceğiz.

Uygulamamıza Kod Ekliyoruz

İlk olarak biraz önce bahsettiğimiz tipleri, özellikleri ve daha fazlasını kullanabilmemiz için Media3D sınıfını uygulamamıza ekliyoruz.

using System.Windows.Media.Media3D;

Şimdi ise üçgen çizebilmemiz için gerekli olan kodları eklemeyelim.

İlk olarak yeni bir MeshGeometry3D oluşturalım;
MeshGeometry3D ucgenYuzey = new MeshGeometry3D();

Sıradaki adımımız üçgenimizi oluşturabilmek için üç nokta eklememiz gerekmektedir.

Point3D nokta0 = new Point3D(0, 0, 0);
Point3D nokta1 = new Point3D(5, 0, 0);
Point3D nokta2 = new Point3D(0, 0, 5);

Şimdi eklediğimiz bu üç noktayı üçgen oluşturabilmesi için ucgenYuzey ’e ekliyoruz.

ucgenYuzey.Positions.Add(nokta0);
ucgenYuzey.Positions.Add(nokta1);
ucgenYuzey.Positions.Add(nokta2);

Şimdi üçgenimizin çizilmesi için Triangle Indices ‘e noktaları tanımlıyoruz. Bu işlemleri yaparken de çizimleri sağ elimizle yaptığımızı anlatan örneği aklımıza getirmek yararlı olacaktır.

ucgenYuzey.TriangleIndices.Add(0);
ucgenYuzey.TriangleIndices.Add(2);
ucgenYuzey.TriangleIndices.Add(1);

Doğrularımızın çizilebilmesi için noktalarımızı Vector3D ‘ye aktarıyoruz ve doğru olarak çizmesini belirtiyoruz.

Vector3D normal = new Vector3D(0,1,0);
ucgenYuzey.Normals.Add(normal);
ucgenYuzey.Normals.Add(normal);
ucgenYuzey.Normals.Add(normal);

Son olarak üçgenimizin yüzeyini ve oluşturulacak olan modele ait bilgileri nereden alacağını belirtmemiz gerekmektedir.

Material madde = new DiffuseMaterial(new SolidColorBrush(Colors.DarkGoldenrod));
GeometryModel3D ucgenModel = new GeometryModel3D(ucgenYuzey, madde);
ModelVisual3D model = new ModelVisual3D();
model.Content = ucgenModel;
this.anaGoruntuleme.Children.Add(model);

Uygulamamızda üçgen çizilmesi için gerekli olan kodları bitirmiş oluyoruz. Bu işlemlerimizin sonucunda buton ‘unun tıklanması olayında oluşan kodlar toplu halde aşağıdaki gibi olmuştur.

private void butonClick(object sender, RoutedEventArgs e)
{
MeshGeometry3D ucgenYuzey = new MeshGeometry3D();
Point3D nokta0 = new Point3D(0, 0, 0);
Point3D nokta1 = new Point3D(5, 0, 0);
Point3D nokta2 = new Point3D(0, 0, 5);
ucgenYuzey.Positions.Add(nokta0);
ucgenYuzey.Positions.Add(nokta1);
ucgenYuzey.Positions.Add(nokta2);
ucgenYuzey.TriangleIndices.Add(0);
ucgenYuzey.TriangleIndices.Add(2);
ucgenYuzey.TriangleIndices.Add(1);
Vector3D normal = new Vector3D(0,1,0);
ucgenYuzey.Normals.Add(normal);
ucgenYuzey.Normals.Add(normal);
ucgenYuzey.Normals.Add(normal);
Material madde = new DiffuseMaterial(new SolidColorBrush(Colors.DarkGoldenrod));
GeometryModel3D ucgenModel = new GeometryModel3D(ucgenYuzey, madde);
ModelVisual3D model = new ModelVisual3D();
model.Content = ucgenModel;
this.anaGoruntuleme.Children.Add(model);
}

Bu işlemlerimiz sonucunda oluşan ekran görüntüsü aşağıdaki gibi oluşmuştur.


Evet, bu şekilde üçgeni çizebilmiş oluyoruz. Şimdi ise 3 boyutlu Mesh ‘i nasıl çizeceğimize değinmeye çalışacağız.

Küp Oluşturmak

Küpü nasıl oluşturacağımızı hatırlamaya çalışalım. Küpün 12 açısı bulunmaktadır (6 yüzeyi ve iki tane kesim noktası bulunmaktadır).
Kilit noktalardan yola çıkarak saatin tersi yönünde (sağ elle çizim alışkanlığına göre) çizim yapacağımız noktaları belirleriz.

Bu iki kısa bilgiyi aklımızda tutarak uygulamamızı yapmaya devam edebiliriz.

İlk olarak yapmamız gereken küpün oluşturulması için formumuza bir buton eklenmesi gerekmektedir. Bunun için XAML kod tarafına aşağıdaki kodu ekleriz.

<Button Name="kupButon" Click="kupButonClick">Kup</Button>

Şimdi kod tarafına geçmek için butonun tıklanması olayını ekliyoruz.

private void kupButonClick(object sender, RoutedEventArgs e)
{
}

Küpümüzü çizerken üç boyutlu modelleme işlemlerimizi daha kolay yapabilmemiz için Model3DGroup sınıfını kullanacağız. Model3DGroup koleksiyonuna dahil olan GeometryModel3D nesnesi işimizi oldukça kolaylaştıracaktır. Bu yapacağımız örnek basit olarak 3D modellemeyi bize kavratacaktır.

3D Modelleme işlemlerimizi yaparken normal çizim işlemlerine ek olarak bizde iki metot ekleyeceğiz. Ekleyeceğimiz bu metotlar UcgenModeliOlustur() ve NormalHesapla() olacaktır. Şimdi bu iki metodumuzun kodlarına göz atalım.

private Model3DGroup UcgenModeliOlustur(Point3D n0, Point3D n1, Point3D n2)
{
MeshGeometry3D mesh = new MeshGeometry3D();
mesh.Positions.Add(n0);
mesh.Positions.Add(n1);
mesh.Positions.Add(n2);
mesh.TriangleIndices.Add(0);
mesh.TriangleIndices.Add(1);
mesh.TriangleIndices.Add(2);
Vector3D normal = NormalHesapla(n0, n1, n2);
mesh.Normals.Add(normal);
mesh.Normals.Add(normal);
mesh.Normals.Add(normal);
Material madde = new DiffuseMaterial(
new SolidColorBrush(Colors.DarkGoldenrod));
GeometryModel3D model = new GeometryModel3D(
mesh, madde);
Model3DGroup grup = new Model3DGroup();
grop.Children.Add(model);
return grup;
}
private Vector3D NormalHesapla(Point3D n0, Point3D n1, Point3D n2)
{
Vector3D v0 = new Vector3D(
n1.X - n0.X, n1.Y - n0.Y, n1.Z - n0.Z);
Vector3D v1 = new Vector3D(
n2.X - n1.X, n2.Y - n1.Y, n2.Z - n1.Z);
return Vector3D.CrossProduct(v0, v1);
}

UcgenModeliOlustur() metodu Model3DGroup mesh ‘i kullanarak oldukça şık ve sevimli bir çizim yapmamıza olanak tanır. NormalHesapla() metodu ise UcgenModeliOlustur() metodu ile aldığımız noktalara ilişkin koordinat bilgilerinden yararlanarak bu noktaları vektöre dönüştürür. Bu iki metodun yaptığı işlemler sonrasında ise oldukça şık bir küp oluşturulmuş olur.

Tabii küpü çizebilmemiz için butonun tıklanması olayında koordinat bilgileri girmemiz gerekmektedir. Bu girdiğimiz bilgilerde UcgenModeliOlustur() metoduna oradan da NormalHesapla() metodu ile çizilmesini sağlayacaktır.


Şimdi küpümüzün butona tıklanması küpü çizebilmesi için koordinatlarına ilişkin bilgilerini kod tarafında girelim.

private void kupButonClick(object sender, RoutedEventArgs e)
{
Model3DGroup kup = new Model3DGroup();
Point3D n0 = new Point3D(0, 0, 0);
Point3D n1 = new Point3D(5, 0, 0);
Point3D n2 = new Point3D(5, 0, 5);
Point3D n3 = new Point3D(0, 0, 5);
Point3D n4 = new Point3D(0, 5, 0);
Point3D n5 = new Point3D(5, 5, 0);
Point3D n6 = new Point3D(5, 5, 5);
Point3D n7 = new Point3D(0, 5, 5);
//ön yüz
kup.Children.Add(UcgenModeliOlustur(n3, n2, n6));
kup.Children.Add(UcgenModeliOlustur(n3, n6, n7));
//sağ yüz
kup.Children.Add(UcgenModeliOlustur(n2, n1, n5));
kup.Children.Add(UcgenModeliOlustur(n2, n5, n6));
//arka yüz
kup.Children.Add(UcgenModeliOlustur(n1, n0, n4));
kup.Children.Add(UcgenModeliOlustur(n1, n4, n5));
//sol yüz
kup.Children.Add(UcgenModeliOlustur(n0, n3, n7));
kup.Children.Add(UcgenModeliOlustur(n0, n7, n4));
//üst yüz
kup.Children.Add(UcgenModeliOlustur(n7, n6, n5));
kup.Children.Add(UcgenModeliOlustur(n7, n5, n4));
//alt yüz
kup.Children.Add(UcgenModeliOlustur(n2, n3, n0));
kup.Children.Add(UcgenModeliOlustur(n2, n0, n1));
ModelVisual3D model = new ModelVisual3D();
model.Content = kup;
this.anaGoruntuleme.Children.Add(model);
}

Bu kodlarımızı uygulamamıza ekledikten sonra derlediğimizde karşımıza aşağıdaki gibi güzel bir görüntü çıkacaktır.



Viewport ‘u Temizleme

Uygulamamızda oluşturduğumuz modelleri birbirleri üzerine tekrardan oluşturmak istediğimizde dikkatimizi çeken bir sorun çıkmıştır. Üçgeni çizdirdikten sonra küpü çizdirdiğimizde bir öncekinin üstünü kapatarak küpü çizerken, küpten üçgene geçmek istediğimiz zaman çizememektedir. Bu durumun ana nedeni küpün kapladığı alanın üçgenden daha büyük olması ve çizimleri yaptırırken bir önceki sildirmeden yapmamızdan kaynaklanmaktadır. Bu kötü durumu ortadan kaldırmak için görüntü alanı olarak kullandığımız Viewport ‘u temizlememiz gerekecektir. Bu temizleme işlemi için aşağıdaki kodları metot olarak oluşturuyoruz.

private void ViewportTemizle()
{
ModelVisual3D m;
for (int i = anaGoruntuleme.Children.Count - 1; i >= 0; i--)
{
m = (ModelVisual3D)anaGoruntuleme.Children[i];
if (m.Content is DirectionalLight == false)
anaGoruntuleme.Children.Remove(m);
}
}

ViewportTemizle() metodunu başarılı bir biçimde kullanabilmemiz için küp ve üçgen çizdirmek için kullandığımız butonların tıklanması olaylarının ilk satırlarına ViewportTemizle(); metodunu çağırarak temizleme işlemini gerçekleştirebiliriz.

Kamera Kontrolleri

Biz küpü ve üçgeni basit bir şekilde oluşturduk. Fakat son kullanıcılar bizlerden bu görüntüleri farklı açılarında da görmek istiyoruz şeklinde isteklerde bulunabilirler. Bizde bu durumu yerine getirebilmek için yapmamız gereken işlemler koordinatlara ait bilgileri kullanıcıdan girmesini istemek olacaktır. Bu işlemi yerine getirebilmek için kullanıcı arayüzüne girdi girilebilmesi için TextBlock ve TextBox eklememiz gerekecektir.

<StackPanel Margin="10">
<Button Name="buton" Click="butonClick">Ucgen</Button>
<Button Name="kupButon" Click="kupButonClick">Kup</Button>
<Button Name="Kapat" Click="kapatButon">Kapat</Button>
<TextBlock Text="Kamera X pozisyonu:"/>
<TextBox Name="kameraPozisyonXTextBox" MaxLength="5"
HorizontalAlignment="Left" Text="9" Width="100" />
<TextBlock Text="Kamera Y Pozisyonu:"/>
<TextBox Name="kameraPozisyonYTextBox" MaxLength="5"
HorizontalAlignment="Left" Text="8" Width="100" />
<TextBlock Text="Kamera Z Pozisyon:"/>
<TextBox Name="kameraPozisyonZTextBox" MaxLength="5"
HorizontalAlignment="Left" Text="10" Width="100" />
<Separator/>
<TextBlock Text="Bakılan X Yönü:"/>
<TextBox Name="bakilanXTextBox" MaxLength="5"
HorizontalAlignment="Left" Text="-9" Width="100" />
<TextBlock Text="Bakılan Y Yönü:"/>
<TextBox Name="bakilanYTextBox" MaxLength="5"
HorizontalAlignment="Left" Text="-8" Width="100" />
<TextBlock Text="Bakılan Z Yönü:"/>
<TextBox Name="bakilanZTextBox" MaxLength="5"
HorizontalAlignment="Left" Text="-10" Width="100" />
<Separator/>
</StackPanel>

XAML kod tarafımız yukarıdaki gibi olmuştur. Şimdi yapmamız gereken işlem ise TextBox lardan alınan bilgiler ile 3D modelimizin kamera açılarının değişmesidir. Bunu yapabilmek için KameraAiınan() isimli bir metot oluşturuyoruz.

private void KameraAlinan()
{
PerspectiveCamera kamera = (PerspectiveCamera)anaGoruntuleme.Camera;
Point3D pozisyon = new Point3D(
Convert.ToDouble(kameraPozisyonXTextBox.Text),
Convert.ToDouble(kameraPozisyonYTextBox.Text),
Convert.ToDouble(kameraPozisyonZTextBox.Text)
);
Vector3D lookDirection = new Vector3D(
Convert.ToDouble(bakilanXTextBox.Text),
Convert.ToDouble(bakilanYTextBox.Text),
Convert.ToDouble(bakilanZTextBox.Text)
);
kamera.Position = pozisyon;
kamera.LookDirection = lookDirection;
}

Uygulamalarımızda da kamera kontrollerinin işleyebilmesi için KameraAlinan() metodunu butonların tıklanması olayına eklememiz yeterli olacaktır. Metodu çağırma işlemini tamamladıktan sonra uygulamamızı çalıştırdığımızda aşağıdaki gibi bir görüntü elde ederiz.

ScreenSpaceLines3D Sınıfı

Bahsettiğimiz bu sınıf .net3.0 yapısının içerisinde bulunmamaktadır. Sınıfı kullanabilmemiz için yapmamız gereken CodePlex 3D Tools ‘te geliştiriciler tarafından geliştirilmekte olan 3DTools uygulaması indirerek uygulamamıza referans olarak eklememiz yeterli olacaktır.



Bu dll ‘i referans olarak uygulamamıza ekleriz.

using _3DTools;

Artık ScreenSpaceLines3D sınıfını kullanabiliriz.

Modelde Köşe Noktalarına ait Doğrularının Eklenmesi

Üç boyutlu modellerimizin daha şık gözükebilmesi için köşe noktalarından devam eden çizgiler göstermek oldukça iyi olacaktır. Bu işlemleri gerçekleştirebilmemiz için ScreenSpaceLines3D sınıfını kullanacağımızdan bahsetmiştik. XAML ve C# kod tarafında bu işlemleri nasıl yapabileceğimize göz atalım.

<Separator/>
<CheckBox Name="normalCheckBox">Doğruları Göster</CheckBox>
<TextBlock Text="Doğru Boyutu:"/>
<TextBox Name="normalBoyutTextBox" Text="1"/>

XAML tarafından kontrolleri ekledikten sonra bu kontroller eşliğinden işlem yapacak olan C# kodlarını da uygulamamıza ekleyelim.

private Model3DGroup NormalYapilandirma(Point3D n0, Point3D n1, Point3D n2, Vector3D normal)
{
Model3DGroup DogruGrup = new Model3DGroup();
Point3D n;
ScreenSpaceLines3D normal0Tel = new ScreenSpaceLines3D();
ScreenSpaceLines3D normal1Tel = new ScreenSpaceLines3D();
ScreenSpaceLines3D normal2Tel = new ScreenSpaceLines3D();
Color c = Colors.Blue;
int genislik = 1;
normal0Tel.Thickness = genislik;
normal0Tel.Color = c;
normal1Tel.Thickness = genislik;
normal1Tel.Color = c;
normal2Tel.Thickness = genislik;
normal2Tel.Color = c;
double num = 1;
double mult = .01;
double denom = mult * Convert.ToDouble(normalBoyutTextBox.Text);
double faktor = num / denom;
n = Vector3D.Add(Vector3D.Divide(normal, faktor), n0);
normal0Tel.Points.Add(n0);
normal0Tel.Points.Add(n);
n = Vector3D.Add(Vector3D.Divide(normal, faktor), n1);
normal1Tel.Points.Add(n1);
normal1Tel.Points.Add(n);
n = Vector3D.Add(Vector3D.Divide(normal, faktor), n2);
normal2Tel.Points.Add(n2);
normal2Tel.Points.Add(n);
this.anaGoruntuleme.Children.Add(normal0Tel);
this.anaGoruntuleme.Children.Add(normal1Tel);
this.anaGoruntuleme.Children.Add(normal2Tel);
return DogruGrup;
}

Kod tarafına eklememiz gereken tek bir kod parçası daha kaldı. O da, CheckBox ‘ta seçilmiş ise doğruların gözükmesidir. Bu işlemi için basit bir if koşulu eklememiz yeterli olacaktır.

if (normalCheckBox.IsChecked == true)
grup.Children.Add(NormalYapilandirma(n0, n1, n2, normal));

UcgenModeliOlustur() metodunun en alt kısmına bu if koşulunu eklediğimiz takdirde aşağıdaki gibi bir uygulamaya sahip olmuş oluruz.



Yeryüzü Oluşturma

3D teorisini anlatırken oluşturulan modellerin maksimum ve minimum noktalarının olduğunu ve bu noktaların rastgele verilmesi durumunda tümsekli eğrilere sahip bir bölgesel yüzey elde edebileceğimizden bahsetmiştik. Şimdi bu yüzeyi nasıl oluşturabileceğimize değineceğiz.

Kullanıcı arayüzümüze yüzey yapısının oluşturmalarını oluşturabilmesi için bir buton ekliyoruz.

<Button Name="yuzeyYapisiButon" Click="yuzeyYapisiButonClick">Yüzey Yapısı</Button>

Modellemeyi yaparken X ve Z koordinatları ile yüzeyi Y koordinatları ile ise yükseklikleri belirtiyoruz. Bu yapacağımız 10x10 ‘luk bir yüzey olacaktır. Yüzeyimizin çok daha gerçekçi olabilmesi için koordinat noktalarına ait değerleri rastgele oluştururuz. Bu işlemi yapmak için aşağıdaki koddan yararlanabilmek mümkündür.

private Point3D[] RastgeleYuzeyNoktalari()
{
//10x10 'luk yüzey oluşturuluyor..
Point3D[] noktalar = new Point3D[100];
Random r = new Random();
double y;
double denom = 1000;
int sayac = 0;
for (int z = 0; z < 10; z++)
{
for (int x = 0; x < 10; x++)
{
System.Threading.Thread.Sleep(1);
y = Convert.ToDouble(r.Next(1, 999)) / denom;
noktalar[sayac] = new Point3D(x, y, z);
sayac += 1;
}
}
return noktalar;
}

Rastgele nokta ürettikten sonra yuzeyYapisi butonunun tıklanması olayına aşağıdaki kodları ekliyoruz.

private void yuzeyYapisiButtonClick(object sender, RoutedEventArgs e)
{
ViewportTemizle();
KameraAlinan();
Model3DGroup yuzeyYapisi = new Model3DGroup();
Point3D[] noktalar = RastgeleYuzeyNoktalari();
for (int z = 0; z <= 80; z = z + 10)
{
for (int x = 0; x < 9; x++)
{
yuzeyYapisi.Children.Add(
UcgenModeliOlustur(
noktalar[x + z],
noktalar[x + z + 10],
noktalar[x + z + 1])
);
yuzeyYapisi.Children.Add(
UcgenModeliOlustur(
noktalar[x + z + 1],
noktalar[x + z + 10],
noktalar[x + z + 11])
);
}
}
ModelVisual3D model = new ModelVisual3D();
model.Content = yuzeyYapisi;
this.anaGoruntuleme.Children.Add(model);
}

Basit olarak çizimlerimizi oluşturmuş oluyoruz. Uygulamamızda Yüzey oluştur butonuna tıkladığımız hazırladığımız kod parçaları bize zig-zag olarak çizilmiş doğrular verecektedir. Bu doğruları da 3D nokta olarak tuttuğumuzdan ötürü bizlere tümsekli bir yeryüzüne benzeyen görüntü sunacaktır.



Uzantı doğrularını göstererek;


Tel görüntü Ekleme

Yüzey ile ilgili uygulamaları incelediğimizde bizlere uzantı noktaları ile birlikte tümsekler üzerinde daha belirleyici olması için tellere benzer çizimlerin yapıldığını görürüz. Şimdi bizde yüzey uygulamamıza bu telleri ekleyeceğiz.

Bu işlemi daha önceden doğruları gösterme işinde yaptığımız gibi CheckBox ile yaparsak sanırım çok daha kullanışlı olacaktır. Kullanıcı arayüzümüze XAML tarafında bu kontrolü ekliyoruz.

<Separator/>
<CheckBox Name="telGoruntuCheckBox">Telleri Goster</CheckBox>

Kontrolleri ekledikten sonra seçildiği zaman işlem görebilmesi için UcgenModeliOlustur() metoduna aşağıdaki koşulu ekliyoruz.

if (telGoruntuCheckBox.IsChecked == true)
{
ScreenSpaceLines3D telGoruntu = new ScreenSpaceLines3D();
telGoruntu.Points.Add(n0);
telGoruntu.Points.Add(n1);
telGoruntu.Points.Add(n2);
telGoruntu.Points.Add(n0);
telGoruntu.Color = Colors.LightBlue;
telGoruntu.Thickness = 3;
this.anaGoruntuleme.Children.Add(telGoruntu);
}

Metot ile bağlantılar bütün butonlarda sağlanmış olduğu için CheckBox ‘ı seçili duruma getirdiğimizde teller gözükecektir. Fakat ekran görüntüsünü göstermeden önce sizlere son olarak UcgenModeliOlustur() metodunun en son halini verelim. Çünkü içerisinde çok fazla oynama yaptık. Karıştırmış olabilme ihtimalinde, nerede hata yaptığınızı da bulabilmemiz mümkün olacaktır.

private Model3DGroup UcgenModeliOlustur(Point3D n0, Point3D n1, Point3D n2)
{
MeshGeometry3D mesh = new MeshGeometry3D();
mesh.Positions.Add(n0);
mesh.Positions.Add(n1);
mesh.Positions.Add(n2);
mesh.TriangleIndices.Add(0);
mesh.TriangleIndices.Add(1);
mesh.TriangleIndices.Add(2);
Vector3D normal = NormalHesapla(n0, n1, n2);
mesh.Normals.Add(normal);
mesh.Normals.Add(normal);
mesh.Normals.Add(normal);
Material madde = new DiffuseMaterial(
new SolidColorBrush(Colors.DarkGoldenrod));
GeometryModel3D model = new GeometryModel3D(
mesh, madde);
Model3DGroup grup = new Model3DGroup();
grup.Children.Add(model);

if (normalCheckBox.IsChecked == true)
grup.Children.Add(NormalYapilandirma(n0, n1, n2, normal));

if (telGoruntuCheckBox.IsChecked == true)
{
ScreenSpaceLines3D telGoruntu = new ScreenSpaceLines3D();
telGoruntu.Points.Add(n0);
telGoruntu.Points.Add(n1);
telGoruntu.Points.Add(n2);
telGoruntu.Points.Add(n0);
telGoruntu.Color = Colors.LightBlue;
telGoruntu.Thickness = 3;
this.anaGoruntuleme.Children.Add(telGoruntu);
}

return grup;
}

Son olarak telli olarak yüzeyimiz aşağıdaki gibidir.



Burada yazımızın sonuna gelmiş bulunuyoruz. 3D teorisinden başlayarak tümsekli yüzey(topoloji) oluşturarak sonlandırmış oluyoruz. 3D modellemeyi incelerken daha anlaşılır olması açısından en basit anlamda anlatmaya çalıştık. Bu anlattıklarımızı rahatlıkla anlayabildiyseniz artık çok daha karmaşık 3D modellemeleri rahatlıkla yapabilmeniz mümkün olacaktır.

Umarım yararlı olabilmiştir.

Uygulamanın kaynak dosyasına linkten ulaşabilirsiniz.

Kaynaklar
CodePlex 3DTools App.
Microsoft Developer Network
Turhal Temizer, Karadeniz Teknik Üniversitesi, Bilgisayar ve İstatistik Bilimleri Bölümü, Bitirme Çalışması

Turhal Temizer
turhal.temizer@csharpnedir.com
http://turhal.blogspot.com/