Xuất phát từ một nền tảng thiết kế đồ họa, một giải pháp tôi thường sử dụng để làm cho hình ảnh mờ xuất hiện sắc nét hơn là che phủ nhiễu. Tất nhiên, thêm tiếng ồn ngẫu nhiên có vẻ không tốt. Tiếng ồn phải liên quan đến vật liệu cơ bản. Trường hợp cổ điển đang làm cho một vật liệu trông phong hóa trong Photoshop bằng cách sử dụng họa tiết grunge và đặt các lớp của chúng thành bội / dodge / burn / vv.
Vì vậy, làm thế nào để chúng ta lấy hình ảnh được xuất ra bởi trình tạo bóng FXAA và trích xuất một số nhiễu có liên quan? Một lần nữa, Photoshop có câu trả lời. Một số hiệu ứng lâu đời nhất trong chương trình như làm mờ, làm sắc nét, trích xuất cạnh và chạm nổi được tạo ra với cái được gọi là ma trận chập.
Ma trận mà chúng ta quan tâm có nhiều tên khác nhau, mặc dù tôi luôn biết nó là "chiết xuất cạnh" và nó trông như thế này:
0, 0, 0
-1, 1, 0
0, 0, 0
Để áp dụng hiệu ứng này, chúng tôi muốn lấy đầu ra của trình đổ bóng FXAA làm đầu vào và hiển thị một hình tứ giác toàn màn hình. Sau đó, trong shader mảnh, chúng tôi lấy mẫu 9 texels với vị trí mảnh ở trung tâm. Nhân mỗi màu được lấy mẫu với số tương ứng trong ma trận, sau đó cộng tất cả các mẫu nhân này lại với nhau. Dưới đây là một shader mảnh mẫu được viết bằng GLSL để đạt được điều này:
#version 330 core
out vec4 out_colour;
uniform sampler2D blit_map;
uniform vec2 screen_size;
void main()
{
vec4 sum = vec4(0.0);
vec2 offset[9] = vec2[](vec2(-1.0, 1.0), vec2(0.0, 1.0), vec2(1.0, 1.0),
vec2(-1.0, 0.0), vec2(0.0, 0.0), vec2(1.0, 0.0),
vec2(-1.0, -1.0), vec2(0.0, -1.0), vec2(1.0, -1.0));
float kernel[9] = float[](0.0, 0.0, 0.0,
-1.0, 1.0, 0.0,
0.0, 0.0, 0.0);
for (int i = 0; i < 9; i++)
{
vec4 colour = texture2D(blit_map, (gl_FragCoord.xy + offset[i]) / screen_size);
sum += colour * kernel[i];
}
out_colour = sum;
}
Nếu tất cả diễn ra chính xác, bạn nên kết thúc với một cái gì đó trông như thế này (hình ảnh ban đầu là một địa hình cỏ được lập bản đồ chiều cao với một số cây):
Bây giờ chúng tôi có một số nhiễu liên quan đến hình ảnh bên dưới của chúng tôi, vì vậy, hãy thêm nó trở lại vào đầu ra ban đầu mà chúng tôi nhận được từ trình đổ bóng FXAA.
#version 330 core
out vec4 out_colour;
uniform sampler2D blit_map;
uniform vec2 screen_size;
void main()
{
vec4 sum = vec4(0.0);
vec2 offset[9] = vec2[](vec2(-1.0, 1.0), vec2(0.0, 1.0), vec2(1.0, 1.0),
vec2(-1.0, 0.0), vec2(0.0, 0.0), vec2(1.0, 0.0),
vec2(-1.0, -1.0), vec2(0.0, -1.0), vec2(1.0, -1.0));
float kernel[9] = float[](0.0, 0.0, 0.0,
-1.0, 1.0, 0.0,
0.0, 0.0, 0.0);
for (int i = 0; i < 9; i++)
{
vec4 colour = texture2D(blit_map, (gl_FragCoord.xy + offset[i]) / screen_size);
sum += colour * kernel[i];
}
float sharpen_amount = 0.25;
out_colour = (sum * sharpen_amount) + texture2D(blit_map, gl_FragCoord.xy / screen_size);
}
Bạn sẽ lưu ý rằng chúng tôi cũng đã chia tỷ lệ trước khi thêm nó vào màu gốc. Độ mờ do FXAA gây ra rất tinh tế, do đó độ sắc nét cũng phải tinh tế để bạn muốn giữ mức độ sắc nét thấp.
Bây giờ bạn có thể nhận thấy rằng shader này không rẻ như nó có thể. Có chín tra cứu kết cấu, hầu hết trong số đó không thêm gì vào hình ảnh cuối cùng khi chúng được nhân với số không. Bước cuối cùng, hãy tối ưu hóa trình đổ bóng.
#version 330 core
out vec4 out_colour;
uniform sampler2D blit_map;
uniform vec2 screen_size;
void main()
{
vec4 colour = texture2D(blit_map, gl_FragCoord.xy / screen_size);
vec4 sum = colour + (texture2D(blit_map, (gl_FragCoord.xy + vec2(-1.0, 0.0)) / screen_size) * -1.0);
out_colour = (sum * 0.25) + colour;
}