Ana Sayfa Blog Sayfa 2

Unity Coroutine Nedir?

Herkese selam, bu yazıda Unity Coroutine Nedir? Nasıl kullanılır? sorularını cevaplayacağım. Unity Coroutine aslında bildiğimiz fonksiyon yapısına sahiptir, tek fark ise bu fonksiyonlar içerisinde bekletme işlemini gerçekleştirebiliyor oluşumuzdur. Update veya FixedUpdate fonksiyonlarını düşündüğümüzde, bunlar her karede çağrılan fonksiyonlardır. Coroutine fonksiyonları ile bizim yaptığımızda bu sürekli çağrılma durumu yerine, verdiğimiz sürelerde beklemeye geçip, komutlarımızın çalışmasını sağlamaktadır. 

Belirli aralıklarla ışıkları yakıp söndürmek, silahın belirli aralıklarla ateşlenmesini sağlamak gibi işlemler için idealdirler. Yapısına baktığımızda, bir nevi uydurma-paralel bir akış oluşturarak ana akış (main thread) dışı çalışıyor gibi gözükebilirler. Ancak multi-threading olayıyla alakası bulunmamakta. Bunu baştan bilmenizde ve karıştırmamanızda fayda var. 

Bahsettiğim gibi, ana akış üzerinde çalışmaya devam eden fonksiyonlar aslında. Ve oyun objelerine bağlıdırlar. Yani bir gameobject üstündeki script ile oluşturulan coroutine, obje yok olduğu anda yok olacaktır. Öte yandan, bir coroutine çalışıyorken, bulunduğu bileşeni deaktif etsek bile, fonksiyon tamamlanana kadar çalışmaya devam edecektir. 

Peki bu bekleme olayını oluşturmamızı sağlayan şey nedir? Aslında, sadece burada dönüş tipi olarak IEnumerator kullanmamız yetiyor. Void tipli fonksiyonlar dışındaki fonksiyonlarda bir değer döndürmemiz gerekmekte normalde. Burada da IEnumaretor tipi ile değer döndürdüğümüzde, aslında sisteme “dur bakayım, şu kadar süre bekleyeceksin” demekteyiz. Ama aklınız karışmasın, bekleme derken bir sayı değeri vs döndürmüyoruz burada. IEnumerator tipinde değişken döndürüyoruz. 

Önemli bir nokta da, eğer bu bekletme işlemini sağlamak istiyorsak, fonksiyonları StartCoroutine isimli fonksiyon aracılığıyla çağırmamız gerekli. Eğer direkt oluşturduğunuz IEnumerator tipindeki fonksiyonu çağırırsanız, bekleme işlemi çalışmayacaktır. Normal bir fonksiyon nasıl işliyorsa, aynı şekilde işleyecektir komutlarımızı. Aşağıdaki örnek kod üzerinde temel mantığı görebilirsiniz. Dönüş tipine sahip olduğu için Coroutine tipinde bir değişkende tutmamız da mümkün oluyor.

using System.Collections;
using UnityEngine;

public class CoroutineBasitOrnek : MonoBehaviour {

    Coroutine test;

    IEnumerator testEnumarator;
    void Start () {
        //Standart başlatma
        test = StartCoroutine (TestCoroutine ());
        /*isterseniz 2 farklı yöntemle daha oluşturabilirsiniz;
        //string ile başlatma
        test = StartCoroutine ("TestCoroutine");
        //IEnumerator ile başlatma
        testEnumarator=TestCoroutine();
        test=StartCoroutine(testEnumarator);
        */
    }

    void Update () {
        if (test == null) {
            test = StartCoroutine (TestCoroutine ());
        }
    }

    IEnumerator TestCoroutine () {
        Debug.Log ("Coroutine Başladı:" + Time.time);
        yield return new WaitForSeconds (2f);
        Debug.Log ("Coroutine Bitti:" + Time.time);
        yield return null;
    }
}

Gördüğünüz gibi, return komutu ile bir değer döndürüyoruz burada. Öncesinde ve sonrasında Log komutları ile zamanı ekrana yazdırıyoruz. Şayet henüz çalıştırmadıysanız, kodu alıp bir script oluşturarak, bir objenize atın ve çalıştırın. İşlem sırasının nasıl ilerlediğini böylece daha iyi anlayabilirsiniz diye düşünüyorum. 

Örnek kod şu an baktığımızda işlevsiz gibi ama çalışma prensibini anlatmak adına yeterli. Öncelikle Coroutine tipinde bir değişkenimiz var, bunu Start içerisinde tanımlıyoruz ve StartCoroutine fonksiyonundan yararlanarak fonksiyonu çalıştırıyoruz. Sonrasında update içerisinde sürekli olarak değişkenimizi kontrol ediyoruz. Eğer null değer geldiyse, ki fonksiyon bitiminde bu değeri döndürmekteyiz, işlem bittiğini anlıyor ve tekrar çalıştırıyoruz. 

Bir değişkende tutup null olup olmadığını kontrol etmek tabii ki bir yöntem. Ama bana çok sağlıklı gelmeyen bir yapı bu. Bunun yerine farklı değişkenler kullanıp Coroutine içerisinde başlangıç ve bitişte bunu değiştirmek daha mantıklı. Yazının devamındaki örnekte de bunu yapıyor olacağız zaten.

Bu arada, Time.time ile oyunda başlangıçtan itibaren geçen zamanı elde ediyoruz. Time sınıfı ile daha fazla bilgi edinmek isterseniz “Unity Time Sınıfı” yazımızı okuyabilirsiniz. WaitForSeconds fonksiyonuna ve null değer döndürmeye yazının devamında detaylı gireceğim ama şimdilik verdiğimiz saniye kadar bekleme yaratmamızı sağladığını bilmeniz yeterli. 

Kodda da gördüğünüz gibi, return komutunun öncesine de, sonrasına da farklı komutlar ekleyebiliyoruz. Normal şartlarda, bir fonksiyonda return komutu sonrasında yazdığımız şeylere erişilmez, o komutlar çalışmaz. Hatta editörünüz genelde bunu size uyarı olarak da gösterir. Coroutine yapısında ise işler biraz daha farklı. Belirttiğimiz süre geçtikten sonra, fonksiyonumuz kaldığı yerden çalışmaya devam ediyor. Temelde Unity Coroutine Nedir? sorusunun cevabı da bu aslında.

Unity Coroutine Kullanımı 

Unity Coroutine Kullanımı için yukarıda verdiğim örnek tek başına yeterli kalmayacaktır. İşleyişi biraz daha iyi anlayabilmeniz adına, bir döngü oluşturup objenin verdiğimiz konuma ilerlemesini sağlayan bir yapı oluşturalım. Lerp komutu basitçe verdiğimiz 2 nokta arasında pozisyon elde etmemizi sağlamakta. Daha detaylı bilgiyi “Unity Vector3 Nedir?” yazımızdan elde edebilirsiniz.

using System.Collections;
using UnityEngine;

public class CoroutineMovementWithWhile : MonoBehaviour {

    Vector3 hedefKonum = new Vector3 (3, 0, 0);

    void Update () {
        if (Input.GetKeyDown (KeyCode.Space)) {
            StartCoroutine (Hareket (hedefKonum));
        }
    }

    IEnumerator Hareket (Vector3 hedef) {
        float yol = 0;
        Vector3 baslangic = transform.position;
        while (yol <= 1f) {
            transform.position = Vector3.Lerp (baslangic, hedef, yol);
            yol += Time.deltaTime;
            yield return null;
        }
    }
}

Gördüğünüz gibi, döngüde hiçbir bozulma olmadan tekrar tekrar çalışmaya devam ediyor. Burada verdiğim null değeri biraz garip gelmiş olabilir. E hiç bekletmiyor muyuz o halde diye sorabilirsiniz. Aslında yine bekleme işlemi belirtiyoruz ama 1 kare boyunca beklemesini sağlıyoruz gibi düşünebilirsiniz. Detaylı bilgi yazının devamında.

Şimdi döngüye gelecek olursak, aynı daha önceki örnekte olduğu gibi, sıradaki komutu yerine getiriyor aslında. Hareket gerçekleşiyor, bekleme işlemi sağlanıyor. return komutu sonrasındaki satırda bakıyoruz ki bir döngü içerisindeyiz. Bu yüzden döngü devam etmeli mi etmemeli mi kontrolü yapılıyor yine. Sanki hiçbir bekleme olmamış gibi aynı devam

Belki farketmişsinizdir, hareket devam ederken, yani Coroutine çalışıyorken tekrar space tuşuna basarsak harekette bir sapıtma meydana geliyor. Hali hazırda bu coroutine çalışıyor mu çalışmıyor mu diye kontrol etmemizi sağlayan bir yapı yok. Elle kendimiz oluşturmamız ve kontrolü sağlamamız lazım. 

Ayrıca örneği biraz daha işe yarar hale getirmek adına, WASD tuşlarını kullanarak öne-arkaya, sağa-sola hareket edebilir bir yapı oluşturacağım sizler için. Öncesinde adım adım ekleyeceklerimi yazacağım, kodun tamamını görmeden sizin de bunu yapmaya çalışmanızı istiyorum. En sonunda kodu vereceğim ancak birazcık kafadaki çarkları çalıştırmanın zararı olmaz 🙂 

Öncelikle Coroutine ile sağladığımız hareket işlemi gerçekleşiyor mu ya da gerçekleşmiyor mu bunu bir değişkende tutmakta fayda var, böylece kontrolü sağlayabiliriz. Bunun için bir enum yapısı kurabilirsiniz, farklı hareket durumlarını kontrol etmek için. Ancak ben şu an bool tipinde “hareketEdiyor” isimli bir değişken oluşturacağım. Hareket fonksiyonu içerisinde en başta bu değeri true hale getirip, hareket işlemi bitince de false hale getirebiliriz. Ve tabii ki, space tuşuna basıldığında “hareketEdiyor” false değere sahip ise kodumuzu çalıştıracağız. 

Bu adımları gerçekleştirip çalıştırdığınızda, space tuşuna arka arkaya bassanız bile çalışmadığını göreceksiniz. Eğer hâlâ çalışıyorsa, bir nokta gözünüzden kaçmış olabilir.

Farklı yönler kısmı da gayet basit aslında. Her bir tuş için kontrol sağlayabiliriz. Ve hedef konum yerine transform.forward, transform.right komutlarından yararlanmamız mümkün. Ancak bu yöntemle yön kısmında karışıklık da olabilir. Çünkü kendi sağı veya ileri yönünü elde ediyoruz transform üzerinden. Peki genel koordinat sistemine göre sağ ve sol istersek ne kullanacağız? Veya farklı büyüklükler? Bunun için de Vector3.forward veya Vector3 left kullanmamız mümkün. Tamamen tercihinize göre bu ikisi arasında seçim yapabilirsiniz.

Ben Vector3 kullanacağım için, öncelikle varolan pozisyonuna gitmek istediğim vector3 değerini eklemek gerekiyor. Bunu isterseniz Coroutine içerisine değişken olarak verirken hesaplatabilirsiniz veya Coroutine içerisinde hesaplatabilirsiniz. Tamamen size kalmış bu tercih. 

Bu işlemleri adım adım yaptığımızda, kodumuzun son hali aşağıdaki gibi olacaktır. Dediğim gibi, ben Vector3 altyapısını kullanarak yaptım. Ancak siz transform değerlerini kullanarak bunu gerçekleştirebilirsiniz. Hatta pratik amacıyla kesinlikle öneririm. Bu arada Transform bileşenine dair daha fazla bilgi edinmek isterseniz de “Unity Transform Nedir?” yazımıza göz atabilirsiniz.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CoroutineMovementWithWhile : MonoBehaviour {

    Vector3 hedefKonum = new Vector3 (3, 0, 0);
    bool hareketEdiyor = false;

    void Update () {
        //eğer hareket etmiyorsa
        if (!hareketEdiyor) {
            if (Input.GetKeyDown (KeyCode.W)) {
                StartCoroutine (Hareket (Vector3.forward)); //ileri
            }
            if (Input.GetKeyDown (KeyCode.S)) {
                StartCoroutine (Hareket (Vector3.back)); //geri
            }
            if (Input.GetKeyDown (KeyCode.D)) {
                StartCoroutine (Hareket (Vector3.right)); //sağ
            }
            if (Input.GetKeyDown (KeyCode.A)) {
                StartCoroutine (Hareket (Vector3.left)); //sol
            }
        }
    }

    IEnumerator Hareket (Vector3 hedef) {
        float yol = 0;
        Vector3 baslangic = transform.position;
        hedef += baslangic; //başlangıç ve hedefi topluyoruz. Böylece global değil local, obje pozisyona göre bir hedef yaratmış oluyoruz
        while (yol <= 1f) {
            transform.position = Vector3.Lerp (baslangic, hedef, yol);
            yol += Time.deltaTime;
            yield return null;
        }
    }
}

Bu haliyle basit bir örnek oluşturduk aslında. Buna dair ufak bir ödev vereceğim size. Her şey iyi güzel çalışıyor ama, hareket sanki birazcık yavaş. Bunu kontrol edebiliyor olsak çok daha iyi olurdu. Bunun için ne yapabiliriz bi düşünmenizi istiyorum. İpucu olarak da şunu belirteyim, objenin konumunu belirlememizi sağlayan şey “yol” isimli değişken. 0 olduğunda ilk pozisyonda, 1 olduğunda ikinci pozisyonda bir değer döndürüyor bize. Time.deltaTime ile arttırmanın yanında bir şeyler daha yapsak sanki olacak gibi. Top artık sizde 🙂

Unity Coroutine Nedir? Nasıl Kullanılır? sorularını hallettik, gayet güzel. Bunları çalıştırıyoruz ama bir noktada durdurmamız da gerekebilir. Şimdi Unity Coroutine işlemleri nasıl durdurulur ona bir bakalım.

Unity Coroutine Durdurma

Unity Coroutine Durdurma için 2 fonksiyon bulunmakta. Herhangi bir durumda Coroutine işlemlerini, yazdığınız fonksiyondan önce durdurmak isteyebilirsiniz. Bu fonksiyonlar da tam bu ihtiyacı gidermek için oluşturulmuş durumda. 

StopCoroutine: Verdiğimiz Coroutine nesnesi aracılığıyla bir Coroutine fonksiyonunu durdurmamıza imkan veren kod. Ve evet, Coroutine işlemini bir değişkende tutmak mümkün. Ancak bunun dışında istersek IEnumarator tipinde istersek de string tipinde değişken vererek durdurma işlemini gerçekleştirebiliriz. Bu noktada dikkat etmemiz gereken şey, StartCoroutine ile nasıl başlattığımız. Örneğin string değişken vererek başlattıysak yine string ile bitirmemiz gerekiyor. Aşağıda 3 durum için de başlatma bitirme örneklerini bulabilirsiniz.

using System.Collections;
using UnityEngine;

public class CoroutineDegisken : MonoBehaviour {

    Coroutine hareketCoroutine;
    // Start is called before the first frame update
    void Start () {
        //Coroutine ile başlatma
        hareketCoroutine = StartCoroutine (Ileri ());
    }

    void Update () {
        if (Input.GetKeyDown (KeyCode.Space)) {
            //değişken ile durdurma
            StopCoroutine (hareketCoroutine);
        }
    }

    IEnumerator Ileri () {
        for (;;) {
            transform.position += Vector3.forward * Time.deltaTime;
            yield return null;
        }
    }
}
using System.Collections;
using UnityEngine;

public class CoroutineString : MonoBehaviour {

    void Start () {
        //String değişken ile başlatma
        StartCoroutine ("Ileri");
    }

    void Update () {
        if (Input.GetKeyDown (KeyCode.Space)) {
            //fonksiyon ismi ile durdurma
            StopCoroutine ("İleri");
        }
    }

    IEnumerator Ileri () {
        for (;;) {
            transform.position += Vector3.forward * Time.deltaTime;
            yield return null;
        }
    }
}
using System.Collections;
using UnityEngine;

public class CoroutineIEnumerator : MonoBehaviour {

    IEnumerator hareket;

    void Start () {
        //IEnumaretor değişken ile başlatma
        hareket = Ileri ();
        StartCoroutine (hareket);
    }
    void Update () {
        if (Input.GetKeyDown (KeyCode.Space)) {
            //IEnumarator ile durdurma
            StopCoroutine (hareket);
        }
    }
    IEnumerator Ileri () {
        for (;;) {
            transform.position += Vector3.forward * Time.deltaTime;
            yield return null;
        }
    }
}

StopAllCoroutine : Bileşenimiz içerisinde oluşturduğumuz bütün coroutine işlemlerini durdurmamızı sağlar. 

using System.Collections;
using UnityEngine;

public class CoroutineStopAll : MonoBehaviour {

    [SerializeField]
    float donusHizi = 30, genislik = 3, boyutHizi = 30;
    // Start is called before the first frame update
    void Start () {
        StartCoroutine ("Don");
        StartCoroutine (Boyutlandir ());
    }

    void Update () {
        if (Input.GetKeyDown (KeyCode.Space)) {
            StopAllCoroutines ();
        }
    }
    //Zamanla açıyı arttırarak sin-cos fonksiyonları ile x-y konumlarını değiştirip dairesel hareket sağlıyoruz.
    IEnumerator Don () {
        float aci = 0;
        while (true) {
            aci += Time.deltaTime * donusHizi;
            float posX = Mathf.Sin (aci * Mathf.Deg2Rad);
            float posY = Mathf.Cos (aci * Mathf.Deg2Rad);
            transform.position = new Vector3 (posX, posY, 0) * genislik;
            yield return null;
        }
    }
    //sinüs fonksiyonununda artma azalma durumundan faydalanarak boyutu büyütüp küçültüyoruz
    IEnumerator Boyutlandir () {
        while (true) {
            float buyukluk = Mathf.Sin (Time.time * boyutHizi * Mathf.Deg2Rad);
            buyukluk = Mathf.Abs (buyukluk);
            transform.localScale = Vector3.one * buyukluk;
            yield return null;
        }
    }
}

Örneklerde kullanmış olduğum Mathf sınıfı hakkında daha detaylı bilgiyi “Unity Mathf Sınıfı” yazımızda bulabilirsiniz. Yazının devamında return komutunda kullanabileceğimiz dönüş değerlerine de yer verdim. Muhakkak bakmanızı öneriyorum.

Unity Coroutine Dönüş Değerleri

Unity Coroutine Dönüş Değerleri için Unity bize hali hazırda seçenekler sunmakta. Yazının devamında bunlara değinip kod örneklerini oluşturacağım sizler için. Daha önceki örneklerde de gördüğünüz gibi “yield return new” yazdıktan sonra bu komutları kullanabilirsiniz. Yalnızca null ve break değeri öncesinde “new” kelimesini kullanmanıza gerek yoktur.

WaitForEndOfFrame : Bu değeri kullandığımızda, komutlarımızı karenin sonuna kadar bekletmemizi sağlar. Ancak burada dikkat etmemiz gereken şey, komutta da belirttiği gibi, karenin en sonunda bu işlemin gerçekleşecek olmasıdır. Eğer update veya lateupdate içerisinde bir işlem yapıp, sonrasında Coroutine fonksiyonunuz içerisinde kontrol etmek isterseniz, bu yöntem faydalı olabilir.

    IEnumerator BuyutKucult () {
        while (true) {
            transform.position += Vector3.forward * Time.deltaTime;
            yield return new WaitForEndOfFrame ();
        }
    }

WaitForFixedUpdate : Bir dahaki Fixed Update fonksiyonu çağırılana kadar komutlarımızı bekletmemizi sağlar.

    IEnumerator Hizlandir (float sure) {
        float zaman = 0;
        while (zaman < sure) {
            zaman += Time.deltaTime;
            Vector3 velocity = rigidbody.velocity;
            velocity *= .1f;
            rigidbody.velocity = velocity;
            yield return new WaitForEndOfFrame ();
        }
    }

WaitForSeconds : Oyun zamanında göre belirttiğimiz saniye kadar beklememizi sağlar. TimeScale değerinden etkilenir. Ancak belirtmekte fayda var, çok kesin bir şekilde bu kontrol yapılmaz. Örneğin, 5 saniye beklemesini istediğimizde, tam olarak 5 saniye olduğunda değil de, 5’i çok çok ufak bir şekilde geçtiği anda çalışacaktır.

    IEnumerator AdimAdımIsinla (int adim, Vector3 yon) {
        for (int i = 0; i < adim; i++) {
            transform.position += yon;
            yield return new WaitForSeconds (.1f);
        }
    }

WaitForSecondsRealtime : Oyun zamanından bağımsız şekilde, gerçek zamana göre saniye cinsinden değer vermemizi sağlayan yapıdır.


    IEnumerator Hatirlatici (float sure) {
        while (true) {
            yield return new WaitForSecondsRealtime (sure);
            Debug.Log (sure + " saniye geçti, su içmeyi unutma!!");
        }
    }

WaitUntil : Belirtiğimiz koşul sağlanana kadar beklememizi sağlayan koddur. Mermi==0 olana kadar beklemeye devam et diyebiliriz örneğin.


    IEnumerator MesafeOlcer (Transform hedef, float mesafe) {
        yield return new WaitUntil (() => Vector3.Distance (transform.position, hedef.position) < mesafe);
        Debug.Log (hedef.name + "isimli objeye çok yakınsın");
    }

WaitWhile : Belirttiğimiz durum sağlandığı sürece beklememizi sağlayan koddur. While döngüsü mantığındaki gibi çalışır.


    IEnumerator TakipKontrol (Transform hedef, float mesafe) {
        yield return new WaitWhile (() => Vector3.Distance (transform.position, hedef.position) < mesafe);
        Debug.Log (hedef.name + " isimli obje takip mesafenden çıktı, artık yakalayamazsın");
    }

null : Çalışma mantığı WaitForEndOfFrame fonksiyonuna benzerdir. Ancak aralarındaki fark, çalıştırılma sıraları ile alakalıdır. null değeri verdiğimizde, bir sonraki karede update fonksiyonu çalıştığı anda çalışacaktır. Yani karenin sonunu beklemeyecektir.

break : Özellikle döngüleri kullandığınız işlemlerde, herhangi bir durumda coroutine işlemini durdurmak için kullanabilirsiniz.


    IEnumerator TusKontrol (int beklenecekKaresayisi) {
        for (int i = 0; i < beklenecekKaresayisi; i++) {
            if (Input.GetKeyDown (KeyCode.Space)) {
                Debug.Log ("Doğru zamanda bastın!!");
                yield break;
            }
            yield return null;
        }
        Debug.Log ("Kaçırdın...");
    }

Böylece Unity Coroutine Nedir? Nasıl kullanılır? sorularını cevaplandırmış olduk. Türkçe dökuman çevirilerine devam edeceğiz ancak her zaman dönüp resmi Unity Dokümanlarına bakmakta fayda var 🙂 Yeni yazılarda görüşmek dileğiyle, umarım faydası olmuştur. Görüşmek üzere.

Unity Animation Curve ile Değişimi Kontrol Etmek

Unity Animation Curve ile Değişimi Kontrol Etmek belki de hiç düşünmeyeceğiniz şekilde mümkün ve kolay. Burada değişimden kastım, bir değişkene verdiğimiz değerin, sabit şekilde değişmesi yerine, başlangıç, bitişte veya bunların arasında farklı hızlarda değişim göstermesi. Objenizi bir noktadan belirli bir noktaya taşırken, sabit hızla ilerlemesi her zaman isteyeceğimiz bir şey olmayabilir. Kimi zaman yavaşça ilerleyip sonrasında hızlanmasını veya tam tersi, ilk başta hızlıca ilerleyip sona doğru yaklaştıkça yavaşlamasını isteyebilirsiniz. Veya bir konuma gidip tekrar geri gelmesini. Kod ile uğraşmadan bu ayarlamaları Unity Animation Curve ile yapmak gayet mümkün bir durum.

Öncelikle, Unity Animation Curve nedir ondan bir bahsetmekte yarar var. Animation Curve aslında Unity’de oluşturduğumuz animasyonlarda en sık kullanılan, değiştirdiğimiz değerleri gözlemleyebildiğimiz ve kontrol edebildiğimiz bir değişken tipi diyebiliriz. Animasyon penceresinde uğraştıysanız illa ki denk geldiğinizi düşünüyorum, ancak bilmeyenler için bir gösterelim.

Animasyon Penceresinde Animation Curve
Animasyon Penceresinde Animation Curve

Animasyonlar içerisinde yatay (x) eksen zamanı, kare sayısını gösterirken, dikey (y) değeri göstermektedir. Az çok matematik derslerinden hatırlarsınız ki, bu resmen bir fonksiyon ve onun grafiği gibi aslında. En basit haliyle, y=f(x) şeklinde gördüğümüz fonksiyonlarda olduğu gibi, x değerini verip y ile sonucu elde ediyoruz. Animasyonlar da aslında bu şekilde çalışıyor, x zamanında y değeri ne olacak, bunun verisini tutuyor. Ancak ben bu yazıda Animasyon penceresinde değil de, bir script içerisinde bir değişken olarak Unity Animation Curve İle Değişimi Kontrol Etmek nasıl olur, buna değineceğim. Eğer açtıysanız animasyon penceresini kapatabilirsiniz, ona bu yazıda ihtiyacımız yok 🙂

Kodumuzda bundan yararlanırken, bir arayüz sayesinde bu grafiği düzenleyebilmemiz nedeniyle, matematiksel hesaplamalar ile çok fazla uğraşmamıza gerek kalmayacak. Kontrol edebilmek için sadece birazcık mantığını oturtmamız yeterli olacaktır. Bunu da oluşturduğumuz grafiği iyice gözlemleyerek yapabiliriz. Bu yapacağımız değişimi kontrol etme olayı için kullanılan bir terim de aslında Easing. Hatta DOTween içerisinde de bu fonksiyonlar bize sunuluyor. DOTween paketini kullanıyorsanız, SetEase fonksiyonu ile bu kontrolü sağlayabilirsiniz. Kendi dokümanlarında ilgili fonksiyonu bulmanız mümkün. Ayrıca çoğunu çevirdiğimiz bir DOTween dokümanı da mevcut. 

Dediğim gibi, matematiksel hesaplamalar kısmına, en azından bu yazıda, girmeyeceğim. Ancak internette ufak bir araştırma ile matematik fonksiyonlarına erişmeniz mümkün. En güzel gösterimlerden biri de https://easings.net/ içerisinde. Farklı Ease tiplerine tıklayıp incelediğinizde, en altta TypeScript ile yazılmış matematik fonksiyonlarını da görebilirsiniz. Kod ile nasıl bunu sağlarım diyorsanız da, verdiğim linkten gidip bu fonksiyonları inceleyebilirsiniz. Bu site temelde web için örneklere sahip olduğundan TypeScript dili kullanılmış. Ancak basitçe C# diline çevirebileceğinizi düşünüyorum.

Unity Animation Curve ile Hareket Değişimi

Şimdi basit bir örnek olarak Unity Animation Curve ile Değişimi Kontrol Etmek nasıl gerçekleştirilebilir, bunu adım adım gerçekleştirelim. Öncelikle, varolan pozisyondan verilen pozisyona giden bir objemiz olsun. Bir küp nesnesi oluşturup aşağıdaki kodu oluşturup objenize atayın. Eğer kodda hareketle ilgili anlamadığınız kısımlar varsa Unity Vector3 Nedir? yazımıza göz atmanızda da fayda var. Sadece ufak bir not olarak şunu belirteyim, Lerp fonksiyonunda, verdiğimiz 2 vector3 konumu arasında hareketi sağlayabiliyoruz. Bunu da son değişken olarak verdiğimiz float tipindeki değer ile yapıyoruz. 0 verirsek ilk konum, 1 verirsek 2. konumu bize döndürecektir. 0,5 verirsek de tam ortalarında bir konum elde edeceğiz.

using System.Collections;
using UnityEngine;

public class AnimationCurveMove : MonoBehaviour {

    Vector3 baslangicKonum;

    [SerializeField]
    Vector3 hedefKonum;

    void Start () {
        baslangicKonum = transform.position;
    }

    void Update () {
        if (Input.GetKeyDown (KeyCode.Space)) {
            StartCoroutine (Hareket ());
        }
    }

    IEnumerator Hareket () {
        //zaman durumunu tuttacağımız değişken.
        float zaman = 0;
        //zaman 1 değeri ve altında olduğu sürece hareketi gerçekleştiriyoruz.
        while (zaman <= 1) {
            //başlangic ve hedef değerlerini toplama sebebim, verdiğimiz hedefi varolan pozisyona göre hesaplamasını istememden kaynaklı
            transform.position = Vector3.Lerp (baslangicKonum, baslangicKonum + hedefKonum, zaman);
            zaman += Time.deltaTime;
            yield return new WaitForEndOfFrame ();
        }
    }
}

Çalıştırıp space tuşuna basarak hareketini gözlemleyin. Baya sıkıcı bir şekilde sabit bir hızda ilerliyor değil mi? Bunu birazcık değiştirelim şimdi, önce yavaşlayarak hızlanma durumunu oluşturacağız, ardından tam tersi, önce hızlı sonra yavaş. Ardından da 3. örnek olarak objenin konuma gidip geri gelmesini sağlayacağız. Tabii ki ilk yapmamız gereken Unity Animation Curve tipinde bir değişken yaratmak. Start fonksiyonu öncesinde değişkenlerin olduğu kısıma aşağıdaki kodu ekleyin.

//Animation Curve Değişkeni
[SerializeField]
AnimationCurve animCurve;

Daha sonrasında editor kısmına tekrar geri dönerseniz, küp objemizde kodumuzun değişkenlerinin arasında bu yarattığımız değişken de gözüküyor. Ancak farklı bir yapıya sahip gibi, hiç beklemeden merakınızı giderelim. O alana tıklayın. Karşınıza şöyle bir pencere açılacaktır.

Unity Animation Curve Paneli
Unity Animation Curve Paneli

Bomboş olması bir garip di mi? Önce bunu bir düzeltelim. Görselde gördüğünüz kırmızı çizgiyle çekilmiş olana tıklamanızı istiyorum. Bu sayede hazır bir grafik kullanmış olacağız. Dikkatinizden kaçtıysa belirteyim, çizginin uçlarında 2 adet nokta oluşturuldu aynı zamanda. Bu noktalar aracılığıyla aslında grafik oluşuyor, biz grafiği kontrol edebiliyoruz. Noktaları isterseniz sürükleyerek isterseniz de sağ tıklayıp “Edit Key” diyerek noktanın değerlerini, konumunu değiştirmeniz mümkün. Detaylı olarak değiştirmeyi yazının devamında göstereceğim, o yüzden şimdilik böyle kalsın.

Öncesinde bahsettiğim yatay ve dikey eksenlerin varlığını tekrar hatırlatmakta fayda var. Unutmayın, yatay bizim verdiğimiz değer, dikey ise elde edeceğimiz değer olacak. İşte buradan alacağımız değeri Lerp fonksiyonunda kullanacağız. Bunun için de yapmanız gereken kodumuza geri dönüp, Vector3.Lerp fonksiyonunun olduğu satırı, aşağıdaki satır ile değiştirmek.

transform.position = Vector3.Lerp (baslangicKonum, baslangicKonum + hedefKonum, animCurve.Evaluate (zaman));

Animation Curve ile kullandığımız Evaluate isimli method, aynı bahsettiğim matematik fonksiyonlarındaki gibi, verdiğimiz değere karşılık fonksiyon sonucunu bize veriyor. Bu durumda da  Animation Curve üzerinden bu değeri bize verecek. Şimdi hazır seçili grafiğin hareketi nasıl değiştirdiğini gözlemlemenizi istiyorum. Çalıştırıp kontrol edin. Hatta çalışırken bir yandan Animation Curve penceresi açık da kalabilir, bu sayede hareketi ve grafiği yorumlamanız daha kolay olacaktır. 

İlk hazır grafiği kullandıktan ve gözlemledikten sonra, bu aşamada topu birazcık size bırakıyorum ve geri kalanları da gözlemlemenizi istiyorum. Grafik değiştikçe hareket değişimi nasıl oluyor, grafikteki hangi özellikler hareketi hızlandırıyor? Bunun üzerine birazcık düşünüp yazıya öyle devam etmenizi istiyorum.

Genel mantığı anladığınızı düşünüyorum ancak iyice oturtmakta fayda var. Bizim bu grafiğe verdiğimiz değer, bu durumda aslında zaman değeri. Geriya aldığımız, bize dönen değer ise yolun hangi kısmında olacağımız değeri. Şu anki kodumuzda bu şekilde kullanıyoruz yani. Şimdi ilk başta tıklamanızı istediğim grafiği ele alalım. 

Dümdüz bir hareket var, herhangi bir noktada çizginin eğimi değişmiyor, ne azalma ne artma var. Bu sürekli, linear bir hareket elde etmemizi sağlıyor aslında. Eğim süre boyunca aynı kaldığı için, değişim de aynı kalmakta. Artış miktarı hiç değişmiyor bu süre içerisinde. Şimdi o hazır grafiğin sağındaki grafiğe tıklayıp seçmenizi istiyorum. 

Yolun yarısına gelmek için 0,7 saniye harcamamız gerekiyor, sonrasında kalan yarımı tamamlamak ve son noktaya gelmek için ise 0,3 saniye. Baktığımızda gidilen mesafe aynı, ama mesafeyi tamamlama süresi farklı oluyor. E haliyle, hız da buna göre değişmiş oluyor.  Bahsettiğim değerleri de grafikten nasıl çıkardığımızı aşağıdaki görselden görebilirsiniz.

Unity Animation Curve Grafik Gözlemi 1
Unity Animation Curve Grafik Gözlemi 1

Yapabileceğimiz bir diğer çıkarım ise, grafikteki yön değişimi. Örneğin bahsettiğim gibi, dikeyde 0,5 değerine erişene kadar grafikteki artış yavaş, nispeten yatay bir şekilde ilerliyor. Ancak dikeydeki 0,5 – 1 değerleri arasındaki artış daha fazla, grafik dikleşmiş halde. Bunu gözlemlemek adına ufak kesitler alarak incelemek de faydalı aslında. Bu çıkarımı yaparken de aşağıdaki gibi, ufak kesitler alarak aynı zaman aralığında dikeydeki değişimleri incelemek mümkün.

Unity Animation Curve Grafik Gözlemi 2
Unity Animation Curve Grafik Gözlemi 2

Unity Animation Curve ile Grafik Oluşturmak

Peki Unity Animation Curve ile Grafik Oluşturmak için noktaları nasıl kullanacağız? Açıkçası gayet basit. Eğer grafiğin, çizginin üzerine çift tıklarsanız, tam o konumda yeni bir nokta yaratacaktır. Aynı şekilde, grafiğin en sağı veya en solunda, yani grafiğin dışında kalan alanlara tıklayarak yeni noktalara oluşturabilirsiniz. Tıkladığınız yerdeki değerleri beğenmediniz veya konumu değiştirmek istiyorsanız, isterseniz noktayı tutup sürükleyere konumu değiştirebilirsiniz. Veya isterseniz de sağ tıklayıp “Edit Key” diyerek noktanın değerlerini değiştirmeniz mümkün. Aşağıdaki görselde sırasıyla, varolan grafiğe yeni bir nokta ekliyorum, sonrasında edit seçeneği ile değerlerini değiştiriyorum. Burada yazan time değişkeni yatayı, value değişkeni dikeyi belirtmektedir. 

Bunu yaptıktan sonra, noktanın bu grafiğe nasıl etki edeceğine de karar verebiliriz. Öncelikle noktaya tıklayarak seçili hale getirmeniz gerekiyor. Ufak bir bilgilendirme olarak da şunu belirteyim, dikdörtgen seçimi yaparak hem tekil hem çoğul nokta seçimini yapabilirsiniz. Bu sayede de toplu hareket ettirme gibi işlemleri gerçekleştirebilirsiniz.

Bir nokta seçili iken, öncesindeki ve/veya sonrasındaki nokta ile arasındaki çizgiyi manipüle etmenizi sağlayan kollar bulundurur. Bunları tutup aşağı yukarı eğerek, noktanın grafiğe olan etkisini kontrol edebilirsiniz. 

İsterseniz sağ tıkladığınızda beliren otomatik ayarlamaları kullanabilirsiniz. Bu ayarlar şunlardır;

  • Clamped Auto: Eklediğimiz noktanın etkisini yumuşatır ve öncesinde- sonrasında bulunan noktalar arasında sert-düz çizgi yerine kıvrımlı bir çizgiyi otomatik olarak oluşturur. Kolları tutup çekerek değiştirirseniz ve sonrasında memnun kalmazsanız, sağ tıklayıp bu seçenekle otomatik olarak şekillendirebilirsiniz. 
  • Auto: Eski sürümlerde varolan bu yapı Clamped Auto gibi çalışır. Bunun yerine Clamped Auto kullanmakta fayda var. 
  • Free Smooth: Kolları manipüle ettiğinizde bu seçeneği aslında aktif etmiş oluyorsunuz. Ancak, birini manipüle ettiğinizde, o yumuşak geçişi sağlamak adına diğer kol da yeniden konumlanacak ve noktanın oluşturduğu etkinin yumuşaklığını koruyacaktır.
  • Flat: Bu seçeneği seçtiğinizde, kolların ikisi de yatay eksene paralel olacaktır, düz bir hal alacaktır. 
  • Broken: Bu seçenek aracılığıyla da, kolları ayrı ayrı kontrol etmeniz mümkün. Bu sayede 2 kol varsa, öncesi ve sonrasında noktalar bulunuyorsa, yumuşatmaksızın grafiğe etkisini kontrol altına alabilirsiniz. 

Bunlar dışında ayrıca, isterseniz bahsettiğim kollara farklı ayarlamalar yapmanız da mümkün. Yine sağ tıkladığınızda “Left Tangent” (sol)  ve “Right Tangent” (sağ) ve “Both Tangent” (her ikisi de) seçeneklerini göreceksiniz. Bunlar altında bulunan seçeneklerle, ayrı ayrı kontroller sağlamanız mümkün. Kollara ait bu seçenekler ise şu şekilde;

  • Free: Belirtilen kolun diğer koldan bağımsız şekilde hareket ettirilebilmesini sağlar.
  • Linear: Kolun oluşturacağı çizginin dümdüz olmasını sağlar. Hiçbir eğilme, yumuşatma uygulatmadan hedefteki noktaya doğru düz bir çizgi oluşturur.
  • Constant: Arada geçişi sağlayan bir çizgi oluşturmak yerine, ilgili noktadan, bu noktaya aniden geçiş yapan bir grafik oluşturmamızı sağlar. 
  • Weighted: Bu seçenek açılıp kapatılabilir bir seçenektir. Free seçeneği aktif iken, kolun uzunluğunu da kontrol etmemizi sağlar. Böylece grafik üzerinde daha fazla kontrole sahip olabiliriz. 

Unity Animation Curve ile Gitgel Grafiği

Şimdi gelelim Unity Animation Curve ile Gitgel Grafiği yapmaya. Şu satırlara kadar okuduğunuz haliyle, grafiği nasıl yorumlayacağınızı ve şekillendireceğinizi temel olarak öğrendiniz. Dikeyde 0’dan başlayıp 1 değerine gelince, şu anki Lerp komutumuz sayesinde ilk pozisyondan, son pozisyona geliyoruz. Bunu da biliyorsunuz. Peki baştan başlayıp, sona gidip tekrar başa dönmesi için ne yapabiliriz? Başlangıç 0, bitiş 1, ve tekrar başlangıç 0.. Bu yapıyı oluşturabilmemiz gerekiyor, yani en az 3 nokta lazım bize. İsterseniz varolan bir grafik üzerinden, isterseniz de boş bir grafik üzerinden 3 nokta oluşturalım. Yataydaki değerleri 0, 0,5 ve 1 olacak. Dikeydeki değerleri ise 0 (başlangıç), 1 (bitiş), 0 (başlangıç) olacak. Yazı hali karmaşık geldiyse, aşağıdaki görselden nasıl oluşturabileceğimizi ve grafiğin son halini görebilirsiniz.

Unity Animation Curve ile Gitgel Grafiği
Unity Animation Curve ile Gitgel Grafiği

Bu grafiği oluşturduktan sonra çalıştırırsanız, objemiz başlangıçtan bitişe gidecek ve tekrar geri gelecektir. Grafik üzerinde bu 3 noktanın dikey konumları şu haliyle kaldığı sürece, bu hareketi sağlayabilirsiniz. Bu konumları korurken, daha önce bahsettiğim gibi noktalar arasındaki çizgileri manipüle etmeniz de mümkün. Ortada bulunan noktayı yatayda hareket ettirerek veya noktalara bağlı kolları kontrol ederek bunu sağlayabileceğinizi tekrar hatırlatayım. Bitişe giderken çok hızlı bir şekilde gitmesini sağlayıp, dönüşte çok yavaş ilerletebilirsiniz. Artık gerisi hayal gücünüze, size kalmış.

Ancak, az başlangıçtaki harekete göre, 2 kat daha hızlı bir hareket gerçekleşiyor gibi. Bunun sebebi verdiğimiz 1 saniyelik süre boyunca artık 2 kat mesafe ilerleniyor. İstediğiniz süre boyunca hareket etmesini sağlamak için, while döngüsünde kullandığımız 1 yerine, float tipinde bir değişken tanımlayabiliriz. Tabii ki sonrasında, yol durumunu da bu süreye bölmemiz gerekiyor ki, yine 0-1 arasında değer elde edelim. Böylece Evaluate içerisine 0-1 arasında bir değer verebilmiş olacağız. Kodun son hali aşağıdaki gibi olacaktır. Ha tabii ki, ufak bir kontrol de ekledim, böylece hareket halindeyken space tuşuna basıla bile hareket komutu çalışmıyor. İstemediğimiz bir durum olmasından kaçınabiliyoruz.

using System.Collections;
using UnityEngine;

public class AnimationCurveMove : MonoBehaviour {

    Vector3 baslangicKonum;

    [SerializeField]
    Vector3 hedefKonum;

    [SerializeField]
    AnimationCurve animCurve;

    [SerializeField]
    float toplamZaman = 2f;

    bool hareketEdiyor = false;

    void Start () {
        baslangicKonum = transform.position;
    }

    void Update () {
        //Space tuşuna basıldıysa ve hareketEdiyor false değere sahip ise
        if (Input.GetKeyDown (KeyCode.Space) && !hareketEdiyor) {
            StartCoroutine (Hareket ());
        }
    }

    IEnumerator Hareket () {
        hareketEdiyor = true;
        //zaman durumunu tuttacağımız değişken.
        float zaman = 0;
        //zaman,  toplamZaman değeri ve altında olduğu sürece hareketi gerçekleştiriyoruz.
        while (zaman <= toplamZaman) {
            //başlangic ve hedef değerlerini toplama sebebim, verdiğimiz hedefi varolan pozisyona göre hesaplamasını istememden kaynaklı
            transform.position = Vector3.Lerp (baslangicKonum, baslangicKonum + hedefKonum, animCurve.Evaluate (zaman / toplamZaman));
            zaman += Time.deltaTime;
            yield return new WaitForEndOfFrame ();
        }
        hareketEdiyor = false;
    }
}

Bu haliyle artık Unity Animation Curve ile Değişimi Kontrol Etmek nasıl gerçekleştirilir için güzel bir örnek oluşturduğumu düşünüyorum sizler için. Lerp fonksiyonu sadece bir örnek, bununla kısıtlı değilsiniz. Evaluate komutunu direkt olarak değişkenlere değer atamak için de kullanabilirsiniz. Tamamen hayalgücünüze kalmış, deneyin, yanılın, uğraşın ve öğrenin. Umarım faydalı olmuştur bu yazı sizler için, ben yazarken keyif aldım açıkçası. Yeni yazılarda görüşmek dileğiyle.

Shader Graph 10 Sürümü Yenilikleri

Shader Graph 10 Sürümü Yenilikleri arasında ufak arayüz güncellemeleri ve debug için bazı kolaylaştırmalar bulunuyor. Şayet daha önceki shader graph sürümlerini kullanıp, 10 sürümüne geçtiğinizde ufak bir afallama yaşadıysanız, bu yazımız bilgileri toparlama konusunda size yardımcı olacaktır. Daha önce hiç shader graph kullanmadıysanız da, temel mantığı için “Unity Shader Graph” yazımıza göz atabilirsiniz. Bunun dışında, tabii ki her zaman güncel Shader Graph dokümanlarına bakarak da bilgi edinmeniz mümkün.

10 sürümü ile beraber, herhangi bir shader oluşturduğunuzda, ki ben Shader > Universal Render Pipeline > Lit seçeneğiyle oluşturdum, aşağıdaki gibi bir yapı ile karşılaşacaksınız.

Shader Graph 10 Arayuz
Shader Graph 10 Arayuz

Öncelikle, varolan yapıda, hâlâ aynı kalan şeylerden bahsedelim. Main Preview, Blackboard ve Graph Inspector pencereleri hâlâ duruyor, hiçbir yere gitmediler. Ufak bir değişiklik olarak, yarattığımız değişkenlerin özelliklerini direkt olarak Blackboard üzerinden değiştirebiliyorken, Shader Graph 10 sürümü yenilikleri ile bu özellikler, Graph Inspector paneli altına geçmiş bulunuyor.

Önceden Shader Graph kullandıysanız, dikkatinizi çekmiştir, tek bir main node yerine, 2 adet node bulunmakta. Bunlar Vertex ve Fragment isimleriyle belirtilmiş. Daha öncesinde Master Node ismiyle tek bir node kullanılıyorken, artık Master Stack isimli bir yapı kullanılıyor. Vertex kısmı, mesh yapısında değişiklikler yapmak istediğimiz zaman kullanacağımız position, normal, tangent değerlerini içeriyor. Fragment kısmı ise, materyal dokusuna dair, örneğin renk, görünürlük vb alanları içerisinde bulunuyor. 

Önceki tek Master Node yapısına göre içerik olarak değişiklik yok. Ancak isterseniz kullanmayacağınız input seçeneklerini silmeniz veya yenilerini eklemeniz artık mümkün. Örneğin Vertex işlemleri yapmayacaksınız, bunların el altında olmasına gerek yok, istediğiniz nodeları seçip “Delete” tuşuna basarak veya sağ tıklayıp “Delete” seçeneğini seçerek kaldırmanız mümkün. Aynı şekilde, Vertex kısmı seçili iken space tuşu veya sağ tıklama ile yeni node yapıları eklemeniz de mümkün. Aşağıdaki görselde silme ve ekleme işlemlerini nasıl yapacağımızı görebilirsiniz.

Shader Graph 10 Input Ekle Çıkar
Shader Graph 10 Input Ekle Çıkar

Graph Inspector paneline gelecek olursak, daha öncesinde genel olarak yarattığımız shader graph özelliklerini belirlediğimiz kısımdı. Bununla beraber artık değişkenler ve kullandığımız node bileşenlerinin özelliklerini de bu panel altında değiştirebiliyoruz. Aslında böylece daha derli toplu bir arayüz sunulduğunu söylemek de mümkün. Her bir node üzerinden açılan ayarlar paneli yerine, artık her işlem için farklı bölümler bulunuyor. 

Graph Inspector altında, 2 adet sekme bulunmakta. Bu sekmelerden ilki olan “Node Settings” kısmında, az önce de bahsettiğim gibi, değişkenler ve node özelliklerini görebiliyoruz. Bir diğer sekme olan “Graph Settings” ise, bahsettiğimiz gibi, Lit-Unlit veya Metallic-Specular gibi shader özelliklerini değiştirmemize imkan sağlıyor.  Graph Inspector altında bulunan 2 sekmenin görünümünü görselde görebilirsiniz. Soldaki görselde yaratmış olduğum “Color” tipindeki bir değişkenin özelliklerini “Node Settings” altında görüp değiştirebiliyor iken, shader özelliklerini ise “Graph Settings” altında değiştirebiliyorum.

Shader Graph 10 Graph Inspector
Shader Graph 10 Graph Inspector

Hazır bu görseli vermişken, bir de bunlar içerisinde bulunan alanların ne işe yaradığını da açıklamakta fayda var diye düşünüyorum. Öncelikle “Graph Settings” altında bulunan alanlara bir göz atalım.

Precision: Shader üzerinde işlemler yapılırken, ne kadar hassasiyet ile gerçekleştirmemizi istediğimizi belirttiğimiz alan.

Target Settings: Shaderınızın çalışmasını istediğiniz render ayarlarını belirlediğiniz kısım. Örneğin URP ve VisualEffects için shader oluştarabilirsiniz. Veya aynı şekilde URP ve HDRP hedefleyen bir shader yaratabilirsiniz. Eklediğiniz ortamlara göre devamında ayarlarda değişecektir. Asıl konumuz Render Pipeline olmadığı için bu yazıda bu detaylara girmeyeceğim. 

Şimdi “Node Settings” altındaki alanların ne olduklarına bir bakalım. Aşağıda listelediklerim her değişken tipinde varolan özellikler. Bunlar dışında, örneğin “Color” tipinde HDR ayarı açmak veya “float” tipinde slider halinde olmasını sağlamak gibi ayarlar bulunuyor ancak onlara burada yer vermiyorum, yoksa yazımız fazlasıyla uzayacak. Farklı tipler ile değişkenler yaratarak hangi farklı özelliklere sahip olduklarına göz atmak da iyi bir pratik olacaktır. 

Name: Değişkenimizin editor üzerinde gözükecek olan ismi.

Reference: Shader ile yarattığımız materyallerde, bu değişkeni kod üzerinden değiştirmek istersek ihtiyacımız olan değişken, referans isim.

Default: Oluşturduğunuz değişkenin hiçbir değer atanmama durumunda sahip olacağı değeri belirttiğimiz alan.

Precision: Aynı alan Graph Settings altında da bulunmakta. Şayet node için “inherit” seçeneğini seçerseniz, yarattığınız graph hangi ayarı kullanıyorsa, node da aynı ayarı kullanacaktır. 

Exposed: True veya false olarak belirlediğimiz bu seçenek, değişkeninizi editor üzerinde, materyal görünümünde görünebilirlik durumunu belirtir.

Son olarak şunu eklemekte de fayda var. Daha öncesinde yarattığımız Shader Graph dosyaları ile yaratılan shader kodlarını, master node üzerinden, sağ tıklayıp görebiliyorduk. Ancak Shader Graph 10 sürümü ile, dosyanızı seçip, Inspector paneli üzerinden “View Generated Shader” butonuna tıklamanız yeterli olacaktır.

Evet, temel olarak aslında yeni olan şeylere böylece değinmiş oldum. Arayüz değişikliği olsa da çalışma prensibinde çok fazla şey değişmiş halde değil. Yeniliklerden, değişimlerden korkmamak lazım hem 🙂 Yeni sistemi de kullandığımız shader graph videolarıma bakmak isterseniz diye şöyle linkini bırakıyorum.

Ayrıca, Unity’nin kendi Shader Graph 10 sürümü yenilikleri videosunu da bırakayım, merak edenler onu da izleyebilsin.

Bir dahaki yazıda görüşmek dileğiyle, kendinize iyi bakın. 

Unity Gizmos Sınıfı

Unity Gizmos sınıfı, özellikle editor üzerinde görsel oluşturmamızı sağlayarak, sahneyi daha iyi analiz edip incelememizi sağlar. Bu sınıf aracılığıyla oluşturduğumuz  görsel ögelere ise Gizmo adı verilmektedir. Eğer İngilizce’ye birazcık aşinaysanız, Gizmos da bunun çoğul hali olduğunu tahmin edersiniz. 

Kelime anlamı olarak Gizmo, Türkçede aygıt, araç, ıvır zıvır gibi  anlamlara gelse de, İngilizce anlamı olarak baktığımızda, belirli amaç için oluşturulan herhangi bir küçük cihaz olduğunu görmekteyiz. Unity içerisinde de Gizmo dediğimiz şeyler sınıfı bahsettiğim gibi belirli görselleştirmeler oluşturmamızı sağlayan küçük araçlardır.

Gizmolar genellikle çok basit formdadırlar. Basit bir çizgi, küp, küre veya bizim belirttiğimiz bir mesh yapısında olabilirler. Boyut, renk, pozisyon ve rotasyon değerlerine sahiptirler, böylece farklı durumlar için bize az ama yeterli sayıda özelleştirme imkanı sunarlar. 

Unity Gizmos Sınıfı, yalnızca OnDrawGizmos ve OnDrawGizmosSelected fonksiyonları içerisinde çalışırlar. Bu iki fonksiyon daha önce GameObject sınıfında bahsettiğimiz gibi, Start(), Update() gibi, Unity tarafından, kodunuzda bulunuyorsa otomatik olarak çağırılan fonksiyonlardır. Monobehaviour sınıfından miras alan her sınıfta bu 2 fonksiyonu da kullanabilirsiniz. 

Bu iki fonksiyonu kullanmadan önce ikisinin farklarından bahsetmek istiyorum. Temelde, ikisi de aynı Update fonksiyonu gibi, her karede çağırılan fonksiyonlardır. Bunları birbirinden ayıran ise, OnDrawGizmosSelected yalnızca objeyi seçtiğinizde çalışacakken, OnDrawGizmos fonksiyonu obje seçili olsun veya olmasın çalışacaktır. Yazımlarını aşağıda görebilirsiniz.

Unity Gizmos Sınıfı ile Kullanılabilecek Kodlar

Unity Gizmos Sınıfı ile kullanılabilecek kodlar renk, matrix ve pozlama (exposure) değerlerini değiştirebildiğimiz statik özellikler(properties) ve gizmo oluşturmamızı sağlayan static fonksiyonlardır. Aşağıda örnek kodlarıyla beraber açıklamalarını bulabilirsiniz.

Unity Gizmos Sınıfı Statik Özellikler

color: Çizilecek olan gizmo rengini belirttiğimiz değişkendir. Color tipinde bir değişken vermemiz gerekir. Örnekte de göreceğiniz üzere, istersek Color sınıfı aracılığıyla istersek de direkt olarak rgba değerlerini vererek bir renk oluşturmamız gerekir. RGB kısmı kırmızı, mavi, yeşil değerleriyle alakalı iken, a değeri alpha, yani görünürlük, şeffaflık ile alakalı değerdir. Hiçbir renk değişikliği yapmazsanız, beyaz rengi otomatik olarak kullanılır.

exposure: Pozlama doğrulamasını sağlayacak olan resim (texture) ayarını yapmamızı sağlar.

matrix: Gizmoyu çizecek olan editorun Transform matrix değerini ayarlamamızı sağlar. Bu sayede local transform değişiklikleri, yön, pozisyon gibi, gizmo üzerinde de gözlemlenecektir. Örneğin gizmoyu objenin altında olacak şekilde şekilde oluşturmak istiyorsunuz.

Unity Gizmos Sınıfı Statik Fonksiyonlar

DrawCube: Sahne üzerinde belirtilen konum ve ölçülerde küp şekli oluşturmamızı sağlar. Aşağıda gördüğünüz örnekte renk ve matrix konularına da farklı açılardan değindim. Özellikel matrix etkisini gözlemlemek için, kodu attığınız objenin rotasyon, scale gibi değerlerini kurcalayarak Gizmoların değişimlerini gözlemlemenizi öneririm. 

using UnityEngine;

//Unity Gizmo ile farklı şekillerde küp görseli oluşturma yöntemleri.
public class DrawCubeGizmo : MonoBehaviour {
    void OnDrawGizmos () {
        /*
        Obje pozisyonunu merkez olarak alan 1,1,1 ölçülerinde Küp gizmosu çizmemizi sağlar.
        .25f alpha değerinde kırmızı bir renk elde etmemizi sağlar.
        */
        Gizmos.color = new Color (255, 0, 0, .25f);
        Gizmos.DrawCube (transform.position, new Vector3 (1, 1, 1));

        /*
        Bu komut ile artık gizmoların transform değerleri obje matrixi üzerinden hesaplanacak
        Böylece objenin pozition, rotation ve scale değerleri de gizmolarımızda etkili olacak.
        eski değişkeni ile yaptığımız da, sonraki satırlarda matrix'i eski haline getirmek için
        öncelikle varolan matrixi bir değişkende tutmaktan başka bir şey değil.
        */
        Matrix4x4 eski = Gizmos.matrix;
        Gizmos.matrix = transform.localToWorldMatrix;
        /*
        Obje matrixine göre y ekseninde 3 birim aşağıda bulunan yeşil renkli bir küp oluşturmamızı sağlar
        Küpün ölçüleri x:3,y:.1f,z:3 şeklindedir.  
        */
        Gizmos.color = Color.green;
        Gizmos.DrawCube (Vector3.down * 3, new Vector3 (3, .1f, 3));
        //Gizmo matrixin eski haline getiriyoruz, böylece genel(world) matrixine göre değer kullanabiliriz.
        Gizmos.matrix = eski;
        //Objenin 1 birim ilerisinde (local z) mavi renkli bir küp oluşturmamızı sağlar. 
        Gizmos.color = Color.blue;
        Gizmos.DrawCube (transform.position + transform.forward, Vector3.one * .25f);
    }
}

DrawFrustum: Kamera nesnelerimizde de görüş açısını gösteren şekil olarak gördüğümüz, verdiğimiz ölçülere göre farklı taban genişliklerine sahip bir frustum şekli oluşturmamızı sağlar. Örneği inceleyin, ufak bir egzersiz olarak obje ile aynı yöne bakmasını nasıl sağlarsınız bunun üzerine düşünün.

using UnityEngine;

public class DrawFrustomGizmo : MonoBehaviour {

    public float fov = 60;
    public float maxRange = 300;
    public float minRange = 1f;
    public float aspect = 16f / 9f;

    void OnDrawGizmosSelected () {
        /*
        Obje merkezini baz alan bir frustom oluşturmayı sağlar.
        fov: dikey görüş alanı (vertical field of view)
        maxRange: frustom gizmosunun uzak kenarının (far plane) mesafesi
        minRange: frustom gizmosunun yakın kenarının (near plane) mesafesi
        aspect: yatay ve dikey kenarların uzunluklarının oranı
        */
        Gizmos.DrawFrustum (transform.position, fov, maxRange, minRange, aspect);
    }
}

DrawGUITexture: Sahneye bir resim (texture) çizmemizi sağlar. Yalnız altını çizmek gerek, resim, aynı UI elementlerinde olduğu gibi z ekseni önemsenmeden çizilir. XY ekseni zemini üzerinde gösterilmektedir. Özellikle 2 boyutla bizi sınırlandırıyor olması, pek kullanılmasa da olur dediğim kodlardan biri.

using UnityEngine;

public class DrawGUITextureGizmo : MonoBehaviour {
    public Texture texture;
    public Material textureMat;

    public float posX = 0, posY = 0, scaleX = 1, scaleY = 1;
    public int leftBorder, rightBorder, topBorder, bottomBorder;

    void OnDrawGizmos () {
        /*
        Verdiğiniz genel pozisyonda bir görsel oluşturmanızı sağlar.
        border değerleri ise, belirtilen kenardan görseli genişletme-ekleme yapmanızı sağlar.
        */
        if (texture != null) {
            //versiyon: Rect değerleri ve resim objeli
            Gizmos.DrawGUITexture (new Rect (transform.position.x, transform.position.y, scaleX, scaleY), texture);
            //Versiyon: Öncekine ek olarak border seçeneklerini de verebilirsiniz 
            Gizmos.DrawGUITexture (new Rect (posX, posY, scaleX, scaleY), texture, leftBorder, rightBorder, topBorder, bottomBorder);

            //isterseniz her iki versiyonda da materyalini de belirtebilirsiniz.
            Gizmos.DrawGUITexture (new Rect (transform.position.x + posX, transform.position.y + posX, scaleX, scaleY), texture, textureMat);
        }

    }
}

DrawIcon: Sahnede bir ikon oluşturmamızı sağlar. Özellikle kalabalık sahnelerinizde, ikonlara tıklayarak objeleriniz gözükmese de objeyi seçebilmenize imkan vermesi açısından faydalıdır. Pozisyon ve dosya ismi vermemiz gerekir. Kullanacağımız resim, icon dosyası da projemizde Assets/Gizmos klasörü altında olmalıdır.Ayrıca, 3. parametre olarak da, bool tipinde, kullandığınız görselin boyutlandırılmasını isteyip istemediğini belirttiğiniz bir değişken de verebilirsiniz.

using UnityEngine;

public class DrawIconGizmo : MonoBehaviour {
    public string iconFileName;
    void OnDrawGizmos () {
        //Örnek bir kullanım olarak, sahnede oyuncunun başlama noktasında ikon oluşturmak mantıklı olabiir
        Gizmos.DrawIcon (transform.position, iconFileName, true);
    }
}

DrawLine: Başlangıç ve bitiş noktalarını belirlediğimiz bir çizgi oluşturmamızı sağlar.

using UnityEngine;

public class DrawLineGizmo : MonoBehaviour {
    public Transform target;

    void OnDrawGizmosSelected () {
        if (target != null) {
            //eğer target değişkeni boş değilse, objeniz ve target arasında kırmızı bir çizgi oluşturmanızı sağlar.
            Gizmos.color = Color.red;
            Gizmos.DrawLine (transform.position, target.position);
        }
    }
}

DrawMesh: Belirttiğimiz mesh objesini sahnede çizmemizi sağlar.

using UnityEngine;

public class DrawMeshGizmo : MonoBehaviour {
    public Mesh mesh;
    public int subMeshIndex = 0;

    void OnDrawGizmos () {
        if (mesh != null) {

            //Belirtilen meshi, objenin poziyonunda, obje rotasyonu ve scale değerine sahip şekilde oluşturmamızı sağlar.
            Gizmos.DrawMesh (mesh, transform.position, transform.rotation, transform.localScale);

            /*
            Eğer mesh objeniz subMesh içeriyorsa, istediğiniz submeshindex değerini belirterek 
            sadece belirli bir parçasını çizdirebilirsiniz.
            */
            if (subMeshIndex < mesh.subMeshCount) {
                Gizmos.DrawMesh (mesh, subMeshIndex, transform.position, transform.rotation, transform.localScale);
            }
        }
    }
}

DrawRay: Başlangıç noktası ve yönünü belirterek bir ışın oluşturmamızı sağlar. DrawLine fonksiyonundan farklı olarak, bitiş noktasını bilmesek de, yön bilgisi ile belirli uzunlukta bir çizgi çizebilmemize imkan tanır.

using UnityEngine;

public class DrawRayGizmo : MonoBehaviour {

    /*
    Objenin ileri, sağ ve yukarı yönlerini gösterir.
    Mesh bulundurmayan objeleri gözlemlemede kullanılabilir.
    */
    void OnDrawGizmos () {
        Gizmos.color = Color.blue;
        Gizmos.DrawRay (transform.position, transform.forward);
        Gizmos.color = Color.red;
        Gizmos.DrawRay (transform.position, transform.right);
        Gizmos.color = Color.green;
        Gizmos.DrawRay (transform.position, transform.up);
    }
}

DrawSphere: Belirttiğimiz yarıçapa sahip bir küre çizmemizi sağlar.

using UnityEngine;

public class DrawSphereGizmo : MonoBehaviour {
    public Vector3[] yollar;

    void OnDrawGizmosSelected () {
        //Belirtilen yol pozisyonlarında küreler oluşturarak görselleştirme sağlar.
        for (int yolIndex = 0; yolIndex < yollar.Length; yolIndex++) {
            //Turuncu renkli 1 birimlik bir küre oluşturmamızı sağlar.
            Gizmos.color = new Color (255, 102, 0);
            Gizmos.DrawSphere (yollar[yolIndex], 1);
        }
    }
}

DrawWireCube: Belirttiğimiz ölçülere sahip bir küp çizmemizi sağlar. DrawCube fonksiyonundan farklı olarak, bu fonksiyonla çizilen küpler yüzeylere sahip değildir, yalnızca kenar çizgilerinden oluşur. 

using UnityEngine;

public class DrawWireCube : MonoBehaviour {
    void OnDrawGizmosSelected () {
        /*
        Obje pozisyonunda 1,1,1 boyutlarında sarı renkli
        yalnızca kenarları görünen bir küp oluşturmayı sağlar.
        */
        Gizmos.color = Color.yellow;
        Gizmos.DrawWireCube (transform.position, new Vector3 (1, 1, 1));
    }
}
using UnityEngine;

public class DrawWireCube : MonoBehaviour {
    void OnDrawGizmosSelected () {
        /*
        Obje pozisyonunda 1,1,1 boyutlarında sarı renkli
        yalnızca kenarları görünen bir küp oluşturmayı sağlar.
        */
        Gizmos.color = Color.yellow;
        Gizmos.DrawWireCube (transform.position, new Vector3 (1, 1, 1));
    }
}

DrawWireMesh: Verdiğimiz mesh objesini ekranda oluşturmamıza imkan tanır. DrawWireCube fonksiyonu gibi, yalnızca kenar çizgilerinin gözükecek şekilde mesh görünümünü oluşturur.

using UnityEngine;

public class DrawWireMeshGizmo : MonoBehaviour {
    public Mesh mesh;
    public int subMeshIndex = 0;

    void OnDrawGizmosSelected () {
        if (mesh != null) {
            /*
            Belirtilen meshi, yalnızca kenar çizgileri gözükecek şekilde,
            objenin poziyonunda, obje rotasyonu ve scale değerine sahip şekilde oluşturmamızı sağlar.
            */
            Gizmos.DrawWireMesh (mesh, transform.position, transform.rotation, transform.localScale);

            /*
            Eğer mesh objeniz subMesh içeriyorsa, istediğiniz submeshindex değerini belirterek 
            sadece belirli bir parçasını çizdirebilirsiniz.
            */
            if (subMeshIndex < mesh.subMeshCount) {
                Gizmos.DrawWireMesh (mesh, subMeshIndex, transform.position, transform.rotation, transform.localScale);
            }
        }
    }
}

DrawWireSphere: Belirtiğimiz konumda, belirttiğimiz yarıçapa sahip bir küre oluşturur. Diğer Wire fonksiyonlarında olduğu gibi yüzey gözükmez. 3 eksene paralel şekilde 3 adet dairenin birleştirilmesiyle oluşturulmuş bir görünüm elde etmemizi sağlar.

using UnityEngine;

public class DrawWireSphereGizmo : MonoBehaviour {
    public float saldiriMesafesi = 5.0f;

    void OnDrawGizmosSelected () {
        /*
        Yapay zeka karakterinizin, saldırıya geçme mesafesini göstermeyi sağlar.
        */
        Gizmos.color = Color.white;
        Gizmos.DrawWireSphere (transform.position, saldiriMesafesi);
    }
}

Böylece Unity Gizmos Sınıfı için de doküman Türkçeleştirmesini gerçekleştirmiş olduk. Eğer dokümanı orjinal dilinde incelemek isterseniz şu link üzerinden erişebilirsiniz. Bunun dışında, diğer Unity bileşenlerine dair bütün türkçe doküman çevirilerimizi de “Unity Özel Bileşenler” kategorimiz altında bulabilirsiniz. Umuyorum ki faydalı olmuştur. Gelecek yazılarda görüşmek dileğiyle.

Unity Mathf Sınıfı

Unity Mathf Sınıfı özellikle int, float gibi sayı tipleri üzerinde, trigonometri hesaplamalarında bize çeşitli fonksiyonlar sağlayan statik bir sınıftır. Bu sınıf aracılığıyla sayı değerlerinizi zamanla yumuşatmak veya bir açının sinüs değerini elde etmek gibi çeşitli işlemler gerçekleştirmeniz mümkündür.

Bunun dışında, renk, vector gibi bileşenlerde de bunları kullanmanız mümkün. Çünkü bu değişkenler de aslında kendi içerisinde float tipinde değişkenler barındırmakta. Yaptığım örneklerde de özellikle Vector3 üzerinden pozisyon değiştirme konularına değindim. Ancak direkt olarak Vector3 sınıfını kullarak da bu işlemleri başarmanız mümkün. Eğer ilgilenirseniz, “Unity Vector3 Nedir?” yazımıza göz atmanızı öneririm.

Unity Mathf Sınıfı ile Kullanılabilecek Kodlar

Unity Mathf Sınıfı ile Kullanılabilecek Kodlar temel olarak ikiye ayrılabilir. Bunlar, direkt olarak değerler içeren Properties yani özellikler ve statik fonksiyonlardır. Fonksiyonlara dair örnekler oluşturdum, ancak benzer kullanımlara sahip kodlar için, özellikle uzun olanlarda tekrar tekrar aynı kullanımı göstermeyeyim istedim. Bu yüzden hepsinin altında örnek bulamayabilirsiniz, ancak emin olun önceki veya sonraki bir fonksiyon da aynı yapıda ve aynı örneği kullanabilirsiniz.

Unity Mathf Sınıfı Properties

Unity Mathf Sınıfı Properties içerisinde, yazının devamında da ilk olarak göreceğiniz gibi, aslında sonsuzluk, Pi gibi genelde matematik işlemlerinde ihtiyaç duyabileceğimiz değişkenler bulunmaktadır.

Deg2Rad: Bu değişken ile elde ettiğimiz sabit değer aslında derece cinsinden açı değerlerini radyan cinsine çevirmemizi sağlar. Bunun için sadece elde ettiğimi açı değeriyle bu değeri çarpmak yeterli olacaktır. 

Epsilon: Float tipinde 0’dan sonraki en küçük sayı değeridir. 

Infinity: Sonsuzluk değerini elde etmemizi sağlar. 

NegativeInfinity: Negatif yönlü sonsuzluk değeri elde etmemizi sağlar..

PI: Özellikle geometri ve çember, daire ve küre işlemlerinde sık kullandığımız 3.14…. şeklinde devam pi(π) sayı değerini elde etmemizi sağlar.

Rad2Deg: Deg2Rad özelliği gibi, bu değişken aracılığıyla radyan cinsinden açı değerini derece cinsine çevirmemiz mümkündür.

    void PropertiesOrnek () {
        Debug.Log (derece + " derece açının radyan karşılığı:" + derece * Mathf.Deg2Rad);
        Debug.Log (radyan + " radyan derece açının derece karşılığı:" + radyan * Mathf.Rad2Deg);
        Debug.Log ("Pi değeri:" + Mathf.PI);
        Debug.Log ("Pi değerine sahip radyan cinsi açının derece olarak karşılığı:" + Mathf.PI * Mathf.Rad2Deg);
        Debug.Log ("Epsilon, yani sıfırdan sonraki en küçük değer:" + Mathf.Epsilon);
    }

Unity Mathf Sınıfı Fonksiyonları

Unity Mathf Sınıfı fonksiyonları ile yazının başında da bahsettiğim gibi, sayı değerini yavaş yavaş değiştirme, bir sayının istenen değerdeki üssünü elde etme gibi matematiksel işlemleri gerçekleştirmemizi sağlayan fonksiyonları içermektedir. Bu fonksiyonlar aracılığıyla baya bir yükten kurtulduğumuz söylenebilir. Bu arada altını çizmekte fayda, 4 temel işlem yani toplama, çıkarma, çarpma ve bölme işlemleri için fonksiyonlar bulunmuyor. Bu işlemleri zaten “+, -, *, /” operatörleriyle halledebiliyoruz. Aşağıda bahsedeceğimiz işlemler genelde daha geniş çaplı, karmaşık işlemleri kapsamakta.

Abs: Verilen sayının mutlak değerini elde etmemizi sağlar. Sayı doğrusunda negatif ve pozitif yönleri düşünürseniz, -1 ve 1 değeri de aynı uzunluğa sahiptir. Abs ile bu yön bilgisinden kutulup yalnızca büyüklüğünü elde etmiş oluruz.

    void AbsOrnek () {
        //ikisi de 10 değerini, yani mutlak değerlerini döndürecektir.
        Debug.Log (Mathf.Abs (10));
        Debug.Log (Mathf.Abs (-10));
    }

Acos: Arkkosinüs, yani kosinüs işleminin tersini verir. Kosinüs ile nasıl açı değerini verip bir sayı değeri elde ediyorsak, bu fonksiyona da sayı değeri vererek, ilgili açı değerini radyan cinsinden elde etmemizi sağlar.

    void AcosOrnek () {
        //Mathf.Acos radyan cinsinden döndürdüğü için bunu Rag2Deg ile dereceye  çeviriyoruz
        Debug.Log ("Cos değeri 1 olan açı:" + Mathf.Acos (1) * Mathf.Rad2Deg);
        Debug.Log ("Cos değeri 0 olan açı:" + Mathf.Acos (0f) * Mathf.Rad2Deg);
    }

Approximately: Verilen 2 sayının birbirine yakın, denk olup olmadıklarını elde etmemizi sağlar. Özellikle float tipindeki sayılarda, “==” ifadesi ile kontrol sağladığımızda, değişkenler birbirine çok yakın olsa da doğru değerini vermeyebilir. Bu tarz yakınlık durumunu kontrol etmek ve işlemin istediğimiz gibi çalıştığından emin olmamızı sağlayan bir fonksiyondur. Eğer sayılar birbirine çok yakın, denk ise true değeri döndürür. Örnekte de bu iki durumun karşılaştırmasını yapıyoruz aslında. Sadece start içerisinde değil, update içerisinde çalıştırırsanız, == komutunun bazen false döndürdüğüne denk gelebilirsiniz. Karşılaşma oranı düşük olabilir ama, bahsettiğim fonksiyon ile bu karşılaştırma durumunu garanti altına alıyoruz.

    void ApproximatelyOrnek () {
        Debug.Log ("10f/10f  ile 1f birbirine eşittir:" + (1.0f == 10.0f / 10.0f));
        Debug.Log ("10f/10f  ile  1f değerine birine denktir, çok yakındır" + Mathf.Approximately (1.0f, 10.0f / 10.0f));
    }

Asin: Arksinüs, yani sinüs işleminin tersidir. Verdiğimiz sayı değerinin sinüs karşılığı olan açı değerini radyan cinsinden bize döndürür.

    void AsinOrnek () {
        //Mathf.Asin radyan cinsinden döndürdüğü için bunu Rag2Deg ile dereceye  çeviriyoruz
        Debug.Log ("Sin değeri -1 olan açı:" + Mathf.Asin (1) * Mathf.Rad2Deg);
        Debug.Log ("Sin değeri .5f olan açı:" + Mathf.Asin (.5f) * Mathf.Rad2Deg);
    }

Atan: Arktanjant, yani tanjant işlemin tersidir. Verdiğimiz sayı değerinin tanjant karşılığı olan açıyı radyan cinsinden bize döndürür.

    void AtanOrnek () {
        //Mathf.Atan radyan cinsinden döndürdüğü için bunu Rag2Deg ile dereceye  çeviriyoruz
        Debug.Log ("Tan değeri -1 olan açı:" + Mathf.Atan (0) * Mathf.Rad2Deg);
        Debug.Log ("Tan değeri .5f olan açı:" + Mathf.Atan (.5f) * Mathf.Rad2Deg);
    }

Atan2: x ve y bileşenleri ayrı ayrı vermemizi imkan tanıyan, bu sayede 0 ile bölünme gibi durumlarına önüne de geçerek tanjantın y/x şeklinde hesaplandığı durumlarda daha doğru sonuçlar almamızı sağlayan ters tan fonksiyonudur.

    public Transform kameraHedef;
    void Atan2Ornek () {
        //Hedefin konumunu kamera konumuna çeviriyoruz 
        Vector3 kamerayaGoreHedefKonum = transform.InverseTransformPoint (kameraHedef.position);
        //ardından  hedefin kamera localindeki x,z değerlerini elde ederek Atan2 ile kaç derecelik açı farkı olduğunu elde ediyoruz
        float angle = Mathf.Atan2 (kamerayaGoreHedefKonum.x, kamerayaGoreHedefKonum.z) * Mathf.Rad2Deg;
        //elde ettiğimiz açı kadar y ekseninde dönüş işlemi gerçekletiriyoruz. Aradaki farkı giderdiğimiz için kamera hedef objeye doğru bakacaktır.
        transform.Rotate (0, angle, 0);
        /*
        burada dikkat etmeniz gereken, tek 1 eksende dönüş işlemini gerçekleştirdiğimiz.
        Bunun yerine LookAt kullanmanız da mümkün. Ancak bu yöntem direkt açı değerleri
        üzerinde işlem yapmanıza da imkan vermekte.
        */
    }

    void Update () {
        Atan2Ornek ();
    }

Ceil: Verilen float tipindeki değere en yakın, ondan büyük veya eşit olan float tipinde tam sayıyı elde etmemizi sağlar.

    void CeilOrnek () {
        //10
        Debug.Log (Mathf.Ceil (10f));
        //11
        Debug.Log (Mathf.Ceil (10.3f));
        //-10
        Debug.Log (Mathf.Ceil (-10.9f));
    }

CeilToInt: Ceil fonksiyonuyla benzer mantıkta çalışır, ancak verilen değere en yakın ve ondan büyük veya eşit tam sayıyı float tipi yerine int tipinde döndürür.

Clamp: Verilen değerin, belirtilen minimum ve maksimum değerlerini aşmadığından emin olmamızı sağlar. Bu fonksiyona verdiğimiz değer eğer belirttiğimiz sınırdan az ise, minimum değeri, sınırdan fazla ise de, belirttiğimiz maksimum değeri bize döndürür.

    float posX = 0, posZ = 0;
    float min = -5, max = 5;
    //Input ile x ve z ekseninde objeyi hareket ettiren
    //ve sınırların dışına çıkmasını engelleyen fonksiyon
    void ClampOrnek () {
        posX += Input.GetAxis ("Horizontal");
        posZ += Input.GetAxis ("Vertical");

        posX = Mathf.Clamp (posX, min, max);
        posZ = Mathf.Clamp (posZ, min, max);
        transform.position = new Vector3 (posX, 0, posZ);
    }

    void Update () {
        ClampOrnek ();
    }

Clamp01: Clamp fonksiyonu ile aynı mantığa sahiptir, ancak sınırları 0 ve 1 olarak önceden belirlenmiştir. Eğer verilen değer sıfırdan ufaksa, 0, eğer birden büyükse 1 değerini geri döndürür.

ClosestPowerOfTwo: Verilen sayıya en yakın olan 2’nin üssü değeri bize geri döndürür.

    void ClosestPowerOfTwoOrnek () {
        //En yakın 2'nin üssü olan değer 4
        Debug.Log (Mathf.ClosestPowerOfTwo (5));
        //En yakın 2'nin üssü olan değer 8
        Debug.Log (Mathf.ClosestPowerOfTwo (7));
    }

CorrelatedColorTemperatureToRGB: Kelvin değerinden varolan renk sıcaklığı değerini RGB türüne çevirir. Kelvin değeri olarak 1000-4000 arası değer girilebilir. Color tipinde değişken döndürür.

Cos: Radyan cinsinden verilen açı değerinin kosinüs değerini elde etmemizi sağlar. -1 ve 1 arasında değer döndürür.

    public int cokgenKenarSayisi = 5;
    public float cokgenYaricap = 5;
    void Update () {
        CokgenCiz (cokgenYaricap, cokgenKenarSayisi);
    }
    //Debug Line ile XZ düzleminde objeyi merkez alan ve verilen yarıçap, kenar sayısına uygun şekilde düzgün çokken çizdirmemizi sağlayan fonksiyon.
    void CokgenCiz (float yaricap, int kenarSayisi) {
        // The corner that is used to start the polygon (parallel to the X axis).
        Vector3 baslangicKosesi = new Vector3 (yaricap, 0, 0) + transform.position;

        // Önceki köşe olarak başlangıcı atıyoruz.
        Vector3 oncekiKose = baslangicKosesi;

        // Başlangıç köşesinden sonraki her bir köşeyi dolanıyoruz...
        for (int i = 1; i < kenarSayisi; i++) {
            // Köşenin açı değerini radyan cinsinden hesaplıyoruz.
            float koseAcisi = 2f * Mathf.PI / (float) kenarSayisi * i;

            //Belirlediğimiz açıya göre, o an yaratacağımız köşe noktasının x ve z değerlerini belirliyoruz.
            //Cos ve Sin fonksiyonlarından nasıl yararlandığımıza dikkat edin.
            Vector3 anlikKose = new Vector3 (Mathf.Cos (koseAcisi) * yaricap, 0, Mathf.Sin (koseAcisi) * yaricap) + transform.position;

            // Önceki köşe ile şu an yarattığımız köşe noktasını kullanarak bir çizgi çiziyoruz.
            Debug.DrawLine (anlikKose, oncekiKose);

            // Anlık olarak yarattığımız köşeyi, onceki köşe olarak atıyoruz, böylece sonraki döngüde gelecek bu noktayı kullanabileceğiz.
            oncekiKose = anlikKose;
        }

        // Son olarak başlangıç ve bitiş yani en son belirlediğimiz köşe noktası arasında da bir çizgi çiziyioruz.
        Debug.DrawLine (baslangicKosesi, oncekiKose);
    }

DeltaAngle: Verilen 2 açı değeri arasındaki mesafenin en kısa halini elde etmemizi sağlar. Örneğin bir dairede, 360 derece ile, 0 derecesi aynı açıyı elde etmemizi sağlayacaktır. Yani aralarındaki fark aslında 0 denilebilir. Ancak 360-0 diyerek bunu elde etmeye çalışırken, alacağımız değer istediğimizden fazla olacaktır. DeltaAngle ile bu en kısa mesafeyi veren açı değerini elde ettiğimiz söylenebilir.

    void DeltaAngleOrnek () {
        // -90
        Debug.Log (Mathf.DeltaAngle (180, 90));
        // 90
        Debug.Log (Mathf.DeltaAngle (360, 90));
    }

Exp: Bu fonksiyon, bir diğer matematiksel sabit olan “e” değerinin verdiğimiz değerdeki üssünü elde etmemizi sağlar.

    void ExpOrnek () {
        Debug.Log (Mathf.Exp (2));
        Debug.Log (Mathf.Exp (4));
    }

Floor: Verdiğimiz sayıyaya en yakın ve ondan daha küçük olan tam sayı değerini float cinsinden bize verir.

    void FloorOrnek () {
        //20
        Debug.Log (Mathf.Floor (20.0F));
        //20
        Debug.Log (Mathf.Floor (20.9F));
        //-21
        Debug.Log (Mathf.Floor (-20.01F));
    }

FloorToInt: Floor fonksiyonu ile aynı şekilde, verdiğimiz sayıya en yakın ve ondan daha küçük olan tam sayıyı verir, ancak int tipinde döndürür. 

GammaToLinearSpace: Verilen gamma  düzlemindeki sayı değerinin linear düzlemindeki değerine erişmemizi sağlar.

InverseLerp: Verdiğimiz değerin, başlangıç ve bitiş değerleri arasındaki hangi konumda olduğunu elde etmemizi sağlar. Eğer verdiğimiz değer, başlangıç değerine eşit ise 0, eğer bitiş değerine eşit ise 1 değerini döndürecektir.

    Vector3 baslangic = Vector3.zero, bitis = Vector3.right * 10;
    /*
    Sidescroll-2d bir haritada, karakterin başlangıç ve bitiş arasındaki
    mesafenin yüzde kaçında olduğunu elde etmemizi sağlayan fonksiyon.
    */
    void InverseLerpOrnek () {
        float yolYuzde = Mathf.InverseLerp (baslangic.x, bitis.x, transform.position.x);
        //InverseLerp değerinin 0-1 arasında değer döndürüyor.
        // Yüzde değerini elde etmek için bunu 100 ile çarparak 0-100 aralığına genişletiyoruz.
        Debug.Log ("Yolunda %" + yolYuzde * 100 + " kısmı tamamlandı.");
    }

IsPowerOfTwo: Verdiğimiz değerin 2’nin üssü olup olmadığını elde etmemizi sağlar, eğer 2’nin üssü ise true, yoksa false değer döndürür.

    void IsPowerOfTwo () {
        //false
        Debug.Log (Mathf.IsPowerOfTwo (18));
        //true
        Debug.Log (Mathf.IsPowerOfTwo (32));
    }

Lerp: Başlangıç ve bitiş değerlerini verdiğimiz ve bu iki değer arasında hangi noktadan değer elde etmek istediğimizi belirttiğimiz bir fonksiyondur. İki değer arasındaki nokta için verdiğimiz değer 0 ise başlangıç değerini, 1 ise bitiş değerini elde etmemizi sağlar. Eğer arasında bir değer verirsek de, örneğin .5, tam olarak iki değerin ortasında bulunan değeri bize döndürür.

    float saglik = 5, saglikMax = 15;
    float saglikYenilemeHizi = 1f;
    void LerpOrnek () {
        if (saglik < saglikMax) {
            //sağlığın  maksimum sağlık ile varolan oranının elde ediyoruz. 0-1 arası bir değer veriyor bize.
            float varolanOran = saglik / saglikMax;
            /*
            daha sonrasında, sağlığı arttırmak istediğimiz için, hedef oran hesaplamasını yapıyoruz.
            Burada saglikYenilemeHizi/saglikMax işlemi yapmamızın sebebi, direkt artış değeri değil, 
            oran kullanıyor olmamız. 
            Time.deltaTime ile çarparak da, belirlediğimiz artış oranını tam olarak 1 saniyede 
            gerçekleştirmemize olanak veriyor.
            */
            float hedefOran = varolanOran + Time.deltaTime * (saglikYenilemeHizi / saglikMax);
            /*
            Minumum olarak 0 değerini ve maksimum olarak saglikMax değerini kullanıyoruz
            verdiğimiz oran da bu ikisi arasında gitmemizi sağlıyor. En başta 
            saglik/saglikMax işlemin yapma sebebimiz de aslında 
            0-1 arasında bir oran elde etmek.
             */
            saglik = Mathf.Lerp (0, saglikMax, hedefOran);
            //debug yerine bir slider kullanarak ekranda görmeniz de mümkün. Slider maks değerini saglikMax ile eşitlemeyi unutmayın tabii.
            Debug.Log (saglik);
        }
    }
    void Update () {
        LerpOrnek ();
    }

LerpAngle: Lerp gibi çalışır, ancak açılarda özellikle 360 derece tam tur dönüldüğü, bu değerin geçilmesi durumlarına göre hesaplanarak, açılar için daha doğru değerler elde etmemizi sağlar.

    float baslangicAci = 0.0f;
    float bitisAci = 450.0f;

    void LerpAngleOrnek () {
        float aci = Mathf.LerpAngle (baslangicAci, bitisAci, Time.time);
        transform.eulerAngles = new Vector3 (0, aci, 0);
    }
    void Update () {
        LerpAngleOrnek ();
    }

LerpUnclamped: Lerp gibi çalışır, ancak vereceğimiz oran değeri, 1’den fazla veya 0’dan az olabilir. Yani sınırlama ortadan kalkar. Ancak başlangıç bitiş değeri arasındaki değer farkından oluşan değişimi koruyarak bu sınırların dışında da hareket etmesini sağlar.

LinearToGammaSpace: Verilen linear düzlemindeki sayı değerinin gamma düzlemindeki değerine erişmemizi sağlar. 

Log: Verilen sayının belirtilen tabandaki logaritmasını elde etmemizi sağlar.

    void LogOrnek () {
        //8'in 2 tabanındaki logaritması
        Debug.Log (Mathf.Log (8, 2));
        //100'ün e sabiti tabanında logaritması, 2.değişkeni belirtmediğimiz taban olarak e sabitini kullanır.
        Debug.Log (Mathf.Log (100));
    }

Log10: Verilen sayının onluk tabanda logaritmasını elde etmemizi sağlar.

Max: Verilen 2 değerden en büyük olanı elde etmemizi sağlar.

Min: Verilen 2 değerden en küçük olanı elde etmemizi sağlar.

    void MinMaxOrnek () {
        float a = .25f, b = 1.5f;
        //1.5f
        Debug.Log (Mathf.Max (a, b));
        //.25f
        Debug.Log (Mathf.Min (a, b));
    }

MoveTowards: Verilen değerden, hedeflenen değere doğru, belirttiğimiz artış miktarıyla değişim olmasını sağlar. Lerp ile benzer işleve sahiptir, ancak Lerp ile başlangıç hedef arası konum oranını verirken, burada direkt olarak değişimin miktarını belirtiriz.

    float anlikSaglik = 5;
    float maxSaglik = 25;
    float iyilesmeHizi = 2;

    void MoveTowardsOrnek () {
        //Anlik sağlık değerinden, maxSaglik değerine her karede verdiğimiz değer kadar artış sağlıyoruz.
        anlikSaglik = Mathf.MoveTowards (anlikSaglik, maxSaglik, iyilesmeHizi * Time.deltaTime);
        Debug.Log ("Anlık Sağlık:" + anlikSaglik);
    }
    void Update () {
        MoveTowardsOrnek ();
    }

MoveTowardsAngle: MoveTowards ile benzer şekilde çalışır, ancak özellikle, 360 derece açılı tam tur durumlarının aşılması durumunda, doğru hesaplamanın yapılmasını sağlar. Açı işlemleri için bunu kullanmanız önerilir. 

NextPowerOfTwo: Verilen değere eşit veya ona yakın olan 2’nin üssü değerini elde etmemizi sağlar.

    void NextPowerOfTwoOrnek () {
        //16
        Debug.Log (Mathf.NextPowerOfTwo (15));
        //32
        Debug.Log (Mathf.NextPowerOfTwo (17));
    }

PerlinNoise: Perlin Noise oluşturmamızı sağlar. Özellikle “procedural generation” olarak karşımıza çıkabilecek, mağara, zindan, arazi yapılarında doğal bir rastgelelik etmemiz için noise kullanmak önemlidir. 2 boyutlu bir noise map üzerinde, verdiğimi x ve y konumundaki değerin ne olacağını bize döndürür. 0 ve 1 arasında float cinsinde değer döndürür.

    [SerializeField]
    float objeMiktarı = 25, noiseScale = 10;
    //PerlinNoise ile farklı yüksekliklere sahip objelerden bir grid yapısı oluşturmamızı sağlayan yapı. 
    void Start () {
        for (int x = 0; x < objeMiktarı; x++) {
            for (int z = 0; z < objeMiktarı; z++) {
                GameObject kup = GameObject.CreatePrimitive (PrimitiveType.Cube);
                //perlin noise için x,z koordinatlarını hesaplıyoruz
                float xCoord = x / objeMiktarı * noiseScale;
                float zCoord = z / objeMiktarı * noiseScale;
                //hesapladığımız koordinatlar ile noise değerini alıyoruz
                float posY = Mathf.PerlinNoise (xCoord, zCoord);
                //noise değerini Y ekseni olarak pozisyona veriyoruz.
                kup.transform.position = new Vector3 (x, posY, z);
            }
        }
    }

PingPong: Zamanla 0 ile verilen değer arasında gidip gelme efekti elde sağlayan bir fonksiyondur.

    float hedefNokta = 8, hareketHiziCarpani = 2;
    //x pozisyonunda 0 ve hedefnokta arasında gidip gelme hareketini sağlayan kod
    //0 pozisyonunu değiştiremiyoruz, yani başlangıç değerini belirtemiyoruz maalesef.
    void PingPongOrnek () {
        float posX = Mathf.PingPong (Time.time * hareketHiziCarpani, hedefNokta);
        transform.position = new Vector3 (posX, 0, 0);
    }
    void Update () {
        PingPongOrnek ();
    }

Pow: Verilen değişkenin herhangi bir üs değerini elde etmemizi sağlar.

    void PowOrnek () {
        //2 üssü 1.5
        Debug.Log (Mathf.Pow (2, 1.5f));
    }

Repeat: Verilen sayı değeri ile 0 arasında başa sarıp tekrar eden bir değişim elde etmemizi sağlar.

    void RepeatOrnek () {
        //x ekseninde 3 konumuna gidip, sonrasında tekrar 0'dan başlamasını sağlıyoruz.
        float posX = Mathf.Repeat (Time.time, 3);
        transform.position = new Vector3 (posX, transform.position.y, transform.position.z);
    }
    void Update () {
        RepeatOrnek ();
    }

Round : Verilen değere en yakın tam sayı değerini float cinsinden elde etmemizi sağlar. Eğer sayının ondalıklı kısım .5 şeklinde ise, sayının kendisi ve yakın olan sayının hangisi çift ise, o tam sayıyı döndürür.

    void RoundOrnek () {
        // 11
        Debug.Log (Mathf.Round (10.7f));
        // 10
        Debug.Log (Mathf.Round (10.5f));
        // 12
        Debug.Log (Mathf.Round (11.5f));
    }

RoundToInt Verilen sayıya en yakın tam sayı değerini int cinsinden elde etmemizi sağlar.

Sign: Verilen değerin negatif veya pozitiflik durumunu elde etmemizi sağlar. Eğer değer 0 veya pozitif değer ise 1, negatif ise -1 döndürür.

    void SignOrnek () {
        Debug.Log (Mathf.Sign (-10));
        Debug.Log (Mathf.Sign (10));
    }

Sin: Radyan cinsinden verilen açının sinüs değerini elde etmemizi sağlar. -1 veya 1 değeri döndürür.

SmoothDamp : Var Olan değeri, istenen hedef değere istenilen sürede ulaştırır. 

    Transform hedef;
    float smoothTime = 0.3f;
    float yVelocity = 0.0f;
    //hedef transform bileşenini Y ekseninde takip eden fonksiyon
    void SmoothDampOrnek () {
        float posY = Mathf.SmoothDamp (transform.position.y, hedef.position.y, ref yVelocity, smoothTime);
        transform.position = new Vector3 (transform.position.x, posY, transform.position.z);
    }
    void Update () {
        SmoothDampOrnek ();
    }

SmoothDampAngle: Var Olan açı değerini, istenen hedef değere istenilen sürede ulaştırır. 

SmoothStep: Verilen maksimum ve minimum değer arasında verilen oranda değer elde etmemizi sağlar. Lerp gibi çalışır ancak minimum-maksimum noktalarına geldiğinde otomatik bir yumuşatma, yavaşlatma yaparak daha doğal bir değişim elde etmemizi sağlar.

Sqrt: Verilen değerin karekökünü elde etmemizi sağlar.

    void SqrtOrnek () {
        Debug.Log (Mathf.Sqrt (9));
        Debug.Log (Mathf.Sqrt (16));
    }

Tan: Radyan cinsinden verilen açı değerinin tanjant değerini elde etmemizi sağlar.

    void TanOrnek () {
        Debug.Log (Mathf.Tan (.5f));
    }

Evet, böylelikle Unity Mathf Sınıfı nedir, hangi fonksiyonları içeriyor, bunlardan örneklerle beraber bahsetmiş oldum. Unity Mathf Sınıfı için 2019.4 sürümü dokümanından faydalandım bu yazıyı oluştururken. Yeni sürümlerde de çok farklılık olacağını sanmıyorum, ama arada dönüp göz atmanızda fayda var diye düşünüyorum. Umarım faydalı olur sizler için, sonraki yazılarda görüşmek dileğiyle.

Karadot Games Kanalı 1000 Aboneye Ulaştı

Karadot Games Kanalı 1000 Aboneye Ulaştı! 2 yılı aşkın süredir Unity ve Oyun Geliştirme üzerine videolar paylaştığımız Karadot Games Kanalı 1000 Aboneye Ulaştı. Ufak ve emin adımlarla ilerlediğimiz bu yolda, sevincimi size nasıl anlatabilirim bilemiyorum. Sevincimin en büyük kaynağı ise kesinlikle, faydalı içerikler üretebiliyor hissinin zihnimin her köşesinde artık varolması.

Bu hissi oluşturan, gerek teşekkürleriyle gerek yaptığı eleştirilerle kanalın büyümesini ve bu sitenin de varolmasını sağlayan sizlere çok teşekkür ediyorum. Bu yazıyı baştan sona teşekkürler yağdırarak devam ettirmeyeceğim tabii ki 🙂 

1000 aboneye ulaştığımız anda, açıkçası kaçıncı rüyamdaydım emin bile değilim. Telefonda kuzenimin tebrik mesajıyla yüzümde ufak bir gülümseme oluştu, sonrasında kanala girip bir baktım. Bu vakte kadar neler yapmışım, hem kendim bir göreyim, cidden bunu haketmiş miyim, hem de bunları tekrar bir toparlayıp sizinle paylaşayım istedim. Şimdi hazırsanız, önemli olduğunu düşündüğüm videolara, serilere yer vereceğim.

Karadot Games Kanalı İle Yaptıklarımız

Bu vakte kadar, Karadot Games Kanalı İle Yaptıklarımız arasında, temel kurulumlardan, C# kodlamada dikkat edilmesi gerekenlere, hazır assetlerin kullanımından, Shader Graph ile shader oluşturmaya kadar çeşitli konulara girmişiz. Kanala şöyle girip baştan sona baktığımda, çok az video varmış gibi gelse de, hepsinin dolu dolu oluşu benim içimdeki eğitim ateşini daha da bir harladı. Aynı ritimle, daha da inançlı ve şevkli bir şekilde üretmeye de devam edeceğim. Benim için önemli olan neler vardı bunları bir sıralayalım şimdi.

Unity3d Kurulumu ve Yeni Sistem Unity Hub

Unity3d Kurulumu ve Yeni Sistem Unity Hub videosu, kanalın ilk videosu ve yanlış hatırlamıyorsam en çok izlenen 2.video. Başlığından da anlayabileceğiniz üzere, kurulum ve Unity Hub yapısından bahsediyorum. Unity Hub yapısı o dönem henüz önizleme sürümünde hâlâ tabii ki. Stabil olmayan bir yapıya video çekmek de ne cesaretse artık. Ama iyi ki yapmışım.

Bu listeye almamın en büyük sebebi de, gerek anlatımım gerek videoya yaklaşımım nasıl değişmiş bunu çok bariz şekilde görebiliyorum. Kendi öğrenme serüvenimi de karşılaştırmak için alabileceğim bir mihenk taşı diyebiliriz. Nasıl daha faydalı olabilirim, her videoda bunu öğreniyorum tekrar tekrar. O dönemlerden bu vakte kadar, benim amatör anlatımıma sabredenlere ayrı bir hayranlık ve minnettarlık duyuyorum.

C# Abstract Class(Temel Sınıf) ve Interface( Arayüz) Kavramları

C# Abstract Class(Temel Sınıf) ve Interface( Arayüz) Kavramları video açıkçası bu kanalın benim için de nasıl bir öğrenme yöntemi olduğunu gösteren videolardan biri bence. Bir şeyi tam olarak oturttuktan sonra, bunu başkasıyla paylaşmak, aktarmak, öğrenmeyi katlayan ve kalıcı hale getiren bir şey. Kodlamaya bakışımızı ve eyleme döküşümüzü nasıl daha etkili hale getireceğimiz konusunda, dilin yapısı ve bize sunduklarını bilmek de çok önemli bir konu. Bu video da buna aracılık eden kaynaklar biri benim için. Ayrıca, videonun yazılı halini de oluşturmuştum, isterseniz şuraya tıklayarak erişebilirsiniz. C# ile kodlama yaparken Unity içerisindeki bileşenlere nasıl erişeceğinizi veya hangi kodlar kullanabileceğimizi merak ediyorsanız, “Unity Özel Bileşenler” kategorimize göz atabilirsiniz.

Shader Graph – X Ray Efekti

Shader Graph videolarım genelde en çok izlenen videolar arasında. Özellikle Türkçe kaynak konusundaki azlık, bunu tetikleyen şeylerden biri sanırım. Bu videonun benim için önemli kısmı ise, örneği tamamen kendim hazırlamış oluşum. Önceki shader graph videolarında öğrendiklerimi farklı durumlara uygulamışken, bu videoda öğrendiğim şeyleri harmanlayıp yorumlayarak kendim bir örnek oluşturmuş ve bunu size sunmuştum. Kanal içinde, her zaman başarılı olamasam da, benim en büyük isteğim sizin de bunu başarabilmeniz. Öğrendiğimiz şeyleri uyguladıkça, farklı durumlar için yeni çözümler oluşturdukça tam olarak öğrenmeyi sağlayabiliyoruz aslında. Grafik konulu yazılı içeriklerimize de “Unity Grafik” başlığı altından ulaşabilirsiniz.

Mesh Oluşturma Temel Ders

Mesh Oluşturma Temel Ders videosu, tam olarak Blender üzerinde modelleme işlerini ciddiye aldığım bir döneme denk gelmişti. Asıl kaynak benim 3D model oluşturma arzum yani. Blender üzerinde yaptığım denemelerde, bazı şeylerin tam oturmaması, istediğim yapıları elde edememem gibi sebeplerden, “bu mesh olayında tam olarak ne yapıyoruz yahu?” sorusu aklımda dolanmaya başladı. Cevabını elde ettikten sonra da, olabildiğince sade bir şekilde bunu size aktarmaya çalıştım. Devam videolarında da farklı örneklere değindim. Ancak daha değinecek çok şey var, özellikle UV konusu aklımda. Tabii, Blender için de temel seviye de olsa bir mini seri çekmek istiyorum. Ansızın görürseniz şaşırmayın 🙂

Web Üzerinden Veri Çekme – Nasıl Çalışır ve Json Formatı Nedir ?

Web Üzerinden Veri Çekme – Nasıl Çalışır ve Json Formatı Nedir ? videosu da aslında çok alakasız gelebilir ancak, özellikle çevrimiçi oyunlar oluştururken işimize yarayacak temel bir konu. Veri haberleşmesi nasıl yapılıyor, veriler nasıl gidiyor, geliyor ve nasıl işliyoruz sorularına olabildiğince sade bir şekilde yanıt verip size aktarmaya çalıştım. Bu videoda makinemizde varolan JSON dosyasını okuyup işleme örneği üzerinden gittik. Sonraki videoda da hava durumu uygulaması oluşturup, bir internet sitesinden API aracılığıyla bu veri alma verme işlemini gerçekleştirdik.

Editor Düzenleme – Editor Sınıfı ile Custom Inspector

Editor Düzenleme – Editor Sınıfı ile Custom Inspector videosu benim en çok zevk aldığım videolar arasında olabilir. Bir aracı kullanarak bir şeyler üretmenin yanında, kullandığımız aracı da özelleştirme işlemini gerçekleştiriyoruz bu videoda aslında. Hazır paket bir şey kullanmak yerine, ihtiyaçlara göre eğip bükebiliyor olma hissi, bence muazzam. Aynı zamanda o kadar faydalı şeyler üretmenize yardımcı oluyor ki. Devam videosunda da basit bir sahne tasarlama aracı oluşturmuştuk. Bu sayede hangi prefab neredeydi uğraşmadan, bu araç sayesinde sahnemize objeleri yerleştirebiliyorduk.

Unity Kodlama Yarışı – 15 Dakikada Mayın Tarlası

Unity Kodlama Yarışı – 15 Dakikada Mayın Tarlası videosu, özellikle Imphenzia ve Coding Train kanallarından görüp sürekli özendiğim video konseptinin Karadot Games kanalı üzerindeki ilk örneğiydi. Bu videoyu yaparkenki heyecanımı hâlâ hatırlıyorum. Daha sonrasında 2 videonun ardında, canlı yayın denemeleriyle farklı oyunları denemiştim. Emin olun bu seri, canlı yayınlar halinde tekrar geri gelecek. Yayın yapmayı ve sohbetinizi çok özledim.

Bir noktada artık kendimi durdurmam gerektiğini farkettim. Bütün videolar için yazabileceğim uzun uzun hikayeler var resmen. Her bir satırda ayrı bir mutluluk yaşayarak ilerlerken farkına varmadım zamanın nasıl geçtiğini. Faydalı olabildiğim, öğrenmenize katkı sağlayabildiğim için çok mutluyum. Umarım aklımdakileri hayata geçirir, Unity ve oyun geliştirme konularında daha güzel içerikler oluşturarak hepimize katkı sağlayabilirim. Yeni yazılarda görüşmek dileğiyle, kendinize iyi bakın.

Ayrıca unutmadan, Discord kanalımıza katılmak için buraya tıklayabilirsiniz.

Unity Time Sınıfı

Unity Time sınıfı, Unity içerisinde zaman hakkında bilgi edinmemizi sağlayan sınıftır. Unity Time sınıfı aracılığıyla oyun içerisindeki zamanı yavaşlatıp hızlandırabilir, geçen zamana göre işlemler gerçekleşmesini sağlayabiliriz. Time sınıfı özellikle Transform ile yaptığımız hareketlerde, saniyedeki kare sayısı(fps) etkisinden kurtularak, gerçek zamana göre işlemler gerçekleştirmemize de imkan sağlayacaktır.

Özellikle bir objeyi hareket ettirmek istediğinizde veya zamanla gerçekleşecek haşka herhangi bir işlem yaptığımızda deltaTime özelliğinden yararlandığımızı farklı örneklerde görmüşsünüzdür. Ancak Time sınıfının bize sundukları bununla sınırlı kalmıyor. Yazının devamında bunları sıralayıp olabildiğince kullanımlarına dair örnekler de oluşturduğumu göreceksiniz. Ancak daha öncesinde, şayet Unity üzerinde C# ile nasıl kod oluşturacağınız ve GameObject üzerine atamaya yapacağınızı bilmiyorsanız, “Unity C# Temel Dersi ve Fizik ile Basit Hareket” yazımıza göz atabilirsiniz.

Unity Time Sınıfı ile Kullanılabilecek Kodlar

Unity Time Sınıfı ile Kullanılabilecek Kodlar tamamıyla zaman hakkında değer okuma veya bir iki tanesinde değer değiştirme, yani yazma amacıyla kullanılmakta. Herhangi bir fonksiyon içermez, tamamen özelliklerden, properties yapılarından oluşmaktadır. Şimdi sırasıyla kullanım örnekleriyle beraber bunları ele alalım.

captureDeltaTime: Oyun içerisinde ekran görüntüleri almamıza yardımcı olmasıyla oynatma zamanını yavaşlatıp hızlandırmamıza imkan veren özellik.Bu sayede karelerin arasına istediğimiz kadar zaman koyabiliyoruz. Unity’nin belirttiği üzere özellikle görsellerden bir gif veya video oluşturmak istiyorsanız işinize yarayacak bir yöntemdir.

using UnityEngine;

public class EkranGoruntusuYakala: MonoBehaviour {

    public string klasorIsmi = "EkranGoruntuleri";
    public int kareSayisi = 25;
    void Start () {
        // Oynatma süresinde kullanılacak, kareler arası geçiş süresini belirliyoruz.
        Time.captureDeltaTime = 1.0f / kareSayisi;

        // Klasörü oluştur
        System.IO.Directory.CreateDirectory (klasorIsmi);
    }

    void Update () {
        // Ekran görüntüsü ismini belirliyoruz, örnek isim formatı'0005 shot.png'
        string dosyaYolu = string.Format ("{0}/{1:D04} kare.png", klasorIsmi, Time.frameCount);

        // Ekran görüntüsünü alıp, belirlediğimiz dosya yolunda dosyayı oluşturuyoruz.
        ScreenCapture.CaptureScreenshot (dosyaYolu);
    }
}

captureFramerate: captureDeltaTime özelliği gibi çalışır, ancak zaman aralığın vermek yerine saniyede elde etmek istediğiniz kare sayısını bu değere atamamız gerekiyor. Yukarıdaki örneğin aynısının captureFramerate halini görebilirsiniz.

using UnityEngine;

public class EkranGoruntusuYakala: MonoBehaviour {

    public string klasorIsmi = "EkranGoruntuleri";
    public int kareSayisi = 25;
    void Start () {
        // Oynatma süresinde kullanılacak, 1 saniyenin kaç kareden oluşacağını belirliyoruz.
        TTime.captureFramerate = kareSayisi;

        // Klasörü oluştur
        System.IO.Directory.CreateDirectory (klasorIsmi);
    }

    void Update () {
        // Ekran görüntüsü ismini belirliyoruz, örnek isim formatı'0005 shot.png'
        string dosyaYolu = string.Format ("{0}/{1:D04} kare.png", klasorIsmi, Time.frameCount);

        // Ekran görüntüsünü alıp, belirlediğimiz dosya yolunda dosyayı oluşturuyoruz.
        ScreenCapture.CaptureScreenshot (dosyaYolu);
    }
}

deltaTime: Bir önceki kare ile şu anki kare arasındaki zamanı elde etmemizi sağlayan özelliktir. Bu değer aynı zamanda Update fonksiyonlarımızın da hangi zaman aralıklarıyla çalıştığını gösteren bir değerdir. Saniye cinsinden değer döndürür ve sadece değer okuma yapabiliriz. Yani bu değeri değiştiremeyiz.

using UnityEngine;

public class DeltaTimeIleHareket : MonoBehaviour {
    float zamanlayici = 0;

    [SerializeField]
    float beklemeZamani = 1;
    //Update içerisinde deltatime ile zamanı tutarak belirlediğimiz aralıklarla pozisyonu değiştiriyoruz.
    void Update () {
        zamanlayici += Time.deltaTime;
        if (zamanlayici >= beklemeZamani) {
            zamanlayici -= beklemeZamani;
            transform.position += Vector3.forward;
        }
    }
}

fixedDeltaTime: FixedUpdate gibi fonksiyonların kullandığı sabit zaman aralığın değeri. MonoBehaviour içerisinde kullandığımız FixedUpdate dışında, Rigidbody vb fizik hesaplamalarında da bu değer kullanılmaktadır. Saniye cinsinden değer döndüren bu özellik, aynı zamanda değerini değiştirmemize de imkan tanır. Bu sebeple bunun yerine Time.deltaTime kullanmakta yarar vardır, çünkü o daha doğru bir zaman farkı elde etmenizi garanti edecektir.

fixedTime: FixedUpdate fonksiyonlarının tümünün çalışmaya başlamasından itibaren geçen süreyi elde etmemizi sağlar. Saniye cinsinden oyun başlangıcından itibaren geçen zamandır.

fixedUnscaledDeltaTime: Önceki kare ile şu anki kare arasında geçen gerçek zamanı elde etmemizi sağlar. timeScale değerinden etkilenmeyen bir değerdir.

fixedUnscaledTime: Oyun başından beri geçen gerçek zamanı elde etmemizi sağlar, ancak unscaledTime değerinden farklı olarak, FixedUpdate fonksiyonlarının çalışmasının başlamasını bekler. En sondaki örnekte karşılaştırmalarını görebilirsiniz.

frameCount: Toplamda geçmiş kare sayısını elde etmemizi sağlar. Kare sayısının hesaplanmaya başlaması ancak bütün Awake fonskiyonları bittikten sonra gerçekleşecektir. 

inFixedTimeStep: Bu kod çağırıldığında FixedUpdate gibi sabit aralıklı bir fonksiyondan çağırılıp çağırılmadığını elde etmemizi sağlar. Eğer bahsedildiği gibi FixedUpdate vb sabit aralıklı çalışan bir yapı içerisindeysek, true değeri döndürecektir.

using UnityEngine;
[RequireComponent (typeof (Rigidbody))]
public class Jump : MonoBehaviour {

    Rigidbody rigidbody;
    float jumpForce = 5f;

    void Start () {
        rigidbody = GetComponent<Rigidbody> ();
    }
    //test amacıyla DoJump fonksiyonumuzu Update ve FixedUpdate içerisinde çağırıyoruz.
    void Update () {
        if (Input.GetKeyDown (KeyCode.E)) {
            DoJump ();
        }
    }
    void FixedUpdate () {
        if (Input.GetKeyDown (KeyCode.Q)) {
            DoJump ();
        }
    }
    void DoJump () {
        //Rigidbody işlemlerimizin yalnızca FixedUpdate gibi 
        if (Time.inFixedTimeStep) {
            rigidbody.AddForce (Vector3.up * jumpForce, ForceMode.Impulse);
        } else {
            Debug.LogWarning ("Jump fonksiyonu sabit aralıklı karelerde (örneğin FixedUpdate) çağırılmalıdır.");
        }
    }
}

maximumDeltaTime: Bir karenin, update işleminin işlem süresinin alabileceği maksimum değeri belirlememizi veya elde etmemizi sağlar. Fizik veya benzeri sabit aralık kullanan sistemler (örneğin FixedUpdate) bu değeri kullanarak işlem sürelerini ayarlayacaklardır. Özellikle Garbage Collector ve fazla işlem gerektiren fizik işlemlerinden kaynaklanan kare sayısı azalmalarını engellemek için kullanılabilir. Unity değer aralığı saniyenin 10’da biri (1/10) ve 3’te biri (1/3) olacak şekilde ayarlanmasını tavsiye etmektedir.

maximumParticleDeltaTime: Particle objelerinin update fonksiyonlarının sürebileceği maksimum değeri elde etmemizi sağlar. Eğer update işlemi bu sürenin üstüne çıkarsa, update işlemleri çoğalarak daha ufak update işlemleri haline dönüşür. Ufak bir değer verildiğinde, particle için daha doğru sonuçlar elde edilse de, iş yükü artacaktır. Büyük değerler verildiğinde ise particle daha az doğruluğa sahip sonuçlar verecektir ama performans artacaktır.

realtimeSinceStartup: Uygulamanın başlatılmasından itibaren geçen geçen gerçek zamanı elde etmemizi sağlar. timeScale değerinden etkilenmez.

smoothDeltaTime: deltaTime ile olduğu gibi, kareler arasında zamanı elde etmemizi sağlar. Ancak, önceki kare arasındaki zaman değerleriyle karşılaştırılması ve buna göre hesaplanması ile daha yumuşak bir değer elde etmemizi sağlar. Aşağıdaki basit tabloda deltaTime ve smoothDeltaTime ile elde edeceğimiz örnek verileri görebilirsiniz. 

deltaTimesmoothDeltaTime
0.250.25
0.250.25
0.250.25
0.95 (+380%)0.4833(+193%)
0.25 (-73%)0.4833
0.250.4833
0.25 0.25   (-51%)
0.250.25
Time.deltaTime ve Time.smoothDeltaTime üzerinden alınacak değerlerin örnek karşılaştırması

time: Oyun çalışmaya başladığı andan itibaren geçen zamanı saniye cinsinden elde etmemizi sağlar.

using UnityEngine;

public class TimeIleDaireselHareket : MonoBehaviour {
    /*Sin ve Cos matematik fonksiyonları aracılığıyla, 
    dairesel hareket sağlıyoruz. 
    */
    void Update () {
        transform.position = new Vector3 (Mathf.Cos (Time.time), Mathf.Sin (Time.time), 0);
    }
}

timeScale: Zaman çarpanı olarak da belirtebileceğimiz bu özellik, oyun içerisinde işlemler gerçekleşirken zamanı nasıl ele alacağını belirlememizi sağlar. En basit örnekle, 0 değerini verirsek oyunda fizik işlemleri, kullanıcıdan veri alma gibi bütün işlemler duracaktır, 2 değerini verirsek de, 2 katı hızında işlemler gerçekleşecektir. Standart haliyle 1 değerine sahiptir.

using UnityEngine;

public class TimeScaleYavaslatma : MonoBehaviour {

    void Update () {
        /*Z tuşuna basılıp bırakılınca timeScale değerini manipule ediyoruz. 
        Bastığımızda yavaşlayacak, bıraktığımızda 1 deeğerine yani eski haline dönecek.
        Bu .5-1 değerlerini aniden atamak yerine yumuşak bir geçiş yapmanız da mümkün.
        Güzel bir alıştırma olur :)
        */
        if (Input.GetKeyDown (KeyCode.Z)) {
            Time.timeScale = .5f;
        }
        if (Input.GetKeyUp (KeyCode.Z)) {
            Time.timeScale = 1;
        }
    }
}

timeSinceLevelLoad: En son sahnenin yüklenme anından itibaren geçen zamanı saniye cinsinden elde etmemizi sağlar.

unscaledDeltaTime: timeScale değerinden etkilenmeyecek şekilde, kareler arasında geçen zamanı elde etmemizi sağlar. Örneğin, timeScale 0 değerine sahipse, deltaTime değerini de 0 alacaktır ancak bu değer kareler arasındaki zamanı elde etmemizi sağlayacaktır. Yani timeScale değerini kullanarak oyundaki işleyişi durdursak bile, unscaledDeltaTime ile kareler arasındaki gerçek zaman değerini saniye cinsinden elde edebiliriz.

unscaledTime: Oyun başlangıcından beri geçen zamanı elde etmemizi sağlar. Yine aynı şekilde, timeScale değerinden etkilenmeyen bir değişkendir. Uygulama başladığından beri geçen gerçek zamanı saniye cinsinden elde etmek için kullanabilirsiniz.

using UnityEngine;

public class TimeKarsilastirma: MonoBehaviour {
    //Ekranda göstereceğimiz verilerin renk ayarını yapıyoruz
    GUIStyle style;
    void Start () {
        style = new GUIStyle ();
        style.normal.textColor = Color.red;
    }
    void Update () {
        /*E tuşuna basılıp bırakılınca timeScale değerini manipule ediyoruz. 
        Bu sayede karşılaştırma yapabiliriz.
        */
        if (Input.GetKeyDown (KeyCode.E)) {
            Time.timeScale = 0;
        }
        if (Input.GetKeyUp (KeyCode.E)) {
            Time.timeScale = 1;
        }
    }

    void OnGUI () {
        //GUI.Label ile istediğimiz içeriği istediğimi konumda ve stilde yazdırıyoruz.
        GUI.Label (new Rect (10, 10, 100, 20), "deltaTime:" + Time.deltaTime, style);
        GUI.Label (new Rect (10, 30, 100, 20), "fixedDeltaTime:" + Time.unscaledDeltaTime, style);
        GUI.Label (new Rect (10, 50, 100, 20), "fixedtime:" + Time.time, style);
        GUI.Label (new Rect (10, 70, 100, 20), "time:" + Time.time, style);
        GUI.Label (new Rect (10, 90, 100, 20), "unscaledDeltaTime:" + Time.unscaledDeltaTime, style);
        GUI.Label (new Rect (10, 110, 100, 20), "fixedUnScaledDeltaTime:" + Time.fixedUnscaledDeltaTime, style);
        GUI.Label (new Rect (10, 130, 100, 20), "fixedUnscaledTime:" + Time.fixedUnscaledTime, style);
        GUI.Label (new Rect (10, 150, 100, 20), "unscaledTime:" + Time.unscaledTime, style);
    }
}

Bu son örnekle beraber aslında farklı zaman özelliklerinin karşılaştırmasını da görebiliyoruz. Yalnızca belirlediğimiz tuşa basarak değil, aynı zamanda editor durdurma (Pause) tuşuna basarak da anlık olarak, özellikle deltaTime tipleri arasındaki farkı görebilirsiniz. Böylelikle bu dokümanı da Türkçeye kazandırmış olduk. Dilerseniz orjinal dokümanı da buraya tıklayarak inceleyebilirsiniz. Faydalı olması dileğiyle, yeni yazılarda görüşmek üzere.

Unity Shader Graph

0

Unity Shader Graph, shader dosyalarınızı standart kodlama yöntemi yerine görsel programlama diyebileceğimiz yöntemle oluşturmamızı sağlayan bir araçtır. Daha önce Shader Forge, Amplify Shader Editor gibi eklentiler ile benzer şekilde shader oluşturma şansımız vardı. Ancak Unity’nin yeni HDRP ve URP teknolojileriyle gelen Shader Graph paketi, bu özelliğe ücretsiz olarak erişmemizi sağlıyor.

HDRP ve URP konusuna gelirsek, aslında standart olan sistemin de üstüne koyarak Unity’nin görsel becerilerini arttıran, render becerisini daha kullanıcı dostu ve daha performanslı halde kullanmamızı sağlayan render pipeline adındaki yapılar. Türkçe’ye çevirdiğimizde direkt çevirirsek “boru hattı” gibi bir anlam karşımıza çıksa da, “edinme yolu” daha doğru bir kelime olacaktır. Grafikleri elde etme yöntemimiz dersek yanlış olmaz.

Shader Graph için bunların önemli olmasının nedeniyse, projemizin ya HDRP ya da URP altyapısına sahip olması gerekmesi. Yani Shader Graph özelliklerinden yararlanabilmek için bu grafik edinme yollarından birini kullanmamız gerekiyor. Aynı anda sadece 1 tanesini kullanabilmekteyiz, bu da aklınızda olsun.

Unity Shader Graph Kurulumu

Unity Shader Graph kurulumu konusunda çok çok şanslıyız, HDRP veya URP tabanlı herhangi bir proje üzerinde, otomatik olarak bunu kullanabilmekteyiz. Yani render pipeline içerisinde dahil olan bir özellik. HDRP veya URP tabanlı bir proje nasıl oluşturulur veya varolan projeye nasıl eklenir konusunda bilgi edinmek isterseni “Unity HDRP ve URP“ adlı yazımıza göz atabilirsiniz. Ancak herhangi bir nedenden dolayı aktif edemediyseniz de, package manager üzerinden kontrolleri nasıl sağlarsınız ona bir göz atalım sizinle.

İlk yapmanız gereken, durumdan emin olmak. Bunu da en garanti şekilde, bir shader yaratabiliyor muyuz buradan anlarız. Project paneli içerisinde boş bir alana sağ tıklayıp “Create>Shader” altında “graph” içeren bir seçenek varsa, tamamdır hiçbir sıkıntımız yok, direkt olarak “Unity Shader Graph Kullanımı” başlığına inebilirsiniz.

Eğer yoksa, yapmamız gereken Window>Package Manager yoluyla, package manager penceresini açmak. Şayet bilmiyorsanız, bu pencere sayesinde Unity’nin bize sunduğu ve bizim AssetStore üzerinden aldığımız paketleri projeye ekleyebilir veya varolanları güncelleyebiliriz. Daha ayrıntılı bilgi edinmek isterseniz “Unity Package Manager” isimli yazımıza göz atabilirsiniz.

Package Manager penceresini açtıktan sonra, solda bulunan “Packages” seçeneğinin yanında “Unity Registery” yazdığından emin olun. Ardından isterseniz sol taraftaki listeyi kaydırarak, isterseniz arama kısmına “Shader Graph” yazarak alakalı eklentiyi bulabilirsiniz. Seçtikten sonra açılan panelde, şayet yüklü değilse Download ve ardından Import ile projenize dahil edin, eğer yüklü halde ise de Update seçeneği aktif olabilir. Bu seçenek ile güncellemeyi deneyin. Bu şekilde artık kullanıma hazır olacaksınız. Aksi bir durum olursa ve kontrol ettiğiniz durumda yine de bahsettiğimiz seçenekleri göremiyorsanız farklı bir proje oluşturup kontrolü sağlayabilirsiniz. Projenin kendisinde bir sorun varsa büyük ihtimalle console üzerinden hata da alacaksınızdır.

Unity Shader Graph Kullanımı

Unity Shader Graph kullanımı için ilk yapmamız gereken tabii ki bir graph dosyası oluşturmak. Yazının öncesinde Create seçeneği altından bir kontrol sağlamıştık. Yine aynı yolu izleyerek “PBR Graph” oluşturmanızı istiyorum. Basitçe bahsetmek gerekirse PBR, İngilizce açılımı ile “Physically based rendering”, gerçek dünyadaki gibi fizik tabanlı render işlemi gerçekleştirmemizi sağlayan bir shader türü. Işığın fiziksel olarak etkilerinden faydalanmamızı sağlıyor bu tür. 

Dosyayı oluşturduktan sonra istediğiniz gibi isimlendirebilirsiniz. Tabii, shader oluşturduk ama Unity içerisinde kullanabimemiz için bunu bir materyale atamamız gerekiyor. İsterseniz yeni oluşturduğunuz dosyamıza sağ tıklayıp “Create>Material” ile direkt bu dosyayı temel alan bir materyal oluşturabilirsiniz ya da var olan bir materyalin üzerine sürükleyip bırakarak atamayı sağlayabilirsiniz. Pek tabii, sahnemizde görsek de fena olmaz bu materyali. O yüzden bir “Sphere” objesi oluşturup materyalimizi bu objemize atayalım. Bunu yaptıktan sonra artık kullanımdan bahsedebiliriz. 

Adım adım bir basit bir örnek yaparak ilerlemek istiyorum burada. Shader dosyamıza çift tıklayarak açmamız gerekiyor öncelikle. Bunu yaptıktan sonra karşınıza aşağıdaki gibi bir pencere gelmeli.

Unity Shader Graph Temel Görünüm
Unity Shader Graph Temel Görünüm

Bu görselde gördüğümüz kutucuk Unity’nin “Node” olarak isimlendirdiği yapılar. Dikkatinizi çekmiştir, sol tarafında bazı noktalar bulunuyor. Bu noktalar sayesinde bu kutucukları birbirine bağlayabiliyor, bu sayede bir akış oluşturabiliyoruz. E akış olunca noluyor derseniz, aslında bu kutuların bir fonksiyon gibi çalıştığı söyleyebiliriz. Mantık çok basit, sol taraftan değişkenleri fonksiyona veriyoruz, sağ taraftan da fonksiyon içerisinden sonuçları elde ediyoruz. Sol giriş, sağ çıkış. Çok basit.

Tahmin ettiğiniz üzere, şu anda PBR Graph kutucuğu bizden giriş için değerler veriyor. Bu aşamada objemizi renklendirmeye geçebiliriz. Bunun için yapmamız gereken “Color” tipinde bir kutucuk oluşturmak. Bu pencere içerisinde boş bir alana sağ tıklayın, ardından “Create Node” seçeneğine tıklayın. Aşağıdaki gibi bir arama penceresi çıkacaktır. GameObject üzerinden bileşen eklemek gibi, gayet basit. İstersek başlıklar altından istersek arama kısmından faydalanarak kutucukları bulabiliriz.

Şu aşamada renklendirme için bize “Color” kutusu gerektiğini söylemiştim. Arama kısmına bunu direkt yazın ve çıkan seçeneğe tıklayın. Bu sayede bir kutucuk eklenecek. Buradaki renk paletinden yararlanarak istediğiniz rengi seçebilirsiniz. Ardından “Out” değerini PBR Master üzerinden “Albedo” kısmına bağlayacağız. Aşağıdaki hareketli görselden adım adım nasıl yapıldığını da görebilirsiniz. Ben siyah rengi seçtim, siz de istediğinizi seçebilirsiniz. Tabii unutmadan, yaptığınız değişiklikler sonrasında sol üstte bulunan “Save Asset” seçeneğine tıklamayı unutmayın, dosyamızı bu şekilde kaydediyoruz.

Unity Shader Graph Renk Eklemek
Unity Shader Graph Renk Eklemek

Eğer kutucukları silmek, çoğaltmak veya kopyalayıp yapıştırmak isterseniz, seçili haldeyken sağ tıklamanız yeterli. Burada bütün seçenekleri görebiliyorsunuz. Ayrıca, boş bir alana tıklayıp farenizi sürükleyip bırakarak, belirlediğiniz alan içerisinde çoklu şekilde de seçim yapmanız mümkün. Standart olarak aslında dosya sisteminden aşina olduğumuz yapılar bunlar.

BlackBoard

Açıkçası, bu rengin materyal üzerinden de değiştirilebiliyor olması güzel olur. Bunu da başarmak çok kolay. İlk görselde dikkatinizi çekmiş olmalı. Sol kısımda koyu renkli bir bölge bulunuyor. Eğer bu sizde aktif değilse, sağ üstte “Blackboard” isimli, evet karatahta, butona tıklamanız gerekli. Bu sayede açıp kapatabiliyorsunuz. 

Eğer konumundan mennun değilseniz, üstündeki daha koyu olan kısmından tutup sürükleyerek ekranda farklı bir yere konumlandırmanız mümkün. Ayrıca, sağ alt kısmından büyütüp küçültmemiz de mümkün.

Blackboard, shader üzerinde değişkenler oluşturmamızı ve bunları sonrasında farklı materyallerde farklı değerlere sahip olacak şekilde düzenlememizi sağlayan bir özellik. Aynı bileşenlerde kısımlardan her objeye farklı bir transform değeri verebilmemiz gibi. Bu kısımda “+” butonuna tıklamanızı ve Color seçeneğini seçmenizi istiyorum. Yeni bir alan oluşacak burada, bunun ismini “Birincil Renk” veya genel kullanımda da olduğu gibi “Main Color” şeklinde belirleyebilirsiniz. 

Altında gördüğünüz gibi farklı seçenekler bulunuyor. Bunları şimdi belirlesek de, sonrasında materyaller üzerinde değiştirebiliriz. Tabii bunu oluşturduk ama nasıl kullanacağız derseniz de, çok basit. Değişkenin isminin olduğu alanın üzerine gelin, etrafının farklı renge büründüğünü göreceksiniz. Bundan sonra tıklayıp sürükleyerek boş bir alana alabilirsiniz. Daha sonrasında da daha önce yaptığımız gibi PBR Master kutucuğuna bağlamanızı istiyorum. 

Eh işlem tamam 🙂 Gidip materyalinizi de kontrol ederseniz, yeni bir alan oluştuğunu göreceksiniz. Bu şekilde farklı değişkenler ekleyebilir ve objelerinizde kullanabilirsiniz. Bunlar arasında texture dosyaları da bulunuyor. Tıkladığımız “+” butonu üzerinden ne tarz değişkenler ekleyebileceğimizi görebilirsiniz. İncelemenizi öneririm. Ayrıca, artık kullanmadığımız “Color” kutucuğunu da silmenizi istiyorum.

Renk dışında, direkt görsel, yani Texture eklemeniz de mümkün. Texture dosyasına sahip herhangi bir modeliniz varsa, direkt onu da kullanabilirsiniz. Anca ben şu linkteki texture dosyalarından birini kullanacağım. Prototipleme aşamasında işime yarayan bir paket, size de öneririm. Aynı Color değişkeni eklediğimiz gibi, Texture değişkenini de blackboard üzerinden ekliyorum. Renk tipindeki değişkenden farklı olarak, Texture dosyamı Albedo kanalına direkt bağlamam mümkün değil.

Resimleri, görselleri shader içerisinde kullanabilmek için, “Sample Texture2D” kutucuğunu kullanmamız gerekiyor. Bunun sayesinde aslında UV işlemlerini de gerçekleştirebiliyoruz, yani tiling, offset gibi ayarları da yapabiliyoruz. Bu yüzden böyle bir yapı kullanmak da mantıklı. Yine aşağıdaki görselde, adım adım nasıl ekleyeceğimizi de görebilirsiniz.

Unity Shader Graph Resim Eklemek
Unity Shader Graph Resim Eklemek

Bunu yaptıktan sonra isterseniz materyal üzerinden, isterseniz de BlackBoard içerisindeki alandan “default” ismindeki alana bir texture objesi atayarak istediğiniz görseli materyalinize ekleyebilirsiniz.

Main Preview

Main Preview, shader graph içerisinde yaptığımız değişikliklerin ön izlemesini görebildiğimiz alandır. Şayet sizde aktif değilse, aynı Blackboard için yaptığımız şekilde sağ üst kısımda “Main Preview” yazan alandan bunu açıp kapatabilirsiniz. Bu sayede sahneye dönmenize gerek kalmadan nasıl bir görüntü elde ediyorsunuz bunu görmeniz mümkün.

Standart olarak küre şeklinde bir obje üzerinde bu değişiklikleri görüyoruz. Ancak bunu değiştirme şansına sahibiz. Eğer görselin üzerine sağ tıklarsak farklı seçeneklerin olduğunu görebiliriz. Buradan “Cube” seçeneğini seçmenizi istiyorum. Bunu yaptıktan sonra büyük ihtimalle bir kare şekli görüyorsunuz, bir şeyler yanlış gibi.

Şayet sol tıklayıp farenizi hareket ettirirseniz, 3 boyutlu olarak bir küp elde ettiğimizi de görebilirsiniz. Sadece başlangıç pozisyonu ve açısı yüzünden öyle gözüküyordu. 

Bunun dışında, en altta “Custom Mesh” seçeneği bulunuyor. Şayet buna tıklarsanız, mesh tipinde bir değişken seçmemiz için bir ekran karşımıza çıkacaktır. Bu sayede hem farklı türlerde objeler üzerinde etkisi görebilirsiniz hem de sadece tek 1 mesh için özel bir shader oluşturuyorsanız direkt bu mesh dosyasını açarak bunu takip edebilirsiniz.

Unity Shader Graph Main Preview
Unity Shader Graph Main Preview

Evet, genel olarak Unity Shader Graph üzerine diyeceklerim şimdilik bu kadar. Farklı node tipleri ve örnekler üzerine de içerikler oluşturarak devam edeceğim bu seriye. Şimdilik kendinize iyi bakın diyorum, bir dahaki yazılarda görüşmek dileğiyle.

Ha unutmadan, son olarak Youtube kanalımdaki “Shader Graph” oynatma listesini de sizinle paylaşayım, yazılı halleri gelene kadar sabredemeyenler olursa bu videolardan da faydalanabilir 🙂

Unity 2020.2 sürümü yayında!

4

Unity 2020.2 sürümü yayında! 15 Aralık 2020 yılı itibariyla çeşitli güncellemeler ve yeni özelliklerle Unity 2020.2 sürümü yayında ve indirmeye açıldı. Bu sürümü ile beraber özellikle çalışma süreçlerini için özellikler geliştirildi ve grafik altyapılarında optimizasyonlar yapıldı. Şayet en son özelliklerden yararlanmak ve 2020.1 sürümünde yaşadığınız sorunlardan kurtulmak istiyorsanız, 2020.2 sürümüne geçmekte yarar var.

Ufak bir hatırlatma da yapalım, Unity’nin de sürekli belirttiği üzere, kararlı bir geliştirme süreci için en son LTS sürümü kullanmanızda yarar var. En son LTS sürümü ise 2019 yılında çıkmıştı, indirmek işlemini Unity Hub  üzerinden gerçekleştirebilirsiniz ya da yazımızı inceleyerek “Unity 2019 LTS sürümü yayınlandı” yazımızdan o sürüm daha fazla detay elde edebilirsiniz. Şimdi, Unity 2020.2 sürümü ile gelenler neler onları farklı başlıklar altında inceleyelim.

Unity 2020.2 sürümü ile gelenler

Unity 2020.2 sürümü ile gelenler neler bunları başlıklar halında anlatmadan önce, HDRP için yeni bir taslak sahne eklendi, bunu belirtmekte fayda var. Bu sahne üzerinde özellikle yapılan grafik altyapısı düzeltmeleri ve eklenen özellikleri görmeniz de mümkün. Ayrıca sahneyi inceleyerek grafik hedefleriniz için neler yapmanız gerektiğini de öğrenebilirsiniz.

Unity 2020.2 Sürümü HDRP Yeni Sahne
Unity 2020.2 Sürümü HDRP Yeni Sahne

Unity 2020.2 Sürümü Grafik Geliştirmeleri

Unity 2020.2 Sürümü Grafik Geliştirmeleri özellikle URP ve HDRP için fazlasıyla güncelleme içeriyor. Özellikle URP için Screen Space Ambient Occlusion (SSAO) geliştirmeleri ile artık sahnedeki çevresel aydınlatma etkileri daha geliştimiş halde. Ayrıca daha ufak boyutlu ve hızlı Build sonuçları elde etmeniz de mümkün. URP için bir diğer yenilik ise yeni bir shader eklenmiş olması. Complex Lit adlı bu yeni shader ile “Clear Coat” özelliği ile objenize ayrı bir katmanda görseller eklemeniz mümkün. Unity’nin kullanım için belirttiği örnek ise araç boyası oluşturmak.

HDRP tarafında ise decal system için geliştirmeler mevcut. Bunun dışında Lightning yani ışıklandırma için daha iyi analiz araçları, debug tool özellikleri eklenmiş durumda. Ayrıca Ray Tracing için de geliştirmeler bu sürümde mevcut.

Unity 2020.2 Sürümü Sanat ve Sinematik Araçlar

Unity 2020.2 Sürümü Sanat ve Sinematik Araçlar konusunda da düzenlemelere ve yeni özelliklere sahip. Bunlardan belki ilk dikkat çeken olay Animation Rigging Paketinin artık tam sürüm haline geçmiş olması. Bu araç sayesinde daha rahat şekilde animasyonlar oluşturabiliyor veya varolan animasyonlara dokunmadan belirli kısımlara müdahale edebiliyorduk. Animation Rigging ile yaptığımız örneklerin bulunduğu oynatma listesini de şöyle bırakalım.

Shader Graph üzerinde de hem arayüz hem de performans bakımında çeşitli güncelleştirilmeler yer almakta. Örneğin artık node yapıların özelliklerini direkt olarak üzerlerinden değil de, aynı sahnede yaptığımız gibi sabit bir Inspector panelinde düzenliyoruz. Ayrıca tasarım kullanımında da daha fazla esneklik ve daha kolay bir kullanım amacıyla da arayüzde çeşitli geliştirilmelere gidilmiş.

Unity 2020.2 Shader Graph Arayüz
Unity 2020.2 Shader Graph Arayüz

VFX Graph konusunda da en önemli gelişme C# üzerinde gerçekleşen Event, yani olaylarla beraber çeşitli kontrolleri de sağlayabiliyoruz olmamız. Bu etkileşim sayesinde ışığı, sesi veya fiziksel etkileşimlere müdahale etmemiz mümkün oluyor.

2D konusunda da geri kalınmamış tabii. Özellikle 2D animation ile dahili IK sisteminin daha basit ve kısa sürede animasyonlar oluşturulması imkanı tanınmakta. Varolan hazır 2D prefabları da görsel, fiziksel gibi farklı alt başlıklara bölünmüş ve aralarına yenileri eklenmiş. Örneğin kare, daire, üçgen gibi farklı şekilleri, kinematik veya dinamik fizik özellikleriyle beraber sahneye eklemeniz ve özellikle protoptipleme açısından zaman kazanmanız mümkün. Bu basit şekillerin yanında SpriteShape veya Tilemap için de çeşitli taslak, hazır objeler bulunmakta.

Unity 2020.2 Sürümü Editor Geliştirmeleri

Unity 2020.2 Sürümü Editor Geliştirmeleri QuickSearch 2.0 yani hızlı arama özelliği önplanda duruyor. Sahne veya projemiz üzerinde istediğimizi bulmamız konusunda fazlasıyla yardımı dokunan bir araç. Özellikle çok fazla obje içeren sahneler veya dallı budaklı dosya yapılarında bu aracı kullanmak olmazsa olmaz bir alışkanlık haline gelecek gibi.

Prefablar konusunda da özellikle performans için çeşitli geliştirmeler var. Bu sayede Prefab yüklemelerin 50 kata kadar hızlanabildiği belirtiliyor. Prefablar dışında ayrıca PhysX fizik altyapısı geliştirmeleri de mevcut.

Son kısımda ise beni en mutlu eden yeni özellikten bahsedeceğim. Artık Inpector kısmında array veya list gibi yapılar kullanırken, sıralarını sürükleyip bırakarak değiştirmemiz mümkün. Tamam farkındayım bunu daha önce yapabiliyorduk Editor özelleştirmeler ile, ancak direkt bunun sunulması beni sebepsiz yere mutlu eden bir şey oldu. Kullanım için sadece [NonReorderable] komutunu değişkenin öncesinde kullanmamız yeterli. Şunun güzelliğine bakar mısınız..

Unity 2020.2 Sürümü Yayınlandı Liste Düzenleme
Unity 2020.2 Sürümü Liste Düzenleme

Unity 2020.2 Sürümü Programlama Araçları ve Geliştirmeler

Unity 2020.2 Sürümü Programlama Araçları ve Geliştirmeler arasında en güzel şeylerden biri Unity Safe Mode özelliğinin eklenmiş olması. Proje açılışlarında herhangi bir hata alma durumunda, direkt rapor göndermek yerine, Unity’nin bir nevi güvenli modda açılması sağlanarak, neyin sebep olabileceğini anlamanıza da imkan veriyor bu özellik.

C# 8.0 sürümü de artık tam olarak desteklenir hale geldi. Bu sayede daha okunaklı kodlar oluşturmanız ve Async Streams, Nullable Types gibi  C# 8.0 ile gelen özellikleri Unity projelerinizde kullanmanız mümkün.

Editor kullanımına da gelirsek de, Configurable Enter Play Mode özelliği ile sahnenin baştan yüklenmesi gibi işlemlerin es geçilmesi ve editor üzerinde oynatma modunda daha hızlı geçilmesi sağlanabiliyor. Projects Setting altında bu seçeneği açıp kapatabiliyorsunuz. Editor için bir diğer yenilik ise editor araçları geliştirirken kullanabilieceğimiz Editor Coroutines yapısının gelmiş olması. Bu sayede MonoBehaviour içerisinde IEnumerator gibi yapılar araçında nasıl Coroutine kullanabiliyorsak, aynısını Editor için yaptığımız geliştirmelerde de kullanmak mümkün hale geliyor.

Ve son olarak, Profiler üzerinden elde edilen Render ve Memory bileşenleri hakkındaki anlık verileri direkt olarak ekrana aktarmanız mümkün. Özellikle build edilmiş halde projelerinizde profiler olmadan, varolan verileri ekranda görebilmeniz ve analiz yapabilmeniz için güzel bir geliştirme olmuş.

Unity 2020.2 sürümü yayında! ve çok daha fazla detay var geliştirmeler ve yeni özellikler hakkında ancak benim gözümden önemli olan kısımlara olabildiğince değindim. İsterseniz Unity’nin blog yazısını okuyabilir ya da sürüm notlarına bakarak daha da detaylı bilgiler edinebilirsiniz. Umarım faydalı olmuştur. Yeni yazılarda görüşmek dileğiyle, hoşçakalın.

Unity HDRP ve URP

2

Unity HDRP ve URP 2018.1 sürümü ile kullanıma sunulan, yüksek kalitede grafikler elde etmemizi sağlayan grafik çözümlerdir. 2018.1 ile tanıtılan yeni sistem Scriptable Render Pipeline dahilinde olan bu iki sistem ile harika grafikler elde etmek fazlasıyla kolaylaşıyor. Bu yazımızda 2019.4 sürümüyle önizlemeden çıkan HDRP ve URP arasındaki farklardan bahsedip, kurulum aşamasını adım adım göreceğiz. 

Öncelikle SRP yani Scriptable Render Pipeline nedir, bundan biraz bahsetmekte fayda var. Bu yeni sistem sayesinde, genel tabirle grafiklerin render olması, objelerin ekranda gösterilmesi kısımlarına müdahale edebilmemiz mümkün hale geliyor. Yani temelinde c# ile kodlayarak cihazımıza nasıl render işlemleri yapacağını söylemek de mümkün. Ki baktığımızda Unity HDRP ve URP de bizim için önceden bu sistem üstünde hazırlanmış taslaklar. Custom olarak kendi Render Pipeline sistemimizi yazmak mümkün. Tabii bu konuya şu an giremeyeceğim ancak özellikle grafik konusunda ilgili kişilerin çok hoşuna gidecek bir şey olduğunu düşünüyorum. Tabii ki, kendiniz bir şey oluştururken vakit alacak ve öğrenmeniz gereken bir ton şey olacak. Bunu belirtmekte fayda var. Bu yüzden hazır olan sistemleri kullanmak da çoğu zaman bizi kurtaracak bir şey. 

HDRP, yani High Definition Render Pipeline, yüksek seviyedeki donanımlara sahip cihazlar yüksek performanslarda istediğiniz grafik kalitesini elde etmeniz amacıyla oluşturulmuş bir altyapı. Masaüstü ve dizüstü bilgisayarlar, konsollar için üst seviye grafiklere sahip bir oyun üretmek istiyorsanız, HDRP sizin için uygun seçim olacak.

URP, yani Universal Render Pipeline ise, mobil cihazlardan üst donanımlı bilgisayarlar ve konsollara kadar geniş ölçekteki cihazlarda optimize halde grafikler elde etmenizi sağlayan bir altyapı. Universal adından da anlayabileceğiniz gibi, evrensel bir yapıya sahip bu özelliği ile. Belirtmekte de fayda var, URP 7.x sürümü öncesinde LWRP yani Light Weight Render Pipeline ismine sahipti. Bu yazımızda bahsetmeyeceğiz ancak buraya tıklayarak orjinal dökümanlardan faydalanarak, LWRP sürümünden URP sürümüne geçiş yapabilirsiniz.

Hazır ikisinin farklarından bahsetmişken, belirtmem gereken önemli bir nokta da bu iki altyapıdan yalnızca birini aynı anda kullanabileceğimizdir. Aynı projede ikisini birden yükleyip kullanmak mümkün değil. Bu yüzden tercihini baştan yapıp bu şekilde projenizi ilerletmeniz sizin için daha sağlıklı olacaktır.

Unity HDRP ve URP Kurulumu

Unity HDRP ve URP kurulumu eğer yeni bir proje oluşturuyorsanız çok basit. Tek yapmanız gereken aşağıdaki görselde gördüğünüz gibi, Unity Hub üzerinden proje oluştururken bu iki altyapı taslağından birini seçmeniz. Bu sayede içerisinde örnek bir sahneyle beraber gerekli paketlerin yüklü olduğu bir proje sizin için otomatik olarak hazırlanmış olacak. Evet, bu kadar basit. Artık bu altyapılardan rahatlıkla faydalanabilirsiniz. 

Unity HDRP ve URP proje seçimi
Unity HDRP ve URP proje seçimi

Varolan Projenize HDRP ve URP Eklemek

Varolan Projenize HDRP ve URP Eklemek ise biraz uğraştırıcı bir durum olabilir. Eğer mümkünse projenize başlarken yukarıda bahsettiğimiz taslaklar üzerinden ilerleniz daha sağlıklı olacaktır. Ama varolan projenize eklemek istiyorsanız, özellikle HDRP için daha fazla adım gerekmekte. Öncelikle, ikisi için de yapmanız gereken şey “Window > Package Manager” yolu ile package manager penceresini açmak. Ardından hangisini istiyorsanız ona göre arama kısmına HDRP veya URP yazarak paketlere erişip indirmeniz. İlk kısım ikisi için de bu kadar basit. 

URP için temelde 2 işlem yapmanız gerekiyor. İlki, proje panelinizde boş bir alana sağ tıklayıp “Create > Rendering > Universal Render Pipeline > Pipeline Asset” ile gerekli pipeline asset dosyasını oluşturmak. İsterseniz farklı bir isim verebilir isterseniz de olduğu gibi bırakabilirsiniz bu aşamada. Daha sonrasında bu dosyayı Render Pipeline içerisinde belirtmemiz gerekiyor. Bunun için de yapmamız gereken şey, “Edit > Project Settings” ile proje ayarlarına girmek. Ardından “Graphics” sekmesi altında, isterseniz sürükleyip bırakarak isterseniz de sağındaki ikona tıklayarak “Scriptable Render Pipeline Settings” alanına dosyanızı atamanız gerekiyor. Aşağıdaki görselde gördüğünüz gibi, bu alanın boş olmaması gerekli.

Unity HDRP ve URP Ayarları
Unity HDRP ve URP Ayarları

HDRP için ise ufak bir kontrol ile işe başlıyoruz. Eğer “Console” panelinde bir sürü hata alıyorsanız, bunun nedeni gerekli ayarları yapmamamızdan. HDRP paketini yüklediğimizde Camera objemize otomatik olarak 2 adet bileşen atıyor, bunlar “HD Additional Light Data” ve “HD Additional Camera Data”. Bu sorunlardan kurtulmak içinse yapmamız gereken “Window > Render Pipeline > HD Render Pipeline Wizard” seçeneği ile kurulum sihirbazını çalıştırmak. Bu yeni pencerede “Configuration Checking” adı altında 3 panel bulunuyor, bunların her birinde varolan hataları görebilirsiniz. “Fix All” butonuna tıklamanız ise sorunlardan kurtulmanıza yetecektir.

Bu aşamadan sonra, büyük ihtimalle bütün objelerinizin magenta renginde olduğunu göreceksiniz. Bunun neden varolan materyal shader dosyalarının HDRP ile uyumlu olmaması, bunun da gayet basit bir çözümü var. Az önce çalıştırdığımız kurulum sihirbazında “Project Migration Quick-links” başlığı altında bazı seçenekler bulunuyor. Buradan “Upgrade Project Materials to High Definition Materials” butonuna tıklarsanız, projeniz içerisindeki bütün materyallere HDRP uyumlu shader atanmasını sağlayacaktır. Diğer seçenekte ise, o an seçili olan materyallerinizde bu değişikliği yapacaktır, tüm materyallerde değil. 

Bunun dışında, ışık konusuna dair de bir şey belirtmem gerekiyor. Standart olarak varolan ışık ayarlarının aksine, HDRP gerçekte olduğu haliyle ışığı simule etmek adına physical lights units adında ışık şiddeti birimleri kullanıyor. Bu yüzden ışıklarınızdaki Intensity değerini baya yüksek değerler vermeniz gerekebilir. Örneğin güneşi temsil etmesi için kullandıkları bir ışık kaynağında 100000 değerini kullanıyorlardı.  

Ayrıca, HDRP içerisinde post processing daha önce varolandan farklı bir altyapıda çalışmakta. Bu sebeple daha öncesinde projenizde varolan post processing dediğimiz, görsel etkiler ve efektler için bunu HDRP bileşeni ile tekrar oluşturmanız gerekecek. Ancak endişelenmeyin, varolan yeni sistemde ufak düzeltmeler yapıp yola devam etmeniz çok zor bir şey değil. Bu konu da aklınızda olsun.

Genel olarak Unity HDRP ve URP hakkında diyeceklerim şimdilik bu kadar. Daha ileri seviye örneklere de gerek youtube kanalımda gerekse de burada yazılı olarak yer vereceğim. Şu anlık temel olarak ne oldukları ve kurulumlarına dair kısım bu yazı içerisinde halledilmiş oldu. Umarım faydalı olmuştur. Ayrıca grafik konusundaki içeriklerimize buraya tıklayarak erişebilirsiniz. İsterseniz yorumlardan isterseniz eposta üzerinden bize ulaşarak içerik önerilerinde de bulunabilirsiniz. Görüşmek üzere.