vlambda博客
学习文章列表

THREE JS 贴图之UV纹理映射

介绍

     Threejs贴图即将图片或canvas作为贴图贴到物体表面,让模型图片表现物体的纹理。通过贴图来使不同的模型展示不同的样式,不仅仅可以实现‘换装’,也可以做一些炫酷的效果。本文主要通过设置geometry的uv坐标来实现道路流光效果。

#简单实现

     思路:抛开真实道路情况的弯曲、倾斜的效果,首先创建个长方形的mesh,给mesh添加纹理,再通过animation方法每帧设置纹理的offset属性移动 -0.036。想法很好,说干就干。效果如图所示:




#查看mesh

     实现直线道路的过程很轻松,以为很快就结束了,只要在场景中选取几个点位,通过Catmull-Rom算法将点解析成平滑的曲线,再生成面,其余的步骤就轻车熟路了。万万没想到出现的不是流光效果,而是闪烁效果!!!



THREE JS 贴图之UV纹理映射


     苦思冥想N天后发现是贴图的问题,泪奔了,原因是通过顶点创建的面在geometry的faceVertexUvs属性中为空的,如图。(具体发生的原因还没有仔细研究,既然知道走到这了,手动映射一下UV就可以了吧)。



THREE JS 贴图之UV纹理映射




UV映射

     材质贴图又称纹理贴图,是将图片包裹到物体的表面,可以理解为给书包书皮,这样可以减少计算机的计算量。UV映射是将2D图形投影到3D模型表面,U、V表示纹理贴图的坐标,范围在0~1之间(即图1的坐标范围为(0,0)~(1,1))。如下图所示图1中0~7表示我们要添加的坐标点,根据这7个点来生成平面,THREE JS中进行UV映射时应按照逆时针构建三角网,正确的顺序应为(0,1,3)、(0,3,2)……一共要构建6个三角网,当然如果要按照顺时针构建的话显示图像就会在背面,也可以设置显示方式为THREE.DOUBLE,可以正反面都显示。假设图二表示我们要映射的图片,图片的左下角对应0坐标,右下角对应1坐标,2坐标对应图片的1/3位置。以此类推即可。

UV映射理解通了很简单,如果做复杂模型的话多一些工作量,大体思路是这样的。




模拟弯曲道路流光效果-完结撒花



    有了以上的知识基础,再实现流光道路就轻车熟路了。

 /** * 弯曲道路 流光效果 */ function initBlendRoad() { //texture var textureLoader = new THREE.TextureLoader(); texture = textureLoader.load("../../static/img/road/newRoad.png"); texture.wrapS = texture.wrapT = THREE.RepeatWrapping; texture.magFilter = THREE.LinearFilter; texture.offset.z = 0.5; texture.repeat.x = 2; texture.repeat.y = 3;
//vertices var points1 = [ new THREE.Vector3(50,-100,0), new THREE.Vector3(43,0,3), new THREE.Vector3(-20,50,0), ]; var vertices1 = new THREE.CatmullRomCurve3(points1); var points2 = [ new THREE.Vector3(60,-100,0), new THREE.Vector3(50,0,5), new THREE.Vector3(-19.5,59.4,0), ]; var vertices2 = new THREE.CatmullRomCurve3(points2);
//mesh var initgeometry = new THREE.INITGEOMETRY(vertices1.getPoints(99), vertices2.getPoints(99)); this.initFaceVertexUvs(initgeometry); var initMaterial = new THREE.INITMATERIAL({texture:texture}); var mesh = new THREE.Mesh(initgeometry, initMaterial); // console.log('curve road',mesh); scene.add(mesh); } /** * 传入geometry,根据 faces属性生成 faceVertexUvs * 默认逆时针加载,从(0,0)点开始 */ function initFaceVertexUvs(geometry){ let len = geometry.faces.length+2; let part = Math.floor((1/(len/2 -1)) * 100) /100; for (let i = 2; i < len; i++) { if (i % 2 == 0){ // 偶数 geometry.faceVertexUvs[0].push( [ new THREE.Vector2(0,((i/2)-1) * part), new THREE.Vector2(1,((i/2)-1) * part), new THREE.Vector2(0,(i/2)* part), ] ); }else if (i%2 == 1){ // 奇数 geometry.faceVertexUvs[0].push( [ new THREE.Vector2(1,(((i-1)/2)-1) * part), new THREE.Vector2(1,((i-1)/2) * part), new THREE.Vector2(0,((i-1)/2) * part), ] ); }
} }





    想要什么类型的效果可以自己用PS制作个图片或从网上下载一个即可,下面附上最终效果图: