使用attribute 變數

文章推薦指數: 80 %
投票人數:10人

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變數,例如: attributevec3position; attributefloatsize; voidmain(void){ gl_Position=vec4(position,1.0); gl_PointSize=size; } voidmain(void){ gl_FragColor=vec4(1.0,0.0,0.0,1.0); } 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也能夠掌握,再來可以考慮實現在著色器之中。

另一方面,如果著色器摻雜越多瀏覽器的情境,就可能越侷在某些應用場合,為了讓著色器更通用,著色器中儘量只針對頂點進行處理,避免摻雜瀏覽器情境,也會是考量之一。



請為這篇文章評分?