雾化
我们可以对我们的场景进行一些雾化的效果
先定义出雾化的方法addFog,并且加到gui中
我们只需要调用scene的fog的api,实例化出fog的对象,然后给出一些控制雾化效果的值即可
雾化效果实现成功
移除雾化
只需要将对象制空即可
材质重写
常见几何体
这里注意要引入一个包,当然,ws的话自动导入即可
我们建立一个数组,用来存放我们的几何体
<template>
<div ref="statsRef"></div>
<div className="contain" ref="containerRef">
</div>
</template>
<script setup lang='ts'>
import {
AxesHelper,
BoxGeometry,
BufferGeometry,
Color,
CylinderGeometry,
Fog,
Mesh,
MeshBasicMaterial,
MeshLambertMaterial,
OctahedronGeometry,
PerspectiveCamera,
PlaneGeometry,
Scene,
SphereGeometry,
SpotLight,
TetrahedronGeometry,
TorusGeometry,
WebGLRenderer
} from 'three';
import { ref, reactive, onMounted } from 'vue'
import Stats from 'stats.js'
import * as dat from 'dat.gui'
import { createMultiMaterialObject } from 'three/examples/jsm/utils/SceneUtils'
const containerRef = ref<HTMLDivElement>()
const statsRef = ref<HTMLDivElement>()
const stats = new Stats()
stats.dom.style.top = "50px"
stats.showPanel(0)
// 创建场景
const scene = new Scene()
// 创建照相机
const camera = new PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000)
// 设置摄像机位置
camera.position.set(-30, 40, 30)
// 设置摄像机朝向(看哪)
camera.lookAt(scene.position)
// webgl渲染器
const renderer = new WebGLRenderer()
renderer.setClearColor(new Color(0xeeeeee))
renderer.setSize(window.innerWidth, window.innerHeight)
// 可以渲染阴影
renderer.shadowMap.enabled = true
// 光源
const spotLight = new SpotLight(0xffffff)
spotLight.castShadow = true
spotLight.position.set(-40, 60, -10)
scene.add(spotLight)
// 添加平面几何体
const planeGeometry = new PlaneGeometry(60, 20)
// 添加材质
const meshBasicMaterial = new MeshLambertMaterial({ color: 0xcccccc })
const plane = new Mesh(planeGeometry, meshBasicMaterial)
// 接受阴影
plane.receiveShadow = true
// 调整位置
plane.rotation.x = -0.5 * Math.PI //放平
plane.position.x = 15
plane.position.y = 0
plane.position.z = 0
scene.add(plane)
// 添加几何体
const cubeGeometry = new BoxGeometry(4, 4, 4)
const cubeMaterial = new MeshLambertMaterial({ color: 0xff0000, wireframe: false })
const cube = new Mesh(cubeGeometry, cubeMaterial)
cube.castShadow = true
cube.position.set(2, 2, 2)
scene.add(cube)
// 球体
const sphereGeometry = new SphereGeometry(4)
const sphereMaterial = new MeshLambertMaterial({ color: 0x7777ff, wireframe: false })
const sphere = new Mesh(sphereGeometry, sphereMaterial)
sphere.castShadow = true
sphere.position.x = 20
sphere.position.y = 4
sphere.position.z = 2
scene.add(sphere)
// 建立一些常见的几何体
const geoms: BufferGeometry[] = []
geoms.push(new CylinderGeometry(1, 4, 8))
geoms.push(new BoxGeometry(2, 2, 2))
// 八面体
geoms.push(new OctahedronGeometry(3))
// 三棱锥
geoms.push(new TetrahedronGeometry(3))
// 环形
geoms.push(new TorusGeometry(3, 1, 10, 10))
// 建立材质的数组
const materials = [
new MeshLambertMaterial({
color: Math.random() * 0xffffff,
flatShading: true
}),
new MeshBasicMaterial({
color: 0x000000,
wireframe: true
})
]
geoms.forEach((g, i) => {
const mesh = createMultiMaterialObject(g, materials);
mesh.castShadow = true
mesh.position.x = -24 + i * 10
mesh.position.y = 4
scene.add(mesh)
})
// 添加坐标系
const axes = new AxesHelper(20)
scene.add(axes)
const controlRef = ref({
rotationSpeed: 0.02,//旋转速度
bouncingSpeed: 0.03,//弹跳速度
numberOfObjects: 0,//统计
addCube: function () {
const cubeGeometry = new BoxGeometry(4, 4, 4)
// const cubeMaterial = new MeshLambertMaterial({ color: Math.random() * 255, wireframe: false })
const cube = new Mesh(cubeGeometry, cubeMaterial)
cube.name = "cube-" + scene.children.length
cube.castShadow = true
cube.position.x = -30 + Math.round((Math.random() * 60))
cube.position.y = Math.round((Math.random() * 5))
cube.position.z = -20 + Math.round((Math.random() * 40))
scene.add(cube)
// console.log(scene.children);
this.numberOfObjects = scene.children.length
},
// 删除
remove: function () {
// 拿到所有子物体
const allChildren = scene.children
// 拿到最后一个
const lastObject = allChildren[allChildren.length - 1]
if (lastObject instanceof Mesh && lastObject.name.startsWith('cube')) {
scene.remove(lastObject)
}
this.numberOfObjects = scene.children.length
},
// 雾化
addFog: function () {
const fog = new Fog(0xffffff, 0.015, 100)
fog.name = 'fog'
scene.fog = fog
this.numberOfObjects = scene.children.length
},
// 移除雾化
removeFog: function () {
scene.fog = null
},
// 改变材质
toggleMaterial: function () {
if (!scene.overrideMaterial) {
scene.overrideMaterial = new MeshLambertMaterial({
color: 0xffffff
})
} else {
scene.overrideMaterial = null
}
}
})
// const gui = new dat.GUI()
// gui.add(controlRef.value,"rotationSpeed",0,0.5)
// gui.add(controlRef.value,"bouncingSpeed",0,0.5)
// 判斷
if (document.querySelectorAll(".dg.ac>.dg.main.a").length === 0) {
const gui = new dat.GUI()
gui.add(controlRef.value, "numberOfObjects").listen()
gui.add(controlRef.value, "addCube")
gui.add(controlRef.value, "remove")
gui.add(controlRef.value, "addFog")
gui.add(controlRef.value, "removeFog")
gui.add(controlRef.value, "toggleMaterial")
gui.add(controlRef.value, "rotationSpeed", 0, 0.5)
gui.add(controlRef.value, "bouncingSpeed", 0, 0.5)
}
let step = 0
function renderScene() {
stats.update()
scene.traverse((e) => {
// if (e instanceof Mesh && e != plane) {
// e.rotation.x += controlRef.value.rotationSpeed
// e.rotation.y += controlRef.value.rotationSpeed
// e.rotation.z += controlRef.value.rotationSpeed
// }
if (e.name.startsWith('cube')) {
e.rotation.x += controlRef.value.rotationSpeed
e.rotation.y += controlRef.value.rotationSpeed
e.rotation.z += controlRef.value.rotationSpeed
}
})
cube.rotation.x += controlRef.value.rotationSpeed
cube.rotation.y += controlRef.value.rotationSpeed
cube.rotation.z += controlRef.value.rotationSpeed
step += controlRef.value.bouncingSpeed
sphere.position.x = 20 + 10 * Math.cos(step)
sphere.position.y = 2 * 10 * Math.abs(Math.sin(step))
requestAnimationFrame(renderScene)
renderer.render(scene, camera)
}
renderScene()
onMounted(() => {
statsRef.value?.append(stats.dom)
containerRef.value?.appendChild(renderer.domElement)
renderer.render(scene, camera)
})
// 监听窗口变化
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight
// 更新相机投影矩阵
camera.updateProjectionMatrix()
renderer.setSize(window.innerWidth, window.innerHeight)
}, false)
</script>
<style scoped>
</style>