纯前端实现图片伪3D视差效果
作者:vivo 互联网前端团队- Su Ning
本文通过depth-anything获取图片的深度图,同时基于pixi.js,通过着色器编程,实现了通过深度图驱动的伪3D效果。该方案支持鼠标/手势与手机陀螺仪双模式交互,在保证性能的同时,为不同终端用户提供沉浸式的视觉体验。
本文提供配套演示代码,可下载体验:
一、引言
在当今的网页设计与交互中,3D 效果能极大地提升用户的视觉体验和沉浸感。但是3D的物料设计成本依然很高,不仅需要专门的设计师掌握专业的建模工具,而且高精度模型带来的渲染压力也使移动端适配变得困难。
在这样的背景下,利用2D图片实现伪3D的效果,就展现出独特的价值。开发者能以极低的资源消耗,在常规图片素材上构建出具有空间纵深的交互效果。这种技术路径不仅规避了传统3D内容生产的复杂性,同时实现了视觉效果与性能消耗的平衡。
二、实现思路
相比二维平面,三维物体多了一个 z 轴作为深度信息。要让 2D 平面呈现 3D 纵深感,关键在于随着视角偏移时,画面中的物体产生不同程度的位移,从而营造前后视差,实现伪 3D 效果。
为此,我们可以通过深度图来获取图片的深度信息,根据这些信息对图片进行分层。当视角改变时,通过调整不同层的偏移来实现视差效果。
三、获取深度图
在前端获取深度图可以借助现有的预训练模型。例如使用 @huggingface/transformers 库,指定任务类型为 'depth-estimation',并选择合适的预训练模型,目前的深度图推理模型尺寸普遍比较大,综合效果和模型尺寸最终选择了 'Xenova/depth-anything-small-hf',量化后的模型尺寸为27.5mb。
import { pipeline } from '@huggingface/transformers'; export async function depthEstimator(url) { const depth_estimator = await pipeline('depth-estimation', 'Xenova/depth-anything-small-hf'); const output = await depth_estimator(url); const blob=await output.depth.toBlob() return URL.createObjectURL(blob) }
四、视差效果的实现
若想借助深度图实现图片分层,可依据深度区间进行划分。假设深度图中纯白的色值为 0,纯黑色值为 1,若将图片切分为两层,那么第一层的色值范围为 0 - 0.5,第二层则是 0.5 - 1。为使画面过渡更自然,可适当增加分层的数量。当镜头偏移时,层数越小的图片位移幅度越大,层数越大的图片位移幅度越小,借此便能实现视差效果。
然而,简单的分层会引发一个问题:不同层的位移可能导致上层的部分区域遮挡背景图案,而另一侧则会出现空白。
针对空白部分,可采用光线步进算法进行颜色采样。
在此,我们选用 Pixi.js 来实现这一效果。作为一款轻量级的 2D 渲染引擎,Pixi.js 在跨平台 2D 动画、游戏及图形界面开发领域表现出色。其精灵支持自定义渲染管线,通过定制图片片段着色器,能够轻松实现视差效果。
4.1 光线步进算法(Ray Marching)
首先我们获取到需要采样颜色的坐标ray_origin,并根据用户的交互事件(鼠标,触摸,陀螺仪)增加镜头偏移offset。得到光线发射的起始坐标。
设置采样步数step,设置光线的偏移向量ray_direction,每一步将光线增加ray_direction/step的坐标。获取到当前深度图坐标的深度信息,由于颜色越浅数值越大,要对深度值进行反转,比对此时光线的z轴是否大于深度的反转值,如果满足条件则挑出循环,取此时光线坐标图片的颜色。
由于每一步增加的偏移值可能跨度比较大,即使满足z轴大于深度反转值的条件,但是二者值的差距依然过大,我们还需要做一个二分搜索来优化采样结果。即偏移值大于深度值,但二者的差值大于阈值的时候,回退一步光线,并将步进值再除以2,可以显著提升采样的精度。
代码实现
varying vec2 vTextureCoord; uniform sampler2D depthMap; uniform sampler2D uSampler; uniform vec3 offset; const float enlarge = 1.06; vec3 perspective(vec2 uv) { const int step_count = 5; vec3 ray_origin = vec3(uv - 0.5, 0); ray_origin.xy -= offset.xy; vec3 ray_direction = vec3(0, 0, 1); ray_direction.xy += offset.xy; ray_direction /= float(step_count); const float hit_threshold = 0.01; vec4 color = vec4(0.0); for (int i = 0; i < step_count; i++) { ray_origin += ray_direction; float scene_z = 1.0 - texture2D(depthMap, ray_origin.xy + 0.5).x; if (ray_origin.z > scene_z) { if (ray_origin.z - scene_z < hit_threshold) { break; } ray_origin -= ray_direction; ray_direction /= 2.0; } } color = texture2D(uSampler, ray_origin.xy + 0.5); return color.rgb; } void main(void ) { vec2 uv = (vTextureCoord - vec2(0.5)) / vec2(enlarge) + vec2(0.5); gl_FragColor = vec4( perspective(uv), 1.0 ); }
五、深度图膨胀
边缘膨胀操作主要用于处理深度图,通过对每个像素邻域内的深度值进行分析和处理,增强图像的边缘,可以使视差图的边缘更加平滑。这里使用一个简单的膨胀函数实现。
varying vec2 vFilterCoord; varying vec2 vTextureCoord; uniform float widthPx; uniform float heightPx; uniform float dilation; uniform sampler2D uSampler; const int MAX_RADIUS = 10; float dilate(vec2 uv, vec2 px) { float maxValue = 0.0; float minValue = 1.0; for (int x = -MAX\_RADIUS; x <= +MAX_RADIUS; x++) { for (int y = -MAX\_RADIUS; y <= +MAX_RADIUS; y++) { vec2 offset = vec2(float(x), float(y)); if (length(offset) > float(MAX_RADIUS)) continue; offset *= px; vec2 uv2 = uv + offset; float val = texture2D(uSampler, uv2).x; maxValue = max(val, maxValue); minValue = min(val, minValue); } } return dilation < 0.0 ? minValue : maxValue; } void main(void ) { const float dilationScale = 1.26; float dilationStep = abs(dilationScale * dilation) / float(MAX_RADIUS); float aspect = widthPx / heightPx; vec2 px = widthPx > heightPx ? vec2(dilationStep / aspect, dilationStep) : vec2(dilationStep, dilationStep * aspect); gl_FragColor = vec4(vec3(dilate(vTextureCoord, px)), 1.0); }
六、总结
综上所述,我们先利用预训练模型生成图片的深度图,再借助 Pixi.js 与光线步进算法达成视差效果,最终通过对深度图进行膨胀处理,实现边缘的平滑过渡。
通过上面的操作,我们成功实现了图片的伪 3D 效果,为用户带来了更具沉浸感的视觉体验。
在实际应用过程中,我们观察到,当视角偏移幅度过大时画面会出现采样失真现象。为解决这一问题,后续可考虑采用动态调整光线步进参数的方法,根据视角变化实时优化光线传播路径,从而减少采样误差;或者引入屏幕空间遮挡关系,通过精准模拟物体间的遮挡效果,增强画面的真实感与层次感。随着 WebGPU 技术的逐步普及,这一方案还有极大的优化空间。我们可借助计算着色器强大的并行计算能力,对复杂的 3D 计算任务进行高效处理,进一步提升计算性能,为网页端 3D 交互开辟更多可能性,打造更加流畅、逼真的 3D 交互场景。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Databend 产品月报(2025年5月)
五月份的更新来啦!这个月我们为大家带来了不少实用的新功能和性能优化,希望能让你的大数据处理工作更加得心应手。 这个月我们一共推出了 31 个新功能 ,修复了 18 个 bug ,还做了 15 项性能优化! 📊 五月更新亮点 重磅功能 Ngram Index - 让 LIKE '%pattern%' 查询飞起来,自带 bloom filter 加速 Iceberg 功能增强 - 新增 ORC 文件支持,数据缓存和 merge-on-read 优化 AVRO 文件支持 - 现在可以直接导入和查询 AVRO 文件了 Streaming Load API - 重新上线,性能比之前更强 Sequence 管理 - 新增 SHOW SEQUENCES 和 DESC SEQUENCE 命令 类型转换优化 - 数字转布尔值、数字字符串转换更智能了 性能提升 Query Optimizer - 优化了 JOIN 条件中的关联子查询 Fragment Forest 执行引擎 - 分布式查询的 Broadcast 操作更高效 Histogram 计算 - 字符串类型的统计信息计算更快了 内存管理 - 没有...
- 下一篇
阿里云人工智能平台PAI开源EasyDistill框架助力大语言模型轻松瘦身
作者:汪诚愚(熊兮)、严俊冰(玖烛)、蔡文睿(清素)、岳元浩(顾城)、黄俊(临在) 前言 随着大型语言模型(LLM)的复杂性和规模不断增长,对于许多研究人员和企业而言,如何有效地利用这些庞大的模型变得愈发重要。然而,巨大的计算需求和训练成本为模型的广泛应用设置了障碍。知识蒸馏是一种将大模型的知识转移到小模型的方法,其核心思想是在不显著降低性能的前提下,通过训练将复杂的模型转化为更小、更高效的版本。通过这种方式,知识蒸馏不仅能够有效降低计算成本,还能够提高模型在资源受限环境中的适应性,从而为大规模应用提供可能。在此背景下,阿里云人工智能平台(PAI)推出了一款新的开源工具包——EasyDistill(https://github.com/modelscope/easydistill),旨在简化大型语言模型的知识蒸馏过程,助力参数量更小但性能卓越的大模型的实际应用。除了 EasyDistill 本身,这一框架还包括了蒸馏大模型 DistilQwen 系列以及相应的开源数据集,供用户使用,其中包括一百万条通用指令遵循数据和两百万条思维链推理数据。尤其是, DistilQwen 系列最新的变长...
相关文章
文章评论
共有0条评论来说两句吧...