前言最近看到一个很酷但是很容易实现的图片伪3D效果,效果如下:下面来看看如何实现吧。材料准备我们需要准备的材料是:一张图片。上图的深度图。什么是深度图?深度图是描述原始图片上的每个像素离屏幕有多远的图片。一般来说,画面越白,离屏幕越近,越暗,离屏幕越远。比如前言中的示例景观的深度图是这样的:可以看到在深度图中远处的山比较暗,而近处的水比较亮。那么,我在哪里可以获得深度图?这时候你需要打开Photoshop,拿起你的小画笔,看着原图,发挥你的想象力,一笔一笔画出深度图。没错,需要自己画。说实话,对于行动不便的人来说,这应该是所有步骤中最难的部分了。画深度图有几个小技巧(不过没用,手残党再多本事):先用渐变剪出轮廓,再画高斯模糊。动手阶段有了图片之后,我们就可以开始往上开发了。这里我们需要用到WebGL。什么是WebGL?说起来太长了,就不说了。如果使用原生的WebGL,冗长琐碎的API会让人很不舒服,所以我们选择了一个优秀的开源库regl,regl封装了WebGL的基本操作,可以大大降低WebGL的使用门槛。首先,我们需要加载准备好的图片:constloadImage=url=>{returnnewPromise(resolve=>{constimage=newImage();image.crossOrigin=''image.onload=()=>resolve(image);image.src=url;});};Promise.all([url,depthMapUrl].map(loadImage)).then(main);加载后初始化我们的函数:constdrawTriangle=regl({frag:`precisionmediumfloat;varyinghighpvec2vTexCoord;uniformsampler2Dtexture;uniformsampler2DdepthMap;uniformfloatx;uniformfloaty;voidmain(){vec2texCoord=(vTexCoord+1.0)/2.0*vec2(1,1);depth=texture2D(depthMap,texCoord);gl_FragColor=texture2D(texture,texCoord+vec2(x,-y)*depth.r);}`,vert:`精度mediumpfloat;attributevec2position;varyinghighpvec2vTexCoord;voidmain(){gl_Position=vec4(position,0,1);vTexCoord=position;}`,attributes:{position:[-1,-1,1,-}1,1,1,1,1,-1,-1,-1,1]},制服:{texture:regl.texture()({data:image,flipY:true}),depthMap:regl.texture({data:depthMapImage,flipY:true}),x:regl.prop('x'),y:regl.prop('y')},count:6});letx=0;lety=0;document.body.onmousemove=e=>{x=(e.pageX-window.innerWidth/2)/10000;y=(e.pageY-window.innerHeight/2)/10000;};regl.frame(()=>{regl.clear({颜色:[0,0,0,0],深度:1});drawTriangle({x,y});});实现伪3d效果的关键代码在片段着色器中://获取当前纹理坐标的深度信息vec4depth=texture2D(depthMap,texCoord);//根据深度信息(使用计算出的新纹理坐标通过蓝色或绿色通道)和鼠标位置gl_FragColor=texture2D(texture,texCoord+vec2(x,y)*depth.r);原理分析我们可以通过深度图中的黑白关系得到当前纹理的坐标与屏幕的距离,距离屏幕越近则越白,深度越大。附近的人有很大的偏移量,这种层次感产生了一种伪立体的效果。最后附上这个demo(毫无疑问,效果不好肯定是深度图不好的原因)。请参阅如何使用WebGL创建假3D图像效果
