65.9K
CodeProject 正在变化。 阅读更多。
Home

HTML 3D 画布的图形过滤器

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2015 年 5 月 20 日

公共领域

7分钟阅读

viewsIcon

8804

解释了 HTML 3D 画布的图形滤镜,以及它们在我公共领域的 HTML 3D 库中的工作方式。

引言

此页面描述了什么是图形滤镜以及它们在我公共领域的 HTML 3D 库中是如何工作的。它还描述了几个图形滤镜的例子。

图形滤镜

在 HTML 3D 库中,图形滤镜是用于在每一帧之后修改屏幕外观的函数。它们使用一种名为 GLSL(GL 着色语言)的语言实现。GLSL 程序被称为“着色器”,它们被编译成在 GPU(图形处理单元)上运行的代码。

图形滤镜被认为是“片段着色器”,即一次处理一个像素的着色器。GPU 可以非常快速地运行着色器,因为片段着色器可以并行处理每个像素,而不会影响其他像素,而且 GPU 通常比 CPU 更适合并行处理。

为了使图形滤镜工作,3D 场景必须渲染到一个名为帧缓冲区的离屏缓冲区。帧缓冲区就像一个 3D 纹理,它将在图形滤镜的着色器程序的帮助下渲染回屏幕。

编写图形滤镜

在 HTML 3D 库中,使用 ShaderProgram 类的 makeEffect 方法创建图形滤镜

  • ShaderProgram 类保存着色器程序的数据。每个着色器程序由一个顶点着色器和一个片段着色器组成。图形滤镜本质上是片段着色器的一部分,因此处理像素。(顶点着色器,它处理三角形、线条和点的顶点,在此页面中不讨论。)
  • makeEffect 方法创建一个着色器程序并编译它,使用图形滤镜作为程序片段着色器的一部分。由于着色器程序也必须有一个顶点着色器,因此该方法还为图形滤镜添加了一个非常基本的顶点着色器。

以下是一个图形滤镜的示例。

return ShaderProgram.makeEffect(context,[
"vec4 textureEffect(sampler2D sampler, vec2 uvCoord, vec2 textureSize){",
// Read the current color from the sampler texture
" vec4 color=texture2D(sampler,uvCoord);",
// Convert the color to a shade of gray.  It gets
// the current color's red, green, and blue components,
// adds them, and divides by 3.  Thus, the gray color
// will be an average of the red/green/blue components.
" float gray=(color.r+color.g+color.b)/3.0;",
// Return the gray color (using the color's original alpha)
" return vec4(gray,gray,gray,color.a);",
"}"].join("\n"));

每个图形滤镜都必须有一个名为 textureEffect() 的 GLSL 函数,如上面的示例所示。textureEffect 函数接受这些参数

  • sampler2D sampler:指向表示当前帧屏幕截图的纹理。要从纹理读取,请使用 texture2D 函数,如上面的示例所示。
  • vec2 uvCoord:当前像素的纹理坐标。uvCoord.x 从左侧的 0 到右侧的 1。uvCoord.y 从底部的 0 到顶部的 1。(请注意,纹理坐标从左下角开始,而不是左上角,也就是说,纹理是“自下而上”的,而不是“自上而下”的)。
  • vec2 textureSize:由 sampler 指向的屏幕截图的大小(以像素为单位)。textureSize.x 是宽度,textureSize.y 是高度。

textureEffect 函数返回一个 vec4(4 元素向量),给出当前像素应有的颜色。上面的示例读取当前像素的颜色,将其转换为灰色调,并返回带有该灰色调的新颜色。因此,滤镜将把屏幕转换为灰度色调。

着色器还可以定义名为“uniforms”的自定义参数。它们通过在着色器顶部使用 uniform [type] [name]; 这样的行来声明。例如:uniform float time; 一旦声明,Uniforms 就可以在 textureEffect 函数中使用。

GLSL 的详细处理超出了本页的范围。可以通过搜索 Web 找到有关 GLSL 的更多信息;请注意,GLSL 有许多版本,用于 HTML 应用程序的版本在如今相对基础。另外,请参阅下面的更多图形滤镜示例。

使用图形滤镜

滤镜创建后,使用起来非常简单;只需使用 Scene3DuseFilter 方法进行设置。滤镜设置后,其工作方式如下

  • 当调用 useFilter 方法设置新的图形滤镜时,HTML 3D 库会创建一个帧缓冲区。帧缓冲区由与 3D 画布大小相同的纹理和一个用作深度缓冲区的 renderbuffer 组成。
  • 当每帧调用 render() 方法时
    • 库确保帧缓冲区与 3D 画布大小相同。
    • 3D 库将绘图切换为使用帧缓冲区而不是 3D 画布,然后将着色器切换为用于绘制 3D 场景的常规着色器。
    • 当前帧渲染到帧缓冲区。帧缓冲区的纹理现在将包含帧的“快照”,可以由图形滤镜修改。
    • 3D 库将绘图切换回 3D 画布,然后将着色器切换到图形滤镜的着色器。
    • 绘制一个占据整个 3D 画布的矩形。这是为了让纹理的每个像素都传递给图形滤镜,并且为每个像素调用滤镜的 textureEffect 方法。在绘图之前,将设置提供给图形滤镜的任何自定义参数或“uniforms”。图形滤镜可以使用当前像素的颜色或更改每个像素的颜色。因此,将绘制当前帧的“过滤后”版本。

目前,HTML 3D 库一次只支持一个滤镜,因此如果 HTML 应用程序需要使用多个效果,例如灰度化和模糊,则两个效果都需要组合在同一个图形滤镜着色器中。

示例

演示 squares.html 包含了许多以着色器形式实现的图形滤镜。

以下是它包含的滤镜的更多详细信息。

灰度

Grayscale filtered image

上面已经给出了将屏幕转换为黑白的灰度滤镜。

反色

Invert filtered image

反色滤镜内置于 HTML 3D 库中。它反转屏幕的颜色,使效果看起来像胶片底片。

此滤镜在方法 ShaderProgram.getInvertEffect() 中实现

ShaderProgram.getInvertEffect=function(context){
return ShaderProgram.makeEffect(context,
[
"vec4 textureEffect(sampler2D sampler, vec2 uvCoord, vec2 textureSize){",
" vec4 color=texture2D(sampler,uvCoord);",
" vec4 ret; ret.xyz=vec3(1.0,1.0,1.0)-color.xyz; ret.w=color.w; return ret;",
"}"].join("\n"));
}

红色色调

Red Tint filtered image

红色色调滤镜为图像添加一丝红色。

function makeRedTint(context){
return ShaderProgram.makeEffect(context,[
"vec4 textureEffect(sampler2D sampler, vec2 uvCoord, vec2 textureSize){",
" vec4 color=texture2D(sampler,uvCoord);",
" return vec4(color.r+0.3,color.g,color.b,color.a);",
"}"].join("\n"));
}

镜像滤镜

Mirror filtered image

此滤镜对其像素进行水平翻转。请注意,下面给出的滤镜不是从当前像素读取,而是从与当前像素相对的另一侧的像素读取(它采用 1 减去当前 X 坐标)。

function makeMirror(context){
return ShaderProgram.makeEffect(context,[
"vec4 textureEffect(sampler2D sampler, vec2 uvCoord, vec2 textureSize){",
" vec4 color=texture2D(sampler,vec2(1.0-uvCoord.x,uvCoord.y));",
" return color;",
"}"].join("\n"));
}

通过简单的更改,此滤镜可以修改为垂直翻转(1.0-uvCoord.y)甚至同时进行水平和垂直翻转。

矩阵滤镜

Blur filtered image Edge detect filtered image

此滤镜启用了一系列图像处理滤镜,例如模糊、锐化、边缘检测和浮雕,它们处理每个像素及其邻居。此滤镜采用一个 3x3 矩阵,称为卷积核,它给出每个像素颜色对最终颜色的贡献。矩阵中的所有数字必须加起来为 1。

请注意,下面给出的 uniformmat3,表示一个 3x3 矩阵。

卷积核的一个例子

[  0,  1/8, 0,
  1/8, 1/2, 1/8,
  0,   1/8, 0  ]

此滤镜意味着目标像素将具有原始像素颜色的一半,以及其 4 个相邻像素颜色的八分之一。请注意,此示例加起来为 1。

此滤镜在演示中的 makeKernelMatrix 函数中实现。它用于“模糊”和“边缘检测”效果。该滤镜展示了滤镜在实现其效果时如何读取相邻像素,而不仅仅是当前像素。

像素化滤镜

Pixelate filtered image

此滤镜通过缩小然后放大来像素化屏幕。此滤镜采用一个名为 coarsenessuniform,表示每个“像素化”像素占据多少个正常像素。

function makePixelate(context){
return ShaderProgram.makeEffect(context,[
"uniform float coarseness;", // coarseness in pixels; 1 means normal
"vec4 textureEffect(sampler2D sampler, vec2 uvCoord, vec2 textureSize){",
" float g=max(coarseness,1.0);",
" float gridSizeX=textureSize.x/g;",
" float gridSizeY=textureSize.y/g;",
" float uv0=floor(uvCoord.x*gridSizeX)/gridSizeX;",
" float uv1=floor(uvCoord.y*gridSizeY)/gridSizeY;",
" vec4 c=texture2D(sampler,vec2(uv0,uv1));",
" return c;",
"}"].join("\n"));
}

演示随着时间改变“coarseness”参数以实现像素化效果的动画。

波浪滤镜

Wave filtered image

此滤镜水平移动每行中的像素,导致屏幕垂直波动。此滤镜采用一个名为 timeuniform,表示波动效果的动画帧。

此滤镜在演示中的 makeWave 函数中实现。

水彩滤镜

Waterpaint filtered image

这是一种水彩效果,基于一个名为“Themaister”的公共领域着色器。

此滤镜在演示中的 makeWaterpaint 函数中实现。

其他页面

我在 CodeProject 上的以下页面也讨论了此库

© . All rights reserved.