_gl.bindBuffer(_gl.ARRAY_BUFFER, buffer); Float32Array (bucu), _gl.STATIC_DRAW);
Izinkan saya menerangkan secara ringkas program ini dahulu ialah tatasusunan yang menyimpan bucu Di sini, 1000 bucu dijana secara rawak Kerana setiap bucu mempunyai tiga koordinat: x, y dan z, tatasusunan 3000 diperlukan Perintah _gl.createBuffer membuka penimbal dalam memori video untuk menyimpan data puncak, dan kemudian menggunakan _gl.bufferData untuk memindahkan salinan data puncak yang dijana daripada memori ke memori video. Diandaikan di sini bahawa terdapat 1000 objek dengan 1000 bucu setiap puncak adalah 3 data apungan 32 bit dan 4 bait Selepas pengiraan, ia hampir 1000 x 1000 x 12 = 11M data. Masa 15ms, di sini anda mungkin melihat bahawa 15ms hanyalah jumlah masa yang begitu kecil, tetapi untuk program masa nyata, jika anda ingin memastikan kadar bingkai 30fps, masa yang diperlukan untuk setiap bingkai harus dikawal pada kira-kira 30ms, yang hanya untuk melakukan data sekali. Penghantaran hanya mengambil separuh masa Anda mesti tahu bahawa kepala besar harus menjadi operasi lukisan dalam GPU dan pelbagai pemprosesan dalam CPU.
Jadi bilangan penghantaran dalam langkah ini harus diminimumkan, sebenarnya, semua data puncak dan data tekstur boleh dipindahkan dari memori ke memori video sebaik sahaja ia dimuatkan . Pertama Pada masa ini, data puncak objek (Geometri) yang perlu dilukis dipindahkan ke memori paparan, dan penimbal dicache ke geometri.__webglVertexBuffer Selepas itu, atribut verticesNeedUpdate Geometri akan dinilai setiap kali ia dilukis. Jika tiada kemas kini diperlukan, cache semasa akan digunakan secara langsung , jika anda melihat bahawa vertexNeedUpate adalah benar, data puncak dalam Geometri akan dihantar semula ke geometri.__webglVertexBuffer Secara amnya, kami tidak memerlukan langkah ini untuk objek statik, tetapi jika kita menemui objek yang bucunya kerap berubah, contohnya, gunakan sistem Zarah yang menggunakan bucu sebagai zarah, dan Mesh yang menggunakan animasi rangkanya akan menukar bucunya setiap bingkai, jadi mereka perlu menetapkan sifat verticesNeedUpdate mereka kepada benar setiap bingkai untuk memberitahu pemapar bahawa saya perlu menghantar semula data.
Malah, dalam program WebGL, kedudukan bucu kebanyakannya ditukar dalam pelorek puncak untuk melengkapkan kesan zarah dan animasi rangka Walaupun ia lebih mudah untuk dikembangkan jika dikira pada bahagian CPU, disebabkan oleh had kuasa pengkomputeran JavaScript , Kebanyakan operasi intensif pengiraan ini akan dilakukan pada bahagian GPU. Dalam kes ini, tidak perlu menghantar semula data puncak, jadi kes di atas sebenarnya tidak banyak digunakan dalam program sebenar Lebih kerap, cache tekstur dan bahan akan dikemas kini.
Kes di atas terutamanya menerangkan adegan penghantaran data puncak Selain data puncak, terdapat juga sebahagian besar tekstur format R8G8B8A8 saiz 1024*1024 akan menduduki sehingga 4M memori. contoh berikut
var canvas = document. createElement('canvas');
var _gl = canvas.getContext('experimental-webgl'); img. onload = function(){
console.profile('texture test');
bindTexture(); src = 'test_tex.jpg';
function bindTexture(){
_gl.bindTexture(_gl.TEXTURE_2D, texture;
_gl.texImage2D(_gl.TEXTURE_2D, 0. , _gl .UNSIGNED_BYTE, img);
}
Tidak perlu mengulanginya 1000 kali di sini. Ia mengambil masa 30ms untuk menghantar tekstur 10241024 sekali, dan hampir 2ms untuk tekstur 256256. Oleh itu, dalam three.js, tekstur hanya dihantar sekali pada permulaan. maka jika sifat texture.needsUpdate tidak ditetapkan secara manual kepada benar, tekstur yang telah dipindahkan ke memori video akan digunakan secara langsung.
Cache yang manakah perlu dikemas kini Di atas menerangkan melalui dua kes mengapa three.js perlu menambah atribut needsUpdate. Seterusnya, mari kita senaraikan beberapa senario untuk mengetahui dalam keadaan apa yang diperlukan untuk dilakukan secara manual.
Pemuatan tekstur tak segerak Ini adalah perangkap kecil, kerana imej bahagian hadapan dimuatkan secara tidak segerak Jika anda menulis texture.needsUpdate=true terus selepas mencipta img, three.js The pemapar akan menggunakan _gl.texImage2D untuk memindahkan data tekstur kosong ke memori video dalam bingkai ini, dan kemudian menetapkan bendera ini kepada palsu Selepas itu, data memori video tidak akan dikemas kini sehingga imej dimuatkan untuk keseluruhan imej dimuatkan dalam acara onload sebelum menulis tekstur.needsUpdate = benar
Tekstur Video Kebanyakan tekstur hanya memuatkan dan memindahkan imej sekali seperti kes di atas , tetapi tidak untuk tekstur video, kerana video adalah aliran gambar, dan gambar yang akan dipaparkan adalah berbeza dalam setiap bingkai, jadi needsUpdate perlu ditetapkan kepada benar dalam setiap bingkai untuk mengemas kini data tekstur dalam kad grafik.
Gunakan penampan render Penimbal render ialah objek khas Secara amnya, atur cara memancarkan keseluruhan pemandangan terus ke skrin, tetapi jika terdapat lebih banyak pemprosesan pos atau xxx berasaskan skrin ini (seperti. oklusi ambien berasaskan skrin), anda perlu melukis pemandangan ke penampan render terlebih dahulu. Penampan ini sebenarnya adalah tekstur, tetapi ia dijana oleh lukisan sebelumnya dan bukannya memuatkan daripada cakera. Terdapat objek tekstur khas WebGLRenderTarget dalam three.js untuk memulakan dan menyimpan renderbuffer Tekstur ini juga perlu menetapkan needsUpdate kepada benar dalam setiap bingkai
Keperluan Bahan Bahan adalah dalam tiga. js diterangkan melalui THREE.Material Sebenarnya, bahan tidak mempunyai apa-apa data untuk dihantar, tetapi mengapa kita perlu membuat kemas kini keperluan Di sini kita juga ingin bercakap tentang shader. yang disediakan dalam gpu Kemungkinan pengaturcaraan untuk memproses bucu dan piksel Dalam lukisan, terdapat istilah teduhan untuk melukis teduhan dalam GPU adalah serupa nyatakan bahan objek ok, kerana shader adalah larian Program pada GPU, seperti semua program, perlu disusun dan dipautkan sekali Dalam WebGL, program shader dikompilasi pada masa larian, yang tentunya memerlukan masa. jadi lebih baik untuk menyusun dan menjalankan program sekali. Oleh itu, dalam three.js, program shader disusun dan dipautkan apabila bahan dimulakan dan objek program yang diperoleh selepas penyusunan dan pemautan dicache. Secara amnya, bahan tidak perlu menyusun semula keseluruhan shader Untuk melaraskan bahan, anda hanya perlu mengubah suai parameter seragam shader. Tetapi jika anda menggantikan keseluruhan bahan, seperti menggantikan shader phong asal dengan shader lambert, anda perlu menetapkan material.needsUpdate kepada true dan compile semula. Walau bagaimanapun, keadaan ini jarang berlaku, dan situasi yang lebih biasa adalah yang disebutkan di bawah.
Menambah dan memadamkan lampu Ini sepatutnya menjadi perkara biasa dalam adegan sehingga lampu, saya dapati bahawa lampu tidak berfungsi Walau bagaimanapun, ini adalah apabila menggunakan shader terbina dalam three.js, seperti phong dan lambert Jika anda melihat kod sumber dalam pemapar, anda akan mendapatinya three.js berada dalam kod shader terbina dalam Gunakan #define untuk menetapkan bilangan lampu dalam pemandangan, dan nilai #define ini diperolehi dengan penyambung rentetan setiap kali bahan dikemas kini
"#define MAX_DIR_LIGHTS " parameter .maxDirLights,
"#define MAX_POINT_LIGHTS " parameters.maxPointLights,
"#define MAX_SPOT_LIGHTS " parameters.maxSpotLights,
"#define MAX_HEMI_LIGHTS "parameters.>
maxHemiLights "
Memang cara penulisan ini dapat mengurangkan penggunaan daftar gpu dengan berkesan Jika hanya ada satu lampu, anda hanya boleh mengisytiharkan pembolehubah seragam yang diperlukan untuk satu lampu, tetapi setiap kali bilangan lampu berubah, terutamanya apabila. menambah Anda perlu menjahit semula, menyusun dan memautkan peneduh Pada masa ini, anda juga perlu menetapkan bahan.keperluanKemas kini semua bahan kepada benar; bukan bermaksud mengemas kini data tekstur, tetapi Ini kerana bahan asal menggunakan tekstur dan kemudian berhenti menggunakannya, atau bahan asal tidak menggunakan tekstur dan kemudian menambahkannya kemudian Jika anda tidak mengemas kini bahan secara manual, kesan akhir akan berlaku menjadi berbeza daripada apa yang anda fikirkan. Sebab-sebab masalah ini adalah seperti berikut Menambah lampu di atas adalah hampir sama, kerana makro ditambahkan pada shader untuk menentukan sama ada tekstur digunakan,
Salin kodparameters.bumpMap ? define USE_NORMALMAP" : "",
parameters.specularMap ? "#define USE_SPECULARMAP" : "",
Jadi setiap kali peta, atau envMap atau lightMap menukar nilai sebenar, bahan perlu dikemas kini
Perubahan dalam data puncak lain
Sebenarnya Perubahan tekstur di atas juga akan menyebabkan masalah kerana tiada tekstur semasa pengamulaan, tetapi kemudiannya ditambah secara dinamik persekitaran ini, tidak cukup untuk menetapkan material.needsUpdate kepada benar Anda juga perlu menetapkan geometri.uvsNeedsUpdate kepada true , Mengapa masalah ini berlaku? geometri dan bahan dimulakan buat kali pertama dalam pemapar, jika dinilai bahawa tiada tekstur, walaupun data dalam memori mengandungi data UV untuk setiap bucu , tetapi three.js masih tidak akan menyalin data ini ke video memori. Tujuan asalnya adalah untuk menjimatkan ruang memori video yang berharga, tetapi selepas menambah tekstur, geometri tidak akan menghantar semula data UV untuk kegunaan tekstur secara manual Masalah uv ini benar-benar mengganggu saya untuk masa yang lama pada mulanya.
Untuk mendapatkan maklumat tentang atribut needUpdate beberapa data puncak, sila lihat isu ini
https://github.com/mrdoob/three.js/wiki/Updates
Akhirnya tiga Pengoptimuman .js adalah baik, tetapi pelbagai pengoptimuman membawa pelbagai perangkap Dalam kes ini, cara terbaik ialah melihat kod sumber atau isu fail pada github.