首先创建一个空间场景,Template等配置文件可参考three.js教程学习初始化配置
director.js
import Template from "../common/Template"
import * as THREE from 'three'
import House from "../objects/House"
export default class Director extends Template{
constructor (ele) {
super()
this.ele = ele
this.PCamera.fov = 45
this.PCamera.far = 10000
this.PCamera.near = 1
this.rendererColor = new THREE.Color(0x01031c)
this.cameraPostion = new THREE.Vector3(150, 100, 0)
this.init(this.ele)
this.addLight()
this.addAxesHelper(1000)
if(this.camera && this.renderer) this.addOrbitControls(this.camera, this.renderer.domElement);
this.animate()
this.addGround()
}
addGround(){
const groundGeometry = new THREE.PlaneGeometry(150,250)
const groundMaterial = new THREE.MeshLambertMaterial({
color:0x454942
})
let ground = new THREE.Mesh(groundGeometry, groundMaterial)
ground.rotation.x = -Math.PI/2
ground.name = '地'
this.scene.add(ground)
this.meshList.push(ground)
}
addLight(){
this.addAmbientLight(0x666666)
this.addDirectionalLight(0xdfebff,{x:50, y:200, z:100},1)
}
animate () {
// 执行运动动画
if(this.renderer && this.camera){
this.renderer.render(this.scene, this.camera)
requestAnimationFrame(this.animate.bind(this))
}
}
}
在object中创建House.js文件夹,新增房子,拆开看就是shape+hole四面墙、窗户、门
house.js代码如下
import {DoubleSide, Group,BoxGeometry,
MeshPhysicalMaterial,
Shape,
MeshLambertMaterial,
Mesh,
Path,
ExtrudeGeometry,BoxBufferGeometry} from 'three'
import * as THREE from 'three'
import Base from "../common/Base"
import {Box} from "./Model"
export default class House extends Base{
constructor (length,width,height,scene) {
super()
this.length = length
this.width = width
this.height = height
this.scene = scene
this.instance = new Group()
// 实体
this.addFloor() // 地面PlaneGeometry
this.addWall() // 四壁墙Shape
this.addAllWindow() // 窗户
this.addDoor() // 门Group
}
addAllWindow(){
this.window1 = this.addWindow('窗户1') // 前左
this.window1.position.set(this.width/2,this.height/3,this.length/4)
this.window1.rotation.y = Math.PI/2
this.window2 = this.addWindow('窗户2') // 前右
this.window2.position.set(this.width/2,this.height/3,-this.length/4)
this.window2.rotation.y = Math.PI/2
// this.window3 = this.addWindow('窗户3') // 后左
// this.window3.position.set(-this.width/2,this.height/3,this.length/4)
// this.window3.rotation.y = Math.PI/2
// this.window4 = this.addWindow('窗户4') // 后右
// this.window4.position.set(-this.width/2,this.height/3,-this.length/4)
// this.window4.rotation.y = Math.PI/2
// this.window5 = this.addWindow('窗户5') // 左
// this.window5.position.set(0,this.height/3,this.length/2)
// this.window6 = this.addWindow('窗户6') // 右
// this.window6.position.set(0,this.height/3,-this.length/2)
}
addFloor () {
const geometry = new THREE.PlaneBufferGeometry(this.width, this.length)
const material = new THREE.MeshLambertMaterial({
color:0x1e7047
})
let floor = new THREE.Mesh(geometry, material)
floor.rotation.x = -Math.PI/2
floor.name = '地面'
this.instance.add( floor )
}
addWall () {
let wall = new THREE.Group()
const shape = new Shape()
shape.moveTo(0,0)
shape.lineTo(this.length,0)
shape.lineTo(this.length,this.height)
shape.lineTo(0,this.height)
// 门
const hole_1 = new Path()
hole_1.moveTo(this.length/2-this.length/30,0)
hole_1.lineTo(this.length/2+this.length/30,0)
hole_1.lineTo(this.length/2+this.length/30,this.height-this.height/4)
hole_1.lineTo(this.length/2-this.length/30,this.height-this.height/4)
shape.holes.push(hole_1)
// 窗户
const hole_2 = new Path()
hole_2.moveTo(this.length/4,this.height/3)
hole_2.lineTo(this.length/4+this.length/16,this.height/3)
hole_2.lineTo(this.length/4+this.length/16,this.height/3+this.height/2)
hole_2.lineTo(this.length/4,this.height/3+this.height/2)
shape.holes.push(hole_2)
const hole_3 = new Path()
hole_3.moveTo(this.length/4+this.length/2,this.height/3)
hole_3.lineTo(this.length/4+this.length/16+this.length/2,this.height/3)
hole_3.lineTo(this.length/4+this.length/16+this.length/2,this.height/3+this.height/2)
hole_3.lineTo(this.length/4+this.length/2,this.height/3+this.height/2)
shape.holes.push(hole_3)
const extrudeSettings = {
depth: 0.1,
bevelEnabled: true,
bevelSegments: 2,
steps: 2,
bevelSize: 0.5,
bevelThickness: 0.1
};
// 前墙
const geometry = new ExtrudeGeometry( shape, extrudeSettings );
const material = new MeshLambertMaterial({
color: 0xffffff,
})
const frontWall = new Mesh( geometry, material )
frontWall.rotation.y = Math.PI/2
frontWall.position.set(this.width/2,0,this.length/2)
wall.add(frontWall)
// 后墙
const backgeometry = new THREE.BoxBufferGeometry( this.length,this.height,1 );
const backWall = new Mesh( backgeometry, material )
backWall.rotation.y = Math.PI/2
backWall.position.set(-this.width/2,this.height/2,0)
wall.add(backWall)
// 左右
const leftrightgeometry = new THREE.BoxBufferGeometry( this.width,this.height,1 );
const leftWall = new Mesh( leftrightgeometry, material )
leftWall.position.set(0,this.height/2,this.length/2)
wall.add(leftWall)
const rightWall = new Mesh( leftrightgeometry, material )
rightWall.position.set(0,this.height/2,-this.length/2)
wall.add(rightWall)
this.instance.add(wall)
}
addWindow (name) {
let window = new Group()
let w = this.length/16
let h = this.height/2
// 窗户边框
const shape = new Shape()
shape.moveTo(0,0)
shape.lineTo(w,0)
shape.lineTo(w,h)
shape.lineTo(0,h)
const hole_1 = new Path()
hole_1.moveTo(w/100,h/100)
hole_1.lineTo(w/2-w/100,h/100)
hole_1.lineTo(w/2-w/100,h-h/100)
hole_1.lineTo(w/100,h-h/100)
const hole_2 = new Path()
hole_2.moveTo(w/2+w/100,h/100)
hole_2.lineTo(w-w/100,h/100)
hole_2.lineTo(w-w/100,h-h/100)
hole_2.lineTo(w/2+w/100,h-h/100)
shape.holes.push(hole_1)
shape.holes.push(hole_2)
const extrudeSettings = {
depth: 0.1,
bevelEnabled: true,
bevelSegments: 2,
steps: 2,
bevelSize: 0.5,
bevelThickness: 0.1
};
const geometry = new ExtrudeGeometry( shape, extrudeSettings );
const frameMaterial = new MeshLambertMaterial({
color: 0xc2bec1
})
const frame = new Mesh( geometry, frameMaterial )
window.add(frame)
// 窗户玻璃
const glassGeometry = new BoxBufferGeometry( w, h, 1 )
const glassMaterial = new MeshPhysicalMaterial( {
color: 0xcfcfcf,
metalness: 0,
roughness: 0,
opacity: 0.3,
transparent: true,
envMapIntensity: 10,
premultipliedAlpha: true
} )
const glass = new Mesh( glassGeometry, glassMaterial )
glass.position.set(w/2,h/2,0)
window.add(glass)
window.name = name
this.instance.add(window)
return window
}
addDoor () {
const geometry = new BoxBufferGeometry( this.length/15, this.height-this.height/4, 1 )
const material = new THREE.MeshPhongMaterial({
color:0x68686b,
side:THREE.DoubleSide,
opacity:0.8,
})
const door = new Mesh( geometry, material )
door.position.set(this.width/2,(this.height-this.height/4)/2,0)
door.rotation.y = Math.PI/2
door.name = '门'
this.instance.add( door )
}
}
diector.js中创建
addHouse(){
const house = new House(150,80,20,this.scene)
console.log(house);
house.setPosition(0, 1, 0)
house.addToScene(this.scene)
this.meshList.push(...house.instance.children)
}
添加物品box,这里只写了五个想接着多写可以自己写规律
addBox(){
let w=6
let x_length = 0
let y_length = 0
let z_length = 0
let boxgroup = new THREE.Group()
const geometry = new THREE.BoxBufferGeometry(w,w,w)
const material = new THREE.MeshLambertMaterial({
color:0xb99b75
})
for (let index = 1; index <= 5; index++) {
if(index%2 == 0){
x_length += w
}else if(index%3 == 0){
x_length -= w , z_length += w
}else if(index%4 == 0){
x_length += w
}else if(index%5 == 0){
x_length -= w , y_length += w , z_length -= w
}else{
x_length += w/2 , y_length += w/2 , z_length += w/2
}
let box = new THREE.Mesh(geometry, material)
box.name = '盒子'+index
let edges = new THREE.EdgesHelper( box, 0x000000 );//设置边框,可以旋转
box.name = '盒子边框'+index
box.position.set(x_length,y_length,z_length)
edges.position.set(x_length,y_length,z_length)
boxgroup.add(box)
boxgroup.add( edges );
this.meshList.push(box,edges)
}
boxgroup.position.set(-10,0,20)
this.scene.add(boxgroup)
}
给门加动画特效,点击开门关门
addMouseDown(){
console.log(this.intersects);
// 门特效
let list = this.intersects.filter((item)=>item.object.name == '门')
if(list.length > 0){
if(this.doorstatus == 'close'){
list[0].object.rotateY(-Math.PI / 2);
list[0].object.translateOnAxis(new THREE.Vector3(0, 0, 1), list[0].object.geometry.parameters.width/2);
list[0].object.translateOnAxis(new THREE.Vector3(1, 0, 0), list[0].object.geometry.parameters.width/2);
this.doorstatus = 'open'
}else{
list[0].object.rotateY(Math.PI/2);
list[0].object.translateOnAxis(new THREE.Vector3(0, 0, 1), -list[0].object.geometry.parameters.width/2);
list[0].object.translateOnAxis(new THREE.Vector3(1, 0, 0), list[0].object.geometry.parameters.width/2);
this.doorstatus = 'close'
}
}
}
完整代码director.js如下,house.js如上,其余three.js教程学习初始化配置
调用new Director(document.querySelector('#threeBox'))即可
import Template from "../common/Template"
import * as THREE from 'three'
import House from "../objects/House"
import TWEEN from '@tweenjs/tween.js'
export default class Director extends Template{
constructor (ele) {
super()
this.ele = ele
this.PCamera.fov = 45
this.PCamera.far = 10000
this.PCamera.near = 1
this.rendererColor = new THREE.Color(0x01031c)
this.cameraPostion = new THREE.Vector3(150, 100, 0)
this.init(this.ele)
this.addLight()
this.addAxesHelper(1000)
if(this.camera && this.renderer) this.addOrbitControls(this.camera, this.renderer.domElement);
this.animate()
this.addGround()
this.addHouse()
this.addBox()
// 监听鼠标点击
this.status = 'close'
this.onMouseDown(this.addMouseDown.bind(this))
}
addMouseDown(){
console.log(this.intersects);
// 门特效
let list = this.intersects.filter((item)=>item.object.name == '门')
if(list.length > 0){
if(this.doorstatus == 'close'){
list[0].object.rotateY(-Math.PI / 2);
list[0].object.translateOnAxis(new THREE.Vector3(0, 0, 1), list[0].object.geometry.parameters.width/2);
list[0].object.translateOnAxis(new THREE.Vector3(1, 0, 0), list[0].object.geometry.parameters.width/2);
this.doorstatus = 'open'
}else{
list[0].object.rotateY(Math.PI/2);
list[0].object.translateOnAxis(new THREE.Vector3(0, 0, 1), -list[0].object.geometry.parameters.width/2);
list[0].object.translateOnAxis(new THREE.Vector3(1, 0, 0), list[0].object.geometry.parameters.width/2);
this.doorstatus = 'close'
}
}
}
addBox(){
let w=6
let x_length = 0
let y_length = 0
let z_length = 0
let boxgroup = new THREE.Group()
const geometry = new THREE.BoxBufferGeometry(w,w,w)
const material = new THREE.MeshLambertMaterial({
color:0xb99b75
})
for (let index = 1; index <= 5; index++) {
if(index%2 == 0){
x_length += w
}else if(index%3 == 0){
x_length -= w , z_length += w
}else if(index%4 == 0){
x_length += w
}else if(index%5 == 0){
x_length -= w , y_length += w , z_length -= w
}else{
x_length += w/2 , y_length += w/2 , z_length += w/2
}
let box = new THREE.Mesh(geometry, material)
box.name = '盒子'+index
let edges = new THREE.EdgesHelper( box, 0x000000 );//设置边框,可以旋转
box.name = '盒子边框'+index
box.position.set(x_length,y_length,z_length)
edges.position.set(x_length,y_length,z_length)
boxgroup.add(box)
boxgroup.add( edges );
this.meshList.push(box,edges)
}
boxgroup.position.set(-10,0,20)
this.scene.add(boxgroup)
}
addHouse(){
const house = new House(150,80,20,this.scene)
console.log(house);
house.setPosition(0, 1, 0)
house.addToScene(this.scene)
this.meshList.push(...house.instance.children)
}
addGround(){
const groundGeometry = new THREE.PlaneGeometry(150,250)
const groundMaterial = new THREE.MeshLambertMaterial({
color:0x454942
})
let ground = new THREE.Mesh(groundGeometry, groundMaterial)
ground.rotation.x = -Math.PI/2
ground.name = '地'
this.scene.add(ground)
this.meshList.push(ground)
}
addLight(){
this.addAmbientLight(0x666666)
this.addDirectionalLight(0xdfebff,{x:50, y:200, z:100},1)
}
animate () {
// 执行运动动画
if(this.renderer && this.camera){
this.renderer.render(this.scene, this.camera)
requestAnimationFrame(this.animate.bind(this))
TWEEN.update();
}
}
}