如何使用WebGL创建伪3D图像效果

Demo: tympanus.net/Tutorials/F...

code: github.com/akella/fake...

WebGL 如今变得越来越流行,它让我们能够为网页创建独特的交互式动画。你可能见过使用 Blotter.js 制作的文字扭曲效果,或者用 THREE.MeshLine 创建的动画线条。今天你将学习如何使用原生 WebGL 创建一个交互式的"伪"3D 效果。

如果你使用一些社交软件,可能见过 3D 照片。3D 照片让场景栩栩如生。我们可以用任意照片和一点点代码来重现这种效果。

通常,这类效果会依赖于 Three.js 或 Pixi.js,这些强大的库在编码时提供了许多有用的功能。今天我们不使用任何库,而是直接使用原生 WebGL API。

那么让我们开始吧。


入门准备

对于这个效果,我们将使用原生 WebGL API。

一个帮助你快速入门 WebGL 的网站: webglfundamentals.org

WebGL 常因其冗长而被诟病,这是有原因的。所有全屏着色器效果(即使是 2D 的)的基础都是某种平面或网格,即所谓的"四边形"(quad),它被拉伸到整个屏幕上。说到冗长,在 three.js 中我们只需写 THREE.PlaneGeometry(1,1) 就能创建一个 1×1 的平面,而在原生 WebGL 中我们需要这样做:

js 复制代码
let vertices = new Float32Array([
  -1, -1,
  1, -1,
  -1, 1,
  1, 1,
])
let buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

现在我们有了平面,就可以对使用顶点着色器和片段着色器了。


准备图像

为了让这个效果生效,我们需要为图像创建一个深度图(depth map) 。构建深度图的主要原则是:我们必须根据图像中物体的 Z 位置(即远近)来分离图像的不同部分,从而将前景与背景区分开。

为此,我们可以在 Photoshop 中打开图像,并按照以下方式在原始照片上绘制灰色区域:

(图像展示了一座山,你可以看到,物体离相机越近,深度图中的区域就越亮。)

下一节我们将解释为什么这种着色方式是有道理的。


着色器(Shaders)

渲染逻辑主要在着色器中完成。正如 MDN Web 文档中所述:

着色器是用 OpenGL ES 着色语言(GLSL)编写的程序,它接收构成形状的顶点的信息,并生成将像素渲染到屏幕上所需的数据:即像素的位置和颜色。绘制 WebGL 内容时会运行两个着色器函数:顶点着色器和片段着色器。

一个学习着色器的资源: The Book of Shaders

顶点着色器不会做太多事情,它只是显示顶点:

glsl 复制代码
attribute vec2 position;
void main() {
    gl_Position = vec4(position, 0, 1);
}

最有趣的部分将发生在片段着色器中。我们在其中加载两张图像:

glsl 复制代码
void main() {
    vec4 depth = texture2D(depthImage, uv);
    gl_FragColor = texture2D(originalImage, uv); // 仅显示原始照片
}

记住,深度图是黑白的。对着色器来说,颜色只是一个数字:1 是白色,0 是纯黑。uv 变量是一个二维坐标,用于存储要显示的像素信息。利用这两样东西,我们可以使用深度信息来稍微移动原始照片的像素。

让我们从鼠标移动开始:

glsl 复制代码
vec4 depth = texture2D(depthImage, uv);
gl_FragColor = texture2D(originalImage, uv + mouse);

看起来是这样的:

现在让我们加入深度:

glsl 复制代码
vec4 depth = texture2D(depthImage, uv);
gl_FragColor = texture2D(originalImage, uv + mouse * depth.r);

效果如下:

由于纹理是黑白的,我们可以只取红色通道(depth.r),并将其乘以鼠标在屏幕上的位置值。这意味着,像素越亮,它跟随鼠标移动的距离就越大;而暗的像素则几乎不动。就这么简单,却能产生如此漂亮的 3D 幻觉。


参考资料与致谢


原文:tympanus.net/codrops/201...

工具:huggingface.co/spaces/pyto...

相关推荐
新的瑞拉公主5 小时前
Unity游戏发布微信小游戏:从构建到提审
unity·webgl·微信小游戏·开放数据域
慧都小妮子2 天前
实时大屏掉帧排查:WebGL 图表库选型的 5 项可实测检查
webgl·scichart.js·实时大屏掉帧·前端图表选型
❀͜͡傀儡师2 天前
移动端 360° 商品展示方案:从 20MB 雪碧图到 800KB 丝滑视频
ffmpeg·webgl·sprite
平行云2 天前
国产GPU云渲染适配实战:驱动兼容、编码调优与多路并发
unity·ue5·webrtc·webgl·实时云渲染·云桌面·像素流送
平行云5 天前
实时云渲染信创架构解析:从GPU池化到全栈适配的技术演进
linux·unity·docker·ue5·webgl·数字孪生·实时云渲染
yyt3630458417 天前
KLineChartQuant:GLSL 的精度问题及 RTC 解法
前端·vue.js·react.js·交互·图形渲染·webgl·数据可视化
灵境(虚幻知音)8 天前
WebGL 不支持>1px的线绘制,那 Cesium 的带宽度的线是怎么画出来的?
webgl·cesium·着色器
云登指纹浏览器9 天前
浏览器指纹检测原理演进:从Canvas到WebGL的4轮风控升级
webgl
前端老爷更车12 天前
从 `renderer.render()` 到地面上的阴影:Three.js 阴影渲染全流程源码解析
webgl
Highcharts.js14 天前
Highcharts 渲染方式解析:SVG 默认渲染与 Boost 模块的 WebGL 加速,以及它与其他可视化库的不同
svg·webgl·可视化·canvas·highcharts·渲染方式