- 3 ay boyunca Vulkan öğrenirken iki demo oyun içeren küçük bir oyun motorunu bizzat geliştirme deneyiminin özeti
- Mevcut OpenGL deneyimine dayanarak Vulkan’ın karmaşıklığını adım adım aşma, glTF yükleme, skinning, shadow mapping gibi temel özelliklerin uygulanması
- Motorun adı EDBR (Elias Daler’s Bikeshed Engine) ve yaklaşık 19 bin satır koddan oluşuyor; bindless descriptor, PVP, BDA gibi modern grafik tekniklerini kullanıyor
- Yazıda vk-bootstrap, VMA, volk gibi temel kütüphaneler ile pipeline pattern, shader build otomasyonu, senkronizasyon yönetimi gibi pratik uygulama ayrıntıları paylaşılıyor
- Vulkan’a geçişle birlikte global state’in kaldırılması, açık kontrol, gelişmiş hata ayıklama ortamı, GPU’lar arası tutarlılık elde edilmiş; ileride render graph, SDF font, volumetric efektler eklenmesi planlanıyor
Vulkan öğrenme ve motor geliştirme özeti
- Yazar, grafik programlamaya kendi kendine öğrenerek başlamış ve 1,5 yıl önce OpenGL ile bir 3D motor yazmış
- Vulkan tabanlı motor, küçük ölçekli seviye tabanlı oyunlar için uygun; verimlilikten çok öğrenme ve deney yapma amacı taşıyor
- Başlangıçta basit bir 3D oyun yapıp ardından yeniden kullanılabilir parçaları ayırarak motorlaştırma yaklaşımı izlenmiş
- 3 ayda tamamlanabilmesinin nedeni, genel amaçlı bir motor değil belirli bir amaç için yapılmış bir motor olması
Grafik programlama öğrenme yolu
- Yeni başlayanların OpenGL ile başlayıp texture/model gösterimi, Blinn-Phong aydınlatma, shadow mapping gibi konuları öğrenmesi öneriliyor
- Önerilen kaynaklar arasında learnopengl.com, Anton’s OpenGL 4 Tutorials, Thorsten Thormählen dersleri yer alıyor
- Güncel OpenGL 4.6 pratik kaynaklarıyla birlikte lineer cebir (vektörler, matrisler, quaternionlar) bilgisinin önemi vurgulanıyor
Bike-shedding’i önlemek için öneriler
- Gereksiz aşırı tasarım ve soyutlamadan kaçınıp “şu anda gerekeni uygula” ilkesine bağlı kalın
- “Önce çalışır hale getir, sonra iyileştir” yaklaşımı öneriliyor
- Genel amaçlı bir motor yerine önce küçük bir oyunu tamamlamak daha verimli
- Başkalarının karmaşık kodunu ya da yapısını birebir kopyalamak yerine basit bir yapıdan başlayın
Neden Vulkan seçildi?
- AAA oyunlarda çoğunlukla DirectX, macOS/iOS’ta Metal, web’de ise WebGPU/WebGL kullanılıyor
- Yazar, açık kaynak ve standart teknolojileri tercih ettiği ve masaüstü için küçük 3D oyun geliştirmeyi hedeflediği için Vulkan’ı seçmiş
- OpenGL artık gelişmiyor ve macOS’ta kullanımdan kaldırılmış durumda
- WebGPU daha sade olsa da yeterince olgun olmaması, özellik kısıtları, bindless ve push constant desteğinin olmaması gibi sınırlamalara sahip
Vulkan öğrenme süreci
- Başta neredeyse “grafik sürücüsünü kendin yazıyormuşsun” gibi hissettirecek kadar zordu, ancak
dynamic rendering, vk-bootstrap, vkguide gibi araçlarla erişilebilirlik arttı
- Başlıca öğrenme kaynakları:
- vkguide.dev (temelden başlayıp uygulamaya odaklanan içerik)
- TU Wien Vulkan Lecture Series
- 3D Graphics Rendering Cookbook, Mastering Graphics Programming with Vulkan
- İlk ay içinde glTF yükleme, compute skinning, frustum culling ve shadow mapping uygulanmış
EDBR motor yapısı ve frame işleme
- Motor kodu yaklaşık 19.000 satır, 3D oyun kısmı 4.600 satır, 2D platform oyunu 1.200 satır
- Başlıca render aşamaları:
- Compute skinning → Cascaded Shadow Mapping (4096×4096) → PBR tabanlı geometri shading
- Depth Resolve → Post FX (depth tabanlı sis) → UI rendering
- Tüm grafik sistemleri Vulkan’a özel olarak baştan yazılmış, önceki OpenGL koduyla karıştırılmamış
Vulkan geliştirmede pratik ipuçları
Önerilen kütüphaneler
- vk-bootstrap: başlatma ve swapchain kurulumunu basitleştirir
- Vulkan Memory Allocator (VMA): bellek yönetimini otomatikleştirir
- volk: extension function yüklemeyi kolaylaştırır
GfxDevice soyutlaması
VkDevice, VkQueue, VmaAllocator gibi bileşenleri tek bir nesnede yönetir
- Frame başlangıcı/bitişi, image ve buffer oluşturma, bindless descriptor yönetimi gibi görevleri üstlenir
Shader yönetimi
- GLSL kullanılıyor; build aşamasında
glslc ile SPIR-V’ye önceden derleniyor
- CMake
DEPFILE kullanılarak shader değiştiğinde otomatik yeniden derleme yapılıyor
Pipeline pattern
- Her render aşaması sınıf düzeyinde bir pipeline olarak ayrılıyor (
init, cleanup, draw)
VK_KHR_dynamic_rendering ile render pass ve subpass ihtiyacı kaldırılarak daha sade bir yapı korunuyor
Programmable Vertex Pulling + Buffer Device Address
- Tüm mesh’ler için tek bir Vertex yapısı kullanılıyor
- Shader içinde buffer_reference ile doğrudan erişim sağlanıyor; VAO gerekmiyor
Bindless Descriptor
- Global texture dizileri (
textures[], samplers[]) kullanılarak texture ID tabanlı örnekleme yapılıyor
- Texture ID’leri material yapısında tutulup push constant ile aktarılıyor
Dinamik veri yükleme
- Frame başına GPU buffer değiştirilerek veya CPU staging buffer kullanılarak veri aktarılıyor
NBuffer sınıfı ile frames-in-flight yapısı yönetiliyor
Kaynak temizliği ve senkronizasyon
- Yıkıcıların otomatik temizliği yerine açık
cleanup fonksiyonları kullanılıyor
vkCmdPipelineBarrier2 ile pass’ler arası bellek senkronizasyonu yapılıyor
- Render Graph ileride eklenecek
Uygulama ayrıntılarından örnekler
Sprite rendering
- Bindless texture ve instancing ile binlerce sprite tek seferde render ediliyor
SpriteDrawCommand yapısı GPU buffer’a yükleniyor, ardından vkCmdDraw(6, N) çağrılıyor
- 10 bin sprite 315μs içinde render ediliyor
Compute skinning
- Compute shader’da kemik matrisleri ve ağırlıklara dayalı vertex deformasyonu yapılıyor
- Her instance için ayrı bir çıktı buffer’ı oluşturuluyor ve sonrasında render aşamasında aynı şekilde işleniyor
Oyun ile renderer’ın ayrılması
- Oyun mantığında entt ECS kullanılıyor, renderer ise yalnızca DrawCommand vektörlerini işliyor
- Render komutları
drawMesh, drawSkinnedMesh çağrılarıyla üretiliyor
Sahne yükleme ve prefab’lar
- Seviyeler Blender’dan glTF olarak hazırlanıyor, node isimlendirme kurallarıyla prefab’lar otomatik spawn ediliyor
- Prefab’lar JSON ile tanımlanıyor ve harici glTF’lere referans veriyor
MSAA, UI, ImGui
- Forward rendering tabanlı MSAA x8 uygulanıyor
- Roblox UI API’sinden ilham alan otomatik yerleşim sistemi geliştirilmiş
- Dear ImGui sRGB sorununu çözmek için özel bir Vulkan backend’i yazılmış
Diğer bileşenler
- Fizik için Jolt Physics, ECS için entt, ses için OpenAL-soft, profilleme için Tracy kullanılıyor
Vulkan’a geçmenin faydaları
- Global state’in kaldırılması sayesinde daha açık ve modüler bir kod yapısı elde edilmiş
- Validation layer’lar ve RenderDoc hata ayıklaması ile sorun takibi kolaylaşmış
- GPU ve işletim sistemleri arasında daha yüksek tutarlılık, OpenGL’e kıyasla daha öngörülebilir davranış sağlanmış
- Yeni shader dilleri (slang, shady) gibi genişleme olanakları kazanılmış
- Daha az soyutlama ve daha net pipeline kontrolü bakım kolaylığını artırmış
Gelecek planları
- SDF fontlar, paralel image yükleme ve mipmap üretimi, Bloom, volumetric fog, animation blending, render graph, AO eklenmesi planlanıyor
- Vulkan öğrenmek zor olsa da modern grafik API’lerini anlama ve motor tasarlama yeteneğini geliştirme açısından çok faydalı olmuş
1 yorum
Hacker News görüşleri
1 yıl önce yazdığım önceki gönderiden sonra bile Vulkan hakkındaki düşüncelerim pek değişmedi
Düşük seviyeli grafik kontrolü isteyenler için ilgi çekici olabilir ama benim için gerçekten kullanması eziyetli bir API idi
Kendi oyun motorumu yapma fikri hâlâ cazip geliyor ama Vulkan'ın ilk kurulumundan bile hâlâ çekiniyorum
Benim istediğim şey, SDL'in 2D grafikleri ele alışının 3D versiyonu gibi bir şey
SDL'de 3D yapmak için sonunda yine OpenGL seviyesine inmek gerekiyor ama benim istediğim seviye bu değil
Belki de WebGPU, keyifle kullanabileceğim alternatif olabilir
Ben de onunla bir motor yaptım ama sonunda daha fazla kontrol ve performans isteyince yine Vulkan tabanlı motora geri döndüm
Yine de SDL GPU kodundan senkronizasyon kalıpları öğrendim ve bunlar Vulkan motorunda çok işime yaradı
wgpu, WebGPU düzeyinde soyutlama sağlayan bir ara noktaOpenGL'den daha güçlü ama kaynak bariyerleri ya da layout geçişleri gibi ayrıntıları doğrudan ele almanız gerekmiyor
Runtime bazı bookkeeping işlerini sizin yerinize yapıyor ve yalnızca tek kuyruk desteklemek gibi kısıtları var
Vulkan zor ama büyük üreticilerin desteklediği eklentileri kullanırsanız epey iyileşiyor
Yine de sürücülerin görmezden geldiği ince ayarları zorunlu kılması gibi, hâlâ gereksiz karmaşıklık barındırıyor
Şu anda yüksek seviyeli oyun motorları ile düşük seviyeli Vulkan/Metal arasında bir ara API kalmadı
Yeni başlayan birinin 3D grafikleri öğrenebilmesi için shader ya da buffer gibi kavramları bilmesini gerektirmeyen, basit bir “üçgen çiz” düzeyinde API gerekiyor
Vulkan'ın sunduğu ayrıntılı kontrol, yalnızca çok küçük bir motor geliştirici kitlesi için gerekli; çoğu kişi için OpenGL düzeyi fazlasıyla yeterli
3D'de, 2D'ye kıyasla birleştirilebilir parça sayısı çok daha fazla olduğu için bunu basit bir grafik API'siyle taşımak zor
OpenGL de aslında bunu hedefliyordu ama sonunda karmaşıklaştı
‘bike shedding’, önemsiz meselelere takılıp asıl önemli kısmı kaçırmak anlamına gelir
Orijinal metinde anlatılan şey ise daha çok feature creep ya da over-engineering'e yakın
Bu, projenin ilerlemesini engelleyip yalnızca kişisel keyfe odaklanma davranışını anlatır
bike shedding genelde “ev bitmeden bisikletliğin rengini seçmek” örneğiyle açıklanır
“Minecraft çok oyunculu klonuyla motor geliştirmeye başlamak iyi bir fikir değil” denmişti ama
aslında birçok kişi ilk motor projesi olarak Minecraft benzeri oyunlar yapıyor
Voxel motorları için bu adeta bir “Hello, world”
(2024) o dönemdeki gönderi 625 puan ve 260 yorum almıştı — orijinal bağlantı
Vulkan, öğrendiğim şeyler arasında en zor teknolojiydi
O kadar sezgisel değil ve o kadar fazla tekrar işi var ki programlama keyfini elinizden alıyor
Daha basit başlamak istiyorsan OpenGL'i, özellikle de shader öncesi sürümlerini öneririm
Ama sektör OpenGL'i giderek daha fazla geri plana itiyor
Eğitimleri takip edip sadece kod kopyalıyor, kavramları gerçekten anlamıyordum
Bu yüzden WebGPU (Google Dawn) tarafına geçtim ve Vulkan'dan çok daha basit geldi
WebGPU'nun kısıtları sayesinde kavramları öğrendikten sonra Vulkan'a geri dönmek çok daha kolay oldu
WebGPU'da push constant yok ve pipeline explosion sorunu var ama Vulkan'da senkronizasyon ve bellek yönetimi daha zor
SDL_GPU da benzer seviyede bir API, başlangıç için iyi
Vulkan aşırı tasarlanmış bir API
CUDA'da tek satırla yapılabilen GPU bellek ayırma işlemi, Vulkan'da sayısız boilerplate gerektiriyor
Modern Vulkan çok gelişti ama hâlâ gidilecek uzun bir yol var
Umarım SDL3 ya da wgpu bu karmaşıklığı azaltan soyutlama katmanı olur
Valve SDL3'ü desteklediği için en güçlü adayın o olduğunu düşünüyorum
Önce “grafikleri çok iş parçacıklı mı yürütmem gerekiyor?” diye sormak lazım
Cevap hayırsa Vulkan/DX12 kullanmak için bir neden yok
Performans sorunu çıkana kadar OpenGL, DX11 ya da bir oyun motoru kullanmak çok daha iyi
3D/oyun programlamasına hayranım ve bazı YouTuber'ların oyun yapım sürecini sık sık izliyorum
Ama web uygulamaları ya da DevOps ile kıyaslayınca çok daha karmaşık bir dünya
Pixel shader, compute shader, geometri, lineer cebir, hatta PDE bile işin içine giriyor
TokyoSpliff YouTube kanalı
Bugünlerde hobi olarak oyun motoru yapmak havalı bir şey sayılıyor olması hoşuma gidiyor
Ben de 10 yıldır kişisel motorumu geliştiriyorum ve bu son derece tatmin edici bir deneyim oldu
Grafik programlamaya ilk kez giriyorsanız OpenGL ile başlamak iyi olur
23 yıl önce NeHe'nin OpenGL eğitimlerini okumuştum; bence hâlâ en iyi yapılandırılmış öğrenme kaynakları arasında
Bu arada, ben orijinal gönderinin yazarı değilim; sadece başlığı korudum