使用attribute 變數
文章推薦指數: 80 %
const gl = getGLContext(document. ... getAttribLocation(prog, 'position'); const gl_size = gl. ... vertexAttrib3f(attr_position, 0.0, 0.0, 0.0); gl.
回WebGL
在〈認識著色器〉中寫死了gl_Position等資訊,如果頂點的座標希望是由應用程式來提供,那麼使用attribute變數,例如:
接下來做個簡單的範例,讓〈認識著色器〉中的紅點跟隨著滑鼠,若按下左鍵會縮小,右鍵會放大,不過,滑鼠的座標是左上角為(0,0),往右為x正方向,往下為y正方向,這與裁剪座標不同,因此先寫個座標轉換函式(公式就自己試著推導吧!):
//從二維繪圖座標轉為三維裁剪空間座標
functiontoClipSpaceCord(canvas,cord){
consthalf_width=canvas.width/2;
consthalf_height=canvas.height/2;
constx=cord.x/half_width-1;
consty=-cord.y/half_height+1;
return{x,y,z:0}
}
想要能從應用程式傳遞頂點資訊給頂點著色器,必須先取得attribute變數的位置,這可以透過WebGLRenderingContext的getAttribLocation方法,從著色器程式中取得:
constgl=getGLContext(document.getElementById('glCanvas'));
constprog=installProgram(gl,
shaderSourceById('vertex-shader'),
shaderSourceById('fragment-shader')
);
constgl_position=gl.getAttribLocation(prog,'position');
constgl_size=gl.getAttribLocation(prog,"size");
由於頂點著色器中,attribute修飾的position與size分別是vec3與float型態,在傳遞資訊時,必須分別使用vertexAttrib3f與vertexAttrib1f方法,例如在初始畫面時,將紅點置於中心:
//初始畫面
gl.vertexAttrib3f(attr_position,0.0,0.0,0.0);
gl.vertexAttrib1f(attr_size,5.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS,0,1);
接著就是滑鼠事件處理了:
//跟隨滑鼠
gl.canvas.addEventListener('mousemove',evt=>{
//轉換座標
constcord=toClipSpaceCord(glCanvas,evt);
gl.vertexAttrib3f(attr_position,cord.x,cord.y,cord.z);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS,0,1);
});
//不顯示快顯功能表
gl.canvas.addEventListener('contextmenu',evt=>{
evt.preventDefault();
});
//縮小、放大
letsize=5.0;
gl.canvas.addEventListener('mousedown',evt=>{
size=evt.button===0?//左鍵
size*0.75:
size*1.25;
gl.vertexAttrib1f(attr_size,size);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.POINTS,0,1);
});
你可以試一下範例頁面看看效果。
到這邊應該會有個問題,有關運算之類的東西,應該放在JavaScript裏,還是在著色器程式裏呢?例如,這邊的範例,也可以將座標轉換的運算實現在著色器裏,只是你也得更認識GLSL這門語言,這之後再來談。
要將運算實現在哪邊,完全取決於開發者,你可以撰寫簡單的著色器,其他都交給JavaScript來處理,或者是除了HTML頁面處理以外的全部運算,都使用著色器來實現,這會直接聯想到效能這件事!
理論上,GPU在運算上會有比較好的效率,然而在〈GettingStartedinWebGL,Part1:IntroductiontoShaders〉有談到,實際上只有CPU才知道怎麼渲染,GPU還是得與CPU合作,亦有常見的效能瓶頸來自於溝通上的開銷,而不是運算。
另一方面,想將更多的運算交給GPU,開發者得更熟悉GLSL,而且GLSL在除錯上還蠻麻煩的,沒什麼殺手級的除錯工具,Firefox是有個著色器編輯器,不過它說要廢棄掉了,Chrome上是有些擴充工具,不過專案看來並不活躍。
(倒是在〈WebGLGLSLShaderEditor〉中,介紹了一些線上的編輯器,提供了一些可視化的方式,便於針對3D網格物件進行設計,有興趣可以自行調查一下是否合用。
)
若是JavaScript開發者想直接接觸WebGL,一開始建議撰寫簡單的著色器,其他由JavaScript來實現,不過,GLSL本身在向量、矩陣運算上蠻友善的,若是發現JavaScript程式中有些通用的向量、矩陣運算,而且對相關的GLSL也能夠掌握,再來可以考慮實現在著色器之中。
另一方面,如果著色器摻雜越多瀏覽器的情境,就可能越侷在某些應用場合,為了讓著色器更通用,著色器中儘量只針對頂點進行處理,避免摻雜瀏覽器情境,也會是考量之一。
延伸文章資訊
- 1WebGL入门-WebGL常用API说明详解_点燃火柴的博客
vertexAttrib3f()的同族函数7. 获取uniform变量地址gl.getUniformLocation()8. ... vertexAttrib3f(); 4.3 给attribu...
- 2在JavaScript程序通过attribute变量向顶点着色器传值 - CSDN博客
gl.vertexAttrib3f() 方法是一系列同族函数中的一个,该系列函数的任务就是从JavaScript程序中向顶点着色器中的attribute变量传值
- 3[Day5] WebGL 修羅道(2) - 資料傳遞 - iT 邦幫忙
而傳入值的話,則是使用 gl.vertexAttrib3f ,要注意attribute 這個型別只能夠用在vertex shader 中!其實在使用attribute,是先取用buffer 中的...
- 4egaku2d_core::gl::VertexAttrib3f - Rust - Docs.rs
API documentation for the Rust `VertexAttrib3f` mod in crate `egaku2d_core`. ... [−][src]Module e...
- 5webgl 入门(二) - 简书
在JavaScript 中使用gl.vertexAttrib3f函数对attribute 变量赋值. gl.vertexAttrib3f()函数拥有很多同族函数,比如gl.vertexAttri...