如何使用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...

相关推荐
Aurora@Hui2 天前
WebGL & Three.js
webgl
CC码码4 天前
基于WebGPU实现canvas高级滤镜
前端·javascript·webgl·fabric
ct9784 天前
WebGL 图像处理核心API
图像处理·webgl
ct9786 天前
Cesium 矩阵系统详解
前端·线性代数·矩阵·gis·webgl
ct9789 天前
WebGL Shader性能优化
性能优化·webgl
棋鬼王9 天前
Cesium(一) 动态立体墙电子围栏,Wall墙体瀑布滚动高亮动效,基于Vue3
3d·信息可视化·智慧城市·webgl
Longyugxq12 天前
Untiy的Webgl端网页端视频播放,又不想直接mp4格式等格式的。
unity·音视频·webgl
花姐夫Jun12 天前
cesium基础学习-坐标系统相互转换及相应的场景
学习·webgl
ct97813 天前
WebGL开发
前端·gis·webgl
作孽就得先起床13 天前
unity webGL导出.glb模型
unity·c#·游戏引擎·webgl