四、Threejs燈光、陰影

castShadow 是否投射陰影

Three.js 中的castShadow屬性用于控制物體是否投射陰影。

  • 定義和作用
    castShadow屬性用于設(shè)置物體是否投射陰影。當(dāng)設(shè)置為true時(shí),物體將投射陰影;設(shè)置為false時(shí),物體不投射陰影。默認(rèn)值為false。

  • 具體應(yīng)用場(chǎng)景和代碼示例
    在Three.js中,要使一個(gè)物體投射陰影,需要在創(chuàng)建光源時(shí)設(shè)置其castShadow屬性為true,并在需要投射陰影的物體上設(shè)置其castShadow屬性為true。以下是一個(gè)簡(jiǎn)單的示例:

// 創(chuàng)建一個(gè)平行光光源
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.position.set(2, 2, -1);
scene.add(directionalLight);
directionalLight.castShadow = true; // 允許投射陰影

// 創(chuàng)建一個(gè)需要投射陰影的物體
const object = new THREE.Mesh(geometry, material);
object.castShadow = true; // 設(shè)置該物體投射陰影
  • 性能影響和優(yōu)化建議
    投射陰影會(huì)增加計(jì)算量和渲染時(shí)間,因此在實(shí)際應(yīng)用中需要注意以下幾點(diǎn)以優(yōu)化性能:

    • 調(diào)整陰影貼圖的大小:可以通過調(diào)整光源的shadow.mapSize.width和shadow.mapSize.height來控制陰影貼圖的大小,從而影響陰影的清晰度。
    • 調(diào)整陰影相機(jī)的視錐體:通過設(shè)置光源的shadow.camera.top、shadow.camera.bottom、shadow.camera.right和shadow.camera.left來調(diào)整陰影相機(jī)的視錐體,決定陰影投射的區(qū)域。
    • 調(diào)整相機(jī)的遠(yuǎn)近平面:通過設(shè)置光源的shadow.camera.near和shadow.camera.far來調(diào)整陰影相機(jī)的遠(yuǎn)近平面,影響陰影的范圍。

receiveShadow 是否接收陰影

Three.js 中的receiveShadow屬性用于設(shè)置物體是否接收陰影。當(dāng)receiveShadow屬性設(shè)置為true時(shí),表示該物體可以接收陰影;設(shè)置為false時(shí),表示該物體不接收陰影。默認(rèn)情況下,receiveShadow屬性為false。

  • 設(shè)置方法
    創(chuàng)建物體時(shí)設(shè)置:在創(chuàng)建物體時(shí),可以通過設(shè)置物體的材質(zhì)來指定其是否接收陰影。例如:
const plane = new THREE.Mesh(new THREE.PlaneGeometry(10, 10), new THREE.MeshStandardMaterial());
plane.receiveShadow = true; // 設(shè)置該平面可以接收陰影

修改現(xiàn)有物體的材質(zhì):如果物體已經(jīng)創(chuàng)建,可以通過修改其材質(zhì)的receiveShadow屬性來設(shè)置是否接收陰影:

plane.material.receiveShadow = true; // 設(shè)置該平面可以接收陰影
  • 場(chǎng)景中的應(yīng)用示例
    在一個(gè)場(chǎng)景中,通常會(huì)有光源(如平行光、點(diǎn)光源等)和多個(gè)物體。為了實(shí)現(xiàn)陰影效果,需要確保以下幾點(diǎn):

  • 光源設(shè)置:光源需要設(shè)置castShadow屬性為true,以投射陰影。例如:

const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.position.set(2, 2, -1);
directionalLight.castShadow = true; // 允許投射陰影
scene.add(directionalLight);
  • 物體設(shè)置:需要接收陰影的物體(如平面、球體等)需要將receiveShadow屬性設(shè)置為true。例如:
const plane = new THREE.Mesh(new THREE.PlaneGeometry(10, 10), new THREE.MeshStandardMaterial());
plane.receiveShadow = true; // 設(shè)置該平面可以接收陰影
scene.add(plane);
  • 渲染器設(shè)置:確保渲染器的 shadowMap.enabled 屬性為true,以允許場(chǎng)景中使用陰影貼圖。例如:
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true; // 允許渲染器生成陰影貼圖

樣例

import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
// import GUI from 'lil-gui';

const canvas = document.querySelector('canvas.webgl');
const scene = new THREE.Scene();
const textureLoader = new THREE.TextureLoader();

const material = new THREE.MeshStandardMaterial();

//球
const sphere = new THREE.Mesh(
    new THREE.SphereGeometry(0.5, 64, 64),
    material
);

//平面
const plane = new THREE.Mesh(
    new THREE.PlaneGeometry(1, 1),
    material
);

//圓環(huán)
const torus = new THREE.Mesh(
    new THREE.TorusGeometry(0.5, 0.2, 32, 64),
    material
);

// 地板
const bakedShadowLoader = new THREE.Mesh(
    new THREE.PlaneGeometry(6, 6),
    new THREE.MeshStandardMaterial()
)
// 接收陰影
bakedShadowLoader.receiveShadow = true;
bakedShadowLoader.rotation.x = -Math.PI / 2;
bakedShadowLoader.position.y = -0.5;
scene.add(bakedShadowLoader);

sphere.castShadow = true;
plane.castShadow = true;
torus.castShadow = true;


scene.add(sphere, plane, torus);
sphere.position.x = -1.5;
torus.position.x = 1.5;

// 環(huán)境光
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
// 點(diǎn)光源
// const pointLight = new THREE.PointLight(0xffffff, 50);
// pointLight.position.set(2, 2, -1);
// scene.add(pointLight);
// pointLight.castShadow = true; // 開啟陰影
// const pointLightHelper = new THREE.PointLightHelper(pointLight, 0.2);
// scene.add(pointLightHelper);
// 聚光燈
const spotLight = new THREE.SpotLight(0x0000ff, 20);
spotLight.position.set(2, 3, -1);
spotLight.castShadow = true; // 開啟陰影
scene.add(spotLight);
const spotLightHelper = new THREE.SpotLightHelper(spotLight);
spotLightHelper.visible = true; // 顯示輔助燈光
scene.add(spotLightHelper);
//優(yōu)化陰影效果一個(gè)Vector2定義陰影貼圖的寬度和高度
spotLight.shadow.mapSize.width=1024
spotLight.shadow.mapSize.height=1024
spotLight.shadow.camera.far=10;
// 平行光
// const directionalLight = new THREE.DirectionalLight(0xffffff, 1.5);
// directionalLight.position.set(3, 9, -8);
// directionalLight.castShadow = true; // 開啟陰影
// scene.add(directionalLight);
// const directionalLightHelper = new THREE.DirectionalLightHelper(directionalLight, 0.2); 
// scene.add(directionalLightHelper);
// 半球光(不能投影)
// const hemisphereLight = new THREE.HemisphereLight(0x0000ff, 0xffffff, 0.3);
// scene.add(hemisphereLight);
// const hemisphereLightHelper = new THREE.HemisphereLightHelper(hemisphereLight, 0.2);
// scene.add(hemisphereLightHelper);

// 渲染
const renderer = new THREE.WebGLRenderer({
    canvas: canvas,
    antialias: true
});
const sizes = {
    width: window.innerWidth,
    height: window.innerHeight
};
window.addEventListener('resize', () => {
    sizes.width = window.innerWidth;
    sizes.height = window.innerHeight;

    camera.aspect = sizes.width / sizes.height;
    camera.updateProjectionMatrix();

    renderer.setSize(sizes.width, sizes.height);
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
});
// 相機(jī)
const camera = new THREE.PerspectiveCamera(75, sizes.width / sizes.height, 0.1, 100);
camera.position.x = 3;
camera.position.y = 3;
camera.position.z = 6;
scene.add(camera);

// 控制器
const controls = new OrbitControls(camera, canvas);
controls.enableDamping = true;
// 渲染器
renderer.setSize(sizes.width, sizes.height);
renderer.shadowMap.enabled=true    //渲染器啟用陰影

function tick() {
    // 更新控制器
    controls.update();

    // 渲染場(chǎng)景
    renderer.render(scene, camera);

    // 循環(huán)調(diào)用tick函數(shù)
    window.requestAnimationFrame(tick);
}
tick();
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容