打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Threejs ShapeGeometry自定义形状贴图

最近项目需要在3D场景中给自定义的楼层区域进行贴图区分,对于普通的的纯色材质,实现比较简单,但是如果要进行纹理贴图的材质,就有点复杂了,这里写篇文章记录下。

首先看看我们的楼层定义,如何实现自定义区域。其实很简单,我们使用有序的点来定义楼层的平面形状,然后根据平面的定义,自动生成3d的平面区域。

var areaPts = [];for (var idx = 0 ; idx < area.points.length; idx++) {    var p = area.points[idx];     var v = new THREE.Vector2(p.px , p.py );     areaPts.push(v);}var areaShape = new THREE.Shape(areaPts);var geometry = new THREE.ShapeGeometry(areaShape);

如果是纯色的贴图我们怎么做,很简单直接设置颜色即可

var material = new THREE.MeshBasicMaterial({ color: color, side: THREE.DoubleSide, transparent: true, opacity: opacity });var mesh = new THREE.Mesh(geometry, material);

对于贴图,我们使用同样的方法,看看会的到什么效果呢

var texture = new THREE.CanvasTexture(canvas); var material = new THREE.MeshPhongMaterial({ map: texture, side: THREE.DoubleSide });

这里使用canvas作为贴图生成材质,运行后,非常不幸,你不会看到正常的贴图。这是为什么呢?原来我们的模型是根据一个shape生成的ShapeGeometry,所以贴图会采用UV坐标进行贴图,关于UV的解释可以看看这篇文章。所以我们需要计算模型的uv坐标供材质贴图使用。

function assignUVs(geometry) {         geometry.computeBoundingBox();         var max = geometry.boundingBox.max,                min = geometry.boundingBox.min;        var offset = new THREE.Vector2(0 - min.x, 0 - min.y);        var range = new THREE.Vector2(max.x - min.x, max.y - min.y);        var faces = geometry.faces;         geometry.faceVertexUvs[0] = [];         for (var i = 0; i < faces.length ; i++) {             var v1 = geometry.vertices[faces[i].a],                    v2 = geometry.vertices[faces[i].b],                    v3 = geometry.vertices[faces[i].c];             geometry.faceVertexUvs[0].push([                new THREE.Vector2((v1.x + offset.x) / range.x, (v1.y + offset.y) / range.y),                new THREE.Vector2((v2.x + offset.x) / range.x, (v2.y + offset.y) / range.y),                new THREE.Vector2((v3.x + offset.x) / range.x, (v3.y + offset.y) / range.y)            ]);        }        geometry.uvsNeedUpdate = true;    }

算好geomotry的uv坐标后,我们就可以放心大胆的进行贴图了。

function getColRowMaterial(mesh)    {        var geometry = mesh.geometry;        assignUVs(geometry);        var area = mesh.userData.area;        geometry.computeBoundingBox();         var canvas = getColRowCanvas(area.rows, area.cols, geometry.boundingBox.size().x, geometry.boundingBox.size().y);        var texture = new THREE.CanvasTexture(canvas);        texture.wrapT = THREE.RepeatWrapping;        texture.repeat.y = -1;        var material = new THREE.MeshPhongMaterial({ map: texture, side: THREE.DoubleSide });        mesh.material = material;    }

需要注意的是我们的图片坐标和uv坐标的Y轴是反的图片Y轴是向下的,UV坐标Y轴是向上的。所以我们需要反向下y。

texture.wrapT = THREE.RepeatWrapping;texture.repeat.y = -1;

经过以上的代码我们就可以得到正确的贴图了。

在线demo

本文由 Leo's Blog 创作,采用 署名-非商业性使用 2.5 中国大陆 进行许可。
如需转载、引用请署名作者且注明文章出处。             
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Three.js - 走进3D的奇妙世界
Three.js源码阅读笔记(物体是如何组织的)
[Unity3D]手机3D游戏开发:关于自定义Joystick的相关设置和脚本源码
URP | 粒子系统Custom自定义数据控制溶解
Moai SDK Basics Part One
Saving and restoring geometries in OpenLayers
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服