Sudah disarankan dalam komentar berulang kali, tetapi tidak ada yang merasa perlu untuk memberikan jawaban yang tepat, jadi demi kelengkapan, solusi langsung dan umum untuk masalah ini mungkin menggunakan tekstur sebagai tabel pencarian, khususnya tekstur 1D yang berisi semua nilai fungsi Anda untuk rentang input yang dimungkinkan (yaitu / ). Ini memiliki berbagai keunggulan:[ 0 , 2 π )[ 0 , 360 )[ 0 , 2 π)
- Itu menggunakan koordinat dinormalisasi, yaitu Anda mengakses tekstur dengan memetakan sudut Anda dari ke . Ini berarti shader Anda sebenarnya tidak perlu peduli dengan jumlah nilai tertentu . Anda dapat menyesuaikan ukurannya sesuai dengan memori / kecepatan vs pengorbanan kualitas apa pun yang Anda inginkan (dan terutama pada perangkat keras yang lebih lama / tertanam, Anda mungkin menginginkan kekuatan dua sebagai ukuran tekstur).[ 0 , 1 ][ 0 , 360 ][0,1]
- Anda mendapatkan manfaat tambahan dari tidak harus melakukan penyesuaian interval seperti loop (walaupun, Anda tidak perlu loop lagi dan hanya bisa menggunakan operasi modulus). Cukup gunakan
GL_REPEAT
sebagai mode pembungkus untuk tekstur dan itu akan secara otomatis mulai dari awal lagi ketika mengakses dengan argumen> 1 (dan juga untuk argumen negatif).
- Dan Anda juga mendapatkan manfaat interpolasi linier antara dua nilai pada dasarnya array gratis (atau katakanlah hampir gratis) dengan menggunakan
GL_LINEAR
sebagai filter tekstur, cara ini mendapatkan nilai yang Anda bahkan tidak menyimpan. Tentu saja interpolasi linier tidak 100% akurat untuk fungsi trigonometri, tetapi tentu saja lebih baik daripada tidak ada interpolasi.
- Anda dapat menyimpan lebih dari satu nilai dalam tekstur dengan menggunakan tekstur RGBA (atau seberapa banyak komponen yang Anda butuhkan). Dengan cara ini Anda bisa mendapatkan mis dosa dan cos dengan pencarian tekstur tunggal.
- Untuk sin dan cos, Anda hanya perlu menyimpan nilai dalam , yang secara alami Anda dapat naik kelas dari rentang normal dari format titik tetap 8-bit yang umum. Namun, itu mungkin tidak cukup presisi untuk kebutuhan Anda. Beberapa orang menyarankan untuk menggunakan nilai floating point 16-bit, karena nilai tersebut lebih tepat daripada nilai fixed point normal 8-bit tetapi kurang intensif memori daripada float 32-bit yang sebenarnya. Tapi sekali lagi, saya juga tidak tahu apakah implementasi Anda mendukung tekstur titik mengambang untuk memulai. Jika tidak, maka mungkin Anda dapat menggunakan 2 komponen titik tetap 8-bit dan menggabungkannya menjadi satu nilai dengan sesuatu seperti (atau bahkan lebih banyak komponen untuk gandum yang lebih halus). Ini memungkinkan Anda mendapat keuntungan dari tekstur multi-komponen lagi.[ 0 , 1 ][−1,1][0,1]
float sin = 2.0 * (texValue.r + texValue.g / 256.0) - 1.0;
Tentu saja masih harus dievaluasi jika ini adalah solusi yang lebih baik, karena akses tekstur juga tidak sepenuhnya gratis, serta kombinasi terbaik dari ukuran dan format tekstur.
Untuk mengisi tekstur dengan data dan memberikan komentar pada salah satu komentar Anda, Anda harus mempertimbangkan bahwa pemfilteran tekstur mengembalikan nilai tepat di pusat texel , yaitu tekstur terkoordinasi dengan setengah ukuran texel. Jadi ya, Anda harus menghasilkan nilai pada .5
texels , yaitu sesuatu seperti ini dalam kode aplikasi:
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);
Namun, Anda mungkin masih ingin membandingkan kinerja pendekatan ini dengan pendekatan yang menggunakan array seragam kecil (yaitu uniform float sinTable[361]
, atau mungkin kurang dalam praktiknya, perhatikan batas implementasi Anda pada ukuran array seragam) yang baru saja Anda muat dengan nilai masing-masing menggunakan glUniform1fv
dan akses dengan menyesuaikan sudut Anda ke menggunakan fungsi dan membulatkannya ke nilai terdekat:[0,360)mod
angle = mod(angle, 360.0);
float value = sinTable[int(((angle < 0.0) ? (angle + 360.0) : angle) + 0.5)];