Dalam beberapa kasus, ada perbedaan dalam bagaimana rendering grafis berperilaku antara API grafis yang berbeda. Sebagian besar waktu Editor Unity menyembunyikan perbedaan, tetapi ada beberapa situasi di mana Editor tidak dapat melakukan ini untuk Anda. Situasi ini, dan tindakan yang perlu Anda ambil jika terjadi, tercantum di bawah ini.
Konvensi koordinat Tekstur vertikal berbeda antara dua jenis platform: Direct3D-like dan OpenGL-like.
Perbedaan ini cenderung tidak memiliki efek pada proyek Anda, selain ketika rendering menjadi Render TeksturJenis Tekstur khusus yang diciptakan dan diperbarui pada runtime. Untuk menggunakannya, pertama membuat Tekstur Render baru dan menunjuk salah satu Kamera Anda untuk membuatnya. Kemudian Anda dapat menggunakan Tekstur Render dalam Bahan seperti Tekstur biasa. More info
Lihat di Glossary. Ketika rendering ke dalam Tekstur pada platform langsung3D-seperti, terbalik secara internal Unity rendering terbalik. Ini membuat konvensi cocok antara platform, dengan platform OpenGL-seperti konvensi standar.
Efek Gambar dan rendering di ruang UV adalah dua kasus umum di ShadersProgram yang berjalan di GPU. More info
Lihat di Glossary di mana Anda perlu mengambil tindakan untuk memastikan bahwa konvensi koordinat yang berbeda tidak membuat masalah dalam proyek Anda.
Ketika Anda menggunakan dan anti-aliasing, Tekstur sumber yang dihasilkan untuk Efek Gambar tidak dipotong sesuai dengan Konvensi platform TerbukaGL-seperti. Dalam hal ini, render Unity ke layar untuk mendapatkan anti-aliasing dan kemudian menyelesaikan rendering ke Tekstur Render untuk pemrosesan lebih lanjut dengan Efek Gambar.
Jika Efek Gambar Anda adalah salah satu sederhana yang memproses satu Tekstur Render pada waktu, Grafik Login berurusan dengan koordinat yang tidak konsisten. Namun, jika Anda memproses lebih dari satu Render Tekstur bersama-sama di Anda, Tekstur Render cenderung keluar pada orientasi vertikal yang berbeda di platform yang mirip Direct3D dan ketika Anda menggunakan anti-aliasing. Untuk menstandardisasi koordinat, Anda perlu secara manual “flip” layar Tekstur terbalik dalam Vertex ShaderProgram yang berjalan pada setiap simpul model 3D ketika model sedang diberikan. More info
Lihat di Glossary Anda sehingga sesuai dengan standar koordinat OpenGL-like.
Sampel kode berikut menunjukkan cara melakukan ini:
// Flip sampling of the Texture:
// The main Texture
// texel size will have negative Y).
#if UNITY_UV_STARTS_AT_TOP
if (_MainTex_TexelSize.y < 0)
uv.y = 1-uv.y;
#endif
Situasi serupa terjadi dengan GrabPass. Tekstur render yang dihasilkan mungkin tidak benar-benar dimatikan di platform Direct3D-like (non-OpenGL-like). Jika sampel kode Shader AmbilPass Tekstur, gunakan fungsi ComputeGrabScreenPos
dari file UnityCG termasuk.
Ketika rendering di ruang berkoordinasi Tekstur (UV) untuk efek atau alat khusus, Anda mungkin perlu menyesuaikan Anda Shaders sehingga rendering konsisten antara sistem Direct3D-like dan OpenGL-like. Anda juga mungkin perlu menyesuaikan rendering Anda antara rendering ke layar dan rendering ke Tekstur. Sesuaikan ini dengan membalikkan proyeksi Direct3D-seperti terbalik sehingga koordinatnya sesuai dengan koordinat proyeksi OpenGL-like.
variabel built-in ProjectionParams.x
mengandung nilai +1
atau –1
. -1
menunjukkan proyeksi telah dibalik ke bawah untuk mencocokkan koordinat proyeksi TerbukaGL-seperti, sementara +1
menunjukkan itu belum selesai. Anda dapat memeriksa nilai ini di Shaders Anda dan kemudian melakukan tindakan yang berbeda. Contoh di bawah ini memeriksa jika proyeksi telah dibalik dan, jika demikian, flips dan kemudian kembali koordinat UV untuk mencocokkan.
float4 vert(float2 uv : TEXCOORD0) : SV_POSITION
{
float4 pos;
pos.xy = uv;
// This example is rendering with upside-down flipped projection,
// so flip the vertical UV coordinate too
if (_ProjectionParams.x < 0)
pos.y = 1 - pos.y;
pos.z = 0;
pos.w = 1;
return pos;
}
Mirip dengan koordinat Tekstur, koordinat ruang klip (juga dikenal sebagai koordinat ruang pasca proyeksi) berbeda antara platform Direct3D-like dan OpenGL-like:
Direct3D-like: Kedalaman ruang klip dari +1.0 di pesawat dekat ke 0,0 di pesawat jauh. Ini berlaku untuk Direct3D, Logam dan konsol.
OpenGL-like: Kedalaman ruang klip dari –1.0 di pesawat dekat ke +1.0 di pesawat jauh. Ini berlaku untuk OpenGL dan OpenGL ES.
Di dalam kode Shader, Anda dapat menggunakan UNITY_NEAR_CLIP_VALUE
makro built-in untuk mendapatkan nilai pesawat dekat berdasarkan platform.
Di dalam kode skrip, gunakan GL.GetGPUProjectionMatrix untuk mengkonversi dari sistem koordinat Unity (yang mengikuti Konvensi OpenGL-like) ke koordinat langsung3D-seperti jika itu adalah apa yang diharapkan platform.
Untuk menghindari masalah presisi, pastikan Anda menguji Shaders Anda di platform target. GPU di perangkat seluler dan PC berbeda dalam bagaimana mereka memperlakukan jenis titik mengambang. PC GPU memperlakukan semua jenis titik mengambang (float, setengah dan tetap) sama - mereka melakukan semua perhitungan menggunakan presisi 32-bit penuh, sementara banyak perangkat seluler GPU tidak melakukan ini.
Lihat dokumentasi tentang jenis data dan presisi untuk rincian.
Penggunaan const
berbeda antara Microsoft HSL (lihat msdn.microsoft.com) dan GLSL OpenGL (lihat Wikipedia) Bahasa Shader.
HLSL const
Microsoft memiliki banyak makna yang sama seperti yang dilakukan di C# dan C++ dalam variabel yang dinyatakan read-only dalam lingkupnya tetapi dapat diinisialisasikan dengan cara apa pun.
OpenGL's GLSL const
berarti bahwa variabel secara efektif adalah waktu kompilasi konstan, dan itu harus diinisialisasi dengan mengkompilasi batasan waktu (baik nilai literal atau perhitungan pada const
s lainnya).
Yang terbaik adalah mengikuti semantik GLSL OpenGL dan hanya menyatakan variabel sebagai const
ketika benar-benar invariant. Hindari menginisialisasi variabel const
dengan beberapa nilai mutableAnda dapat mengubah isi paket mutable. Ini adalah kebalikan dari immutable. Hanya Local packages dan Embedded packages mutable.
Lihat di Glossary lainnya (misalnya, sebagai variabel lokal dalam fungsi). Ini juga bekerja di HLSL Microsoft, sehingga menggunakan const
dengan cara ini menghindari kesalahan membingungkan pada beberapa platform.
Untuk mendapatkan Shaders bekerja di semua platform, beberapa nilai Shader harus menggunakan semantik ini:
Vertex Shader output (clip space) position: SV_POSITION
. Terkadang Shaders menggunakan semantik POSITION untuk mendapatkan Shaders bekerja di semua platform. Perhatikan bahwa ini tidak berfungsi pada Sony PS4 atau dengan tesselasi.
Fragment Shader output color: SV_Target
. Terkadang Shaders menggunakan COLOR
atau COLOR0
untuk mendapatkan Shaders bekerja pada semua platform. Perhatikan bahwa ini tidak berfungsi pada Sony PS4.
Ketika rendering Meshes sebagai Poin, output PSIZE
semantik dari simpul (misalnya, set ke 1). Beberapa platform, seperti OpenGL ES atau Metal, memperlakukan ukuran titik sebagai “tidak ditentukan” ketika tidak ditulis dari Shader.
Lihat dokumentasi tentang Shader semantics untuk rincian lebih lanjut.
Login Platform D menggunakan Login Catalog Microsoft. compiler HLSL lebih ketat daripada kompiler lain tentang berbagai kesalahan Shader halus. Misalnya, tidak menerima nilai output fungsi yang tidak diinisialisasi dengan benar.
Situasi yang paling umum yang mungkin Anda jalankan menggunakan ini adalah:
out
. Memastikan output seperti ini: void vert (inout appdata_full v, out Input o)
{
**UNITY_INITIALIZE_OUTPUT(Input,o);**
// ...
}
Nilai awal yang sebagian. Misalnya, fungsi kembali float4
tetapi kode hanya menetapkan nilai .xyz
dari itu. Mengatur semua nilai atau perubahan ke float3
jika Anda hanya membutuhkan tiga nilai.
Menggunakan tex2D
di Vertex Shader. Ini tidak valid, karena turunan UV tidak ada di Shader simpul. Anda perlu sampel tingkat mip eksplisit bukan; misalnya, gunakan tex2Dlod
(tex, float4(uv,0,0)
). Anda juga perlu menambahkan #pragma target 3.0
sebagai tex2Dlod
adalah fitur Shader model 3.0.
Beberapa bagian dari pipa kompilasi Permukaan Shader tidak mengerti DirectX 11-specific HLSL (bahasa naungan Microsoft) sintaks.
Jika Anda menggunakan fitur HLSL seperti StructuredBuffers
, RWTextures
dan sintaksis non-DirectX 9 lainnya, bungkusnya di DirectX X11-only preprocessor macro seperti yang ditunjukkan dalam contoh di bawah ini.
#ifdef SHADER_API_D3D11
// DirectX11-specific code, for example
StructuredBuffer<float4> myColors;
RWTexture2D<float4> myRandomWriteTexture;
#endif
Beberapa GPU (yang paling terkenal dengan PowerVR di iOS) memungkinkan Anda untuk melakukan bentuk campuran yang dapat diprogram dengan menyediakan warna fragmen saat ini sebagai masukan ke Shader Fragment (lihat EXT_shader_framebuffer_fetch
pada khronos.org).
Hal ini dimungkinkan untuk menulis Shaders di Unity yang menggunakan fungsi pengambilan bingkaibuffer. Untuk melakukan ini, gunakan argumen warna inout
ketika Anda menulis Shader Fragment dalam bahasa HLSL (bahasa pencukur Microsoft - lihat msdn.microsoft.com) atau Cg (bahasa yang dicukur oleh Nvidia - lihat nvidia.co.uk).
Contoh di bawah ini dalam Cg.
CGPROGRAM
// only compile Shader for platforms that can potentially
// do it (currently gles,gles3,metal)
#pragma only_renderers framebufferfetch
void frag (v2f i, inout half4 ocol : SV_Target)
{
// ocol can be read (current framebuffer color)
// and written into (will change color to that one)
// ...
}
ENDCG
Arah kedalaman (Z) berbeda pada platform Shader yang berbeda.
DirectX 11, DirectX 12, Metal: Reversed direction
Penyangga kedalaman (Z) adalah 1,0 di pesawat dekat, menurun menjadi 0,0 di pesawat jauh.
Rentang ruang klip adalah [dekat,0] (meskipun jarak dekat pesawat di dekat pesawat, menurun menjadi 0,0 di pesawat jauh).
Other platforms: Traditional direction
Nilai penyangga kedalaman (Z) adalah 0,0 di pesawat dekat dan 1.0 di pesawat jauh.
Perhatikan bahwa kedalaman arah terbalik (Z), dikombinasikan dengan titik mengambang depth bufferSebuah toko memori yang memegang kedalaman nilai z setiap pixel dalam gambar, di mana nilai z adalah kedalaman untuk setiap piksel yang diberikan dari pesawat proyeksi. More info
Lihat di Glossary, secara signifikan meningkatkan presisi penyangga kedalaman terhadap arah tradisional. Keuntungan dari ini adalah kurang konflik untuk koordinat Z dan bayangan yang lebih baik, terutama ketika menggunakan pesawat dekat kecil dan pesawat jauh besar.
Jadi, ketika Anda menggunakan Shaders dari platform dengan kedalaman (Z) terbalik:
_CameraDepth
Texture texture range is 1 (near) to 0 (far).Namun, makro dan fungsi berikut secara otomatis melakukan perbedaan dalam arah (Z):
Linear01Depth(float z)
LinearEyeDepth(float z)
Jika Anda mengambil nilai buffer kedalaman (Z) secara manual, Anda mungkin ingin memeriksa arah penyangga. Berikut ini adalah contoh dari ini:
float z = tex2D(_CameraDepthTexture, uv);
#if defined(UNITY_REVERSED_Z)
z = 1.0f - z;
#endif
Jika Anda menggunakan ruang klip (Z) secara manual, Anda mungkin juga ingin perbedaan platform abstrak dengan menggunakan makro berikut:
float clipSpaceRange01 = UNITY_Z_0_FAR_FROM_CLIPSPACE(rawClipSpace);
Note: Makro ini tidak mengubah ruang klip di platform OpenGL atau OpenGL ES, sehingga kembali dalam "near"1 (near) sejauh ini (far) di platform ini.
GL.GetGPUProjectionMatrix() mengembalikan matriks z-reverted jika Anda berada di platform di mana kedalaman (Z) terbalik. Namun, jika Anda bersaing dari matriks proyeksi secara manual (misalnya, untuk bayangan kustom atau rendering kedalaman), Anda perlu mengalihkan kedalaman (Z) arahkan diri Anda di mana itu berlaku melalui script.
Contoh ini di bawah ini:
var shadowProjection = Matrix4x4.Ortho(...); //shadow camera projection matrix
var shadowViewMat = ... //shadow camera view matrix
var shadowSpaceMatrix = ... //from clip to shadowMap texture space
//'m_shadowCamera.projectionMatrix' is implicitly reversed
//when the engine calculates device projection matrix from the camera projection
m_shadowCamera.projectionMatrix = shadowProjection;
//'shadowProjection' is manually flipped before being concatenated to 'm_shadowMatrix'
//because it is seen as any other matrix to a Shader.
if(SystemInfo.usesReversedZBuffer)
{
shadowProjection[2, 0] = -shadowProjection[2, 0];
shadowProjection[2, 1] = -shadowProjection[2, 1];
shadowProjection[2, 2] = -shadowProjection[2, 2];
shadowProjection[2, 3] = -shadowProjection[2, 3];
}
m_shadowMatrix = shadowSpaceMatrix * shadowProjection * shadowViewMat;
Unity secara otomatis berurusan dengan bias kedalaman (Z) untuk memastikannya cocok dengan arah kedalaman Unity (Z). Namun, jika Anda menggunakan plugin rendering kode asli, Anda perlu mengabaikan kedalaman (kebalikan) (Z) bias dalam kode C++ Anda.