Mengambil contoh Anda, Anda memiliki fungsi langkah jarak, yang menghasilkan tepi yang sangat keras (alias). Cara sederhana untuk antialias lingkaran adalah mengubahnya menjadi ambang lunak, seperti:
float distFromEdge = 1.0 - dist; // positive when inside the circle
float thresholdWidth = 0.01; // a constant you'd tune to get the right level of softness
float antialiasedCircle = saturate((distFromEdge / thresholdWidth) + 0.5);
return lerp(outsideColor, insideColor, antialiasedCircle);
Di sini saya menggunakan jalan linear dijepit untuk fungsi ambang lunak, tetapi Anda juga bisa menggunakan smoothstep
atau sesuatu yang lain. The + 0.5
adalah untuk pusat jalan di lokasi matematika dari tepi. Pokoknya, intinya adalah bahwa fungsi ini dengan lancar berubah dari outsideColor
ke insideColor
beberapa rentang jarak, jadi jika Anda memilih dengan thresholdWidth
tepat, Anda akan mendapatkan tepi yang tampak antialiased.
Tetapi bagaimana Anda memilih thresholdWidth
? Jika terlalu kecil, Anda akan mendapatkan aliasing lagi, dan jika terlalu besar ujungnya akan terlalu buram. Selain itu, umumnya akan tergantung pada posisi kamera: jika dist
diukur dalam ruang dunia atau unit ruang tekstur, maka thresholdWidth
yang bekerja untuk satu posisi kamera akan salah untuk yang lain.
Di sinilah turunan layar-ruang masuk (ya, mereka adalah ddx
dan ddy
berfungsi seperti yang Anda duga). Dengan menghitung panjang gradien dist
Anda bisa mendapatkan ide seberapa cepat itu berubah dalam ruang layar dan menggunakannya untuk memperkirakan thresholdWidth
, seperti:
float derivX = ddx(distFromEdge);
float derivY = ddy(distFromEdge);
float gradientLength = length(float2(derivX, derivY));
float thresholdWidth = 2.0 * gradientLength; // the 2.0 is a constant you can tune
Anda masih memiliki nilai yang dapat Anda sesuaikan untuk mendapatkan tingkat kelembutan yang diinginkan, tetapi sekarang Anda harus mendapatkan hasil yang konsisten terlepas dari posisi kamera.
derivX
danderivY
sebenarnya mewakili.