Three.js开发案例:VR全景看房
项目初始化
1. 创建并配置项目
使用可视化面板创建项目:
- 功能选择:
Bable
、Router
、CSS Pre-processors
、Linter / Formatter
、Use config files
- 配置选择:
2.x
、Less
、ESLint + Standard config
创建代码格式化配置文件.prettierrc.js
:
1 2 3 4 5 6 7 8 9
| module.exports = { semi: false, singleQuote: true, bracketSpacing: true, useTabs: false, tabWidth: 2, trailingComma: 'none', printWidth: 100, }
|
在代码审查配置文件.eslintrc.js
中添加一行规则:
1 2 3 4 5
| rules: { 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 'space-before-function-paren': 0 }
|
创建全局css样式文件/src/assets/css/global.css
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
* { margin: 0; padding: 0; }
html, body{ height: 100%; margin: 0; padding: 0; } ::-webkit-scrollbar { display: none; }
|
在/src/main.js
中导入全局样式文件:
1 2 3 4 5 6 7 8 9 10 11 12 13
| import Vue from 'vue' import App from './App.vue' import router from './router'
import './assets/css/global.css'
Vue.config.productionTip = false
new Vue({ router, render: h => h(App) }).$mount('#app')
|
2. 初始化页面
在可视化面板中安装运行依赖three
,初始化App.vue
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| <template> <div class="container" ref="container"></div> </template>
<script> import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
export default { data() { return {} }, mounted() { this.scene = null this.camera = null this.renderer = null this.controls = null
this.init() this.render() }, methods: { init() { this.scene = new THREE.Scene()
this.camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ) this.camera.position.z = 5
this.renderer = new THREE.WebGLRenderer() this.renderer.setSize(window.innerWidth, window.innerHeight)
const container = this.$refs.container container.appendChild(this.renderer.domElement)
this.controls = new OrbitControls(this.camera, container) this.controls.enableDamping = true }, render() { this.controls.update() this.renderer.render(this.scene, this.camera) requestAnimationFrame(this.render) } }, beforeDestroy() { this.scene = null this.camera = null this.renderer = null this.controls = null } } </script>
<style lang="less" scoped> .container { height: 100vh; width: 100vw; background-color: #f0f0f0; } </style>
|
一、立方体场景(天空盒)
1. 添加立方体
1 2 3 4 5
| const geometry = new THREE.BoxGeometry(1, 1, 1) const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 }) const cube = new THREE.Mesh(geometry, material) this.scene.add(cube)
|
2. 添加图片纹理贴图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| const geometry = new THREE.BoxGeometry(1, 1, 1)
const arr = ['4_l', '4_r', '4_u', '4_d', '4_b', '4_f'] const boxMaterials = [] arr.forEach((item) => { const texture = new THREE.TextureLoader().load(`./imgs/living/${item}.jpg`) boxMaterials.push(new THREE.MeshBasicMaterial({ map: texture })) }) const cube = new THREE.Mesh(geometry, boxMaterials) this.scene.add(cube)
|
3. 翻转贴图到内部
放大盒子,并设置z周缩放为负值,从而将贴图由外翻转到盒子内部:
1 2 3 4 5 6 7 8 9 10 11 12
| const arr = ['4_l', '4_r', '4_u', '4_d', '4_b', '4_f'] const boxMaterials = [] arr.forEach((item) => { const texture = new THREE.TextureLoader().load(`./imgs/living/${item}.jpg`) boxMaterials.push(new THREE.MeshBasicMaterial({ map: texture })) }) const cube = new THREE.Mesh(geometry, boxMaterials) cube.geometry.scale(1, 1, -1) this.scene.add(cube)
|
4. 调整部分贴图旋转
天花板和地面的贴图角度不对,给它们旋转过来:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| const arr = ['4_l', '4_r', '4_u', '4_d', '4_b', '4_f'] const boxMaterials = [] arr.forEach((item) => { const texture = new THREE.TextureLoader().load(`./imgs/living/${item}.jpg`) if (item === '4_u' || item === '4_d') { texture.rotation = Math.PI texture.center = new THREE.Vector2(0.5, 0.5) boxMaterials.push(new THREE.MeshBasicMaterial({ map: texture })) } else { boxMaterials.push(new THREE.MeshBasicMaterial({ map: texture })) } }) const cube = new THREE.Mesh(geometry, boxMaterials) cube.geometry.scale(1, 1, -1) this.scene.add(cube)
|
完整Vue代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
| <template> <div class="container" ref="container"></div> </template>
<script> import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
export default { data() { return {} }, mounted() { this.scene = null this.camera = null this.renderer = null this.controls = null
this.init() this.render() }, methods: { init() { this.scene = new THREE.Scene()
this.camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ) this.camera.position.z = 5
const geometry = new THREE.BoxGeometry(10, 10, 10)
const arr = ['4_l', '4_r', '4_u', '4_d', '4_b', '4_f'] const boxMaterials = [] arr.forEach((item) => { const texture = new THREE.TextureLoader().load(`./imgs/living/${item}.jpg`) if (item === '4_u' || item === '4_d') { texture.rotation = Math.PI texture.center = new THREE.Vector2(0.5, 0.5) boxMaterials.push(new THREE.MeshBasicMaterial({ map: texture })) } else { boxMaterials.push(new THREE.MeshBasicMaterial({ map: texture })) } }) const cube = new THREE.Mesh(geometry, boxMaterials) cube.geometry.scale(1, 1, -1) this.scene.add(cube)
this.renderer = new THREE.WebGLRenderer() this.renderer.setSize(window.innerWidth, window.innerHeight)
const container = this.$refs.container container.appendChild(this.renderer.domElement)
this.controls = new OrbitControls(this.camera, container) this.controls.enableDamping = true
}, render() { this.controls.update() this.renderer.render(this.scene, this.camera) requestAnimationFrame(this.render) } }, beforeDestroy() { this.scene = null this.camera = null this.renderer = null this.controls = null } } </script>
<style lang="less" scoped> .container { height: 100vh; width: 100vw; background-color: #f0f0f0; } </style>
|
二、球体场景(全景图片)
1. 添加球体
1
| const geometry = new THREE.SphereGeometry(5, 32, 32)
|
2. 加载hdr纹理
1 2 3 4 5 6 7 8 9 10 11 12
| import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader'
const geometry = new THREE.SphereGeometry(5, 32, 32) const loader = new RGBELoader() loader.load('./imgs/hdr/Living.hdr', (texture) => { const material = new THREE.MeshBasicMaterial({ map: texture }) const sphere = new THREE.Mesh(geometry, material) sphere.geometry.scale(1, 1, -1) this.scene.add(sphere) })
|
完整Vue代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
| <template> <div class="container" ref="container"></div> </template>
<script> import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader'
export default { data() { return {} }, mounted() { this.scene = null this.camera = null this.renderer = null this.controls = null
this.init() this.render() }, methods: { init() { this.scene = new THREE.Scene()
this.camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 ) this.camera.position.z = 5
const geometry = new THREE.SphereGeometry(5, 32, 32) const loader = new RGBELoader() loader.load('./imgs/hdr/Living.hdr', (texture) => { const material = new THREE.MeshBasicMaterial({ map: texture }) const sphere = new THREE.Mesh(geometry, material) sphere.geometry.scale(1, 1, -1) this.scene.add(sphere) })
this.renderer = new THREE.WebGLRenderer() this.renderer.setSize(window.innerWidth, window.innerHeight)
const container = this.$refs.container container.appendChild(this.renderer.domElement)
this.controls = new OrbitControls(this.camera, container) this.controls.enableDamping = true
}, render() { this.controls.update() this.renderer.render(this.scene, this.camera) requestAnimationFrame(this.render) } }, beforeDestroy() { this.scene = null this.camera = null this.renderer = null this.controls = null } } </script>
<style lang="less" scoped> .container { height: 100vh; width: 100vw; background-color: #f0f0f0; } </style>
|
三、小思考
全景效果是进入物体内部实现的,但是鼠标拖动屏幕时,画面的旋转方向是按照外面的情况旋转的。
因此,造成了观看全景场景的时候鼠标拖动方向与画面旋转方向“相反”。如何解决?
【参考内容】:
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 百里飞洋! 技术内容: 若存在错误或不当之处,还望兄台不吝赐教,期待与您交流!