使用 WebGL 进行 2D 图像处理

2024-02-12

我打算用 JS 创建一个简单的照片编辑器。我的主要问题是,是否可以创建实时渲染的滤镜?例如,调整亮度和饱和度。我所需要的只是一个 2D 图像,我可以在其中使用 GPU 应用滤镜。

我读过的所有教程都非常复杂,并且没有真正解释 API 的含义。请指出我正确的方向。谢谢。


我本来打算写一个教程并将其发布在我的博客上,但我不知道什么时候有时间完成,所以这就是我所拥有的这是我博客上的一组更详细的帖子 http://games.greggman.com/game/webgl-fundamentals/.

WebGL实际上是一个光栅化库。我接受属性(数据流)、制服(变量),并期望您提供二维中的“剪辑空间”坐标和像素的颜色数据。

这是 WebGL 中 2d 的简单示例(省略了一些细节)

// Get A WebGL context
var gl = canvas.getContext("experimental-webgl");

// setup GLSL program
vertexShader = createShaderFromScriptElement(gl, "2d-vertex-shader");
fragmentShader = createShaderFromScriptElement(gl, "2d-fragment-shader");
program = createProgram(gl, vertexShader, fragmentShader);
gl.useProgram(program);

// look up where the vertex data needs to go.
var positionLocation = gl.getAttribLocation(program, "a_position");

// Create a buffer and put a single clipspace rectangle in
// it (2 triangles)
var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
   -1.0, -1.0,
    1.0, -1.0,
   -1.0,  1.0,
   -1.0,  1.0,
    1.0, -1.0,
    1.0,  1.0]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);

// draw
gl.drawArrays(gl.TRIANGLES, 0, 6);

这是 2 个着色器

<script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;
void main() {
   gl_Position = vec4(a_position, 0, 1);
}
</script>

<script id="2d-fragment-shader" type="x-shader/x-fragment">
void main() {
   gl_FragColor = vec4(0,1,0,1);  // green
}
</script>

这将绘制一个整个画布大小的绿色矩形。

在 WebGL 中,您有责任提供一个提供剪辑空间坐标的顶点着色器。无论画布大小如何,剪辑空间坐标始终从 -1 到 +1。如果您想要 3d,则需要您提供从 3d 转换为 2d 的着色器,因为 WebGL 只是一个光栅化 API

在一个简单的示例中,如果您想以像素为单位进行工作,您可以传入一个使用像素而不是剪辑空间坐标的矩形,并在着色器中转换为剪辑空间

例如:

<script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;

uniform vec2 u_resolution;

void main() {
   // convert the rectangle from pixels to 0.0 to 1.0
   vec2 zeroToOne = a_position / u_resolution;

   // convert from 0->1 to 0->2
   vec2 zeroToTwo = zeroToOne * 2.0;

   // convert from 0->2 to -1->+1 (clipspace)
   vec2 clipSpace = zeroToTwo - 1.0;

   gl_Position = vec4(clipSpace, 0, 1);
}
</script>

现在我们可以通过更改我们提供的数据来绘制矩形

// set the resolution
var resolutionLocation = gl.getUniformLocation(program, "u_resolution");
gl.uniform2f(resolutionLocation, canvas.width, canvas.height);

// setup a rectangle from 10,20 to 80,30 in pixels
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
    10, 20,
    80, 20,
    10, 30,
    10, 30,
    80, 20,
    80, 30]), gl.STATIC_DRAW);

您会注意到 WebGL 将右下角视为 0,0。为了使其成为用于 2d 图形的更传统的右上角,我们只需翻转 y 坐标。

   gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);

您想要操作需要传入纹理的图像。同样,画布的大小由剪辑空间坐标表示,纹理由从 0 到 1 的纹理坐标引用。

<script id="2d-vertex-shader" type="x-shader/x-vertex">
attribute vec2 a_position;
attribute vec2 a_texCoord;

uniform vec2 u_resolution;

varying vec2 v_texCoord;

void main() {
   // convert the rectangle from pixels to 0.0 to 1.0
   vec2 zeroToOne = a_position / u_resolution;

   // convert from 0->1 to 0->2
   vec2 zeroToTwo = zeroToOne * 2.0;

   // convert from 0->2 to -1->+1 (clipspace)
   vec2 clipSpace = zeroToTwo - 1.0;

   gl_Position = vec4(clipSpace, 0, 1);

   // pass the texCoord to the fragment shader
   // The GPU will interpolate this value between points.
   v_texCoord = a_texCoord;
}
</script>

<script id="2d-fragment-shader" type="x-shader/x-fragment">
precision float mediump;

// our texture
uniform sampler2D u_image;

// the texCoords passed in from the vertex shader.
varying vec2 v_texCoord;

void main() {
   gl_FragColor = texture2D(u_image, v_texCoord);
}
</script>

要绘制图像需要加载图像,由于这是异步发生的,我们需要稍微更改一下代码。将我们拥有的所有代码放入一个名为“render”的函数中

var image = new Image();
image.src = "http://someimage/on/our/server";  // MUST BE SAME DOMAIN!!!
image.onload = function() {
  render();
}

function render() {
   ...
   // all the code we had before except gl.draw


   // look up where the vertex data needs to go.
   var texCoordLocation = gl.getAttribLocation(program, "a_texCoord");

   // provide texture coordinates for the rectangle.
   var texCoordBuffer = gl.createBuffer();
   gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
   gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
       1.0,  1.0, 
       0.0,  1.0, 
       0.0,  0.0, 
       1.0,  1.0, 
       0.0,  0.0, 
       1.0,  0.0]), gl.STATIC_DRAW);
   gl.enableVertexAttribArray(texCoordLocation);
   gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);

   var texture = gl.createTexture();
   gl.bindTexture(gl.TEXTURE_2D, texture);
   gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
   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);

   gl.draw(...)

如果你想做图像处理,你只需改变你的着色器。示例,交换红色和蓝色

void main() {
   gl_FragColor = texture2D(u_image, v_texCoord).bgra;
}

或者与其旁边的像素混合。

uniform vec2 u_textureSize;

void main() {
   vec2 onePixel = vec2(1.0, 1.0) / u_textureSize;
   gl_FragColor = (texture2D(u_image, v_texCoord) +
                   texture2D(u_image, v_texCoord + vec2(onePixel.x, 0.0)) +
                   texture2D(u_image, v_texCoord + vec2(-onePixel.x, 0.0))) / 3.0;
}

我们必须传入纹理的大小

var textureSizeLocation = gl.getUniformLocation(program, "u_textureSize");
...
gl.uniform2f(textureSizeLocation, image.width, image.height);

等等...单击下面的最后一个链接以获取卷积示例。

以下是进度略有不同的工作版本

在剪辑空间中绘制矩形 http://greggman.com/downloads/examples/webgl/webgl-fundamentals.html

以像素为单位绘制矩形 http://greggman.com/downloads/examples/webgl/webgl-2d-rectangle.html

绘制矩形,原点位于左上角 http://greggman.com/downloads/examples/webgl/webgl-2d-rectangle-top-left.html

用不同颜色绘制一堆矩形 http://greggman.com/downloads/examples/webgl/webgl-2d-rectangles.html

绘制图像 http://greggman.com/downloads/examples/webgl/webgl-2d-image.html

绘制红色和蓝色交换的图像 http://greggman.com/downloads/examples/webgl/webgl-2d-image-red2blue.html

绘制左右像素平均的图像 http://greggman.com/downloads/examples/webgl/webgl-2d-image-blend.html

使用 3x3 卷积绘制图像 http://greggman.com/downloads/examples/webgl/webgl-2d-image-3x3-convolution.html

绘制具有多种效果的图像 http://greggman.com/downloads/examples/webgl/webgl-2d-image-processing.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 WebGL 进行 2D 图像处理 的相关文章

  • 由于 apollo-client 未定义,无法解构 GraphQL 查询?

    我正在寻找调试与错误消息相关的问题 未捕获的类型错误 无法解构 0 apollo client WEBPACK IMPORTED MODULE 4 useQuery 因为它未定义 Context 我正在为我的 React js 项目设置后端
  • 将鼠标悬停时的鼠标光标更改为锚状样式

    如果我将鼠标悬停在div鼠标光标将更改为 HTML 锚点中的光标 我怎样才能做到这一点 假设你的div has an id myDiv 将以下内容添加到您的 CSS 中 这cursor pointer指定光标应与用于锚点 超链接 的手形图标
  • 在 contenteditable div 中选择范围

    我有一个contenteditablediv 和其中的一些段落 这是我的代码 div style border solid 1px black width 300px height 300px div Hello world div div
  • 渲染货币和符号并与来自不同单元格的数据相结合

    我正在使用最新的 jQuery DataTables v1 10 7 我正在尝试将数字解析为以下格式 239 90 USD 我可以使用此命令使货币正常工作 columns data Price render fn dataTable ren
  • 以编程方式填写reactjs表单

    我正在编写一个用户脚本 但无法填写由reactjs制作的表单 我的代码 document querySelector id username value email protected cdn cgi l email protection
  • 使用 JavaScript 禁用第三方 cookie

    我正在努力根据所有在欧盟运营的公司的数据保护规则实施新的 Cookie 政策合规性 根据该规则 用户在使用任何网站时必须能够拒绝 接受除必需的 Cookie 之外的所有内容 在我客户的网站中 我可以看到正在存储以下第三方 cookie ga
  • 如何将内联 JavaScript 与 Express/Node.js 中动态生成的内容分开?

    对于具有几年 Web 开发经验但没有找到答案的人来说 这是一个有点菜鸟的问题程序员堆栈交换 or Google 我决定在这里问一下 我在用Express网络框架Node js 但这个问题并不特定于任何 Web 框架或编程语言 以下是从数据库
  • 可以在初始 DOM 解析期间/之前修改 DOM 吗?

    是否可以在初始 DOM 解析期间或之前修改 DOM 或者我是否必须等到 DOM 被解析和构建之后才能与其交互 更具体地说 是否有可能阻止 DOM 中的脚本元素使用用户脚本 内容脚本或 Chrome 或 Firefox 中的类似脚本运行 在解
  • 使用 dc.js 按条形值对条形图中的条形进行排序(排序)

    如何通过维度的计算值而不是维度本身的名称对 dc js 示例中的 x 轴 维度 进行排序 例如 请考虑序数条形图的 dc js 示例 https github com dc js dc js blob master web examples
  • Snap.svg - 停止在可悬停元素的子元素上重新触发悬停事件

    对于一个项目 我使用的 SVG 形状由背景多边形和背景多边形上方的一些文本 我已将其转换为路径 组成 我正在使用 Snap svg 为我的形状设置动画 当我将鼠标悬停在多边形上时 形状应该缩放到特定尺寸 包括其中的所有内容 鼠标移开时 形状
  • 将 GMT 时间转换为当地时间

    我以这种格式从我的服务器获取 GMT 时间 Fri 18 Oct 2013 11 38 23 GMT 我的要求是使用Javascript将此时间转换为本地时间 例如 如果用户来自印度 首先我需要采用时区 5 30并将其添加到我的服务器时间并
  • Vuejs 2:去抖动不适用于手表选项

    当我在 VueJs 中反跳此函数时 如果我提供毫秒数作为原语 它就可以正常工作 但是 如果我将其提供为对 prop 的引用 它会忽略它 这是道具的缩写版本 props debounce type Number default 500 这是不
  • Firebase 函数 onWrite 未被调用

    我正在尝试使用 Firebase 函数实现一个触发器 该触发器会复制数据库中的一些数据 我想观看所有添加的内容votes user vote 结构为 我尝试的代码是 const functions require firebase func
  • 正则表达式 - 从 markdown 字符串中提取所有标题

    我在用灰质 https www npmjs com package gray matter 以便将文件系统中的 MD 文件解析为字符串 解析器产生的结果是这样的字符串 n Clean er ReactJS Code Conditional
  • 使用强光混合模式时突出显示伪影

    我正在 iPhone 应用程序中使用顶部图像的 HardLight 混合模式混合两个图像 它看起来像这样 UIGraphicsBeginImageContext size sourceImage drawInRect rectangle b
  • 如何使用 crypto-js 解密 AES ECB

    我正在尝试将加密数据从 flash 客户端 发送到服务器端的 javascript 在 asp 中作为 jscript 运行 有几个 javascript Aes 库 但它们实际上没有文档记录 我正在尝试使用 crypto js 但无法让代
  • Javascript - 水波纹效果

    我需要 JS 上的脚本 它将以 水波纹 样式更改 images html 抱歉 6MB GIF 文件 http fcuunited ru temp listening2 gif http fcunited ru temp listening
  • Javascript Replace() 和 $1 问题

    我正在尝试创建一个脚本来搜索文本中的模式并在它找到的字符串周围包裹一个标签 shop attributes td each function this html function i html return html replace E 0
  • JavaScript 相对路径

    在第一个 html 文件中 我使用了一个变量类别链接 var categoryLinks Career prospects http localhost Landa DirectManagers 511 HelenaChechik Dim0
  • 如何在react-highcharts中使用图表工具提示格式化程序?

    如何使用图表工具提示格式化程序 我正在使用高图表的反应包装器 我有这样的配置 const CHART CONFIG tooltip formatter tooltip gt var s b this x b each this points

随机推荐

  • android 可以像整数数组一样存储可绘制的 id 吗?

    我想要一个drawableid 整数值数组 我可以像这样存储integer array in res values XXX xml通过使用integer array标签 下面是声明的整数数组strings xml
  • Jupyter 笔记本内嵌图像中的光标位置和像素值

    我使用 Python 2 7 x 和 Jupyter Notebook matplotlib 和 pylab 后端以及内联标志 pylab inline 在活动单元格下方打印图像 我希望能够将光标移动到图像上并知道它的位置和像素值示例可以是
  • CSS 100% 宽度但避免滚动条

    这可能是一个已经解决了几十次的问题的变体 但 CSS 真的让我觉得自己像个傻瓜 我正在尝试构建一个可以通过多种方式定位和调整大小的小部件 这是一个非常简单的布局 固定高度的页眉 固定高度的页脚以及占用剩余空间的正文 整体宽度和高度各不相同
  • Crontab 无法在 Windows 上的 Ubuntu 上使用 Bash

    我正在尝试安排一个 bash 脚本在 Windows 10 中的 Windows 上的 Ubuntu 上使用 Bash 运行 每次我编写 cron 时 我都会在终端中收到以下错误消息 crontab installing new cront
  • wicket:child 标签可以嵌套在页面上的另一个组件下吗?

    在 Wicket 1 4 中 我试图允许子页面更改父页面中标签上的 CSS 类 我一直这样做 这种情况的奇怪之处在于我想要定位的标签包装子页面标记 这是我尝试过的简化片段 父页面 html div div
  • 简单登录unity c#脚本

    应该很简单 但仍然找不到直接答案 如何使用 C Unity 脚本记录简单的消息 我试过这个 Debug Log Hello Log 它不起作用 或者我没有找对地方 Debug Log Hello Log 可以在控制台选项卡 为了让您能够看到
  • 如何防止 Silverlight RIA 实体在我准备好之前附加到数据上下文

    我有一个用于简单 TODO 列表的 Silverlight 4 应用程序 我遇到的问题是数据绑定正在连接我的关系TODO对象 这会导致 RIA 数据上下文将其添加到DataContext TODOs在我想要它之前列出它 我想将该对象视为新的
  • 指针数组作为函数参数

    我有一个关于 C C 中数组和指针的基本问题 假设我有 Foo fooPtrArray 4 如何通过fooPtrArray变成一个函数 我努力了 int getResult Foo fooPtrArray failed int getRes
  • PostgreSQL 比较两个 jsonb 对象

    With PostgreSQL v9 5 http www postgresql org the JSONB https stackoverflow com questions 22654170 explanation of jsonb i
  • 刷新表 - 访问被拒绝

    我需要备份数据库 但是在备份之前尝试刷新表时出现此错误 这是什么意思RELOAD特权 在 phpmyadmin 中找不到任何 RELOAD 权限 Error Access denied you need the RELOAD privile
  • 禁用/隐藏“下载 React DevTools...”

    如何完全禁用或隐藏 持久 控制台消息 Download the React DevTools for a better development experience在开发过程中 从 React 16 2 0 开始 您可以在 webpack
  • C++ 类似 C# 中的 Vector 类

    C 的类似类是什么std vector in C 我想要一个类 它在内部保存一个内部数组并支持在后面插入O 1 time 这是一个包含一些内容的列表C C 容器是roughly彼此等价 不是完全替代 std vector http en c
  • 如何在 R 编程中从数据框创建表格图像

    如何将数据框中的数据转换为表格的图形 我的数据在dataframe并想将其转换为图形 以便我可以使用 Power BI 软件显示它 e g x lt data frame Sex c M M F F F Color c brown blue
  • ImportError:无法使用 Brew 导入名称 HTTPSHandler [重复]

    这个问题在这里已经有答案了 我在设置 python 环境时遇到了一些麻烦 我安装了 pythonbrew但是当我尝试使用 easy install 或 pip 安装某些东西时 我收到此错误 在本例中我尝试使用 pip 安装软件包 我正在使用
  • 今天扩展在 iOS 8.1.2 上启动之前崩溃了

    我一直在制作一个今日扩展 可以从提要中下载文章并显示最新的文章 整个事情在 iOS 8 上运行良好 在 iOS 8 1 上仍然运行 然后是 iOS 8 1 2 我们开始抱怨今天的扩展不再运行 我尝试在 iOS 8 1 2 设备上进行调试 在
  • ActionController::估值中的UrlGenerationError#new

    我读过其他相关文章UrlGenerationError似乎指向一个单词的单数或复数 但我认为这不是问题所在 当我从valuations form html erb中删除时它起作用 提交 form name tag list readd 然后
  • Stripe:没有这样的令牌。测试模式下存在类似的对象,但使用实时模式密钥来发出此请求

    在实时模式下使用 Stripe 时 我收到以下 PHP 错误 没有这样的令牌 tok fgfhn 测试模式下存在类似的对象 但使用实时模式密钥来发出此请求 在 Stripe 测试模式下一切运行良好 并且我已切换到实时 API 密钥 我像这样
  • 检测字符串是否包含字符串数组的任何元素

    如何检测字符串是否包含字符串数组 单词 的任何成员 这是数组 let str String house near the beach let wordGroups String beach waterfront with a water v
  • Javascript 中的事件处理程序、闭包和垃圾收集

    我的应用程序尚未遇到内存泄漏 但我担心将来可能出现问题 我想知道是否做这样的事情 SomeClass prototype someMethod function var that this this div2 click function
  • 使用 WebGL 进行 2D 图像处理

    我打算用 JS 创建一个简单的照片编辑器 我的主要问题是 是否可以创建实时渲染的滤镜 例如 调整亮度和饱和度 我所需要的只是一个 2D 图像 我可以在其中使用 GPU 应用滤镜 我读过的所有教程都非常复杂 并且没有真正解释 API 的含义