Nó đã được đề xuất trong các bình luận nhiều lần, nhưng không ai cảm thấy cần phải đưa ra một câu trả lời thích hợp, vì vậy để hoàn thiện, một giải pháp đơn giản và phổ biến cho vấn đề này có thể là sử dụng kết cấu như bảng tra cứu, cụ thể là kết cấu 1D có chứa tất cả các giá trị của hàm của bạn cho phạm vi đầu vào có thể (ví dụ / ). Điều này có những lợi thế khác nhau:[ 0 , 360 )[ 0 , 2 π)
- Nó sử dụng tọa độ chuẩn hóa, tức là bạn truy cập vào kết cấu bằng cách ánh xạ các góc của bạn từ đến . Điều này có nghĩa là shader của bạn không thực sự phải quan tâm đến số lượng giá trị cụ thể . Bạn có thể điều chỉnh kích thước của nó theo bất kỳ bộ nhớ / tốc độ nào so với sự đánh đổi chất lượng mà bạn muốn (và đặc biệt là trên phần cứng cũ / nhúng mà bạn có thể muốn có sức mạnh bằng hai kích thước kết cấu).[ 0 , 360 ][ 0 , 1 ]
- Bạn nhận được lợi ích bổ sung khi không phải thực hiện điều chỉnh khoảng thời gian giống như vòng lặp của mình (mặc dù vậy, dù sao bạn cũng không cần vòng lặp và chỉ có thể sử dụng thao tác mô đun). Chỉ cần sử dụng
GL_REPEAT
làm chế độ gói cho kết cấu và nó sẽ tự động bắt đầu lại từ đầu khi truy cập với các đối số> 1 (và tương tự cho các đối số phủ định).
- Và bạn cũng nhận được lợi ích của việc nội suy tuyến tính giữa hai giá trị trong mảng về cơ bản miễn phí (hoặc giả sử gần như miễn phí) bằng cách sử dụng
GL_LINEAR
làm bộ lọc kết cấu, theo cách này nhận được các giá trị mà bạn thậm chí không lưu trữ. Tất nhiên phép nội suy tuyến tính không chính xác 100% cho các hàm lượng giác, nhưng chắc chắn tốt hơn là không nội suy.
- Bạn có thể lưu trữ nhiều hơn một giá trị trong kết cấu bằng cách sử dụng kết cấu RGBA (hoặc tuy nhiên nhiều thành phần bạn cần). Bằng cách này bạn có thể nhận được ví dụ sin và cos với một tra cứu kết cấu duy nhất.
- Đối với sin và cos, bạn chỉ cần lưu trữ các giá trị trong , dù sao bạn cũng có thể nâng cấp một cách tự nhiên từ phạm vi chuẩn hóa của định dạng điểm cố định 8 bit phổ biến. Tuy nhiên, điều đó có thể không đủ chính xác cho nhu cầu của bạn. Một số người đề xuất sử dụng các giá trị điểm nổi 16 bit, vì chúng chính xác hơn các giá trị điểm cố định 8 bit thông thường nhưng ít bộ nhớ hơn so với số float 32 bit thực. Nhưng một lần nữa, tôi cũng không biết liệu việc triển khai của bạn có hỗ trợ kết cấu dấu phẩy động hay không. Nếu không, thì có lẽ bạn có thể sử dụng 2 thành phần điểm cố định 8 bit và kết hợp chúng thành một giá trị duy nhất với một cái gì đó như (hoặc thậm chí nhiều thành phần hơn cho hạt mịn hơn). Điều này cho phép bạn kiếm lợi nhuận từ kết cấu nhiều thành phần một lần nữa.[ - 1 , 1 ][ 0 , 1 ]
float sin = 2.0 * (texValue.r + texValue.g / 256.0) - 1.0;
Tất nhiên nó vẫn phải được đánh giá nếu đây là một giải pháp tốt hơn, vì truy cập kết cấu cũng không hoàn toàn miễn phí, cũng như sự kết hợp tốt nhất của kích thước và định dạng kết cấu sẽ là gì.
Để điền vào kết cấu với dữ liệu và nhấn vào một trong những bình luận của bạn, bạn phải xem xét rằng lọc kết cấu trả về giá trị chính xác tại trung tâm texel , tức là kết cấu giảm đi một nửa kích thước texel. Vì vậy, có, bạn nên tạo các giá trị tại .5
texels , tức là một cái gì đó như thế này trong mã ứng dụng:
float texels[256];
for(unsigned int i = 0; i < 256; ++i)
texels[i] = sin((i + .5f) / 256.f) * TWO_PI);
glTexImage1D(GL_TEXTURE_1D, 0, ..., 256, 0, GL_RED, GL_FLOAT, texels);
Tuy nhiên, bạn vẫn có thể muốn so sánh hiệu suất của phương pháp này với cách tiếp cận bằng cách sử dụng một mảng thống nhất nhỏ (nghĩa là uniform float sinTable[361]
, hoặc có thể ít hơn trong thực tế, để mắt đến giới hạn thực hiện của bạn về kích thước mảng đồng nhất) mà bạn chỉ cần tải với các giá trị tương ứng bằng cách sử dụng glUniform1fv
và truy cập bằng cách điều chỉnh góc của bạn thành bằng cách sử dụng chức năng và làm tròn nó đến giá trị gần nhất:[ 0 , 360 )mod
angle = mod(angle, 360.0);
float value = sinTable[int(((angle < 0.0) ? (angle + 360.0) : angle) + 0.5)];