携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第21天,点击查看活动详情 >>
我们接着上一篇来实现如下的鬼屋效果:
地面草坪
加载草坪纹理:
const grassColorTexture = textureLoader.load('/textures/grass/color.jpg')
const grassAmbientOcclusionTexture = textureLoader.load(
'/textures/grass/ambientOcclusion.jpg'
)
const grassNormalTexture = textureLoader.load('/textures/grass/normal.jpg')
const grassRoughnessTexture = textureLoader.load(
'/textures/grass/roughness.jpg'
)
设置地面材质:
const floor = new THREE.Mesh(
new THREE.PlaneBufferGeometry(20, 20),
// new THREE.MeshStandardMaterial({ color: "#a9c388" })
new THREE.MeshStandardMaterial({
map: grassColorTexture,
aoMap: grassAmbientOcclusionTexture,
normalMap: grassNormalTexture,
roughnessMap: grassRoughnessTexture,
})
);
floor.geometry.setAttribute(
"uv2",
new THREE.Float32BufferAttribute(floor.geometry.attributes.uv.array, 2)
);
设置完后观察上图你会发现草坪非常违和,这是因为我们把一张草坪纹理图片给应用到整块平面上,因此我们要设置纹理repeat属性使得纹理在一块平面上多次重复:
grassColorTexture.repeat.set(8,8)
grassAmbientOcclusionTexture.repeat.set(8,8)
grassNormalTexture.repeat.set(8,8)
grassRoughnessTexture.repeat.set(8,8)
grassColorTexture.wrapS = THREE.RepeatWrapping
grassAmbientOcclusionTexture.wrapS = THREE.RepeatWrapping
grassNormalTexture.wrapS = THREE.RepeatWrapping
grassRoughnessTexture.wrapS = THREE.RepeatWrapping
grassColorTexture.wrapT = THREE.RepeatWrapping
grassAmbientOcclusionTexture.wrapT = THREE.RepeatWrapping
grassNormalTexture.wrapT = THREE.RepeatWrapping
grassRoughnessTexture.wrapT = THREE.RepeatWrapping
增加幽灵漂浮效果
我们用一些简单的灯光来制造出幽灵漂浮的效果,这些灯光会在房子四周漂浮并且会穿过草坪和墓碑。
添加点光源
//ghost
const ghost1 = new THREE.PointLight('#ff00ff', 2, 3)
const ghost2 = new THREE.PointLight('#00ffff', 2, 3)
const ghost3 = new THREE.PointLight('#ffff00', 2, 3)
scene.add(ghost1, ghost2, ghost3)
设置动画
// Animate
const clock = new THREE.Clock();
const tick = () => {
const elapsedTime = clock.getElapsedTime();
// Ghosts
const ghost1Angle = elapsedTime * 0.5;
// x和z设置点光源圆周运动
ghost1.position.x = Math.cos(ghost1Angle) * 4;
ghost1.position.z = Math.sin(ghost1Angle) * 4;
// 设置点光源高度上下变化
ghost1.position.y = Math.sin(elapsedTime * 3);
const ghost2Angle = -elapsedTime * 0.32;
ghost2.position.x = Math.cos(ghost2Angle) * 5;
ghost2.position.z = Math.sin(ghost2Angle) * 5;
ghost2.position.y = Math.sin(elapsedTime * 4) + Math.sin(elapsedTime * 2.5);
const ghost3Angle = -elapsedTime * 0.18;
ghost3.position.x = Math.cos(ghost3Angle) * (7 + Math.sin(elapsedTime * 0.32));
ghost3.position.z = Math.sin(ghost3Angle) * (7 + Math.sin(elapsedTime * 0.5));
ghost3.position.y = Math.sin(elapsedTime * 4) + Math.sin(elapsedTime * 2.5);
controls.update();
renderer.render(scene, camera);
window.requestAnimationFrame(tick);
};
tick();
阴影
激活阴影
renderer.shadowMap.enabled = true;
为能投射阴影的光源开启castShadow
moonLight.castShadow = true;
doorLight.castShadow = true;
ghost1.castShadow = true;
ghost2.castShadow = true;
ghost3.castShadow = true;
为物体开启castShadow
walls.castShadow = true;
bush1.castShadow = true;
bush2.castShadow = true;
bush3.castShadow = true;
bush4.castShadow = true;
grave.castShadow = true;
设置地面接收阴影
floor.receiveShadow = true;
优化阴影贴图
一般来讲,优化步骤是通过设置相机助手,把用于渲染阴影的灯光的摄像机给添加到助手里面,再调整相机的远近等属性,缩小灯光相机可视范围。
doorLight.shadow.mapSize.width = 256;
doorLight.shadow.mapSize.height = 256;
doorLight.shadow.camera.far = 7;
ghost1.shadow.mapSize.width = 256;
ghost1.shadow.mapSize.height = 256;
ghost1.shadow.camera.far = 7;
ghost2.shadow.mapSize.width = 256;
ghost2.shadow.mapSize.height = 256;
ghost2.shadow.camera.far = 7;
ghost3.shadow.mapSize.width = 256;
ghost3.shadow.mapSize.height = 256;
ghost3.shadow.camera.far = 7;
最后改变阴影贴图的算法类型:
// PCF柔软阴影贴图
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
效果达成,欢迎 指正 (๑╹◡╹)ノ"""