Blending and Unity Terrain: cara menyingkirkan persimpangan dan berhenti membuat mata Anda sakit

Untuk mendapatkan dunia yang realistis di dalam permainan, perlu untuk mempertimbangkan interaksi berbagai bentuk lahan satu sama lain dan dengan model lainnya. Dan jika garis persimpangan yang terlihat antara model 3D merusak integritas gambar, ada baiknya mempertimbangkan cara menghilangkannya. Kasus paling umum dari garis-garis tersebut, yang mungkin akrab bagi banyak orang, adalah persimpangan papan-papan partikel dengan geometri buram.

gambar

Contoh lain adalah komposisi alami yang mengganggu dari persimpangan bebatuan dan vegetasi dengan permukaan lanskap dalam adegan-adegan “di luar”.

gambar

Selain berbagai metode penghalusan (SSAA, MSAA, CSAA, FXAA, NFAA, CMAA, DLAA, TAA, dll.), Yang walaupun mengurangi tampilan garis persimpangan yang menantang, tetapi tidak sepenuhnya memperbaiki situasi, ada teknik yang lebih efektif. Kami akan mempertimbangkannya.

Pencampuran kedalaman


Unity memiliki solusi bawaan untuk menghilangkan persimpangan yang terlihat antara partikel transparan dan geometri buram yang disebut partikel lunak. Shader yang mendukung efek ini semakin meningkatkan transparansi partikel, tergantung pada seberapa kecil perbedaan antara kedalaman fragmen partikel dan kedalaman geometri buram.

gambar
Prinsip pengoperasian partikel lunak

Jelas, untuk operasi partikel lunak yang benar, diperlukan penyangga dalam. Dalam kasus penangguhan yang ditangguhkan, buffer kedalaman dibentuk pada tahap render buffer layar penuh, dan dengan mempertimbangkan MRT (Target Ganda, bukan Tomografi Resonansi Magnetik), keberadaannya tidak dinyatakan dalam biaya komputasi tambahan.

Dalam kasus shading ke depan dan menggunakan Unity Legacy Pipeline, diperlukan pass tambahan untuk membuat geometri buram ke buffer kedalaman [1] . Lulus ini diaktifkan dengan menetapkan nilai yang sesuai ke properti Camera.depthTextureMode. Properti ini tidak tersedia di jendela inspektur, tetapi tersedia di API [2] .

Sekarang Anda dapat mengimplementasikan versi Anda sendiri dari Scriptable Render Pipeline dengan forward shading, yang dengan bantuan MRT secara bersamaan dapat membuat baik buffer kedalaman maupun buffer warna.


Menghilangkan garis persimpangan dalam shader yang mendukung partikel lunak

Secara umum, tidak ada kendala teknis untuk menggunakan metode pencampuran kedalaman untuk menghilangkan persimpangan terlihat model 3D dengan lanskap:

Lihat kode
// Blending with depth buffer

#include "UnityCG.cginc"

float BlendStart;
float BlendEnd;
UNITY_DECLARE_DEPTH_TEXTURE(_CameraDepthTexture);

struct v2f
{
    // ...

    half4 projPos : TEXCOORD0;
};

v2f vert(appdata v)
{
    v2f o;
    UNITY_INITIALIZE_OUTPUT(v2f,o);

    // ...

    o.projPos = ComputeScreenPos(o.pos);
    COMPUTE_EYEDEPTH(o.projPos.z);

    // ...

    return o;
}

fixed4 frag(v2f i) : COLOR
{     
    fixed4 result = 0;
      
    // ... 

    float depth = SAMPLE_DEPTH_TEXTURE_PROJ(_CameraDepthTexture, UNITY_PROJ_COORD(i.projPos));
    float sceneZ = LinearEyeDepth(depth);
    float partZ = i.projPos.z;
    float fade = saturate( sceneZ - partZ );
    result.a = smoothstep( BlendStart, BlendEnd, fade );

    // ... 
       
    return result; 
}


Namun, pendekatan ini memiliki beberapa kelemahan.

Kelemahan pertama terkait dengan kinerja. Pencampuran kedalaman bekerja pada tahap pencampuran pipa perangkat keras, yaitu segera setelah rasterisasi dan perhitungan shader fragmen. Pada tahap ini, hasil dari eksekusi shader fragmen dicampur dengan hasil yang direkam dalam buffer output [3] [4] [5] sesuai dengan formula yang ditentukan oleh panggilan ke API [6] [7] [8] [9] .

Ini adalah bagian paling tidak progresif dari setiap pipa perangkat keras dalam arti bahwa ia bekerja persis seperti pendahulunya bekerja dua puluh tahun yang lalu. GPU membaca nilai dari memori, mencampurnya dengan nilai fragmen shader, dan menulisnya kembali ke memori.

Ada juga perbedaan apakah akan menggunakan pencampuran dalam untuk model 3D yang sepenuhnya transparan atau sebagian transparan. Transparan - misalnya, papan iklan partikel - bahkan tanpa memadukan secara mendalam, seluruh render transparan. Dalam kasus model 3D yang buram, transparansi yang nyata, nyata, terlihat ketika pencampuran secara mendalam akan hanya memiliki jumlah fragmen yang sangat kecil, sementara sebagian besar dari mereka akan tetap buram. Tetapi yang terakhir tidak berarti sama sekali bahwa pencampuran tidak akan digunakan untuk rendering mereka - itu hanya akan bekerja menganggur.

Kelemahan kedua terkait dengan bagaimana warna untuk pencampuran dipilih. Singkatnya, maka semua fragmen yang tercampur dalam piksel layar tertentu terletak pada satu sinar yang berasal dari posisi dunia kamera dan melewati posisi dunia piksel layar ini. Ini, pada gilirannya, berarti bahwa dengan perubahan posisi atau orientasi kamera, paralaks akan diamati: fragmen model 3D yang terletak lebih dekat ke kamera akan bergerak lebih cepat daripada fragmen lanskap yang terletak lebih jauh dari kamera [10] [11] . Ini terutama terlihat ketika dilihat dari jarak dekat dengan perpindahan lateral kamera yang konstan.


Paralaks lateral saat menggerakkan kamera: fragmen dari model 3D digeser ke jarak yang lebih besar dibandingkan dengan fragmen lanskap


Parallax lateral saat menggerakkan kamera: ketika memperbaiki kamera pada sebuah fragmen lanskap, menjadi terlihat seberapa cepat fragmen model bergerak.

Ketika kamera diputar, paralaks diamati langsung di sepanjang dua sumbu koordinat layar. Namun, dalam dinamika ini kurang jelas dibandingkan paralaks lateral.


Paralaks azimuthal ketika kamera digeser: lebih sulit bagi otak untuk mengenali pola paralaks ketika fragmen digeser sepanjang dua

sumbu. Namun yang paling mencolok, penampilan pencampuran pada kedalaman berubah tergantung pada sudut di mana pengamat melihat permukaan lanskap. Zona pencampuran menjadi hampir tidak terlihat ketika arah pandang tegak lurus dengan normal ke permukaan lanskap, tetapi ukuran zona ini meningkat dengan cepat jika Anda memiringkan kamera ke bawah.


Mengubah lebar zona pencampuran saat memiringkan kamera

secara mendalam Pencampuran mungkin merupakan opsi yang baik untuk menghilangkan garis persimpangan model 3D dengan lanskap, jika bukan karena banyaknya artefak yang menyertainya. Metode ini lebih cocok untuk efek partikel yang tidak statis dan, sebagai aturan, tidak mengandung tekstur yang sangat rinci, oleh karena itu, efek paralaks tidak diamati dalam kasus mereka.


Pencampuran Peta Tinggi


Pilihan lain untuk menerapkan pencampuran lanskap adalah menggunakan peta ketinggian, yang Unity menyediakan akses melalui API TerrainData [12] .

Mengetahui posisi objek Medan dan dimensi medan yang ditunjukkan dalam TerrainData, dan memiliki "peta ketinggian" di tangan, Anda dapat menghitung ketinggian medan di titik mana pun yang ditentukan dalam koordinat dunia.


Parameter medan diperlukan untuk pengambilan sampel peta ketinggian

// Setting up a heightmap and uniforms to use with shaders... 

Shader.SetGlobalTexture(Uniforms.TerrainHeightmap, terrain.terrainData.heightmapTexture);
Shader.SetGlobalVector(Uniforms.HeightmapScale, terrain.terrainData.heightmapScale);
Shader.SetGlobalVector(Uniforms.TerrainSize, terrain.terrainData.size);
Shader.SetGlobalVector(Uniforms.TerrainPos, terrain.transform.position);

Nah, sekarang, setelah menghitung ketinggian lanskap, Anda juga dapat menghitung koordinat uv di shader untuk mencicipi peta ketinggian lanskap di koordinat dunia.

// Computes UV for sampling terrain heightmap... 

float2 TerrainUV(float3 worldPos)
{
    return (worldPos.xz - TerrainPos.xz) / TerrainSize.xz;
}

Agar dapat menggunakan kode yang sama dalam fragmen dan vertex shader, fungsi tex2Dlod digunakan untuk pengambilan sampel. Selain itu, peta ketinggian tidak memiliki level mip, jadi pengambilan sampel dengan fungsi tex2D, yang secara otomatis menghitung level mip, pada dasarnya tidak ada artinya.

// Returns the height of terrain at a given position in world space... 

float TerrainHeight(float2 terrainUV)
{
    float heightmapSample = tex2Dlod(TerrainHeightmap, float4(terrainUV,0,0));
    return TerrainPos.y + UnpackHeightmap(heightmapSample) * HeightmapScale.y * 2;
}

Anda dapat mencoba mereproduksi penghapusan persimpangan melalui transparansi tanpa menggunakan buffer kedalaman. Ini tidak menyelesaikan masalah lain yang terkait dengan metode ini, tetapi memungkinkan untuk memverifikasi pengoperasian blending menggunakan peta ketinggian.

Lihat kode
// Blending with terrain heightmap

#include "UnityCG.cginc"

float BlendStart;
float BlendEnd;

sampler2D_float TerrainHeightmap; 
float4 HeightmapScale;
float4 TerrainSize;
float4 TerrainPos;        

struct v2f
{
   // ...

   float3 worldPos : TEXCOORD0;
   float2 heightMapUV : TEXCOORD1;

   // ...
};


v2f vert(appdata v)
{
    v2f o;
    UNITY_INITIALIZE_OUTPUT(v2f,o);
   
    // ...
    
    o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
    o.heightMapUV = TerrainUV(o.worldPos);

    // ...

    return o;
}

fixed4 frag(v2f i) : COLOR
{
    fixed4 result = 0;

    // ... 

    half height = TerrainHeight(i.heightMapUV);
    half deltaHeight = i.worldPos.y - height;
    result.a = smoothstep( BlendStart, BlendEnd, deltaHeight );

    // ... 
       
    return result; 
}





Kedalaman pencampuran dan pencampuran ketinggian. Lebar zona pencampuran berbeda dengan parameter shader yang sama.

Ilustrasi menggunakan parameter pencampuran identik untuk kedua metode. Lebar zona pencampuran secara visual berbeda, karena pencampuran dengan peta ketinggian tidak tergantung pada sudut antara pandangan pengamat dan normal ke lanskap.

Memadukan dengan peta ketinggian setidaknya dalam satu hal lebih baik daripada memadukan secara mendalam: memadukan ketergantungan pencampuran yang terlihat dengan mata telanjang pada sudut di mana kamera melihat lanskap. Sayangnya, efek paralaks masih akan diamati.


Pencampuran rekonstruksi lansekap


Untuk menghilangkan paralaks, Anda perlu mencampur fragmen model 3D dengan fragmen lanskap yang secara vertikal di bawahnya (pemilihan warna untuk pencampuran dalam hal ini tidak tergantung pada posisi dan orientasi kamera).


Cara memperbaiki paralaks: memilih fragmen lanskap untuk dicampur

Tentu saja, kita berbicara lebih banyak tentang fragmen lanskap virtual. Tergantung pada posisi kamera, situasi mungkin terjadi ketika sebuah fragmen lanskap, yang dengannya diperlukan untuk mencampur fragmen model 3D, bahkan tidak akan jatuh ke bidang pandang kamera. Masalah serupa ada dalam rendering refleksi lokal di ruang layar (SSLR). Ini terdiri dari fakta bahwa tidak mungkin untuk membuat refleksi dari sebuah fragmen yang tidak ada di layar [13] .

Dalam kasus lanskap, warna fragmen virtual dapat direkonstruksi dengan akurasi tinggi menggunakan tekstur tambahan yang disediakan oleh Unity API: peta normal [14] , peta cahaya [15] , tekstur tertimbang untuk lapisan campuran [16] , dan tekstur yang termasuk dalam komposisi lapisan [17] .


Rekonstruksi fragmen lanskap

Semua tekstur yang membentuk lanskap disampel menurut UV yang sama dengan peta ketinggian. Dalam kasus lapisan, koordinat untuk pengambilan sampel disesuaikan dengan parameter ubin yang ditentukan untuk lapisan tertentu [18] [19] .

Lihat kode
// Blending with reconstructed terrain fragments

#include "UnityCG.cginc"

float BlendStart;
float BlendEnd;

sampler2D_float TerrainHeightmapTexture;
sampler2D_float TerrainNormalTexture;
sampler2D TerrainAlphaMap;

float4 HeightmapScale;
float4 TerrainSize;
float4 TerrainPos;
Float4 TerrainLightmap_ST;

UNITY_DECLARE_TEX2D(TerrainSplatMap0);
UNITY_DECLARE_TEX2D_NOSAMPLER(TerrainNormalMap0);
half4 TerrainSplatMap0_ST;

UNITY_DECLARE_TEX2D(TerrainSplatMap1);
UNITY_DECLARE_TEX2D_NOSAMPLER(TerrainNormalMap1);
half4 TerrainSplatMap1_ST;

UNITY_DECLARE_TEX2D(TerrainSplatMap2);
UNITY_DECLARE_TEX2D_NOSAMPLER(TerrainNormalMap2);
half4 TerrainSplatMap2_ST;

UNITY_DECLARE_TEX2D(TerrainSplatMap3);
UNITY_DECLARE_TEX2D_NOSAMPLER(TerrainNormalMap3);
half4 TerrainSplatMap3_ST;

struct v2f
{
   // ...

   float3 worldPos : TEXCOORD0;
   float2 heightMapUV : TEXCOORD1;
#if defined(LIGHTMAP_ON)
   float2 modelLightMapUV : TEXCOORD2;
   float2 terrainLightMapUV : TEXCOORD3;
#endif

   // ...
};


v2f vert(appdata v)
{
    v2f o;
    UNITY_INITIALIZE_OUTPUT(v2f,o);
   
    // ...
    
    o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
    o.heightMapUV = TerrainUV(o.worldPos);

#if defined(LIGHTMAP_ON)
    o.modelLightMapUV = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
    o.terrainLightMapUV = o.heightMapUV * TerrainLightmap_ST.xy + TerrainLightmap_ST.zw;
#endif

    // ...

    return o;
}
half3 TerrainNormal(float2 terrainUV)
{
    return tex2Dlod( TerrainNormalTexture, float4(terrainUV,0,0) ).xyz * 2.0 - 1.0;
}

half4 TerrainSplatMap(float2 uv0, float2 uv1, float2 uv2, float2 uv3, half4 control)
{
    half4 splat0 = UNITY_SAMPLE_TEX2D_SAMPLER(TerrainSplatMap0, TerrainSplatMap0, uv0);
    half4 splat1 = UNITY_SAMPLE_TEX2D_SAMPLER(TerrainSplatMap1, TerrainSplatMap1, uv1);
    half4 splat2 = UNITY_SAMPLE_TEX2D_SAMPLER(TerrainSplatMap2, TerrainSplatMap2, uv2);
    half4 splat3 = UNITY_SAMPLE_TEX2D_SAMPLER(TerrainSplatMap3, TerrainSplatMap3, uv3);         
    half4 result = splat0 * control.r + 
                   splat1 * control.g + 
                   splat2 * control.b + 
                   splat3 * control.a;
    return result;
}

half3 TerrainNormalMap(float2 uv0, float2 uv1, float2 uv2, float2 uv3, half4 control)
{
    half4 n0 = UNITY_SAMPLE_TEX2D_SAMPLER(TerrainNormalMap0, TerrainSplatMap0, uv0);
    half4 n1 = UNITY_SAMPLE_TEX2D_SAMPLER(TerrainNormalMap1, TerrainSplatMap1, uv1);
    half4 n2 = UNITY_SAMPLE_TEX2D_SAMPLER(TerrainNormalMap2, TerrainSplatMap2, uv2);
    half4 n3 = UNITY_SAMPLE_TEX2D_SAMPLER(TerrainNormalMap3, TerrainSplatMap3, uv3);
    half3 result = UnpackNormalWithScale(n0, 1.0) * control.r +
                   UnpackNormalWithScale(n1, 1.0) * control.g +
                   UnpackNormalWithScale(n2, 1.0) * control.b +
                   UnpackNormalWithScale(n3, 1.0) * control.a;
    result.z += 1e-5;
    return result;
}

half3 TerrainLightmap(float2 uv, half3 normal)
{
#if defined(LIGHTMAP_ON)
#if defined(DIRLIGHTMAP_COMBINED)
    half4 lm = UNITY_SAMPLE_TEX2D(unity_Lightmap, uv);
    half4 lmd = UNITY_SAMPLE_TEX2D_SAMPLER(unity_LightmapInd, unity_Lightmap, uv);
    half3 result = DecodeLightmapRGBM(lm, unity_Lightmap_HDR);
    result = DecodeDirectionalLightmap(result, lmd, normal);
#else
    half4 lm = UNITY_SAMPLE_TEX2D(unity_Lightmap, uv);
    half3 result = DecodeLightmapRGBM(lm, unity_Lightmap_HDR);
#endif                
#else
    half3 result = UNITY_LIGHTMODEL_AMBIENT.rgb;
#endif
    return result;
}

fixed4 frag(v2f i) : COLOR
{
    fixed4 result = 0;

    // ...

    // compute model color and put it to the result

    // ... 

    // reconstruction of terrain fragment

    float2 splatUV0 = TRANSFORM_TEX(i.heightMapUV, TerrainSplatMap0);
    float2 splatUV1 = TRANSFORM_TEX(i.heightMapUV, TerrainSplatMap1);
    float2 splatUV2 = TRANSFORM_TEX(i.heightMapUV, TerrainSplatMap2);
    float2 splatUV3 = TRANSFORM_TEX(i.heightMapUV, TerrainSplatMap3);

    half4 control = tex2D(_TerrainAlphaMap, i.heightMapUV);
    half4 terrainColor = TerrainSplatMap(splatUV0, splatUV1, splatUV2, splatUV3, control);

    half3 terrainSurfaceNormal = TerrainNormal(i.heightMapUV);
    half3 terrainSurfaceTangent = cross(terrainSurfaceNormal, float3(0,0,1));
    half3 terrainSurfaceBitangent = cross(terrainSurfaceTangent, terrainSurfaceNormal);

    half3 terrainNormal = TerrainNormalMap(splatUV0, splatUV1, splatUV2, splatUV3, control);
    terrainNormal = terrainNormal.x * terrainSurfaceTangent + 
                    terrainNormal.y * terrainSurfaceBitangent + 
                    terrainNormal.z * terrainSurfaceNormal;
    
    half3 terrainLightmapColor = TerrainLightmap(i.heightMapUV, terrainNormal);
    terrainColor *= terrainLightmapColor;

    // blend model color & terrain color

    half height = TerrainHeight(i.heightMapUV);
    half deltaHeight = i.worldPos.y - height;
    half blendingWeight = smoothstep(BlendStart, BlendEnd, deltaHeight);

    result.rgb = lerp(result.rgb, terrainColor, blendingFactor);
       
    return result; 
}


Jadi, pencampuran dengan rekonstruksi fragmen lanskap memperbaiki semua masalah yang khas untuk pencampuran kedalaman dan pencampuran dengan peta ketinggian, termasuk paralaks.



Pencampuran rekonstruksi lansekap


Kinerja rekonstruksi fragmen medan


Pada titik ini, saatnya bertanya, apa nilai kompromi semacam ini? Sekilas, intensitas sumber daya merekonstruksi fragmen lanskap jauh melebihi intensitas sumber daya pencampuran alfa. Untuk rekonstruksi perlu dilakukan dengan selusin operasi baca tambahan dari memori. Untuk alpha blending, Anda hanya perlu satu operasi baca dari memori dan satu operasi tulis ke memori.

Pada kenyataannya, semuanya akan tergantung pada fitur platform perangkat keras. Rekonstruksi fragmen didukung oleh kompresi tekstur, pemetaan mip, kekuatan pemrosesan inti GPU, dan optimisasi pipa perangkat keras tertentu (penolakan kedalaman awal). Dan melawan alpha-blending, fakta yang telah disebutkan di atas akan menunjukkan bahwa itu adalah bagian yang paling tidak progresif dari GPU mana pun.

Namun, selalu ada ruang untuk optimasi. Misalnya, dalam kasus rekonstruksi warna lanskap, kebutuhan untuk rekonstruksi ini hanya untuk potongan sempit fragmen model 3D yang terletak tidak lebih tinggi dari ketinggian tertentu di atas permukaan lanskap.

Percabangan dinamis dalam shader dapat memberikan hasil kinerja yang buruk, tetapi ada dua hal yang harus diperhitungkan:

  1. Melewati perhitungan yang tidak perlu dalam percabangan dengan suatu kondisi harus dilakukan jika kondisi ini tidak dipenuhi dalam sebagian besar kasus.
  2. . , ( , ), GPU. ― (branch granularity), , , , , . , , . , GPU , , . , GPU, , 1 (PowerVR SGX).


Visualisasi berbagai tingkat koherensi

Dalam kasus rekonstruksi fragmen, kedua poin ini diperhitungkan: kondisi percabangan dalam kebanyakan kasus akan memungkinkan untuk memotong implementasi operasi intensif sumber daya untuk merekonstruksi warna lanskap, dan kondisi ini koheren, dengan pengecualian sejumlah kecil fragmen (dalam ilustrasi, fragmen-fragmen yang terletak pada di perbatasan antara zona "merah" dan "hijau").


Koherensi rekonstruksi fragmen lanskap

Masih ditambahkan beberapa komentar mengenai metode campuran ini:

  1. Unity menyediakan semua tekstur yang diperlukan hanya jika lanskap telah mengaktifkan mode Draw Instanced [20] , jika tidak, peta normal tidak akan tersedia, yang, pada gilirannya, tidak akan memungkinkan Anda untuk merekonstruksi pencahayaan lanskap dengan benar untuk pencampuran.
  2. Unity API , (base map) . - .
  3. , API (, Metal 16 ).
  4. 3D- , Terrain, SRP.
  5. 3D- , 3D- .
  6. , «» , «» . , «» , . «» .






Saat merancang model 3D, tidak mungkin untuk memperhitungkan variasi relief medan yang digunakan oleh model ini. Seringkali, model 3D harus sangat "tenggelam" dalam lanskap atau diputar untuk menyembunyikan bagian yang menonjol, atau sebaliknya - untuk menunjukkan yang tersembunyi yang harus terlihat. "Pemanasan" model membatasi penerapannya, dan jika model 3D diberikan lebih awal dari lanskap, itu juga mengarah pada efek penarikan berlebih. Gilirannya, pada gilirannya, juga jauh dari cocok untuk semua model 3D (misalnya, bukan untuk rumah dan pohon).


Untuk menyembunyikan elemen yang menonjol dari model 3D, itu harus "tenggelam" di lanskap

Gertakan adalah istilah yang akrab bagi pengguna editor grafis. Ini adalah fungsi yang memungkinkan titik kontrol untuk "menempel" ke node grid spasial, dan dalam editor 3D ke wajah dan permukaan objek lainnya. Memotret peta ketinggian lanskap di vertex shader dapat sangat menyederhanakan desain pemandangan.


Model 3D tanpa gertakan. Model 3D dengan vertex gertakan. Model 3D dengan vertex snapping dan blending. Model 3D dengan vertex snapping, blending dan pencahayaan statis

Kesulitan utama dalam mengimplementasikan gertakan adalah bahwa Anda perlu mengetahui simpul model 3D mana yang harus Anda jepret ke peta ketinggian, dan mana yang tidak sepadan. Vertex hanya berisi informasi tentang sifat lokal permukaan (yang tidak cukup) dan tidak mengandung informasi apa pun tentang topologinya (yang diperlukan).

Seperti dalam kasus aplikasi lain, masalah ini paling mudah diselesaikan pada tahap pemodelan dengan langsung menerapkan parameter yang diperlukan dalam simpul. Sebagai parameter seperti itu, Anda harus memilih atribut intuitif - misalnya, faktor bobot untuk memotret (dan bukan jarak ke batas permukaan terbuka, seperti yang kami inginkan untuk fleksibilitas).


Pembobotan Kode untuk Memotret

Lihat kode
// Per-vertex snapping with terrain heightmap

#include "UnityCG.cginc"

sampler2D_float TerrainHeightmapTexture;

float4 HeightmapScale;
float4 TerrainSize;
float4 TerrainPos;

struct v2f
{

   // ...

   float3 worldPos : TEXCOORD0;
   float2 heightMapUV : TEXCOORD1;

   // ...

};

v2f vert(appdata v)
{
    v2f o;
    UNITY_INITIALIZE_OUTPUT(v2f,o);
   
    // ...
    
    o.worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
    o.heightMapUV = TerrainUV(o.worldPos);
    float snappingWeight = v.color.r;                
    half height = TerrainHeight( o.heightMapUV );                
    o.worldPos.y = lerp( o.worldPos.y, height, snappingWeight );
    o.pos = UnityWorldToClipPos( half4( o.worldPos, 1 ) );

    // ...

    return o;
}


Penerapan vertex snapping dibatasi oleh korespondensi umum antara medan dan permukaan model 3D. Untuk mengimbangi perbedaan signifikan mereka, perlu untuk menggunakan metode lain yang lebih intensif sumber daya - misalnya, menggunakan model 3D dengan menguliti.


Kesimpulan


Gagasan utama yang harus dikeluarkan dari artikel: setiap shader yang cukup kompleks dan berpotensi scalable membutuhkan data dasar. Dan tugas pengembang adalah untuk memahami bagaimana sistem grafis dapat dioperasikan: data apa yang disediakannya, bagaimana dapat dikombinasikan satu sama lain dan bagaimana menggunakannya dalam shader.

Dalam kasus umum, kita dapat menyimpulkan bahwa satu-satunya pilihan untuk mengatasi kerangka kerja dengan mana kemungkinan efek grafis terbatas adalah untuk menggabungkan hasil dari berbagai shader.


Referensi



All Articles