本项目是基于vue3+threejs封装的3d渲染器 , 可加载glb obj fbx格式的3d效果
总结
onMounted(() => {
InitBase() //初始化基础设施
InitModels() //初始化模型
renderer.setAnimationLoop(animation) //循环渲染
})
1 初始化基础设施中包括: 初始化场景 + 初始化相机 + 初始化渲染器 + 初始化控制器 +初始化灯光
const InitScene = () => {
scene = new THREE.Scene() // 场景
const path = '/src/assets/pisa/' // 环境贴图
const format = '.png'
const urls = [
path + 'px' + format,
path + 'nx' + format,
path + 'py' + format,
path + 'ny' + format,
path + 'pz' + format,
path + 'nz' + format
]
sceneTexture = new THREE.CubeTextureLoader().load(urls)
scene.background = sceneTexture // 环境贴图展示
}
const InitCamera = () => {
camera = new THREE.PerspectiveCamera(
40,
width.value / height.value,
0.01,
2000
)
camera.position.x = 0
camera.position.y = 10
camera.position.z = 20
}
const InitRenderer = () => {
renderer = new THREE.WebGLRenderer({ //渲染器
antialias: true,
alpha: true,
canvas: canvasElement.value
})
renderer.shadowMap.enabled = true //阴影渲染
renderer.shadowMap.type = THREE.PCFSoftShadowMap
}
const InitControls = () => {
controls = new OrbitControls(camera, renderer.domElement)
controls.enableDamping = true; //阻尼
}
const InitLight = () => {
const ambientHemisphere = new THREE.HemisphereLight(0xffffff, 0xbfd4d2, 1) //环境光
scene.add(ambientHemisphere)
const hemiLight = new THREE.HemisphereLight(0xffffff, 0xffffff, 2) //半球光可以让3d人物亮起来
hemiLight.position.set(0, 50, 0)
scene.add(hemiLight)
const dirLight = new THREE.DirectionalLight(0xffffff, 3) //平行光,类似于太阳光照
dirLight.color.setHSL(0.1, 1, 0.95)
dirLight.position.set(-30, 52.5, 30)
dirLight.castShadow = true
dirLight.shadow.camera.top = 4
dirLight.shadow.camera.bottom = -4
dirLight.shadow.camera.left = -4
dirLight.shadow.camera.right = 4
dirLight.shadow.camera.near = 0.1
dirLight.shadow.camera.far = 400
scene.add(dirLight)
}
2 初始化模型
const InitModels = () => {
const loader = new GLTFLoader() // 创建GLTF加载器
loader.load( // 加载GLB模型
props.modelUrl,
gltf => {
gltf.scene.traverse(function (child: any) {
if (child.isMesh) { // 为每个mesh设置环境贴图
{
child.castShadow = true
child.receiveShadow = true
child.material.envMap = sceneTexture
child.material.needsUpdate = true
}
const model = gltf.scene //设置box3包围盒
const box = new THREE.Box3().setFromObject(model)
const size = new THREE.Vector3()
box.getSize(size)
const center = new THREE.Vector3() //拿到盒子中心
box.getCenter(center)
const targetWidth = 2
const scaleRatio = targetWidth / size.z
model.scale.x *= scaleRatio // 等比例缩放和调整3d人物中心位于底部中心
model.scale.y *= scaleRatio
model.scale.z *= scaleRatio
model.position.y -= center.y - (size.y * scaleRatio) / 2
scene.add(gltf.scene) // 将模型添加到场景中
},
undefined,
error => {
console.error(error)
}
)
}
}
3 循环渲染
function animation() {
renderer.setPixelRatio(window.devicePixelRatio) //高分辨率屏幕上更加清晰
renderer.setSize(width.value, height.value)
if (camera) { //更新相机纵横比,匹配当前画布的宽高比,确保不被拉伸压缩
camera.aspect = width.value / height.value
camera.updateProjectionMatrix()
}
renderer.render(scene, camera)
}
效果图如下
拓展1: 如果效果是下图 , 说明环境贴图没效果 , 需查看自己初始化场景中是否设置了相关属性
const InitScene = () => {
scene = new THREE.Scene() // 场景
const path = '/src/assets/pisa/' // 环境贴图
const format = '.png'
const urls = [
path + 'px' + format,
path + 'nx' + format,
path + 'py' + format,
path + 'ny' + format,
path + 'pz' + format,
path + 'nz' + format
]
sceneTexture = new THREE.CubeTextureLoader().load(urls)
scene.background = sceneTexture // 环境贴图展示
}
拓展2 : 如果需要人物阴影 , 应再添加地面 , 并让地面可以接受阴影效果 (在初始化场景中去添加地面效果)
const InitScene = () => {
scene = new THREE.Scene() // 场景
const path = '/src/assets/pisa/' // 环境贴图
const format = '.png'
const urls = [
path + 'px' + format,
path + 'nx' + format,
path + 'py' + format,
path + 'ny' + format,
path + 'pz' + format,
path + 'nz' + format
]
sceneTexture = new THREE.CubeTextureLoader().load(urls)
scene.background = sceneTexture // 环境贴图展示
,
{
const groundGeo = new THREE.PlaneGeometry(20, 20) // 创建了矩形
const groundMat = new THREE.MeshLambertMaterial({ // 创建了材质
color: 0x888888,
envMap: sceneTexture // 是否开启环境贴图
})
const ground = new THREE.Mesh(groundGeo, groundMat) // 创建了一个网格对象作为地面
ground.rotation.x = -Math.PI / 2 // 旋转地面与x轴平行
ground.receiveShadow = true // 能接收阴影
scene.add(ground)
}
}
拓展3 : 平行光和聚光灯效果的互换 , 上图是平行光效果图 , 下图是切换为聚光灯效果图
const InitLight = () => {
let spotLight = new THREE.SpotLight(0xffffff, 300)
spotLight.position.set(2.5, 5, 2.5)
spotLight.angle = Math.PI / 4
spotLight.penumbra = 1
spotLight.decay = 2
spotLight.distance = 0
// 设置聚光灯的旋转角度
// spotLight.rotation.x = Math.PI / -4 // 绕X轴旋转180度,使其朝下照射
spotLight.castShadow = true
spotLight.shadow.mapSize.width = 1024
spotLight.shadow.mapSize.height = 1024
spotLight.shadow.camera.near = 1
spotLight.shadow.camera.far = 10
spotLight.shadow.focus = 1
scene.add(spotLight)
// scene.add(new THREE.CameraHelper(spotLight.shadow.camera))
const ambientHemisphere = new THREE.HemisphereLight(0xffffff, 0xbfd4d2, 1)
scene.add(ambientHemisphere)
const hemiLight = new THREE.HemisphereLight(0xffffff, 0xffffff, 2)
hemiLight.position.set(0, 50, 0)
scene.add(hemiLight)
}