作者:saint37
链接:https://www.jianshu.com/p/66bfd791e85a

最近在研究三维可视化,发现了一堆奇怪的问题,我好菜啊我怎么这么菜,记录一下过程和一些坑。

Three.js官网:https://threejs.org/
学犀牛中文论坛:http://www.xuexiniu.com/

最近在研究三维可视化,发现是个水很深的领域。Three.js是一个基于WebGL的三维可视化库,功能很强大,官网上有很多炫酷的例子。

Rhino是一个类似3Dmax的建模软件,为什么不用3Dmax……是因为Mac电脑装不了3Dmax ╮(╯_╰)

官网的Documentation中对Three.js的基础用法介绍的很详细,这里就不般教程了,只是稍微记录下这两天学习(爬坑)的过程。

警告⚠️:本篇不是个详细的Three.js教程,事实上,Vue,Three.js,Rhino单拎出来都不是很困难,遇到的大部分问题都是因为作者心血来潮要同时用这仨。

一. 环境搭建

Three.js的官网教程是基于html+js的,集成到Vue里直接npm或者yarn装就行了。

npm install three

Vue是我们的老朋友了这里就不讲相关知识啦,在我们的Vue工程里,引入Three,并创建一个简单的场景。

Three.js三要素场景Scene、相机Camera、渲染器Renderer,场景Scene定义了整体空间,用于保存、追踪所渲染物体;相机Camera定义了观察场景的角度;渲染器Renderer最终在浏览器中渲染出画面。

所以我们在Vue的data里,先定义好camera, scene, renderer,初值给null即可。

<template>  <div class="area"><!-- Three.js主体展示 --><div id="container"></div></div>
</template>
<script>
import * as THREE from 'three'export default {name: 'ThreeTest',data() {return {camera: null,scene: null,renderer: null,}}methods: {}
}
</script>

接下来在method里面创建场景,基本是跟在html里写没什么差别。关于相机,渲染器的基本参数请参照官网api。

methods: {    init() {let container = document.getElementById('container');this.scene = new THREE.Scene();this.camera = new THREE.PerspectiveCamera(45, container.clientWidth/container.clientHeight, 0.1, 1000);this.camera.position.x = 40;this.camera.position.y = 40;this.camera.position.z = 40;this.camera.lookAt(this.scene.position);this.renderer = new THREE.WebGLRenderer();this.renderer.setClearColor(0xEEEEEE); //背景色this.renderer.setSize(container.clientWidth, container.clientHeight); //场景大小this.renderer.shadowMap.enabled = true; //启用阴影console.log(scene);console.log(camera);console.log(renderer);container.appendChild(this.renderer.domElement);this.renderer.render(this.scene, this.camera);}},mounted() {this.init();}

添加完毕后,虽然屏幕上一片灰啥都没有,但我们可以在控制台输出场景、相机、渲染器参数查看。自此,证明我们已经在Vue里成功创建了一个three.js的三维场景。

Three.js三要素

如果控制台遇到问题

"ReferenceError: THREE is not defined"

请确定导入的时候是不是写对了

import * as THREE from 'three'

二. Three.js基础元素

Step1: 坐标系建立
为了便于查看,先在场景中建立一个直角坐标系,包括坐标轴和平面。

//添加坐标轴
let axes = new THREE.AxesHelper(20);this.scene.add(axes);//平面let planeGeometry = new THREE.PlaneGeometry(60,20)let planeMaterial = new THREE.MeshLambertMaterial({color: 0xcccccc});let plane = new THREE.Mesh(planeGeometry, planeMaterial);plane.receiveShadow = true;plane.rotation.x = -0.5* Math.PI;this.scene.add(plane);

为了渲染,还需要加个光源,不然所有元素都会是一片黑色。

let spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(40, 80, -20);spotLight.castShadow = true;this.scene.add(spotLight);

在Three.js的坐标系里,红色是x轴,绿色是y轴,蓝色是z轴。注意这时候根据我们的设定,相机位置在(40,40,40),所以看到的是如下效果。可以适当调整相机位置感受一下坐标变换。

坐标系建立

Step2: 添加几何体
下面给这个场景加两个几何体。加一个球和一个方块。
首先在data里加上cube和sphere用来存储球和方块。

data() {    return {……sphere:null,cube:null,}}

然后init方法里定义一下位。

//方体
let cubeGeometry = new THREE.BoxGeometry(5, 5, 5);let cubeMaterial = new THREE.MeshLambertMaterial({color: 0xffee6b});this.cube = new THREE.Mesh(cubeGeometry, cubeMaterial);this.cube.castShadow = true;this.cube.position.x = -10;this.cube.position.y = 10;this.scene.add(this.cube);//球体let sphereGeometry = new THREE.SphereGeometry(2, 20, 20);let sphereMaterial = new THREE.MeshLambertMaterial({color: 0x7777ff});this.sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);this.sphere.castShadow = true;this.sphere.position.x = 20;this.sphere.position.y = 5;this.sphere.position.z = 0;this.scene.add(this.sphere);

立体几何学的好,坐标设置无烦恼。
MeshLambertMaterial是Three.js中一种不太亮的纯色材质,Three.js中的材质还有很多,可以去官网文档的Materials那栏多尝试几个。

立方体和球

推荐试一下MeshNormalMaterial,效果非常炫酷。

MeshNormalMaterial

Step3: 添加动画
现在我们想让这两个元素动一动,所以新建一个animate方法。(记得先在data里定义好step,用来作为球移动的变量。)

  animate() {        requestAnimationFrame(this.animate);//旋转方体this.cube.rotation.x += 0.02;this.cube.rotation.y += 0.02;//弹跳球this.step += 0.03;this.sphere.position.x = 10 + ( 10 * (Math.cos(this.step)));this.sphere.position.y = 2 + ( 10 * Math.abs(Math.sin(this.step)));this.renderer.render(this.scene, this.camera);}

并且在mounted里把animate加上。

mounted() {
this.init();this.animate();}

为了光效更好一些我们可以在init中刚刚定义光源的地方加个环境光源。

let ambiColor = "#523318";
let ambientLight = new THREE.AmbientLight(ambiColor);
this.scene.add(ambientLight);

这样元素就动起来了,不会上传动图请假装下面是个动图。

我想起那天夕阳下的弹球,那是我逝去的……

Step4: 添加纹理贴图
现在方块和球的颜色都是我们自己定的rgb颜色,但是三维模型一般都是需要贴图的,(我在给外部Obj贴图的时候遇到了个很大的坑!这个第四部分再述。)Three.js中,提供TextureLoader可以直接加载外部纹理图片。

比如我们有一张伊丽莎白痴呆图。在Vue中,需要把它放在public静态资源文件夹下。(Vue3.0之前的工程应该是static文件夹。)这里静态资源不建议跟代码放在同一目录,因为Vue工程会自动变动目录地址,可能会匹配不到。

不是假发是伊丽莎白

Vue的静态资源文件夹

之后,用TextureLoader加载图片。注意引用静态资源直接加个/就行。

//加载纹理
new THREE.TextureLoader().load('/Elizabeth.jpg',
texture => {this.cube.material = new THREE.MeshLambertMaterial({map: texture});});

这时,场景中的方块就贴上了图。

我想起那天夕阳下的伊丽莎白……

三. 添加Control组件

Three.js里一般用gui.dat作为辅助的控制组件,Vue添加gui.dat基本上没遇到什么坑。Html里怎么写的,除了把控制变量都放Data里定义,其他写法照搬过来就行。

npm install dat.gui
import dat from 'dat.gui'

之后使用方式基本跟在html中一样了,这里就不逐行介绍了。比如希望控制立方体旋转速度和小球弹跳速度,Data里先定义好两个速度变量。

data() {    return {      ……      step:0,      controls: {        rotationSpeed: 0.02,        bouncingSpeed: 0.03      }    }  },

method里增加方法初始化gui,并在init中调用一下。

   initgui() {        const gui = new dat.GUI(); // gui监测器        gui.add(this.controls, 'rotationSpeed', 0, 0.2);        gui.add(this.controls, 'bouncingSpeed', 0, 0.2);        this.init();    },

之后改一下animate,将动画绑定到controls中。

let { controls } = this        requestAnimationFrame(this.animate);        //旋转方体        this.cube.rotation.x += controls.rotationSpeed;        this.cube.rotation.y += controls.rotationSpeed;//弹跳球        this.step += controls.bouncingSpeed;        this.sphere.position.x = 10 + ( 10 * (Math.cos(this.step)));        this.sphere.position.y = 2 + ( 10 * Math.abs(Math.sin(this.step)));this.renderer.render(this.scene, this.camera);

这样,就能通过控制组件改变动画速度。

控制组件

四. 引入外部三维模型

现在,终于要轮到我们Rhino出场了ヾ(≧▽≦*)o。这一步非常不顺利会有很多坑,我用加粗注明了。

我们首先在Rhino中建个模型。怎么建模的就不讲了,总之我们有了一条草鱼(草纹理的鱼,简称草鱼)。

草鱼建模

然后,把这个模型导出成obj文件。会看到包括一个obj,一个mtl和一个png文件。obj是模型的基本轮廓,没有颜色。mtl是相关联的色彩配置文件。png就是mtl里用到的纹理图片。把这三个文件都放到public文件夹下。

草鱼模型文件

这里的第一个坑,是如果不放到public里面,可能会报以下错误,因为vue会编译时会更改资源路径。

Uncaught Error: THREE.OBJLoader: Unexpected line: “”

Three.js可以加载多种3D模型,需要单独引入js文件。但放到Vue里,毕竟不是引个js就能搞定的事,首先要保证npm上有这些加载模型的工具包。好在常见的Obj,Stl加载工具都是有的。

npm install three-obj-mtl-loader

装完后引入。

import { MTLLoader, OBJLoader } from 'three-obj-mtl-loader'

我们去掉刚刚的屏幕,立方体和弹球,或者新建另一个组件,加载这条鱼。
首先data里定义一个数据存放鱼。

data() {    return {      camera: null,      scene: null,      renderer: null,      fish: null,    }  }

然后method里用MTLLoader和OBJLoader加载鱼。

    init() {          ……        //加载模型        let mtlLoader = new MTLLoader();        let objLoader = new OBJLoader();        mtlLoader.load('/fish.mtl', (materials) => {          materials.preload();          objLoader.setMaterials(materials);          objLoader.load('/fish.obj', (object) => {            object.scale.set(1, 1, 1);            this.fish = object;            this.scene.add(object);          })        })        ……    },    animate() {      requestAnimationFrame(this.animate);      if(this.fish){        this.fish.rotation.y += 0.006;      }      this.renderer.render(this.scene, this.camera);    }

这里的第二个坑是如果模型没有显示,并且控制台也不报错,请先在控制台输出scene,确认模型是不是被加载上了。一般来讲都是因为相机视角不对,把相机位置和模型的缩放比例调一调,理论上就可以看到。

object.scale.set(1, 1, 1); 对于有些模型,可能要放大到100倍才能看到,也有些模型可能要缩小到0.1.

调整完毕后,OK,有一条鱼在动了!

鱼模型

但是为什么是条黑鱼不是草鱼(⊙ˍ⊙)?纹理没有加载上,整个模型呈黑色。

这是第三个坑,经测试,如果用的是html+js,其实是没有任何问题的可以看到草鱼,但是在Vue里,大概又是路径的配置问题,其实mtl并没有获取到对应的png。需要我们打开mtl文件做一些更改。

mtl文件详情

可以看到最后一行,是匹配到Grass.png中的,我们将它改成。

map_Kd /Grass.png

对,就加上一个/路径(°ー°〃)。再回到浏览器里,发现纹理已经加上了。

草鱼

当然,很多情况下,加载模型的时候会出现各种纹理加载不上的状况,所以这里介绍另一种曲线救国的万能解决方法。
就是只加载obj,然后手动用前文所说的TextureLoader自己加载纹理。

//曲线救国加载纹理        new OBJLoader().load('/fish.obj' , obj => {          let texture = new THREE.TextureLoader().load('/Grass.png');          let material = new THREE.MeshLambertMaterial( { map: texture } );          obj.children.forEach(child => {              child.material = material;          });          this.fish = obj;          this.scene.add(obj);        })

效果也是一样的!改个背景色,于是:

水中草鱼

五. 总结

Three.js很强大,三维可视化还有很大的发展空间,篇幅所限,以后再对材质,纹理,动画做更深入研究。本文中记录的坑希望大家不要遇到。

Vue+Three.js+Rhino三维建模研究学习相关推荐

  1. 基于skyline的城市三维建模研究(转)

    自从戈尔提出"数字地球"的概念后,用数字形式表示地理空间成为热点,数字省市.数字城镇已经成为世界各国发达省市和地区21世纪的发展战略,成为争先抢占科技.产业和经济的制高点之一.在构 ...

  2. 基于skyline的城市三维建模研究

    基于skyline的城市三维建模研究 自从戈尔提出"数字地球"的概念后,用数字形式表示地理空间成为热点,数字省市.数字城镇已经成为世界各国发达省市和地区21世纪的发展战略,成为争先 ...

  3. Vue+Three.js实现三维管道可视化及流动模拟

    最近在研究Geotoolkit过程中,发现很多三维的应用场景,用其实现起来比较复杂,就开展了利用Three.js实现海底管道流动的模拟. 推荐一个学习地址:Three.js教程,这这里的学习示例基本上 ...

  4. 标记三维点_SSW系统在地下大型停车场三维建模中的应用研究

    作 者 信 息 邓学锋,徐 娜,贾 宝 (河南省测绘工程院,河南 郑州 450003) " [摘要]针对地下空间GNSS信号弱.空间狭窄等特殊场景,基于国产SSW移动激光测量系对大型地下停车 ...

  5. 无人机倾斜摄影—三维建模和DSM,DEM,DOM(正射影像)的生成「CC(Smart3D)),Pix4d,Photoscan,Inpho」

    CC(Smart3D)),Pix4d,Photoscan,Inpho所有教程做了个汇总 已下为文章目录 由于文章较多,在CSDN中做单个超链接比较麻烦 所所以大家可以关注微信公众号-GIS前沿 关注后 ...

  6. 最新Rhino 犀牛 7 for Mac(三维建模软件)7.21.22208

    Rhino 犀牛 7 for Mac,是一款超强的三维建模工具,它包含了所有的NURBS建模功能,用它建模感觉非常流畅,所以大家经常用它来建模,然后导出高精度模型给其他三维软件使用.Rhino可以广泛 ...

  7. 三维家导入户型镜像怎么使用_UG虎钳三维建模教学,认真看仔细学习了!

    虎钳作为机加工行业中最频繁出现的夹具,相信大家一定都不陌生,用的次数估计也不少,那么你了解UG是怎么做出虎钳模型的吗? 今天就带大家来看看虎钳模型是怎么用UG做出来的,赶紧学习起来吧! 建模过程: 一 ...

  8. 全景虚拟漫游技术实现(three.js vs ThingJS) Javascript 3D开发 前端 物联网 webgl 三维建模 3D模型 虚拟 全景

    三维建模无非就是通过专业技能加工成立体图形,使之图形成为直观.易懂,容易判读的立体图件.对于开发者来说,选择一个好的3D开发框架,在全景虚拟漫游场景上实现3D动效,ThingJS vs three.j ...

  9. 用matlab绘制树叶,UG画树叶的叶子,这个三维建模方法值得学习

    原标题:UG画树叶的叶子,这个三维建模方法值得学习 今天来教大家绘制一片树叶,学会了大家再做个树干,这样就能完成一些塑料盆栽模型了,来学习一下绿叶的画法吧,这可是最简单的曲面做法了. 建模过程: 1. ...

最新文章

  1. 安防行业成巨头必争之地 一文梳理安防AI芯片产品与主要企业
  2. xadmin2 django 搭建学生系统 model层
  3. python小程序源代码-Python数据库小程序源代码
  4. java.lang.UnsatisfiedLinkError: org.apache.hadoop.util.NativeCrc32.nativeComputeChunkedSumsByteArray
  5. python waitkey_python中VideoCapture(),read(),waitKey()的使用
  6. 去掉窗口_Flink 基础——窗口(Window)理论篇
  7. ad域需要自建dns服务器吗,创建AD DS域服务(图文详解)
  8. jquery:临时禁止鼠标滚动 How to disable scrolling temporarily?
  9. 当当购书双十一钜惠,5折封顶!附图灵人工智能书单
  10. 12306微信小程序上线 提供余票查询暂不支持购票
  11. 虚拟均衡器:Producers Vault Baby Bass for Mac
  12. java开发文档怎么写?教你写java技术文档
  13. 电脑软件测试英雄联盟,怎么测试电脑能不能玩英雄联盟
  14. php如何批量发送短信,如何在php中运行批量短信api [关闭]
  15. 使用PS去掉、添加、复制图片中的文字
  16. swift 下标 subscript
  17. 大学里青年教师待遇真的很低吗?
  18. HOW2J.CN - 学习笔记(类和对象)
  19. nltk中文分句_利用NLTK进行分句分词
  20. linux音频子系统 - pcm设备

热门文章

  1. 修改el-image 查看原图
  2. 白马培训机构招生管理系统-程序流程图
  3. 谷歌周彦祺:LLM浪潮中的女性科学家多面手丨智源大会嘉宾风采
  4. 博达路由器常见功能教学1
  5. CocosCreator 音效管理
  6. 浅谈cesium在vue2中的使用---踩坑日记(一)
  7. 理解和使用zlib库 - 我个人的救赎
  8. QT 繁琐API记录
  9. LEARNING VOLUMETRIC SEGMENTATION FOR LUNG TUMOR
  10. 自定义ViewGroup与SurfaceView