在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ HTML/ WebGL 圖像處理(續(xù))
WebGL 文本 HTML
WebGL 文本 Canvas 2D
WebGL 2D 圖像旋轉(zhuǎn)
WebGL 圖像處理(續(xù))
WebGL 2D 矩陣
WebGL 繪制多個(gè)東西
WebGL 圖像處理
WebGL 2D 圖像轉(zhuǎn)換
WebGL 3D 透視
WebGL 是如何工作的
WebGL 文本 紋理
WebGL 2D 圖像伸縮
WebGL 場景圖
WebGL 3D 攝像機(jī)
WebGL 文本 使用字符紋理
WebGL 正交 3D
WebGL 基本原理
WebGL - 更少的代碼,更多的樂趣
WebGL 著色器和 GLSL

WebGL 圖像處理(續(xù))

這篇文章是 WebGL 圖像處理內(nèi)容擴(kuò)展。

下一個(gè)關(guān)于圖像處理的顯著問題就是如何應(yīng)用多重效果?讀者當(dāng)然可以嘗試著寫一下著色器。生成一個(gè) UI 來讓用戶使用不同的著色器選擇他們希望的效果。這通常是不太可能的,因?yàn)檫@個(gè)技術(shù)通常需要實(shí)時(shí)的渲染效果。

一種比較靈活的方式是使用兩種或更多的紋理和渲染效果來交替渲染,每次應(yīng)用一個(gè)效果,然后反復(fù)應(yīng)用。

Original Image -> [Blur]-> Texture 1
Texture 1  -> [Sharpen] -> Texture 2
Texture 2  -> [Edge Detect] -> Texture 1
Texture 1  -> [Blur]-> Texture 2
Texture 2  -> [Normal]  -> Canvas

要做到這一點(diǎn),就需要?jiǎng)?chuàng)建幀緩存區(qū)。在 WebGL 和 OpenGL 中,幀緩存區(qū)實(shí)際上是一個(gè)非常不正式的名稱。 WebGL/OpenGL 中的幀緩存實(shí)際上僅僅是一些狀態(tài)的集合,而不是真正的緩存。但是,每當(dāng)一種紋理到達(dá)幀緩存,我們就會(huì)渲染出這種紋理。

首先讓我們把舊的紋理創(chuàng)建代碼寫成一個(gè)函數(shù)。

 function createAndSetupTexture(gl) {
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);

// Set up texture so we can render any size image and so we are
// working with pixels.
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);

return texture;
  }

  // Create a texture and put the image in it.
  var originalImageTexture = createAndSetupTexture(gl);
  gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);   

然后,我們使用這兩個(gè)函數(shù)來生成兩種問題,并且附在兩個(gè)幀緩存中。

// create 2 textures and attach them to framebuffers.
  var textures = [];
  var framebuffers = [];
  for (var ii = 0; ii < 2; ++ii) {
var texture = createAndSetupTexture(gl);
textures.push(texture);

// make the texture the same size as the image
gl.texImage2D(
gl.TEXTURE_2D, 0, gl.RGBA, image.width, image.height, 0,
gl.RGBA, gl.UNSIGNED_BYTE, null);

// Create a framebuffer
var fbo = gl.createFramebuffer();
framebuffers.push(fbo);
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);

// Attach a texture to it.
gl.framebufferTexture2D(
gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
  }   

現(xiàn)在,我們生成一些核的集合,然后存儲(chǔ)到列表里來應(yīng)用。

  // Define several convolution kernels
  var kernels = {
normal: [
  0, 0, 0,
  0, 1, 0,
  0, 0, 0
],
gaussianBlur: [
  0.045, 0.122, 0.045,
  0.122, 0.332, 0.122,
  0.045, 0.122, 0.045
],
unsharpen: [
  -1, -1, -1,
  -1,  9, -1,
  -1, -1, -1
],
emboss: [
   -2, -1,  0,
   -1,  1,  1,
0,  1,  2
]
  };

  // List of effects to apply.
  var effectsToApply = [
"gaussianBlur",
"emboss",
"gaussianBlur",
"unsharpen"
  ];   

最后,我們應(yīng)用每一個(gè),然后交替渲染。

// start with the original image
  gl.bindTexture(gl.TEXTURE_2D, originalImageTexture);

  // don't y flip images while drawing to the textures
  gl.uniform1f(flipYLocation, 1);

  // loop through each effect we want to apply.
  for (var ii = 0; ii < effectsToApply.length; ++ii) {
// Setup to draw into one of the framebuffers.
setFramebuffer(framebuffers[ii % 2], image.width, image.height);

drawWithKernel(effectsToApply[ii]);

// for the next draw, use the texture we just rendered to.
gl.bindTexture(gl.TEXTURE_2D, textures[ii % 2]);
  }

  // finally draw the result to the canvas.
  gl.uniform1f(flipYLocation, -1);  // need to y flip for canvas
  setFramebuffer(null, canvas.width, canvas.height);
  drawWithKernel("normal");

  function setFramebuffer(fbo, width, height) {
// make this the framebuffer we are rendering to.
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);

// Tell the shader the resolution of the framebuffer.
gl.uniform2f(resolutionLocation, width, height);

// Tell webgl the viewport setting needed for framebuffer.
gl.viewport(0, 0, width, height);
  }

  function drawWithKernel(name) {
// set the kernel
gl.uniform1fv(kernelLocation, kernels[name]);

// Draw the rectangle.
gl.drawArrays(gl.TRIANGLES, 0, 6);
  }   

下面是更靈活的 UI 的可交互版本。勾選相應(yīng)的效果即可檢查效果。

以空值調(diào)用 gl.bindFramebuffer 即可告訴 WebGL 程序希望渲染到畫板而不是幀緩存中的紋理.

WebGL 不得不將投影矩陣轉(zhuǎn)換為像素。這是基于 gl.viewport 的設(shè)置。當(dāng)我們初始化 WebGL 的時(shí)候, gl.viewport 的設(shè)置默認(rèn)為畫板的尺寸。因?yàn)椋覀儠?huì)將幀緩存渲染為不同的尺寸,所以畫板需要設(shè)置合適的視圖。

最后,在原始例子中,當(dāng)需要渲染的時(shí)候,我們會(huì)翻轉(zhuǎn) Y 坐標(biāo)。這是因?yàn)?WebGL 會(huì)以 0 來顯示面板。 0 表示是左側(cè)底部的坐標(biāo),這不同于 2D 圖像的頂部左側(cè)的坐標(biāo)。當(dāng)渲染為幀緩存時(shí)就不需要了。這是因?yàn)閹彺娌⒉粫?huì)顯示出來。其部分是頂部還是底部是無關(guān)緊要的。所有重要的就是像素 0,0 在幀緩存里就對(duì)應(yīng)著 0。為了解決這一問題,我們可以通過是否在著色器中添加更多輸入信息的方法來設(shè)置是否快讀交替。

<script id="2d-vertex-shader" type="x-shader/x-vertex">
...
uniform float u_flipY;
...

void main() {
   ...
   gl_Position = vec4(clipSpace * vec2(1, u_flipY), 0, 1);
   ...
}
</script>

當(dāng)我們渲染的時(shí)候,就可以設(shè)置它。

  var flipYLocation = gl.getUniformLocation(program, "u_flipY");
  ...
  // don't flip
  gl.uniform1f(flipYLocation, 1);
  ...
  // flip
  gl.uniform1f(flipYLocation, -1);

在這個(gè)簡單的例子中,通過使用單個(gè) GLSL 程序可以實(shí)現(xiàn)多個(gè)效果。

如果你想做完整的圖像處理你可能需要許多 GLSL 程序。一個(gè)程序?qū)崿F(xiàn)色相、飽和度和亮度調(diào)整。另一個(gè)實(shí)現(xiàn)亮度和對(duì)比度。一個(gè)實(shí)現(xiàn)反相,另一個(gè)用于調(diào)整水平。你可能需要更改代碼以更新 GLSL 程序和更新特定程序的參數(shù)。我本來考慮寫出這個(gè)例子,但這是一個(gè)練習(xí),所以最好留給讀者自己實(shí)現(xiàn),因?yàn)槎鄠€(gè) GLSL 項(xiàng)目中每一種方法都有自己的參數(shù),可能意味著需要一些重大重構(gòu),這很可能導(dǎo)致成為意大利面條似的大混亂。

我希望從這里和前面的示例中可以看出 WebGL 似乎更平易近人,我希望從 2D 方面入手,以有助于使 WebGL 更容易理解。