Skip to content

Fog

这是一个可以直接在 VitePress 页面中运行的 Three.js 示例。上方显示运行效果,下方展示对应源码。

运行效果

源码

js
import * as THREE from 'three'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
import { GUI } from 'three/addons/libs/lil-gui.module.min.js'

const canvas = document.querySelector('canvas')
const demo = canvas.parentElement

const scene = new THREE.Scene()

const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 100)
camera.position.set(0, 4, 10)

const renderer = new THREE.WebGLRenderer({
	canvas,
	antialias: true
})

renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
renderer.setSize(window.innerWidth, window.innerHeight)

const ambientLight = new THREE.AmbientLight('#ffffff', 0.7)
scene.add(ambientLight)

const directionalLight = new THREE.DirectionalLight('#ffffff', 1.4)
directionalLight.position.set(4, 8, 6)
scene.add(directionalLight)

const boxGeometry = new THREE.BoxGeometry(1, 1, 1)
const floorGeometry = new THREE.PlaneGeometry(14, 30)
const floorMaterial = new THREE.MeshStandardMaterial({
	color: '#64748b',
	roughness: 0.85,
	metalness: 0
})

const floor = new THREE.Mesh(floorGeometry, floorMaterial)
floor.rotation.x = -Math.PI / 2
floor.position.z = -7
scene.add(floor)

for (let index = 0; index < 14; index += 1) {
	const material = new THREE.MeshStandardMaterial({
		color: index % 2 === 0 ? '#f97316' : '#38bdf8',
		roughness: 0.55,
		metalness: 0.05
	})

	const cube = new THREE.Mesh(boxGeometry, material)
	cube.position.set(index % 2 === 0 ? -1.4 : 1.4, 0.55, 2 - index * 1.55)
	cube.rotation.y = index * 0.25
	scene.add(cube)
}

const gridHelper = new THREE.GridHelper(14, 14, '#ffffff', '#94a3b8')
gridHelper.position.z = -7
scene.add(gridHelper)

const controls = new OrbitControls(camera, renderer.domElement)
controls.enableDamping = true
controls.target.set(0, 0.5, -6)

const guiState = {
	type: '线性雾',
	color: '#dbeafe',
	near: 4,
	far: 18,
	density: 0.12
}

const applyFog = () => {
	scene.background = new THREE.Color(guiState.color)

	if (guiState.type === '线性雾') {
		scene.fog = new THREE.Fog(guiState.color, guiState.near, guiState.far)
		return
	}

	if (guiState.type === '指数雾') {
		scene.fog = new THREE.FogExp2(guiState.color, guiState.density)
		return
	}

	scene.fog = null
}

applyFog()

const gui = new GUI({
	title: 'Fog 控制',
	autoPlace: false
})

gui.domElement.classList.add('three-gui')
demo.appendChild(gui.domElement)

gui
	.add(guiState, 'type', ['线性雾', '指数雾', '关闭'])
	.name('雾类型')
	.onChange(applyFog)

gui
	.addColor(guiState, 'color')
	.name('雾颜色')
	.onChange(applyFog)

gui
	.add(guiState, 'near', 0.1, 12, 0.1)
	.name('线性 near')
	.onChange(applyFog)

gui
	.add(guiState, 'far', 4, 35, 0.1)
	.name('线性 far')
	.onChange(applyFog)

gui
	.add(guiState, 'density', 0.01, 0.35, 0.01)
	.name('指数 density')
	.onChange(applyFog)

function animate() {
	requestAnimationFrame(animate)

	controls.update()
	renderer.render(scene, camera)
}

animate()