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

相关推荐
敲敲敲敲暴你脑袋1 天前
用3Dmol.js展示3D分子结构
typescript·webgl·数据可视化
supermapsupport2 天前
SuperMap iClient3D for WebGL 调用GPA服务实现地质体模型裁剪封边
3d·webgl
爱看书的小沐5 天前
【小沐学WebGIS】基于Three.JS绘制飞行轨迹Flight Tracker(Three.JS/ vue / react / WebGL)
javascript·vue·webgl·three.js·航班·航迹·飞行轨迹
GISer_Jing7 天前
前端GIS篇——WebGIS、WebGL、Java后端篇
java·前端·webgl
爱看书的小沐9 天前
【小沐学GIS】基于C++瓦片地图下载工具(高德/天地图/谷歌/必应/OSM/MapBox/ArcGIS)第十三期
c++·webgl·谷歌地图·earth·osm·瓦片地图下载·mapdowloader
xhload3d14 天前
智慧停车场合集 | 图扑数字孪生静态交通一网统管
物联网·3d·智慧城市·html5·webgl·数字孪生·可视化·工业互联网·三维建模·智慧停车·智慧交通·轻量化·电力能源·智慧停车场·智慧停车楼
ssshooter14 天前
WebGL 切换 Shader 的策略
前端·webgl
Zuckjet_14 天前
第 5 篇:WebGL 从 2D 到 3D - 坐标系、透视与相机
前端·javascript·3d·webgl
ssshooter15 天前
linkProgram 和 useProgram 分别执行了什么动作?
前端·webgl