Vue+Three.js建造3D小房子
文章目录
前言
一、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小房子相关推荐
- vue + Three.js实现3d动画效果
1.安装依赖 // 引入three.js相关插件npm install three --save// 安装轨道控件插件// npm install three-orbit-controls//安装加载 ...
- 首页小房子图标html代码,html5及css3做的3D小房子
.z-=50;FFqHTML5中文学习网 - HTML5先行者学习网 }FFqHTML5中文学习网 - HTML5先行者学习网 FFqHTML5中文学习网 - HTML5先行者学习网 FFqHTML5 ...
- Vue里使用three.js实现3D模型小案例
Vue里使用three.js实现3D模型小案例 1.下载three.js包 npm install three --save 或者 yarn add three --save 2.组件代码 <t ...
- 用Three.js写h5小游戏-3d飞机大战
用Three.js写h5小游戏-飞机大战 博主的话 运行图片 目录路径![在这里插入图片描述](https://img-blog.csdnimg.cn/20190829103702978.jpg?x- ...
- mpvue 微信小程序_使用Vue.js开发微信小程序:开源框架mpvue解析
戳蓝字"CSDN云计算"关注我们哦! 作者 | 成全 责编 | 阿秃 转自 | 美团技术团队企业博客 前言 mpvue是一款使用Vue.js开发微信小程序的前端框架.使用此框架,开 ...
- 用Vue.js开发微信小程序:开源框架mpvue解析
前言 mpvue 是一款使用 Vue.js 开发微信小程序的前端框架.使用此框架,开发者将得到完整的 Vue.js 开发体验,同时为 H5 和小程序提供了代码复用的能力.如果想将 H5 项目改造为小程 ...
- 数独动态解题演示小网站 - 基于Vue/pixi.js/Flask
解数独不难,但如果能动态演示解题步骤就更好了. 参考:最难数独的快速解法 - python https://www.jianshu.com/p/1b2ee6539d4b 功能 读取公开网站的数独题目 ...
- h5+js调取相机做取景框_使用Vue.js开发微信小程序:开源框架mpvue解析
戳蓝字"CSDN云计算"关注我们哦! 作者 | 成全 责编 | 阿秃 转自 | 美团技术团队企业博客 前言 mpvue是一款使用Vue.js开发微信小程序的前端框架.使用此框架,开 ...
- Laravel6.0 + vue.js + elementUI + 微信小程序 实现沃尔玛扫码购
本次项目使用 Laravel6.0 + vue.js + elementUI + 微信小程序 实现沃尔玛扫码购 项目设计-接口 本次项目所有接口使用 laravel 框架实现. 项目设计-后台 后台开 ...
最新文章
- ubuntu 安装linux 下vmVMware tools 步骤及问题解决
- 广播,多播(二)(Broadcasting, Multicasting)
- 多线程相互排斥--mutex(二)
- [设计原则与模式] 如何理解TDD的三条规则
- 部署到ABAP服务器上的SAP UI5应用,其index.html的读取逻辑
- 顺丰负债300亿就压力山大,而万达曾经负债4000亿却稳如泰山
- Hdu 4514 湫湫系列故事——设计风景线
- steam一键授权工具_半个东的时间让你省了一个亿 Steam免费游戏一键领取
- rundll32的使用和使用c#调用dll
- 随便选一张扑克牌_教大家怎么快速记忆扑克牌?一学就会
- 动态排名系统(整体二分)
- 在 React 中使用 TypeScript
- Tensorflow 获取model中的变量列表,用于模型加载等
- idp 苹果开发账号续费
- Spring 揭秘 12.1
- 【学习笔记】汇编语言入门
- Unirech腾讯云代充-云服务器登陆及远程连接常见问题
- 2019最实用的8种精准微信引流方法教程
- netstat 查看tcp 网络连接
- 【学习笔记】数据结构之单链表(先进先出、先进后出)
热门文章
- python爬虫登录教程_Python爬虫之模拟知乎登录的方法教程
- 【无标题】 车规级60V 3A同步降压芯片-ZCC5160
- 如果我们刚刚计算出“excel”的散列函数,那么我们就不必再从头开始计算“excel”的散列函数。调整散列函数使得它能够利用前面的计算
- 树莓派编译安装 FFmpeg(添加 H.264 硬件编解码器支持)
- Python_编程特色
- 华为快游戏调用登录接口失败,返回错误码 -1
- 【电竞数据】电竞实时指数数据API接口调用和数据推送
- oracle中怎么判断全为空格_生活中常见的哪些蔬菜草酸低?怎么判断呢
- 平级同事总是给我安排工作,怎么破?领导在群里安排工作给他,他却说病假没空,让我做
- 树莓派3B+使用0.96 oled 屏幕(附完整可运行代码)