文章目录

前言

一、Three.js简介

二、开发步骤

1.安装Three.js

2.创建容器

3.创建模型

总结


前言

3D模型给人一种更真实的感受,带来极致的视觉体验。本文介绍Vue结合Three.js开发3D小房子,接触过OpenGL的小伙伴看起来会更轻松一点。


一、Three.js简介

Three.js,一个WebGL引擎,基于JavaScript,可直接运行GPU驱动游戏与图形驱动应用于浏览器。其库提供大量特性与API以绘制3D场景于浏览器。官网地址

二、开发步骤

1.安装Three.js

这里是使用的npm安装

npm install three

2.创建容器

Three.js是使用Js将3D模型渲染在一个画布中,需要创建一个容器来存放。

<div class="three_page" id="threePage">
</div>

3.创建模型

Three.js有几个非常重要的概念,场景、相机、光源、坐标系,渲染器......首先需要创建一个场景对象,因为其他模型都需要放在场景中,最后将场景交由渲染器进行渲染。

initScene(){this.scene = new THREE.Scene();
}

为了方便确定模型的位置,所以我引入了坐标系。红色代表 X 轴.,绿色代表 Y 轴.,蓝色代表 Z 轴。

initAxes(){let axes = new THREE.AxesHelper(50);// 将坐标加入到场景this.scene.add(axes)
}

创建一个地面

initPlane(){let plane = new THREE.PlaneGeometry(this.planeWidth, this.planeHeight);let materialPlane = new THREE.MeshLambertMaterial({color: 0xcccccc});let planeMesh = new THREE.Mesh(plane, materialPlane);planeMesh.rotation.x = -0.5 * Math.PI;planeMesh.position.set(0, 0, 0);this.scene.add(planeMesh);
},

创建光源,光源是非常重要的,要是没有光源,将会什么都看不见。光源有好几种,本文中使用的是环境光和点光源。

initLight(){this.scene.add(new THREE.AmbientLight(0x444444));//环境光,可以看到所有物体// 光源1// DirectionalLight 方向光let pointLight = new THREE.PointLight(0xffffff);//点光源pointLight.position.set(20, 30, 20);this.scene.add(pointLight);// 光源2let pointLight2 = new THREE.PointLight(0xffffff);//点光源pointLight2.position.set(150, 100, 20);this.scene.add(pointLight2);
},

创建相机,相机就相当于人眼,你要在什么位置看,看多大的范围,都在相机里面配置。

initCamera(){this.camera = new THREE.PerspectiveCamera(45, 2, 0.1, 2000);this.camera.position.set(120, 100, 0);this.camera.lookAt(this.scene.position);
},

创建渲染器,这一步很重要,我们创建的模型都是放在Scene里面的,最后需要将Scene和Samera交由渲染器进行渲染。

initRenderer(){this.container = document.getElementById('threePage');this.renderer = new THREE.WebGLRenderer({antialias: true //消除锯齿});this.renderer.setSize(this.container.clientWidth, this.container.clientHeight);this.renderer.setClearColor(0xb9d3ff, 1);this.renderer.render(this.scene, this.camera);this.container.appendChild(this.renderer.domElement);this.container.addEventListener('click', this.onMouseClick);//增加鼠标拾取效果let controls = new OrbitControls(this.camera, this.renderer.domElement);controls.addEventListener('change', () => {this.renderer.render(this.scene, this.camera);});
},

到此,就已经完成了平面和坐标系的渲染。

接着往容器中加入模型,官网介绍了很多模型的创建方法,本文是导入的外部模型,感兴趣的小伙伴可以去一些网站下载模型,这里提供一个网站。模型也有很多种格式,本文导入的是glb的格式

async initModel() {let glb = await this.loadGlb('./model/house_type13.glb');// 设置模型位置 (y,z,x)glb.position.set(0, 0, 0);// 设置模型缩放比例glb.scale.set(30, 30, 30);this.houseData.push(glb)this.scene.add(glb);let three=await this.loadGlb('./model/tree_large.glb');three.position.set(30, 0, 20);three.scale.set(30, 30, 30);this.houseData.push(three)this.scene.add(three);let three2=await this.loadGlb('./model/tree_large.glb');three2.position.set(30, 0, 30);three2.scale.set(30, 50, 50);this.houseData.push(three2)this.scene.add(three2);let house2=await this.loadGlb('./model/house_type15.glb');house2.position.set(30, 0, 50);house2.scale.set(30, 30, 30);this.houseData.push(house2)this.scene.add(house2);
},
loadGlb(path) {return new Promise((resolve, reject) => {var loader = new GLTFLoader();loader.setCrossOrigin('Anonymous');//跨域问题loader.load(path, (glb) => {resolve(glb.scene);}, undefined, (error) => {reject(error);});}).catch((e) => {console.log("异常", e);});
},

同样,将模型加入到场景(Scene)后,需要交给渲染器进行渲染。最后小房子也出来了呀。

完整代码

<template><div class="three_page" id="threePage"></div>
</template><script>
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader"
import { MTLLoader } from "three/examples/jsm/loaders/MTLLoader"
export default {data() {return {renderer: '',cube: '',planeWidth: 150,planeHeight: 200,raycaster: new THREE.Raycaster(),mouse: new THREE.Vector2(),dialogControl: '',houseData: [],container: '',dialogData: '',modelName: []}},created() {},mounted() {this.init()},methods: {// 创建场景initScene() {this.scene = new THREE.Scene();},// 创建坐标initAxes() {let axes = new THREE.AxesHelper(50);// 将坐标加入到场景this.scene.add(axes)},// 创建平面initPlane() {let plane = new THREE.PlaneGeometry(this.planeWidth, this.planeHeight);let materialPlane = new THREE.MeshLambertMaterial({color: 0xcccccc});let planeMesh = new THREE.Mesh(plane, materialPlane);planeMesh.rotation.x = -0.5 * Math.PI;planeMesh.position.set(0, 0, 0);this.scene.add(planeMesh);},// 创建光源initLight() {this.scene.add(new THREE.AmbientLight(0x444444));//环境光,可以看到所有物体// 光源1// DirectionalLight 方向光let pointLight = new THREE.PointLight(0xffffff);//点光源pointLight.position.set(20, 30, 20);this.scene.add(pointLight);// 光源2let pointLight2 = new THREE.PointLight(0xffffff);//点光源pointLight2.position.set(150, 100, 20);this.scene.add(pointLight2);},// 创建相机initCamera() {this.camera = new THREE.PerspectiveCamera(45, 2, 0.1, 2000);this.camera.position.set(120, 100, 0);this.camera.lookAt(this.scene.position);},// 创建渲染器initRenderer() {this.container = document.getElementById('threePage');this.renderer = new THREE.WebGLRenderer({antialias: true //消除锯齿});this.renderer.setSize(this.container.clientWidth, this.container.clientHeight);this.renderer.setClearColor(0xb9d3ff, 1);this.renderer.render(this.scene, this.camera);this.container.appendChild(this.renderer.domElement);this.container.addEventListener('click', this.onMouseClick);//增加鼠标拾取效果let controls = new OrbitControls(this.camera, this.renderer.domElement);controls.addEventListener('change', () => {this.renderer.render(this.scene, this.camera);});},init() {this.initScene()this.initAxes()this.initPlane()this.initLight()this.initCamera()this.initRenderer()this.initModel()setInterval(() => {this.renderer.render(this.scene, this.camera);}, 1000)},// 加载模型async initModel() {let glb = await this.loadGlb('./model/house_type13.glb');// 设置模型位置 (y,z,x)glb.position.set(0, 0, 0);// 设置模型缩放比例glb.scale.set(30, 30, 30);this.houseData.push(glb)this.scene.add(glb);let three = await this.loadGlb('./model/tree_large.glb');three.position.set(30, 0, 20);three.scale.set(30, 30, 30);this.houseData.push(three)this.scene.add(three);let three2 = await this.loadGlb('./model/tree_large.glb');three2.position.set(30, 0, 30);three2.scale.set(30, 50, 50);this.houseData.push(three2)this.scene.add(three2);let house2 = await this.loadGlb('./model/house_type15.glb');house2.position.set(30, 0, 50);house2.scale.set(30, 30, 30);this.houseData.push(house2)this.scene.add(house2);},// 加载DLBloadGlb(path) {return new Promise((resolve, reject) => {var loader = new GLTFLoader();loader.setCrossOrigin('Anonymous');//跨域问题loader.load(path, (glb) => {resolve(glb.scene);}, undefined, (error) => {reject(error);});}).catch((e) => {console.log("异常", e);});},// 加载gltfaddGltfItem() {let that = this;let loader = new GLTFLoader();loader.load("./glb/model.gltf", function (gltf) {gltf.scene.position.set(0, 0, 95);gltf.scene.scale.set(16, 12, 12);that.scene.add(gltf.scene);});},// 加载objaddObjItem() {var loader = new OBJLoader();var mat = new MTLLoader();let that = this;mat.load("./glb/house_type01.mtl", function (materials) {materials.preload();loader.setMaterials(materials);loader.load("./glb/house_type01.obj",function (object) {console.log("数据==>", object);object.position.set(0, 0, 0);object.scale.set(13, 13, 13);that.scene.add(object);});});},// 点击事件onMouseClick(event) {event.preventDefault();this.dialogControl = {show: false,top: 0,left: 0};let mou = new THREE.Vector2()// 将鼠标位置归一化为设备坐标。x 和 y 方向的取值范围是 (-1 to +1)mou.x = (event.clientX / this.container.clientWidth) * 2 - 1;mou.y = -(event.clientY / this.container.clientHeight) * 2 + 1;console.log("x", "y", this.mouse.x, this.mouse.y);this.raycaster.setFromCamera(mou, this.camera);let intersects = this.raycaster.intersectObjects(this.scene.children, true);// 获取选中最近的 Mesh 对象if (intersects.length !== 0 && intersects[0].object.type === "Mesh") {let selectName = intersects[0].object.name;console.log("模型名字", intersects[0].object.name);this.houseData.forEach(h => {console.log(h.name);if (h.name === selectName) {this.dialogData = h;this.dialogControl = {show: true,top: event.clientY,left: event.clientX};console.log("模型被点击--", h);}});}console.log(this.dialogData);}}
}
</script><style>
.three_page {width: 100%;height: 100%;box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
</style>

总结

第一次接触Three.js做3D,可能也存在很多错误,希望小伙伴多多指点。刚收到要做3D的需求时觉得自己根本做不出来,但是看了一下Three.js的官方文档以后还是慢慢做出来了,以前接触过OpenGL,所以也大概了解流程,总是要逼自己一把才能进步。

Vue+Three.js建造3D小房子相关推荐

  1. vue + Three.js实现3d动画效果

    1.安装依赖 // 引入three.js相关插件npm install three --save// 安装轨道控件插件// npm install three-orbit-controls//安装加载 ...

  2. 首页小房子图标html代码,html5及css3做的3D小房子

    .z-=50;FFqHTML5中文学习网 - HTML5先行者学习网 }FFqHTML5中文学习网 - HTML5先行者学习网 FFqHTML5中文学习网 - HTML5先行者学习网 FFqHTML5 ...

  3. Vue里使用three.js实现3D模型小案例

    Vue里使用three.js实现3D模型小案例 1.下载three.js包 npm install three --save 或者 yarn add three --save 2.组件代码 <t ...

  4. 用Three.js写h5小游戏-3d飞机大战

    用Three.js写h5小游戏-飞机大战 博主的话 运行图片 目录路径![在这里插入图片描述](https://img-blog.csdnimg.cn/20190829103702978.jpg?x- ...

  5. mpvue 微信小程序_使用Vue.js开发微信小程序:开源框架mpvue解析

    戳蓝字"CSDN云计算"关注我们哦! 作者 | 成全 责编 | 阿秃 转自 | 美团技术团队企业博客 前言 mpvue是一款使用Vue.js开发微信小程序的前端框架.使用此框架,开 ...

  6. 用Vue.js开发微信小程序:开源框架mpvue解析

    前言 mpvue 是一款使用 Vue.js 开发微信小程序的前端框架.使用此框架,开发者将得到完整的 Vue.js 开发体验,同时为 H5 和小程序提供了代码复用的能力.如果想将 H5 项目改造为小程 ...

  7. 数独动态解题演示小网站 - 基于Vue/pixi.js/Flask

    解数独不难,但如果能动态演示解题步骤就更好了. 参考:最难数独的快速解法 - python https://www.jianshu.com/p/1b2ee6539d4b 功能 读取公开网站的数独题目 ...

  8. h5+js调取相机做取景框_使用Vue.js开发微信小程序:开源框架mpvue解析

    戳蓝字"CSDN云计算"关注我们哦! 作者 | 成全 责编 | 阿秃 转自 | 美团技术团队企业博客 前言 mpvue是一款使用Vue.js开发微信小程序的前端框架.使用此框架,开 ...

  9. Laravel6.0 + vue.js + elementUI + 微信小程序 实现沃尔玛扫码购

    本次项目使用 Laravel6.0 + vue.js + elementUI + 微信小程序 实现沃尔玛扫码购 项目设计-接口 本次项目所有接口使用 laravel 框架实现. 项目设计-后台 后台开 ...

最新文章

  1. ubuntu 安装linux 下vmVMware tools 步骤及问题解决
  2. 广播,多播(二)(Broadcasting, Multicasting)
  3. 多线程相互排斥--mutex(二)
  4. [设计原则与模式] 如何理解TDD的三条规则
  5. 部署到ABAP服务器上的SAP UI5应用,其index.html的读取逻辑
  6. 顺丰负债300亿就压力山大,而万达曾经负债4000亿却稳如泰山
  7. Hdu 4514 湫湫系列故事——设计风景线
  8. steam一键授权工具_半个东的时间让你省了一个亿 Steam免费游戏一键领取
  9. rundll32的使用和使用c#调用dll
  10. 随便选一张扑克牌_教大家怎么快速记忆扑克牌?一学就会
  11. 动态排名系统(整体二分)
  12. 在 React 中使用 TypeScript
  13. Tensorflow 获取model中的变量列表,用于模型加载等
  14. idp 苹果开发账号续费
  15. Spring 揭秘 12.1
  16. 【学习笔记】汇编语言入门
  17. Unirech腾讯云代充-云服务器登陆及远程连接常见问题
  18. 2019最实用的8种精准微信引流方法教程
  19. netstat 查看tcp 网络连接
  20. 【学习笔记】数据结构之单链表(先进先出、先进后出)

热门文章

  1. python爬虫登录教程_Python爬虫之模拟知乎登录的方法教程
  2. 【无标题】 车规级60V 3A同步降压芯片-ZCC5160
  3. 如果我们刚刚计算出“excel”的散列函数,那么我们就不必再从头开始计算“excel”的散列函数。调整散列函数使得它能够利用前面的计算
  4. 树莓派编译安装 FFmpeg(添加 H.264 硬件编解码器支持)
  5. Python_编程特色
  6. 华为快游戏调用登录接口失败,返回错误码 -1
  7. 【电竞数据】电竞实时指数数据API接口调用和数据推送
  8. oracle中怎么判断全为空格_生活中常见的哪些蔬菜草酸低?怎么判断呢
  9. 平级同事总是给我安排工作,怎么破?领导在群里安排工作给他,他却说病假没空,让我做
  10. 树莓派3B+使用0.96 oled 屏幕(附完整可运行代码)