简介
使用 threejs + react 创建一个简单的 场景, 包括灯光,相机,阴影,以及一个简单的模型加载。
import React, {useEffect, useRef} from 'react'
import * as THREE from 'three'
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader'
function HelloShadow() {
const canvasRef = useRef()
const scene = useRef(new THREE.Scene()).current
const camera =useRef( new THREE.PerspectiveCamera()).current
const renderer = useRef(new THREE.WebGLRenderer({alpha:true, antialias:true})).current
let controls = new OrbitControls(camera, renderer.domElement)
const meshList = []
useEffect(() => {
canvasRef.current.appendChild(renderer.domElement)
init()
initLight()
initMesh()
}, [])
const init = () => {
renderer.setSize(canvasRef.current.offsetWidth, canvasRef.current.offsetHeight)
// renderer.setClearColor(0x111111)
renderer.shadowMap.enabled = true
camera.aspect = canvasRef.current.offsetWidth / canvasRef.current.offsetHeight
camera.fov = 45
camera.near = 0.01
camera.far = 2000
camera.position.set(30, 20, 30)
camera.lookAt(0, 0, 0)
camera.updateProjectionMatrix()
scene.add(camera)
const axis = new THREE.AxesHelper(100)
scene.add(axis)
}
const initLight = () => {
const light = new THREE.PointLight(0xFFFFFF, 1)
light.castShadow = true
light.position.set(0, 10, 0)
// light.target.position.set(-4, 0, -4)
scene.add(light)
scene.add(light.target)
const shadowCamera = light.shadow.camera
shadowCamera.left = -10
shadowCamera.right = 10
shadowCamera.top = 10
shadowCamera.bottom = -10
shadowCamera.updateProjectionMatrix()
// const lightHelp = new THREE.DirectionalLightHelper(light)
// scene.add(lightHelp)
// const shadowHelper = new THREE.CameraHelper(shadowCamera)
// scene.add(shadowHelper)
}
const initMesh = () => {
const planeGeometry = new THREE.PlaneGeometry(40, 40)
const planeMaterial = new THREE.MeshPhongMaterial({color: 'gray'})
const mesh = new THREE.Mesh(planeGeometry, planeMaterial)
mesh.receiveShadow = true
mesh.rotation.x = Math.PI * -0.5
scene.add(mesh)
const boxMaterial = new THREE.MeshPhongMaterial({color:0x88AACC})
const boxGeometry = new THREE.BoxBufferGeometry(4, 4, 4)
const boxMesh = new THREE.Mesh(boxGeometry, boxMaterial)
boxMesh.castShadow = true
boxMesh.receiveShadow = true
boxMesh.position.set(5, 3, 0)
scene.add(boxMesh)
const sphereGeometry = new THREE.SphereBufferGeometry(3, 32, 16)
const sphereMaterial = new THREE.MeshPhongMaterial({color:0x88AACC})
const sphereMesh = new THREE.Mesh(sphereGeometry, sphereMaterial)
sphereMesh.castShadow = true
sphereMesh.receiveShadow = true
sphereMesh.position.set(-4, 5, 0)
scene.add(sphereMesh)
meshList.push(boxMesh,sphereMesh)
const loader = new GLTFLoader()
let galaxy = "https://modelwarehouse.oss-cn-beijing.aliyuncs.com/Solaris%20bake%20pack%200601.glb"
loader.load(galaxy,(glb) => {
console.log(glb)
let model = glb.scene
model.scale.multiplyScalar(0.2)
scene.add(model)
},(e) => {
const loaderProgress = Math.floor((e.loaded / e.total) * 100)
console.log(loaderProgress)
}
)
let geometry = new THREE.SphereBufferGeometry( 60, 320, 320 );
let texture = new THREE.TextureLoader().load('https://img.alicdn.com/imgextra/i2/O1CN01uyMTm41zvuqddPG9A_!!6000000006777-0-tps-4096-2048.jpg');
let material = new THREE.MeshBasicMaterial( {map: texture} );
material.map.encoding = THREE.sRGBEncoding;
let sphere = new THREE.Mesh( geometry, material );
sphere.geometry.scale(1, 1, -1);
scene.add( sphere );
}
const render = () => {
// lightHelp.update()
meshList.forEach((item) => {
item.rotation.y += 0.01
})
controls.update()
controls.enableZoom = false // 禁止缩放
controls.minZoom = 0.1; // 缩放最小范围
controls.maxZoom = 1; // 最大
renderer.render(scene, camera)
window.requestAnimationFrame(render)
}
window.requestAnimationFrame(render)
const handleResize = () => {
camera.aspect = window.innerWidth / window.innerHeight
camera.updateProjectionMatrix()
renderer.setSize(window.innerWidth, window.innerHeight)
}
window.addEventListener('resize', handleResize)
return (
<div ref={canvasRef}></div>
)
}
export default HelloShadow