Unity Terrane dan Mesh Blending

Halo semuanya, pada bulan Juni OTUS meluncurkan kursus Pengembang Unity Games lagi . Untuk mengantisipasi dimulainya kursus, kami telah menyiapkan terjemahan materi yang menarik tentang topik ini.



Hari ini kita akan berbicara tentang cara memadukan mesh terrane (atau mesh lainnya) di Unity. Panduan ini cukup canggih, tetapi saya mencoba memecahnya menjadi beberapa langkah terpisah. Diasumsikan bahwa Anda memiliki keterampilan Persatuan umum dan pengetahuan C # dasar. Panduan ini dirancang untuk memperkuat, tetapi saya pikir itu juga dapat diterapkan pada Grafik Shader. Ini adalah panduan pertama saya, jadi saya harap ini akan cukup jelas. Jika Anda ingin menambahkan sesuatu, beri tahu saya. Saya telah memasukkan starter kit di sini, yang memiliki beberapa shader tambahan untuk proyek ini, serta kit dasar untuk memulai. Semua file proyek dari manual hari ini tersedia untuk pelanggan saya seharga $ 5, tetapi dalam waktu dekat, mereka akan tersedia untuk semua orang.

Starter kit
Seluruh proyek

: , , . . , , , . ( ) unity . , , .

Jadi, mari kita mulai. Untuk memulai, saya akan memilih masalah dan mempelajari teori yang menjadi dasar solusinya. Untuk membuat campuran antara terrane dan jerat lainnya, Anda perlu memberi tahu shader di mana persimpangan dengan terran terjadi. Mengatakan lebih mudah daripada melakukan, tetapi ada cara. Dan apa isinya? Render Texture akan membantu kami !

Apa itu tekstur render?


Render Texture , pada kenyataannya, adalah posisi kamera, yang disimpan dalam file aset. Render Texture dalam game paling sering digunakan untuk hal-hal seperti membuat layar pengawasan video. Kita dapat menggunakan Tekstur Render untuk menyimpan tampilan kamera di editor sehingga tekstur ini kemudian dapat digunakan sebagai shader. Ini berguna karena kita dapat memanggang informasi tentang medan kita, seperti tinggi, normal dan warna, ke dalam tekstur yang kemudian dapat digunakan dalam runtime untuk memadukan antara jerat dan terran.


Render tekstur digunakan untuk menampilkan gambar angsa di TV di Game Tanpa Judul Angsa

Kustomisasi


Untuk memulai, mari buat adegan dan terrane baru. Tetapkan beberapa ukuran yang nyaman untuk bekerja, misalnya, 200x200. Sekarang Anda dapat mengatur terran sesuai keinginan Anda. Kemudian buat layer baru dan beri nama "Terrain" dan tetapkan terrain ke layer ini. Ini diperlukan agar topeng kamera dapat merekam terrane dalam Render Texture .


My masterpiece terrane

File sumber proyek memiliki cetakan yang disebut "BlendBakingCamera" - seret ke atas panggung. Anda akan mendapatkan kamera ortografi sederhana. Pada kamera, Anda perlu menempatkan topeng pemusnahan pada lapisan terrane baru. Posisikan kamera di tengah terran sedikit di atas titik tertinggi di medan. Kemudian sesuaikan bidang klip jauh sehingga kamera melihat lantai terrane. Pada akhirnya, pemandangannya akan terlihat seperti ini:


Pengganti shader


Sekarang setelah kamera diatur, Anda perlu menemukan cara untuk merekam data terrane. Untuk ini, kita perlu Penggantian Shader. Pengganti Shader sepertinya prospek yang meragukan, saya sendiri belum mengerti cara kerjanya untuk waktu yang lama. Tetapi pada kenyataannya, semuanya sangat sederhana dan efektif. Menggunakan Shader Pengganti pada dasarnya berarti merender setiap objek dalam bidang pandang kamera dengan shader tunggal, terlepas dari shader mana yang ditumpangkan pada objek. Akibatnya, semua objek akan dirender menggunakan Replacement Shader yang dipilih , yang sebenarnya hanyalah shader biasa.

Shader yang kita butuhkan untuk blending adalah shader kedalaman. Itu membuat kedalaman adegan dan merupakan komponen kunci dalam menciptakan efek blending kami, karena ia menulis nilai kedalaman kamera kami ke tekstur sehingga kami dapat membacanya nanti. Untuk mempelajari lebih lanjut tentang shader ini dan Pengganti Shader secara umum, saya sarankan Anda membaca manual ini dari Making Stuff Good Good in Unity .


Contoh Kedalaman Shader

Ayo mulai memanggang


Mari kita buat kelas baru dan beri nama "TerrainBlendingBaker" . Mari kita mulai dengan menerapkan topeng kedalaman untuk terrane dasar. Nanti kita akan kembali ke script ini untuk menambah warna dan normals.

Tentukan beberapa variabel.

//Shader that renders object based on distance to camera
public Shader depthShader;
//The render texture which will store the depth of our terrain
public RenderTexture depthTexture;
//The camera this script is attached to
private Camera cam;

Sekarang mari kita membuat metode baru dan menyebutnya "UpdateBakingCamera" . Dalam metode ini, kita akan menentukan data kamera yang shader mungkin perlu render dalam variabel global.

private void UpdateBakingCamera()
    {
        //if the camera hasn't been assigned then assign it
        if (cam == null)
        {
            cam = GetComponent<Camera>();
        }
 
        //the total width of the bounding box of our cameras view
        Shader.SetGlobalFloat("TB_SCALE", GetComponent<Camera>().orthographicSize * 2);
        //find the bottom corner of the texture in world scale by subtracting the size of the camera from its x and z position
        Shader.SetGlobalFloat("TB_OFFSET_X", cam.transform.position.x - cam.orthographicSize);
        Shader.SetGlobalFloat("TB_OFFSET_Z", cam.transform.position.z - cam.orthographicSize);
        //we'll also need the relative y position of the camera, lets get this by subtracting the far clip plane from the camera y position
        Shader.SetGlobalFloat("TB_OFFSET_Y", cam.transform.position.y - cam.farClipPlane);
        //we'll also need the far clip plane itself to know the range of y values in the depth texture
        Shader.SetGlobalFloat("TB_FARCLIP", cam.farClipPlane);
 
        //NOTE: some of the arithmatic here could be moved to the shader but keeping it here makes the shader cleaner so ¯\_(ツ)_/¯
    }

Sekarang mari kita panggang kedalaman terrane ke dalam tekstur.

// The context menu tag allows us to run methods from the inspector (https://docs.unity3d.com/ScriptReference/ContextMenu.html)
[ContextMenu("Bake Depth Texture")]
public void BakeTerrainDepth()
{
    //call our update camera method 
    UpdateBakingCamera();
 
    //Make sure the shader and texture are assigned in the inspector
    if (depthShader != null && depthTexture != null)
    {
        //Set the camera replacment shader to the depth shader that we will assign in the inspector 
        cam.SetReplacementShader(depthShader, "RenderType");
        //set the target render texture of the camera to the depth texture 
        cam.targetTexture = depthTexture;
        //set the render texture we just created as a global shader texture variable
        Shader.SetGlobalTexture("TB_DEPTH", depthTexture);
    }
    else
    {
        Debug.Log("You need to assign the depth shader and depth texture in the inspector");
    }
}

Nilai-nilai akan menjadi lebih jelas ketika kita mulai bekerja dengan shader. Berikut adalah gambar kecil yang dapat menjelaskan:


Kami akan memindahkan terrane ke tekstur kedalaman untuk kemudian membacanya dan memahami di mana harus melakukan blending.

Sekarang kami memiliki semua yang kami butuhkan untuk menciptakan efek blending dasar di shader. Pada titik ini, skripnya terlihat seperti ini: pastebin.com/xNusLJfh

Oke, sekarang kita memiliki skrip, kita dapat menambahkannya ke kamera pemanggang yang kita tambahkan sebelumnya. Aset awal memiliki shader yang disebut 'DepthShader' (Inresin / Shaders / DepthShader) dan Tekstur Render disebut 'DepthTerrainRT' (Inresin / RenderTextures / DepthTextureRT) , Anda perlu menempatkannya di bidang yang sesuai di inspektur.

Setelah itu, cukup jalankan metode melalui menu konteks untuk memanggang kedalaman medan kami di Tekstur Render .


Shader


Akhirnya mari kita buat shader untuk blending. Buat shader amplifikasi standar baru dan buka, beri nama 'TerrainBlending' atau lebih.

Sekarang kita perlu membuat UV untuk tekstur render . Ini akan menjadi perbedaan antara titik yang sedang diberikan dan posisi kamera pemanggang diskalakan relatif terhadap total area. Tiga variabel global di sini adalah yang baru saja kita nyatakan dalam kode. Kami juga menetapkan worldY sebagai variabel lokal, kami akan membutuhkannya nanti.



Mari kita ambil tekstur kedalaman yang kita tetapkan sebagai variabel global (untuk ini, tambahkan simpul sampel tekstur , buat global dan beri nama 'TB_DEPTH'), jika kita menempatkan output di bidang debug memperkuat shader ', kita bisa melihat apa yang terjadi. Buat pesawat dengan bahan yang akan digunakan shader baru kami.


Jadi, di shader, kami memiliki informasi tentang kedalaman, sekarang kami perlu menambahkan offset di y untuk mendapatkan blending.



Blok ini menskala posisi y dari mask bidang klip jarak jauh , mengurangi nilai ini dari posisi dunia sepanjang sumbu y dari titik yang sedang dirender, dan akhirnya menggesernya ke sisi bawah kotak pembatas kamera (posisi kamera dikurangi bidang farclip ).

Sudah sesuatu! Kita melihat bagaimana ujung-ujung pesawat bergabung dengan terrane.



Ok, mari membuat blending lebih terkontrol.



Sekarang kita dapat mengontrol ketebalan dan luas blending terrane.



Saya pikir kita bahkan dapat menambahkan sedikit noise. Mari kita gunakan posisi dunia untuk menghasilkan noise dari tekstur.



Tekstur noise ada di folder tekstur dalam proyek startup, mereka dapat ditugaskan di inspektur atau sebagai konstanta dalam shader itu sendiri.

Akhirnya saatnya untuk menambahkan beberapa tekstur! Untuk memulai, mari gunakan beberapa tekstur satu warna sederhana, saya menambahkan dua tekstur ke folder dengan aset tekstur. Jadikan tekstur 'SingleColorGrass' sebagai tekstur terrane . Kemudian dalam shader Anda perlu membuat tekstur terran dan simpul tekstur objek . Kami akan beralih di antara mereka di saluran merah topeng yang baru saja kami buat.




Dan di sini adalah shader lengkap.



Menambahkan pencahayaan kustom toon atau model pencahayaan yang tidak menyala akan memberikan hasil terbaik untuk shader ini. Saya menyalakan lamputerrane shader dan versi gelap dari shader dalam paket lengkap yang tersedia untuk sponsor.


Unlit Terrane dan Jerat

Saya juga merekomendasikan menambahkan triplanar shader ke terrane dan mungkin jerat lainnya. Saya dapat mempertimbangkan masalah ini di panduan berikutnya.

Yah, kita hampir selesai dengan tema utama panduan hari ini. Saya telah menambahkan beberapa bagian yang dapat membantu dengan ekstensi shader.

Ekstensi Shader - Normal


Saya menambahkan shader reguler ke file, Anda dapat menggunakannya untuk menulis normal ke permukaan terrane dan juga menggunakan blending. Untuk permainan saya, saya tidak perlu campuran normal, jadi saya hanya bereksperimen sedikit dan sepertinya percobaan itu sukses, dan ide saya berfungsi dengan baik untuk medan tanpa perubahan ketinggian tinggi. Saya menyertakan shader pemetaan normal dalam direktori dengan set shader awal. Di sini Anda dapat melihat implementasi dasar saya dari peta normal:



Kode hampir sama dengan peta kedalaman, tapi kali ini kita akan menggunakan peta normal sebagai pengganti shader . Saya juga menambahkan satu set tekstur render untuk merekam normal (di sini Anda mungkin memerlukan konfigurasi tambahan).

Agar normal bekerja dengan baik, mungkin diperlukan sedikit usaha lebih banyak terkait penyetelan, dan mungkin juga ada batasan yang terkait dengan terran tingkat rendah (tapi saya belum melakukan tes yang cukup untuk mengonfirmasi hal ini).

Ekstensi Shader - Semua Warna


Saya tidak akan masuk jauh ke detail topik ini, karena melampaui apa yang diperlukan untuk permainan saya, tapi saya memikirkannya saat menulis panduan ini. Untuk menambahkan campuran banyak warna, kita dapat memilih warna terran yang tidak terang dan menyimpannya sebagai tekstur. Dalam hal ini, kami dibatasi oleh resolusi yang cukup rendah, tetapi metode ini berfungsi dengan baik saat menggunakan tekstur medan satu warna dan tekstur resolusi rendah, atau saat menggunakan redup samar . Dengan penyesuaian kecil, mereka juga dapat diterapkan pada jerat terrane.

Berikut adalah kode untuk opsi multicolor:

[Header("The following settings are only if using the multi-color terrain shader")]
//Shader that renders the unlit terraom of an object
public Shader unlitTerrainShader;
//The render texture which will store the normals of our terrain
public RenderTexture surfaceTexture;
//An unlit terrain material used to capture the texture of our terrain without any lighting
public Material unlitTerrainMaterial;
//The terrain you want to capture the textures of
public Terrain yourTerrain;
 
[ContextMenu("Bake Surface Texture")]
public void BakeTerrainSurface()
{
    UpdateBakingCamera();
 
    //return if there is no terrain assigned
    if (yourTerrain == null)
    {
        Debug.Log("You need to assign a terrain to capture surface texture");
        return;
    }
 
    StartCoroutine(BakeColors());
}
 
IEnumerator BakeColors()
{
    Material tempTerrainMaterial = yourTerrain.materialTemplate;
 
    yourTerrain.materialTemplate = unlitTerrainMaterial;
 
    yield return 0;
 
    cam.SetReplacementShader(unlitTerrainShader, "RenderType");
    cam.targetTexture = surfaceTexture;
    Shader.SetGlobalTexture("TB_SURFACE", surfaceTexture);
 
    yield return 0;
 
    cam.targetTexture = null;
    yourTerrain.materialTemplate = tempTerrainMaterial;
 
    yield return null;
 
}

Satu-satunya perubahan dalam shader adalah bahwa alih-alih menggunakan tekstur yang telah ditentukan, kami menggunakan tekstur permukaan medan yang ditentukan secara global yang akan menggunakan posisi relatif sebagai UV. Ekstensi tambahan memungkinkan Anda mendapatkan perpaduan tekstur yang lebih menyenangkan.


Memadukan banyak tekstur

Berikut adalah grafik multicolor lengkap dengan shader blending normal:




Kesimpulan


Selamat jika Anda telah membaca hingga titik ini! Seperti yang saya katakan, ini adalah panduan pertama saya, jadi saya akan sangat menghargai umpan balik. Jika Anda ingin mendukung saya dalam membuat game dan tutorial, lihat di sini atau berlangganan Twitter saya .



Pelajari lebih lanjut tentang kursus

All Articles