Rumah > Artikel > hujung hadapan web > Gunakan kanvas untuk mencapai kemahiran effect_javascript triangulasi gambar (POLI RENDAH).
Saya secara tidak sengaja melihat Ovilia menggunakan threejs untuk membuat POLY RENDAH, yang merupakan kesan triangulasi satah gambar, saya fikir ia adalah menakjubkan, jadi saya meluangkan masa untuk mencubanya sendiri.
Saya tidak banyak menggunakan threejs, jadi saya hanya menggunakan API lukisan 2D kanvas untuk melakukannya, kerana nampaknya threejs tidak boleh digunakan untuk kesan ini.
Pergi terus ke demo dahulu: http://whxaxes.github.io/canvas-test/src/Funny-demo/lowpoly/index.html (Anda juga boleh menontonnya di telefon bimbit terminal, tetapi kerana pengiraan Jumlahnya agak besar, dan ia akan mengambil lebih banyak masa untuk mengira pada peranti mudah alih berbanding pada PC)
Untuk mencapai kesan ini, anda perlu melakukan triangulasi imej dan melakukan pengesanan tepi pada imej. Daripada kedua-dua ini, yang pertama menggunakan algoritma triangulasi delaunay, dan yang kedua menggunakan algoritma pengesanan tepi sobel. Bunyinya sangat mewah, tetapi kedua-dua algoritma mempunyai komponen sumber terbuka yang sepadan yang boleh digunakan secara langsung: komponen delaunay ironwallaby dan komponen sobel Miguel Mota.
Daripada dua algoritma ini, sobel adalah lebih baik, tetapi delaunay agak rumit Kita boleh mengkajinya pada masa hadapan. Walau bagaimanapun, jika anda hanya mahu mencipta kesan pada masa ini, anda masih boleh menggunakan komponen ini.
Memandangkan dua komponen yang paling penting sudah tersedia, selebihnya adalah sangat mudah:
Mula-mula lukis imej pada kanvas:
canvas.width = (img.width > 800) ? 800 : img.width; canvas.height = img.height * canvas.width/img.width; ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
Kemudian dapatkan imgData kanvas, dan kemudian kembalikan imgData baharu melalui pengiraan sobel
var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height); var newImgData = Sobel(imgData);
Jika kita meletakkan newImgData pada kanvas, kita akan mendapati bahawa imej berwarna menjadi imej skala kelabu seperti ini:
Memandangkan komponen Sobel yang dinyatakan di atas tidak begitu sesuai untuk penggunaan saya, dan kod itu juga tidak sesuai, saya membuat pengubahsuaian dan pengoptimuman yang sesuai, mengoptimumkan kaedah gelung, mempercepatkan kelajuan pengiraan dan menambah fungsi panggil balik. Untuk butiran, sila lihat fail sobel.js dalam github projek
Apabila melintasi imgData.data dalam kaedah Sobel, fungsi panggil balik akan dipanggil dan titik koordinat dengan nilai warna lebih besar daripada 40 (iaitu, skala kelabu di atas rgb(40,40,40)) akan direkodkan dalam panggilan balik. Kemudian secara rawak dapatkan sebahagian daripada titik tepi, dan kemudian tambahkan beberapa koordinat rawak dan nilai koordinat empat penjuru. Dengan cara ini, kita boleh mendapatkan mata koordinat yang kita perlukan
var imgData = ctx.getImageData(0, 0, canvas.width, canvas.height); // 收集色值大于40的边缘像素点 var collectors = []; Sobel(imgData , function(value , x , y){ if(value > 40){collectors.push([x , y]);} }); // 添加一些随机点 for(var i=0;i<300;i++){particles.push([Math.random()*canvas.width , Math.random()*canvas.height]);} // 添加随机边缘点,数量为边缘点数量除于50 var length = ~~(collectors.length/50), random; for(var l=0;l<length;l++){ random = (Math.random()*collectors.length)<<0; particles.push(collectors[random]); collectors.splice(random , 1); } // 添加四顶点坐标 particles.push([0,0] , [0,canvas.height] , [canvas.width,0] , [canvas.width,canvas.height]);
Selepas mendapatkan titik koordinat, anda boleh menggunakan komponen delaunay untuk mengira dan mendapatkan tatasusunan koordinat segi tiga dalam susunan yang betul Dengan menyambungkan titik dalam tatasusunan ini, anda boleh mempunyai kesan berikut:
Sudah tentu, kesan yang kita mahukan bukan untuk menyambungkan garisan, tetapi untuk mengisi warna semua segi tiga, iaitu, untuk mendapatkan tiga koordinat segitiga, kemudian mengira koordinat titik tengah, dan kemudian mendapatkan yang sepadan koordinat dalam imgData berdasarkan nilai warna RGB koordinat titik tengah, dan kemudian isikannya ke dalam kawasan segi tiga:
// 使用delaunay三角化获取三角坐标 var triangles = Delaunay.triangulate(particles); var x1,x2,x3,y1,y2,y3,cx,cy; for(var i=0;i < triangles.length; i+=3) { x1 = particles[triangles[i]][0]; x2 = particles[triangles[i+1]][0]; x3 = particles[triangles[i+2]][0]; y1 = particles[triangles[i]][1]; y2 = particles[triangles[i+1]][1]; y3 = particles[triangles[i+2]][1]; // 获取三角形中心点坐标 cx = ~~((x1 + x2 + x3) / 3); cy = ~~((y1 + y2 + y3) / 3); // 获取中心点坐标的颜色值 index = (cy*imgData.width + cx)*4; var color_r = imgData.data[index]; var color_g = imgData.data[index+1]; var color_b = imgData.data[index+2]; // 绘制三角形 ctx.save(); ctx.beginPath(); ctx.moveTo(x1, y1); ctx.lineTo(x2, y2); ctx.lineTo(x3, y3); ctx.closePath(); ctx.fillStyle = "rgba("+color_r+","+color_g+","+color_b+",1)"; ctx.fill(); ctx.restore(); }
Satu perkara yang perlu diperhatikan di atas ialah koordinat titik tengah yang diperolehi mesti dibundarkan untuk mendapatkan parameter warna yang betul Jika anda tidak mahu membulat, tetapi untuk membundarkan apabila mendapat indeks rgb, anda boleh mendapatkan Nilai warna adalah salah. Kerana piksel yang diperoleh dengan cara ini bukanlah piksel tengah yang kita inginkan.
Selepas warna diperoleh, ia adalah sambungan mudah dan kemudian operasi pengisian Kesan akhir ialah:
Kandungan di atas memperkenalkan anda untuk menggunakan kanvas untuk mencapai kesan triangulasi gambar (POLI RENDAH Saya harap ia akan membantu anda!