热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

three.js制作魔方

原标题:three.js制作魔方因为之前的几节讲了一些数学方法,例如Vector3、Matrix4、Euler还有Quaternion的知识。所以这篇郭先生就来说说用three.

原标题:three.js 制作魔方

因为之前的几节讲了一些数学方法,例如Vector3、Matrix4、Euler还有Quaternion的知识。所以这篇郭先生就来说说用three.js怎么制作一个魔方。在线案例请点击博客原文

制作魔方主要运用坐标变换的知识,制作魔方的方法有很多,建议你先在大脑中构思,然后试着做一做,下面我将一种比较简单的方法。


  1. 制作出魔方各个方块的位置坐标(27个)的数组,然后制作出魔方各个面的材质(6个)

  2. 根据坐标和材质制作魔方的方块,并添加到一个组group

  3. 制作一个标志被选面的几何体(我是用球体),然后隐藏

  4. 使用THREE.Raycaster,给模型绑定事件,并记录选定的一些数据,将标志显示并放到合适的位置

  5. 点击模拟方向键盘,根据之前记录的数据,转动魔方(重点)

以上是主要的步骤,但是对于新同学,需要注意的仍然很多,下面上主要代码,按照方法说

1. 定义的变量

posArr = [
[
100,100,100],[100,100,0],[100,100,-100],[100,0,100],[100,0,0],[100,0,-100],[100,-100,100],[100,-100,0],[100,-100,-100],
[
0,100,100],[0,100,0],[0,100,-100],[0,0,100],[0,0,0],[0,0,-100],[0,-100,100],[0,-100,0],[0,-100,-100],
[
-100,100,100],[-100,100,0],[-100,100,-100],[-100,0,100],[-100,0,0],[-100,0,-100],[-100,-100,100],[-100,-100,0],[-100,-100,-100]
],
//方块位置坐标
materials,//材质数组
mouse = new THREE.Vector2(),//通过鼠标点击的位置计算出raycaster所需要的点的位置,以屏幕中心为原点,值的范围为-1到1.
raycaster,//射线对象
grouwww.yii666.comp,//存放魔方方块的数组
groupTemp,//魔方转动时临时数组
object3d,//魔方被选择面的标志物对象
currentPos,//魔方被点击小块的位置
currentNor,//魔方被点击小块面的法向量
currentUp,//魔方被点击时,相机up的向量


2. 定义材质数组

initMaterial() {
var map_red = new THREE.TextureLoader().load('/static/images/color/m_red.jpg', () => this.loadover --);
var map_orange = new THREE.TextureLoader().load('/static/images/color/m_orange.jpg', () => this.loadover --);
var文章来源站点https://www.yii666.com/ map_yellow = new THREE.TextureLoader().load('/static/images/color/m_yellow.jpg', () => this.loadover --);
var map_blue = new THREE.TextureLoader().load('/static/images/color/m_blue.jpg', () => this.loadover --);
var map_green = new THREE.TextureLoader().load('/static/images/color/m_green.jpg', () => this.loadover --);
var map_white = new THREE.TextureLoader().load('/static/images/color/m_white.jpg', () => this.loadover --);
var map_sprite = new THREE.TextureLoader().load('/static/images/base/direction.png', () => this.loadover --);
let mater_red
= new THREE.MeshBasicMaterial({map: map_red, side: THREE.DoubleSide});
let mater_orange
= new THREE.MeshBasicMaterial({map: map_orange, side: THREE.DoubleSide});
let mater_yellow
= new THREE.MeshBasicMaterial({map: map_yellow, side: THREE.DoubleSide});
let mater_white
= new THREE.MeshBasicMaterial({map: map_white, side: THREE.DoubleSide});
let mater_blue
= new THREE.MeshBasicMaterial({map: map_blue, side: THREE.DoubleSide});
let mater_green
= new THREE.MeshBasicMaterial({map: map_green, side: THREE.DoubleSide});
materials
= [mater_red, mater_orange, mater_yellow,mater_white, mater_blue, mater_green];
}


3. 绘制小方块并绘制标志物(先隐藏)

initsquare() {
var sphereGeom = new THREE.SphereGeometry(10, 30, 20);
var sphereMate = new THREE.MeshPhongMaterial({color: 0x333333});
object3d
= new THREE.Mesh(sphereGeom, sphereMate);
object3d.name
= 'object3d';
object3d.visible
= false;
scene.add(object3d);
group
= new THREE.Group();
group.name
= 'group';
var geometry = new THREE.BoxGeometry(100, 100, 100);
var mesh = new THREE.Mesh(geometry, materials);
posArr.forEach((d,i)
=> {
let meshCopy
= mesh.clone();
meshCopy.position.set(d[
0], d[1], d[2])
meshCopy.name
= 'box-' + i;
group.add(meshCopy);
})
scene.add(group);
this.render();
document.getElementById(
"loading").style.display = "none";
}


4. 监听模型的点击事件

initEventListener() {
raycaster
= new THREE.Raycaster();
document.ad文章来源地址30518.htmldEventListener(
'mousemove', function (event) {
event.preventDefault();
mouse.x
= (event.clientX / window.innerWidth) * 2 - 1;
mouse.y
= - (event.clientY / window.innerHeight) * 2 + 1;
},
false)
document.addEventListener(
'mousedown', () => {
if (scene.children && scene.getObjectByName('group')) {
raycaster.setFromCamera(mouse, camera);
let intersects
= raycaster.intersectObjects(scene.getObjectByName('group').children);
if (intersects[0] && intersects[0].object.name != 'object3d') {
let index
= intersects[0].faceIndex;
let point
= intersects[0].point;
currentUp
= this.computedUp(camera);
currentNor
= this.computedNor(point)
currentPos
= intersects[0].object.position;
let pos
= this.computedPos(point);
object3d.position.copy(pos);
object3d.visible
= true;
}
}
})
}


5. 监听方向软键盘的点击,根据点击键的不同,生成旋转轴


handleRotate(num) {
if(!rotateFlag || !currentPos) return ;
rotateFlag
= false;
groupTemp
= new THREE.Group();
groupTemp.name
= 'group-temp';
let axis;
let tempMeshArr
= [];
switch (num) {
case 1:
axis
= currentNor.clone().cross(currentUp);
break;
case 2:
axis
= currentNor.clone().cross(currentUp).negate();
break;
case 3:
axis
= currentUp.clone().negate();
break;
cwww.yii666.comase 4:
axis
= currentUp;
break;
}
let plane
= new THREE.Plane().setFromNormalAndCoplanarPoint(axis, currentPos);
scene.getObjectByName(
'group').children.forEach(d => Math.abs(plane.distanceToPoint(d.position)) <1 && tempMeshArr.push(d))
tempMeshArr.forEach(d
=> {
group.remove(d);
groupTemp.add(d);
})
// object3d.visible = false;
scene.remove(scene.getObjectByName('group-temp'));
scene.add(groupTemp);
this.handleTween(axis);
}


6. 加一点tween的补间动画,效果更好哦

handleTween(axis) {
let start
= {angle: 0, axis};
let end
= {angle: Math.PI/2, axis};
tween = new TWEEN.Tween(start).to(end, 500);
tween.easing(TWEEN.Easing.Linear.None);
tween.onUpdate(
function () {
let quaternion
= new THREE.Quaternion().setFromAxisAngle(axis, this._object.angle);
groupTemp.rotation.setFromQuaternion(quaternion);
});
tween.onComplete(()
=> {
let matrix
= this.standerMatrix(groupTemp.matrix);
groupTemp.children.forEach(d
=> {
let mesh
= d.clone();
mesh.applyMatrix4(matrix)
mesh.position.copy(
this.standarPos(mesh.position))
group.add(mesh);
})
scene.remove(groupTemp)
rotateFlag
= true;
})
tween.start();
}

郭先生制作魔方的主要思路就是先做出27个方块添加到组A,6个面分别添加不同颜色的贴图(自己p的哦),然后使用raycaster选择点击的面,并确定当时的up方向和法向量方向以备后用,点击上下左右并结合u方向和法向量方向计算出旋转矩阵,根据已有条件计算出是那一排方块改变,并将这9个块添加到组B文章来源地址30518.html中,从组A中删除这9个,根据旋转矩阵旋转组B,并且在旋转完之后将组B中的方块添加到组A中,旋转完毕(这里比较难的就是根据上下左右判断旋转轴向量)。

以上就是一种制作魔方的方法,综合了很多矩阵向量四元数欧拉角和平面的知识,希望对新来的同游有些帮助

转载请注明地址:郭先生的博客

来源于:three.js 制作魔方


推荐阅读
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文介绍了PhysioNet网站提供的生理信号处理工具箱WFDB Toolbox for Matlab的安装和使用方法。通过下载并添加到Matlab路径中或直接在Matlab中输入相关内容,即可完成安装。该工具箱提供了一系列函数,可以方便地处理生理信号数据。详细的安装和使用方法可以参考本文内容。 ... [详细]
  • 推荐系统遇上深度学习(十七)详解推荐系统中的常用评测指标
    原创:石晓文小小挖掘机2018-06-18笔者是一个痴迷于挖掘数据中的价值的学习人,希望在平日的工作学习中,挖掘数据的价值, ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Final关键字的含义及用法详解
    本文详细介绍了Java中final关键字的含义和用法。final关键字可以修饰非抽象类、非抽象类成员方法和变量。final类不能被继承,final类中的方法默认是final的。final方法不能被子类的方法覆盖,但可以被继承。final成员变量表示常量,只能被赋值一次,赋值后值不再改变。文章还讨论了final类和final方法的应用场景,以及使用final方法的两个原因:锁定方法防止修改和提高执行效率。 ... [详细]
  • Nginx使用(server参数配置)
    本文介绍了Nginx的使用,重点讲解了server参数配置,包括端口号、主机名、根目录等内容。同时,还介绍了Nginx的反向代理功能。 ... [详细]
  • 电销机器人作为一种人工智能技术载体,可以帮助企业提升电销效率并节省人工成本。然而,电销机器人市场缺乏统一的市场准入标准,产品品质良莠不齐。创业者在代理或购买电销机器人时应注意谨防用录音冒充真人语音通话以及宣传技术与实际效果不符的情况。选择电销机器人时需要考察公司资质和产品品质,尤其要关注语音识别率。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • javascript  – 概述在Firefox上无法正常工作
    我试图提出一些自定义大纲,以达到一些Web可访问性建议.但我不能用Firefox制作.这就是它在Chrome上的外观:而那个图标实际上是一个锚点.在Firefox上,它只概述了整个 ... [详细]
  • 本文介绍了使用PHP实现断点续传乱序合并文件的方法和源码。由于网络原因,文件需要分割成多个部分发送,因此无法按顺序接收。文章中提供了merge2.php的源码,通过使用shuffle函数打乱文件读取顺序,实现了乱序合并文件的功能。同时,还介绍了filesize、glob、unlink、fopen等相关函数的使用。阅读本文可以了解如何使用PHP实现断点续传乱序合并文件的具体步骤。 ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
author-avatar
phpyi
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有