diff options
Diffstat (limited to 'files/zh-tw/web/api/webgl_api/tutorial')
5 files changed, 572 insertions, 0 deletions
diff --git a/files/zh-tw/web/api/webgl_api/tutorial/adding_2d_content_to_a_webgl_context/index.html b/files/zh-tw/web/api/webgl_api/tutorial/adding_2d_content_to_a_webgl_context/index.html new file mode 100644 index 0000000000..45de8b801f --- /dev/null +++ b/files/zh-tw/web/api/webgl_api/tutorial/adding_2d_content_to_a_webgl_context/index.html @@ -0,0 +1,280 @@ +--- +title: 增加一個 2D 物件到 WebGL 環境 +slug: Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context +translation_of: Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context +--- +<div>{{WebGLSidebar("Tutorial")}} {{PreviousNext("Web/API/WebGL_API/Tutorial/Getting_started_with_WebGL", "Web/API/WebGL_API/Tutorial/Using_shaders_to_apply_color_in_WebGL")}}</div> + +<p>當你<a href="/zh-TW/docs/Web/API/WebGL_API/Tutorial/Getting_started_with_WebGL">建立了WebGL的context</a>後,便可開始渲染。最簡單的例子就是加入一個普通的正方形。接下來,我們會介紹如何畫一個正方形。</p> + +<h2 id="畫場景">畫場景</h2> + +<p>首先我們需要知道雖然這個範例只是要畫一個正方形,但我們還是在3D的空間裡作圖。基本上,我們就是畫一個正方形並把它放在相機前面,使正方形與使用者的視角垂直。我們要定義一個 shader,透過它來渲染我們的物件。接下來,我們會展示如何在螢幕前顯示一個正方形。</p> + +<h3 id="Shader">Shader</h3> + +<p>WebGL Shader使用 <a href="https://www.khronos.org/files/opengles_shading_language.pdf">OpenGL ES Shading Language</a>。 這邊不討論 shader 的細節的,但簡而言之,我們需要定義兩個shader (GPU上可執行的函數): vertex shader 和 fragment shader。這兩個 shader 會以字串的形式傳入WebGL,編譯後在GPU上執行。</p> + +<h4 id="Vertex_shader">Vertex shader</h4> + +<p>Vertex shader是用來定義一個變數 gl_Position 的值來控制畫布空間的值(-1到+1),下面的範例,我們設了一個變數<code>aVertexPosition</code>用來記錄 vertex 的位置。接下來我們將該位置乘上兩個4x4的矩陣(<code>uProjectionMatrix</code>和<code>uModelMatrix</code>),並將結果設定為 gl_Position 的值。如果想要了解更多關於 Projection 和其他矩陣可以參閱這篇<a href="https://webglfundamentals.org/webgl/lessons/webgl-3d-perspective.html">文件</a>。</p> + +<pre class="brush: html"> // Vertex shader program + + const vsSource = ` + attribute vec4 aVertexPosition; + + uniform mat4 uModelViewMatrix; + uniform mat4 uProjectionMatrix; + + void main() { + gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition; + } + `; +</pre> + +<h4 id="Fragment_shader">Fragment shader</h4> + +<p>每次 vertex shader 給 gl_Position 1到3個值的時候,它會分別畫出點、線、三角形。畫圖的時候,會呼叫 fragment shader 來詢問每個 pixel 的顏色。在這個範例中,我們對於每次詢問都回傳白色。</p> + +<p><code>gl_FragColor</code> 是GL預設的變數用來定義每個 fragment 的顏色,透過設定該變數的值來定義每個 pixel 的顏色,如下:</p> + +<pre class="brush: html"> const fsSource = ` + void main() { + gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); + } + `; +</pre> + +<h3 id="初始化_shader">初始化 shader</h3> + +<p>現在我們已經定義了兩個 shader ,我們接下來要將它們傳入WebGL,編譯並連結。下面的程式碼呼叫了 loadShader 來建立兩個shader。接下來,我們要新增一個程式,並將 shader 加入該程式,並將程式連結起來。如果編譯或連接失敗,程式碼會顯示錯誤訊息。</p> + +<p> </p> + +<pre class="brush: js">// +// 初始化 shader 來告知WebGL怎麼畫 +// +function initShaderProgram(gl, vsSource, fsSource) { + const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource); + const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource); + + // 建立 shader 程式 + + const shaderProgram = gl.createProgram(); + gl.attachShader(shaderProgram, vertexShader); + gl.attachShader(shaderProgram, fragmentShader); + gl.linkProgram(shaderProgram); + + // 錯誤處理 + + if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { + alert('Unable to initialize the shader program: ' + gl.getProgramInfoLog(shaderProgram)); + return null; + } + + return shaderProgram; +} + +// +// creates a shader of the given type, uploads the source and +// compiles it. +// +function loadShader(gl, type, source) { + const shader = gl.createShader(type); + + // Send the source to the shader object + + gl.shaderSource(shader, source); + + // Compile the shader program + + gl.compileShader(shader); + + // See if it compiled successfully + + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader)); + gl.deleteShader(shader); + return null; + } + + return shader; +} +</pre> + +<p> </p> + +<p>我們可以透過呼叫 initShaderProgram 來建立 shader 程式</p> + +<pre class="brush: js"> const shaderProgram = initShaderProgram(gl, vsSource, fsSource); +</pre> + +<p>接下來我們需要找到 WebGL 生成出的位置。這個例子中我們有一個 attribute、兩個 uniform。 Attributes 從 buffer 獲得值。每次迭代時,vertex shader 從 buffer 得到下一個值並傳入到 attribute。 Uniform 則像是 Javascript 的全域變數。每次迭代,他們的值不會改變。為了之後方便,我們將 shader 程式與 attribute 和 uniform 存放在同一個物件中。</p> + +<pre class="brush: js"> const programInfo = { + program: shaderProgram, + attribLocations: { + vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'), + }, + uniformLocations: { + projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'), + modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'), + }, + }; +</pre> + +<h2 id="建立正方形平面">建立正方形平面</h2> + +<p>在我們渲染前,我們要建立一個 buffer 用來儲存頂點的座標。在此我們宣告一個函數 <code>initBuffers()</code> ,隨著之後建立更多複雜的物件,這個動作會重複見到很多次。</p> + +<pre class="brush: js">function initBuffers(gl) { + + // 建立一個 buffer 來儲存正方形的座標 + + const positionBuffer = gl.createBuffer(); + + // Select the positionBuffer as the one to apply buffer + // operations to from here out. + + gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); + + // Now create an array of positions for the square. + + const positions = [ + 1.0, 1.0, + -1.0, 1.0, + 1.0, -1.0, + -1.0, -1.0, + ]; + + // Now pass the list of positions into WebGL to build the + // shape. We do this by creating a Float32Array from the + // JavaScript array, then use it to fill the current buffer. + + gl.bufferData(gl.ARRAY_BUFFER, + new Float32Array(positions), + gl.STATIC_DRAW); + + return { + position: positionBuffer, + }; +} +</pre> + +<p>這個步驟非常簡單,一開始呼叫<code>gl</code>物件的函數 {{domxref("WebGLRenderingContext.createBuffer()", "createBuffer()")}} 來產生一個儲存座標的 buffer,並將將該 buffer 綁定 WebGL 的 context。</p> + +<p>完成後,我們宣告一個陣列來儲存正方形平面各頂點的座標,並轉型為浮點數陣列並用{{domxref("WebGLRenderingContext.bufferData()", "bufferData()")}}函數傳入 <code>gl</code> 物件。</p> + +<h2 id="渲染場景">渲染場景</h2> + +<p>Shader 建立好了、位置也確定好了、正方形平面頂點的位置也已經放到 buffer後,我們就可以實際來渲染場景了。因為這個例子沒有任何的動畫,<code>drawScene()</code>函數非常單純。</p> + +<pre class="brush: js">function drawScene(gl, programInfo, buffers) { + gl.clearColor(0.0, 0.0, 0.0, 1.0); // 設定為全黑 + gl.clearDepth(1.0); // 清除所有東西 + gl.enable(gl.DEPTH_TEST); // Enable 深度測試 + gl.depthFunc(gl.LEQUAL); // Near things obscure far things + + // 開始前先初始化畫布 + + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + + // Create a perspective matrix, a special matrix that is + // used to simulate the distortion of perspective in a camera. + // Our field of view is 45 degrees, with a width/height + // ratio that matches the display size of the canvas + // and we only want to see objects between 0.1 units + // and 100 units away from the camera. + + const fieldOfView = 45 * Math.PI / 180; // in radians + const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight; + const zNear = 0.1; + const zFar = 100.0; + const projectionMatrix = mat4.create(); + + // note: glmatrix.js always has the first argument + // as the destination to receive the result. + mat4.perspective(projectionMatrix, + fieldOfView, + aspect, + zNear, + zFar); + + // Set the drawing position to the "identity" point, which is + // the center of the scene. + const modelViewMatrix = mat4.create(); + + // Now move the drawing position a bit to where we want to + // start drawing the square. + + mat4.translate(modelViewMatrix, // destination matrix + modelViewMatrix, // matrix to translate + [-0.0, 0.0, -6.0]); // amount to translate + + // Tell WebGL how to pull out the positions from the position + // buffer into the vertexPosition attribute. + { + const numComponents = 2; // pull out 2 values per iteration + const type = gl.FLOAT; // the data in the buffer is 32bit floats + const normalize = false; // don't normalize + const stride = 0; // how many bytes to get from one set of values to the next + // 0 = use type and numComponents above + const offset = 0; // how many bytes inside the buffer to start from + gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position); + gl.vertexAttribPointer( + programInfo.attribLocations.vertexPosition, + numComponents, + type, + normalize, + stride, + offset); + gl.enableVertexAttribArray( + programInfo.attribLocations.vertexPosition); + } + + // Tell WebGL to use our program when drawing + + gl.useProgram(programInfo.program); + + // Set the shader uniforms + + gl.uniformMatrix4fv( + programInfo.uniformLocations.projectionMatrix, + false, + projectionMatrix); + gl.uniformMatrix4fv( + programInfo.uniformLocations.modelViewMatrix, + false, + modelViewMatrix); + + { + const offset = 0; + const vertexCount = 4; + gl.drawArrays(gl.TRIANGLE_STRIP, offset, vertexCount); + } +} + +</pre> + +<p>第一步,我們先將畫布背景設定為黑色,並設定相機的視角。我們將角度設為45°,並設定成與畫布的長寬比相同。另外我們指定我們只要渲染離相機 0.1 ~ 100 單位遠的物件。</p> + +<p>接下來,我們讀入正方形的位置,並把它擺在離相機6單位遠的位置。然後我們將正方形頂點的 buffer 綁定到 gl 上。最後我們呼叫{{domxref("WebGLRenderingContext.drawArrays()", "drawArrays()")}}函數來渲染物件。</p> + +<p>{{EmbedGHLiveSample('webgl-examples/tutorial/sample2/index.html', 670, 510) }}</p> + +<p><a href="https://github.com/mdn/webgl-examples/tree/gh-pages/tutorial/sample2">檢視完整程式碼</a> | <a href="http://mdn.github.io/webgl-examples/tutorial/sample2/">開啟新頁面來檢視結果</a></p> + +<h2 id="矩陣運算">矩陣運算</h2> + +<p>矩陣的運算看起來很複雜,但其實<a href="https://webglfundamentals.org/webgl/lessons/webgl-2d-matrices.html">一步一步運算其實不會那麼困難</a>。大部分使用者不會寫自己的運算函數,多半是使用現成的矩陣函數庫,這個例子中我們用的是 <a href="http://glmatrix.net/">glMatrix library</a> 。</p> + +<p>可參考以下資料</p> + +<ul> + <li><a href="https://webglfundamentals.org/webgl/lessons/webgl-2d-matrices.html">Matrices</a> on WebGLFundamentals</li> + <li><a class="external" href="http://mathworld.wolfram.com/Matrix.html">Matrices</a> on Wolfram MathWorld</li> + <li><a class="external" href="http://en.wikipedia.org/wiki/Matrix_(mathematics)">Matrix</a> on Wikipedia</li> +</ul> + +<p>{{PreviousNext("Web/API/WebGL_API/Tutorial/Getting_started_with_WebGL", "Web/API/WebGL_API/Tutorial/Using_shaders_to_apply_color_in_WebGL")}}</p> diff --git a/files/zh-tw/web/api/webgl_api/tutorial/animating_objects_with_webgl/index.html b/files/zh-tw/web/api/webgl_api/tutorial/animating_objects_with_webgl/index.html new file mode 100644 index 0000000000..cea74d65cf --- /dev/null +++ b/files/zh-tw/web/api/webgl_api/tutorial/animating_objects_with_webgl/index.html @@ -0,0 +1,55 @@ +--- +title: 利用 WebGL 產生動畫 +slug: Web/API/WebGL_API/Tutorial/Animating_objects_with_WebGL +translation_of: Web/API/WebGL_API/Tutorial/Animating_objects_with_WebGL +--- +<p>{{WebGLSidebar("Tutorial")}} {{PreviousNext("Web/API/WebGL_API/Tutorial/Using_shaders_to_apply_color_in_WebGL", "Web/API/WebGL_API/Tutorial/Creating_3D_objects_using_WebGL") }}</p> + +<p>這個章節中,我們將示範如何旋轉之前的正方形平面。</p> + +<h2 id="旋轉正方形">旋轉正方形</h2> + +<p>首先我們需要宣告一個變數來追蹤現在正方形旋轉的角度:</p> + +<pre class="brush: js">var squareRotation = 0.0; +</pre> + +<p>Now we need to update the <code>drawScene()</code> function to apply the current rotation to the square when drawing it. After translating to the initial drawing position for the square, we apply the rotation like this:</p> + +<pre class="brush: js"> mat4.rotate(modelViewMatrix, // destination matrix + modelViewMatrix, // matrix to rotate + squareRotation, // amount to rotate in radians + [0, 0, 1]); // axis to rotate around +</pre> + +<p>This rotates the modelViewMatrix by the current value of <code>squareRotation</code>, around the Z axis.</p> + +<p>To actually animate, we need to add code that changes the value of <code>squareRotation</code> over time. We can do that by creating a new variable to track the time at which we last animated (let's call it <code>then</code>), then adding the following code to the end of the main function</p> + +<pre class="brush: js"> var then = 0; + + // Draw the scene repeatedly + function render(now) { + now *= 0.001; // convert to seconds + const deltaTime = now - then; + then = now; + + drawScene(gl, programInfo, buffers, deltaTime); + + requestAnimationFrame(render); + } + requestAnimationFrame(render); +</pre> + +<p>This code uses <code>requestAnimationFrame</code> to ask the browser call the function "<code>render</code>" each frame. <code>requestAnimationFrame</code> passes us the time in milliseconds since the page loaded. We convert that to seconds and then subtract it from the last time to compute <code>deltaTime</code> which is the number of second since the last frame was rendered. At the end of drawscene we add the code to update <code>squareRotation.</code></p> + +<pre class="brush: js"><code> squareRotation += deltaTime;</code> +</pre> + +<p>This code uses the amount of time that's passed since the last time we updated the value of <code>squareRotation</code> to determine how far to rotate the square.</p> + +<p>{{EmbedGHLiveSample('webgl-examples/tutorial/sample4/index.html', 670, 510) }}</p> + +<p><a href="https://github.com/mdn/webgl-examples/tree/gh-pages/tutorial/sample4">View the complete code</a> | <a href="http://mdn.github.io/webgl-examples/tutorial/sample4/">Open this demo on a new page</a></p> + +<p>{{PreviousNext("Web/API/WebGL_API/Tutorial/Using_shaders_to_apply_color_in_WebGL", "Web/API/WebGL_API/Tutorial/Creating_3D_objects_using_WebGL") }}</p> diff --git a/files/zh-tw/web/api/webgl_api/tutorial/getting_started_with_webgl/index.html b/files/zh-tw/web/api/webgl_api/tutorial/getting_started_with_webgl/index.html new file mode 100644 index 0000000000..ef5e910f93 --- /dev/null +++ b/files/zh-tw/web/api/webgl_api/tutorial/getting_started_with_webgl/index.html @@ -0,0 +1,73 @@ +--- +title: WebGL 入門 +slug: Web/API/WebGL_API/Tutorial/Getting_started_with_WebGL +tags: + - WebGL + - 教學 +translation_of: Web/API/WebGL_API/Tutorial/Getting_started_with_WebGL +--- +<p>{{WebGLSidebar("Tutorial")}} {{Next("Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context")}}</p> + +<p><a href="http://www.khronos.org/webgl/" title="http://www.khronos.org/webgl/">WebGL</a> 讓網頁內容能藉由一種基於 <a href="http://www.khronos.org/opengles/" title="http://www.khronos.org/opengles/">OpenGL ES</a> 2.0 的 API 的幫助,於支援此 API 的瀏覽器環境中,不需使用外掛程式就能在HTML的 <a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API"><code>canvas</code></a> 元素中實現二維及三維渲染。 WebGL 程式包含了由 JavaSrcipt 及著色器(GLSL)撰寫的控制碼以及在電腦的圖形處理器( GPU )上執行的特效程式碼(著色器程式碼)。WebGL 元素可以加入其他 HTML 元素之中並與網頁或網頁背景的其他部分混合。</p> + +<p>這篇文章將會向您介紹 WebGL 的基礎。這篇文章假設您已經對於三維圖學涉及的數學有所了解,並且它將不會被佯裝為三維圖學的教材。在我們的學習區域內有初學者指南讓你完成編程任務:<a href="https://developer.mozilla.org/zh-TW/docs/Learn/WebGL">Learn WebGL for 2D and 3D graphics</a>.</p> + +<p>在此教學文件中的程式碼範例都能在 <a href="https://github.com/mdn/webgl-examples/tree/gh-pages/tutorial">webgl-examples GitHub repository</a> 之中找到。</p> + +<h2 id="準備三維渲染">準備三維渲染</h2> + +<p>首先你需要一個 canvas 元素讓WebGL進行渲染。下面的 HTML 定義的 canvas 元素供後續的範例繪製。</p> + +<pre class="brush: html"><body> + <canvas id="glCanvas" width="640" height="480"></canvas> +</body></pre> + +<h3 id="準備_WebGL背景資料">準備 WebGL背景資料</h3> + +<div class="note"> +<p>背景資料為Context翻譯而來</p> +</div> + +<p>在下面的JavaScript 程式碼,當指令完成讀取後會執行 <code>main()</code> 函式。目的是為了設定 WebGL 背景資料並且開始渲染內容。</p> + +<pre class="brush: js">main(); + +// 從這開始 +function main() { + const canvas = document.querySelector("#glCanvas"); + // 初始化 GL context + const gl = canvas.getContext("webgl"); + + // 當 WebGL 有效才繼續執行 + if (gl === null) { + alert("無法初始化 WebGL,您的瀏覽器不支援。"); + return; + } + + // 設定清除色彩為黑色,完全不透明 + gl.clearColor(0.0, 0.0, 0.0, 1.0); + // 透過清除色來清除色彩緩衝區 + gl.clear(gl.COLOR_BUFFER_BIT); +}</pre> + +<p>在此我們做的第一件事是取得 canvas 元素的參考,並存入 canvas 變數中。</p> + +<p>一旦我們取得了 canvas ,我們透過呼叫 <a href="https://developer.mozilla.org/zh-TW/docs/Web/API/HTMLCanvasElement/getContext">getContext</a> 並傳入 <code>"webgl"</code> 字串來取得 <a href="https://developer.mozilla.org/zh-TW/docs/Web/API/WebGLRenderingContext">WebGLRenderingContext</a>。若瀏覽器不支援 webgl <code>getContext</code> 會回傳 <code>null</code> 同時會顯示訊息給使用者並且離開。</p> + +<p>如果成功初始化, <code>gl</code> 就會成為一個 WebGL背景資料的參考。在這裡我們設置清除色為黑色,並透過該色清除 context (用背景色重新繪製 canvas )。</p> + +<p>至此,您已經有足夠初始化 WebGL 背景資料的程式碼,並且準備好了等待接收內容的容器。</p> + +<p>{{EmbedGHLiveSample('webgl-examples/tutorial/sample1/index.html', 670, 510) }}</p> + +<p><a href="https://github.com/mdn/webgl-examples/tree/gh-pages/tutorial/sample1">檢視完整程式碼</a> | <a href="http://mdn.github.io/webgl-examples/tutorial/sample1/">開啟新頁面來檢視結果</a></p> + +<h2 id="亦可參考">亦可參考</h2> + +<ul> + <li><a href="https://dev.opera.com/articles/introduction-to-webgl-part-1/">An introduction to WebGL</a>: 由 Luz Caballero 撰寫,並出版在 dev.opera.com。 這篇文章點出了 WebGL 的意義,解釋了其運作(包含渲染管路的觀念),並介紹了一些 WebGL libraries。</li> + <li><a href="http://webglfundamentals.org/">WebGL Fundamentals</a></li> + <li><a href="http://duriansoftware.com/joe/An-intro-to-modern-OpenGL.-Table-of-Contents.html">An intro to modern OpenGL:</a> 由 Joe Groff 撰寫的一系列關於 OpenGL 的好文章,提供了 OpenGL清楚的簡介,從其歷史到重要的圖像管路概念,以及一些展示其原理的範例。如果您完全不懂OpenGL,這將是一個好的入門介紹。</li> +</ul> + +<p>{{Next("Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context")}}</p> diff --git a/files/zh-tw/web/api/webgl_api/tutorial/index.html b/files/zh-tw/web/api/webgl_api/tutorial/index.html new file mode 100644 index 0000000000..549c3f40ba --- /dev/null +++ b/files/zh-tw/web/api/webgl_api/tutorial/index.html @@ -0,0 +1,41 @@ +--- +title: WebGL tutorial +slug: Web/API/WebGL_API/Tutorial +tags: + - TopicStub + - Tutorial + - WebGL +translation_of: Web/API/WebGL_API/Tutorial +--- +<div>{{WebGLSidebar}}</div> + +<div class="summary"> +<p><a class="external" href="http://www.khronos.org/webgl/" title="http://www.khronos.org/webgl/">WebGL</a> 讓網頁內容可以使用一個基於 <a class="external" href="http://www.khronos.org/opengles/" title="http://www.khronos.org/opengles/">OpenGL ES</a> 2.0 的API以在HTML {{HTMLElement("canvas")}}中執行3D渲染,且瀏覽器無需使用任何plug-in。WebGL programs 由JavaScript撰寫的指令碼以及透過電腦的Graphics Processing Unit (GPU)上運行的特殊效果程式碼(shader code)組成。WebGL元件可與其他HTML元件混合,並與該頁的其他部分或該頁背景組合使用。 </p> +</div> + +<p><span class="seoSummary">本教學描述如何使用 <code><canvas></code> 元件描繪 WebGL 圖像/圖形, 從基礎開始。提供的範例將讓你對於可以用WebGL做到什麼有清楚的概念,並提供程式碼片段讓你可以著手建立自己的內容。</span></p> + +<h2 id="開始之前">開始之前</h2> + +<p>使用<code><canvas></code> 元件不會非常困難,但你需要有對<a href="/en-US/docs/Web/HTML" title="HTML">HTML</a> 與 <a href="/en-US/docs/Web/JavaScript" title="JavaScript">JavaScript</a> 的基礎認識。<code><canvas></code> 元件跟WebGL在某些舊瀏覽器中不支援,但近來的每個主流瀏覽器都有支援。我們用 JavaScript context object 在canvas繪製圖形,這樣圖形就能動態(on the fly)產生。</p> + +<h2 id="教學文件">教學文件</h2> + +<dl> + <dt><a href="/Web/API/WebGL_API/Tutorial/Getting_started_with_WebGL">WebGL新手上路</a></dt> + <dd>如何建置 WebGL 環境</dd> + <dt><a href="/Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context">加入2D內容至WebGL環境</a></dt> + <dd>如何用 WebGL 渲染簡單平面的形狀</dd> + <dt><a href="/zh-TW/docs/Web/API/WebGL_API/Tutorial/Using_shaders_to_apply_color_in_WebGL">使用 shaders 在 WebGL 上色</a></dt> + <dd>示範如何使用 shaders 在圖形上上色</dd> + <dt><a href="/zh-TW/docs/Web/API/WebGL_API/Tutorial/Animating_objects_with_WebGL">WebGL 產生動畫</a></dt> + <dd>示範如何旋轉與移動物件以製作簡單的動畫</dd> + <dt><a href="/en-US/docs/Web/API/WebGL_API/Tutorial/Creating_3D_objects_using_WebGL">建立三維物件</a></dt> + <dd>示範如何創造並讓 3D 物件(立方體)有動畫</dd> + <dt><a href="/en-US/docs/Web/API/WebGL_API/Tutorial/Using_textures_in_WebGL">在物件表面貼上材質</a></dt> + <dd>示範如何在物件的表面上貼上材質圖</dd> + <dt><a href="/en-US/docs/Web/API/WebGL_API/Tutorial/Lighting_in_WebGL">模擬打光</a></dt> + <dd>如何在 WebGL 環境模擬打光效果</dd> + <dt><a href="/en-US/docs/Web/API/WebGL_API/Tutorial/Animating_textures_in_WebGL">讓材質產生動畫</a></dt> + <dd>如何移動材質圖,在範例中是將 Ogg 影片 貼到一個旋轉中的立方體</dd> +</dl> diff --git a/files/zh-tw/web/api/webgl_api/tutorial/using_shaders_to_apply_color_in_webgl/index.html b/files/zh-tw/web/api/webgl_api/tutorial/using_shaders_to_apply_color_in_webgl/index.html new file mode 100644 index 0000000000..b234bd013e --- /dev/null +++ b/files/zh-tw/web/api/webgl_api/tutorial/using_shaders_to_apply_color_in_webgl/index.html @@ -0,0 +1,123 @@ +--- +title: 使用 shaders 在 WebGL 上色 +slug: Web/API/WebGL_API/Tutorial/Using_shaders_to_apply_color_in_WebGL +translation_of: Web/API/WebGL_API/Tutorial/Using_shaders_to_apply_color_in_WebGL +--- +<p>{{WebGLSidebar("Tutorial")}} {{PreviousNext("Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context", "Web/API/WebGL_API/Tutorial/Animating_objects_with_WebGL")}}</p> + +<p><a href="/zh-TW/docs/Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context">上一篇</a>我們建立了一個正方形平面,接下來我們要透過修改 shakder 來加入顏色。</p> + +<h2 id="指定頂點顏色">指定頂點顏色</h2> + +<p>WebGL中物件是由許多頂點來組成,每個頂點有自己的座標、顏色。其他像素的屬性(顏色、位置)預設是透過計算多頂點的內差值來得到的。之前的例子,vertex shader 並沒有指定頂點任何顏色。</p> + +<p>In WebGL, objects are built using sets of vertices, each of which has a position and a color; by default, all other pixels' colors (and all its other attributes, including position) are computed using interpolation, automatically creating smooth gradients. Previously, our vertex shader didn't apply any specific colors to the vertices; between this and the fragment shader assigning the fixed color of white to each pixel, the entire square was rendered as solid white.</p> + +<p>Let's say we want to render a gradient in which each corner of the square is a different color: red, blue, green, and white. The first thing to do is to establish these colors for the four vertices. To do this, we first need to create an array of vertex colors, then store it into a WebGL buffer; we'll do that by adding the following code to our <code>initBuffers()</code> function:</p> + +<pre class="brush: js"> const colors = [ + 1.0, 1.0, 1.0, 1.0, // white + 1.0, 0.0, 0.0, 1.0, // red + 0.0, 1.0, 0.0, 1.0, // green + 0.0, 0.0, 1.0, 1.0, // blue + ]; + + const colorBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW); + + return { + position: positionBuffer, + color: colorBuffer, + }; +} +</pre> + +<p>這段程式碼一開始先宣告一個陣列來存放四個四維向量,分別為四個頂點的顏色。接下來,將陣列轉型為浮點數並存入一個新的 WebGL buffer 。</p> + +<p>為了使用這些顏色,我們需要修改 vertex shader,讓他可以從 buffer 中取得正確的顏色。</p> + +<pre class="brush: html"> const vsSource = ` + attribute vec4 aVertexPosition; + attribute vec4 aVertexColor; + + uniform mat4 uModelViewMatrix; + uniform mat4 uProjectionMatrix; + + varying lowp vec4 vColor; + + void main(void) { + gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition; + vColor = aVertexColor; + } + `; +</pre> + +<p>The key difference here is that for each vertex, we pass its color using a <code>varying</code> to the fragment shader.</p> + +<h2 id="替_fragment_上色">替 fragment 上色</h2> + +<p>我們重新回顧一下,<a href="/zh-TW/docs/Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context">之前</a>我們的 fragment shader 如下:</p> + +<pre class="brush: html"> const fsSource = ` + void main() { + gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); + } + `; +</pre> + +<p>為了要讓每個 pixel 使用內插的顏色,我們讓 <code>gl_FragColor</code> 取得 vColor的值。</p> + +<pre class="brush: html"> const fsSource = ` + varying lowp vec4 vColor; + + void main(void) { + gl_FragColor = vColor; + } + `; +</pre> + +<p>這樣的改變可以使每個 fragment 得到利用相對位置內插法所產生顏色,而不是得到一個固定的值。</p> + +<h2 id="畫出顏色">畫出顏色</h2> + +<p>接下來我們要</p> + +<p>Next, it's necessary to add the code look up the attribute location for the colors and setup that attribute for the shader program:</p> + +<pre class="brush: js"> const programInfo = { + program: shaderProgram, + attribLocations: { + vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'), + vertexColor: gl.getAttribLocation(shaderProgram, 'aVertexColor'), + }, + ...</pre> + +<p>Then, drawScene() can be revised to actually use these colors when drawing the square:</p> + +<pre class="brush: js"> // Tell WebGL how to pull out the colors from the color buffer + // into the vertexColor attribute. + { + const numComponents = 4; + const type = gl.FLOAT; + const normalize = false; + const stride = 0; + const offset = 0; + gl.bindBuffer(gl.ARRAY_BUFFER, buffers.color); + gl.vertexAttribPointer( + programInfo.attribLocations.vertexColor, + numComponents, + type, + normalize, + stride, + offset); + gl.enableVertexAttribArray( + programInfo.attribLocations.vertexColor); + } +</pre> + +<p>{{EmbedGHLiveSample('webgl-examples/tutorial/sample3/index.html', 670, 510) }}</p> + +<p><a href="https://github.com/mdn/webgl-examples/tree/gh-pages/tutorial/sample3">View the complete code</a> | <a href="http://mdn.github.io/webgl-examples/tutorial/sample3/">Open this demo on a new page</a></p> + +<p>{{PreviousNext("Web/API/WebGL_API/Tutorial/Adding_2D_content_to_a_WebGL_context", "Web/API/WebGL_API/Tutorial/Animating_objects_with_WebGL")}}</p> |