我想做成像 sketchfab 這樣類似陽光透過窗框打在建築物地板上的效果。
以下是我的 code
import './style.css'
import * as THREE from 'three'
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
function main () {
const canvas = document.querySelector('#c');
const renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias: true,
});
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setClearColor(0xAAAAAA);
renderer.shadowMap.enabled = true;
const camera =new THREE.PerspectiveCamera(75, canvas.offsetWidth / canvas.offsetHeight, 0.1, 2000);
camera.position.set(80, 40, 100);
camera.lookAt(0, 0, 0);
const scene = new THREE.Scene();
{
const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set( 300, 200, 100 );
light.target.position.set( 0, 0, 0 );
light.castShadow = true;
light.shadow.mapSize.width = canvas.offsetWidth;
light.shadow.mapSize.height = canvas.offsetHeight;
light.shadow.bias = 0.01;
light.shadow.camera.left = -500;
light.shadow.camera.right = 500;
light.shadow.camera.top = 500;
light.shadow.camera.bottom = -500;
scene.add( light );
const lightHepler = new THREE.DirectionalLightHelper(light)
scene.add(lightHepler);
const cameraHelper = new THREE.CameraHelper(light.shadow.camera)
scene.add(cameraHelper)
}
{
const planeGeo = new THREE.PlaneBufferGeometry(1000, 1000, 1, 1);
const planeMet = new THREE.MeshLambertMaterial({ color: 0x999999, side: THREE.DoubleSide });
const plane = new THREE.Mesh(planeGeo, planeMet);
plane.receiveShadow = true;
plane.rotateX(Math.PI / 2);
scene.add(plane);
}
/*
Load 3D model
*/
const loader = new GLTFLoader();
// loader.load( './shiba/scene.gltf', gltf => {
// scene.add( gltf.scene );
// }, undefined, error => {
// console.error( error );
// })
// loader.load('./horse/Horse.glb', gltf => {
// const mesh = gltf.scene.children[ 0 ];
// mesh.scale.set(0.1, 0.1, 0.1);
// mesh.castShadow = true;
// mesh.receiveShadow = true;
// scene.add( mesh );
// }, undefined, error => {
// console.error( error );
// })
loader.load('./showroom/scene.gltf', gltf => {
gltf.scene.scale.set(0.01, 0.01, 0.01);
gltf.scene.traverse(child => {
child.receiveShadow = true;
})
console.log(gltf.scene);
scene.add( gltf.scene );
}, undefined, error => {
console.error( error );
})
/*
Add OrbitControl
*/
const controls = new OrbitControls(camera, renderer.domElement)
function resizeRendererToDisplaySize(renderer) {
const canvas = renderer.domElement;
const width = canvas.clientWidth;
const height = canvas.clientHeight;
const needResize = canvas.width !== width || canvas.height !== height;
if (needResize) {
renderer.setSize(width, height, false);
}
return needResize;
}
function render() {
if (resizeRendererToDisplaySize(renderer)) {
const canvas = renderer.domElement;
camera.aspect = canvas.clientWidth / canvas.clientHeight;
}
controls.update()
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
}
main()
不確定還缺少哪些東西,沒辦法做的像 sketchfab 那樣有陰影。
每個 Object3D 物件都有 castShadow
與 receiveShadow
castShadow 被設定為 true 的物件才會產生陰影
receiveShadow 被設定為 true 的物件才能在這上面顯示別人的陰影
所以你可能要在所有牆壁都設定 castShadow
另外 Material 那邊有 shadowSide 屬性
這會決定平面的哪一邊可以產生陰影
若不確定哪一邊可以把 shadowSide 設定為 THREE.DoubleSide
代表從兩邊都會產生陰影