Lấy ví dụ của bạn, bạn có một hàm bước của khoảng cách, tạo ra một cạnh hoàn toàn cứng (bí danh). Một cách đơn giản để chống lại vòng tròn sẽ là biến nó thành một ngưỡng mềm, như:
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);
Ở đây tôi đã sử dụng đoạn đường nối được kẹp cho hàm ngưỡng mềm, nhưng bạn cũng có thể sử dụng smoothstephoặc một cái gì đó khác. Đây + 0.5là để tập trung các đoạn đường nối vào vị trí toán học của cạnh. Dù sao, vấn đề là chức năng này trơn tru thay đổi từ outsideColorđến insideColorqua một số phạm vi khoảng cách, vì vậy nếu bạn chọn thresholdWidthmột cách thích hợp bạn sẽ nhận được một cạnh chống răng cưa nhìn.
Nhưng bạn nên chọn thresholdWidthnhư thế nào? Nếu nó quá nhỏ, bạn sẽ lại bị răng cưa và nếu nó quá lớn thì cạnh sẽ bị mờ quá mức. Ngoài ra, thông thường sẽ phụ thuộc vào vị trí camera: nếu distđược đo bằng đơn vị không gian thế giới hoặc không gian kết cấu, thì một thresholdWidthvị trí hoạt động cho một vị trí camera sẽ bị sai đối với vị trí khác.
Đây là nơi các dẫn xuất không gian màn hình xuất hiện (vâng, chúng là ddxvà các ddychức năng như bạn đoán). Bằng cách tính toán độ dài của độ dốc, distbạn có thể biết được tốc độ thay đổi trong không gian màn hình và sử dụng điều đó để ước tính thresholdWidth, như:
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
Bạn vẫn có một giá trị bạn có thể điều chỉnh để có được mức độ mềm mong muốn, nhưng bây giờ bạn sẽ nhận được kết quả nhất quán bất kể vị trí máy ảnh.
derivXvàderivYthực sự đại diện.