three.js 利用uv和ThreeBSP制作一个快递柜
最近有three网友,问我要不要学习blender,其实我感觉学习一下也无妨,不过花大量时间精通,尚可不必,术业有专攻给别人留一条路吧,哈哈。那我我们就是用ThreeBSP和uv贴图的知识来制作一个定制化的快递柜,先上图,在线案例请点击博客原文。
下面我们来讲解一下这样一个柜子的制作。
1. 主角是一个JSON
这样一个快递柜的核心是JSON数据的创建,有了jSON数据,我们就可以通过循环遍历出柜子,柜门和uv映射关系。那面下面来看看我们的JSON数据(部分代码)。
- var doorArray = [
- [94, 10, -176, 196, false], [94, 10, -76, 196, false], [94, 10, 76, 196, false], [94, 10, 176, 196, false], [46, 15, 0, 186, false], [46, 60, 0, 147, false],
- [46, 21, 0, 105.5, true], [46, 10, 0, 89, true], [46, 10, 0, 78, true], [46, 20, 0, 62, true], [46, 20, 0, 41, true], [46, 20, 0, 20, true]
- ]
他是以一个数组的形式表现的,每一个数组代表一个柜子数据,每一个数组中的第一项为当前柜子宽度,第二项为高度,第三项为中心x位置,第四项而中心y位置,第五项为柜子是否能打开(因为有的地方为操作面板等)。
2. ThreeBSP绘制柜子的整体架构。
说完核心,我们在看看柜子的整体框架。下面是柜子的侧面图,通过侧面图我们可以很清晰的看出我们做了什么
其实加的不多,就是在上面加了一个檐,下面加了两个底座,还有就是在每个小快递柜中掏出一个洞。
我们看代码
- var texture = new THREE.TextureLoader().load('/static/images/base/cabinet.jpg')
- let pubMate = new THREE.MeshNormalMaterial();
- let frameGeom = new THREE.BoxGeometry(450, 200, 50);
- let frameMesh = new THREE.Mesh(frameGeom, pubMate);
- frameMesh.position.y = 106;
- let footShape = new THREE.Shape();
- footShape.moveTo(0, 2);
- footShape.lineTo(8, -2);
- footShape.lineTo(8, -4);
- footShape.lineTo(0, -4);
- footShape.lineTo(0, 0);
- footShape.lineTo(-12, 0);
- footShape.lineTo(-12, 2);
- footShape.lineTo(0, 2);
- let footExtrudeSettings = {
- steps: 5,
- depth: 450,
- bevelEnabled: false
- };
- let footGeom = new THREE.ExtrudeGeometry(footShape, footExtrudeSettings);
- let footMesh = new THREE.Mesh(footGeom, pubMate);
- let footMesh1 = footMesh.clone();
- footMesh1.rotation.y = -Math.PI / 2;
- footMesh1.position.x = 225;
- footMesh1.position.y = 4;
- footMesh1.position.z = 25;
- let footMesh2 = footMesh.clone();
- footMesh2.rotation.y = Math.PI / 2;
- footMesh2.position.x = -225;
- footMesh2.position.y = 4;
- footMesh2.position.z = -25;
- let headGeom = new THREE.BoxGeometry(450, 5, 20);
- let headMesh = new THREE.Mesh(headGeom, pubMate);
- headMesh.position.z = 23;
- headMesh.position.y = 206 - 2.5;
- let framebsp = new ThreeBSP(frameMesh);
- let foot1bsp = new ThreeBSP(footMesh1);
- let foot2bsp = new ThreeBSP(footMesh2);
- let headbsp = new ThreeBSP(headMesh);
- res = framebsp.union(foot1bsp).union(foot2bsp).union(headbsp);
- for(var i=0; i<doorArray.length; i++) {
- let geom = new THREE.BoxGeometry(doorArray[i][0]-1, doorArray[i][1]-1, 50);
- let mesh = new THREE.Mesh(geom, pubMate);
- mesh.position.set(doorArray[i][2], doorArray[i][3], 4)
- let meshbsp = new ThreeBSP(mesh);
- res = res.subtract(meshbsp);
- }
- let cabinetGeom = res.toGeometry();
- let cabinetMate = new THREE.MeshPhongMaterial({color: 0xD8C513, specular: 0xD8C513, shininess: 10});
- let cabinetMesh = new THREE.Mesh(cabinetGeom, cabinetMate);
- cabinetMesh.position.y = 106;
- scene.add(cabinetMesh);
这里就是在框架BoxGeometry的基础上加了两个底座ExtrudeGeometry,和一个檐BoxGeometry,然后遍历减去小柜子。掌握好各自的空间位置,制作其实并不难。
3. 柜子的统一贴图
将一张图作为贴图,贴到所有的mesh上,如最上面图的效果,因为上节课已经大致的说了关于uv的一点知识。
- for(var i=0; i<doorArray.length; i++) {
- let a0 = doorArray[i][0];
- let a1 = doorArray[i][1];
- let a2 = doorArray[i][2];
- let a3 = doorArray[i][3];
- let x1 = ((a2 - a0 / 2) + 223) / 446;
- let x2 = ((a2 + a0 / 2) + 223) / 446;
- let y1 = ((a3 - a1 / 2) - 10) / 191;
- let y2 = ((a3 + a1 / 2) - 10) / 191;
- doorMesh.geometry.faceVertexUvs[0][8] = [new THREE.Vector2(x1, y2), new THREE.Vector2(x1, y1), new THREE.Vector2(x2, y2)];
- doorMesh.geometry.faceVertexUvs[0][9] = [new THREE.Vector2(x1, y1), new THREE.Vector2(x2, y1), new THREE.Vector2(x2, y2)];
- }
上面已经说过,这里的a0是柜子的宽,a1是柜子的高,a2是柜子中心x的坐标值,a3是柜子中心y的坐标值。因为柜子整体x的范围是[-223, 223],y的范围的[10, 201]。经过换算x1是纹理x坐标的最小值,x2是纹理x坐标的最大值,y1是纹理y坐标的最小值,y2是纹理y坐标的最大值,最后设置数组索引为8和9小三角面的uv映射(因为我们要设置的面为长方体的左面,就是8和9控制的面)。
最后加上一点点开柜子的动画就大功告成了。
转载请注明地址:郭先生的博客
three.js 利用uv和ThreeBSP制作一个快递柜的更多相关文章
- js利用点击事件做一个简单的计算器
先放一个样式图: 源代码如下: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"&g ...
- 一起学HTML基础-利用CSS和JavaScript制作一个切换图片的网页
由于个人原因,不详细写步骤 思路: 一.布局 二.制作图片区和按钮区的div及颜色.边框.背景属性等 三.用PS将四张图片剪切到同一个尺寸,重叠放置在图片切换区,透明度设置为0 四.点击对应按钮时,将 ...
- 利用yacc和lex制作一个小的计算器
买了本<自制编程语言>,这本书有点难,目前只是看前两章,估计后面的章节,最近一段时间是不会看了,真的是好难啊!! 由于本人是身处弱校,学校的课程没有编译原理这一门课,所以就想看这两章,了解 ...
- 百度前端技术学院2018笔记 之 利用 CSS animation 制作一个炫酷的 Slider
前言 题目地址 利用 CSS animation 制作一个炫酷的 Slider 思路整理 首先页面包含三种东西 一个是type为radio的input其实就是单选框 二是每个单选框对应的label 三 ...
- three.js cannon.js物理引擎制作一个保龄球游戏
关于cannon.js我们已经学习了一些知识,今天郭先生就使用已学的cannon.js物理引擎的知识配合three基础知识来做一个保龄球小游戏,效果如下图,在线案例请点击博客原文. 我们需要掌握的技能 ...
- 用JS制作一个信息管理平台完整版
前 言 JRedu 在之前的文章中,介绍了如何用JS制作一个实用的信息管理平台. 但是那样的平台功能过于简陋了,我们今天来继续完善一下. 首先我们回顾一下之前的内容. 1.JSON的基础知识 ...
- JS制作一个创意数字时钟
通过js代码制作一个创意数字时钟 通过JS代码实现创意数字时钟效果如下:由数字化的卡通形象图片取代常规的数字显示当前实时北京时间.具体效果示例: 核心重点: (1)Date方法的初步了解 (2)构建模 ...
- three.js 制作一个三维的推箱子游戏
今天郭先生发现大家更喜欢看我发的three.js小作品,今天我就发一个3d版本推箱子的游戏,其实webGL有很多框架,three.js并不合适做游戏引擎,但是可以尝试一些小游戏.在线案例请点击博客原文 ...
- 利用DreamweaverCS5制作一个含有动态标题的教程
DreamweaverCS5怎么制作一个含有动态标题?做一个网页就先要做一个标题,一个好标题会让网页让人印象深刻,有动态的标题会让网页更生动,下面我就介绍一下怎么制作一个含有动态的标题 做一个网页 ...
随机推荐
- 题解 洛谷 P3298 【[SDOI2013]泉】
考虑到年份数很小,只有 \(6\),所以可以 \(2^6\) 来枚举子集,确定流量指数对应相同的位置,然后通过哈希和排序来计算相同的方案数. 但是这样计算出的是大于等于子集元素个数的方案数,所以还需要 ...
- Python过滤掉numpy.array中非nan数据实例
代码 需要先导入pandas arr的数据类型为一维的np.array import pandas as pd arr[~pd.isnull(arr)] 补充知识:python numpy.mean( ...
- No implementation found for void `org.webrtc.PeerConnectionFactory.initializeAndroidGlobals(android.content.Context, boolean)
背景介绍 最近在使用 AndroidRTC 利用WebRtc屏幕共享时使用PeerConnectionFactory.initializeAndroidGlobals(context, true, t ...
- linux命令笔记记录(自用)
1.解除yum锁定: sudo rm -rf /var/run/yum.pid 2.删除文件夹: rm -rf /var/log/httpd/access 3.更新pip: python -m pip ...
- vue中v-for
在vue中我们只要操作数据,就可以渲染和更新数据,这背后的boss就是diff算法 vue和react的虚拟DOM的Diff算法大致相同,其核心是基于两个简单的假设: 1. 俩个相同组件产生类似DOM ...
- Spring事务处理时自我调用
1.预备知识 aop概念请参考[http://www.iteye.com/topic/1122401]和[http://jinnianshilongnian.iteye.com/blog/141859 ...
- vue学习(十六) 自定义私有过滤器 ES6字符串新方法 填充字符串
<div id="app"> <p>{{data | formatStr('yyyy-MM-dd')}}</p></div> //s ...
- string类型 C++
(C++递归预习到了string类型,这个是处理字符串的一个非常好用的东西,在C里面没有.今天来学习一下) 顺便推荐一个很不错的网站:http://c.biancheng.net/view/400.h ...
- 在html页面中引入另一个html页面
我们在使用html编写一个网站的时候,通常情况下头部和尾部是相同的,如果一个网站的每个页面都把这些代码写一遍,不仅浪费时间,还显得重复代码很多,所以此时把重复的页面单独摘出来,在用到的时候从外部直接引 ...
- Redis 的 KEYS 命令不能乱用啊
KESY 命令 时间复杂度: O(N) , 假设Redis中的键名和给定的模式的长度有限的情况下,N为数据库中key的个数. Redis Keys 命令用于查找所有符合给定模式 pattern 的 k ...