效果

源码
import { useEffect, useRef } from 'react'
import * as T from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { DragControls } from 'three/examples/jsm/controls/DragControls'
import Stats from 'stats.js'
import { GUI } from 'dat.gui'
const Demo15 = () => {
let stats, scene, camera, renderer, plane, planeGeometry, gui, controls, orbitControls
useEffect(() => {
init()
}, [])
const ThreeContainer = useRef()
const initGui = () => {
controls = {
addBox,
removeBox,
numberOfObjects: scene.children.length,
rotationSpeed: 0.01,
}
gui = new GUI()
gui.add(controls, 'addBox')
gui.add(controls, 'removeBox')
gui.add(controls, 'numberOfObjects').listen()
gui.add(controls, 'rotationSpeed', 0, 0.1)
}
const initStats = () => {
stats = new Stats()
stats.showPanel(1)
ThreeContainer.current.append(stats.dom)
}
const initScene = () => {
scene = new T.Scene()
}
const initCamera = () => {
camera = new T.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000)
camera.position.set(-30, 40, 30)
camera.lookAt(scene.position)
}
const initRenderer = () => {
renderer = new T.WebGLRenderer()
renderer.setClearColor(0xeeeeee)
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.shadowMap.enabled = true
ThreeContainer.current.append(renderer.domElement)
}
const initOrbitControls = () => {
orbitControls = new OrbitControls(camera, renderer.domElement)
}
const createPlane = () => {
planeGeometry = new T.PlaneGeometry(60, 20, 1, 1)
const planeMaterial = new T.MeshLambertMaterial({
color: 0xffffff
})
plane = new T.Mesh(planeGeometry, planeMaterial)
plane.rotation.x = -0.5 * Math.PI
plane.position.set(15, 0, 0)
plane.receiveShadow = true
scene.add(plane)
}
const addLight = () => {
const spotLight = new T.SpotLight(0xffffff)
spotLight.position.set(-40, 60, -10)
spotLight.castShadow = true
scene.add(spotLight)
}
const renderScene = () => {
stats.update()
scene.traverse(e => {
if (e instanceof T.Mesh && e != plane) {
e.rotation.y += controls.rotationSpeed
}
})
requestAnimationFrame(renderScene)
renderer.render(scene, camera)
}
const addBox = () => {
const geometry = new T.BufferGeometry()
const vertices = new Float32Array([
0, 0, 0,
10, 0, 0,
0, 10, 0,
10, 0, 0,
0, 10, 0,
10, 10, 0,
])
const attribute = new T.BufferAttribute(vertices, 3)
geometry.attributes.position = attribute
const material = new T.MeshBasicMaterial({
color: Math.random() * 0xffffff,
side: T.DoubleSide
})
const mesh = new T.Mesh(geometry, material)
mesh.name = `box-${scene.children.length}`
scene.add(mesh)
controls.numberOfObjects = scene.children.length
}
const removeBox = () => {
const allChildren = scene.children
const lastObject = allChildren[allChildren.length - 1]
if (lastObject instanceof T.Mesh) {
scene.remove(lastObject)
controls.numberOfObjects = scene.children.length
}
}
const initDragControls = () => {
const dragControls = new DragControls(scene.children, camera, renderer.domElement)
dragControls.addEventListener( 'dragstart', function ( event ) {
orbitControls.enabled = false;
} );
dragControls.addEventListener( 'dragend', function ( event ) {
orbitControls.enabled = true;
} );
}
const resize = () => {
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix()
renderer.setSize(window.innerWidth, window.innerHeight)
}, false)
}
const init = () => {
initStats()
initScene()
initCamera()
initRenderer()
initOrbitControls()
createPlane()
initGui()
addLight()
initDragControls()
renderScene()
resize()
}
return (
<div ref={ThreeContainer} />
)
}
export default Demo15