gui 辅助调节光源阴影
光源阴影范围,也可以通过 GUI 界面可视化调节,这样更形象。
阴影范围可视化调节
- 根据工厂尺寸数量级预先设置
.shadow.camera
,然后通过 GUI 调试选择一个合适的值 .shadow.camera
的位置通过光源的位置调试.shadow.camera
参数改变后,注意执行cameraHelper.update()
更新
阴影子菜单
js
const shadowFolder = gui.addFolder("平行光阴影");
const cam = directionalLight.shadow.camera;
// 相机left、right等属性变化执行.updateProjectionMatrix();
// 相机变化了,执行CameraHelper的更新方法.update();
shadowFolder.add(cam, "left", -500, 0).onChange(function (v) {
cam.updateProjectionMatrix(); //相机更新投影矩阵
cameraHelper.update(); //相机范围变化了,相机辅助对象更新
});
其他参数类似设置
js
shadowFolder.add(cam, "right", 0, 500).onChange(function (v) {
cam.updateProjectionMatrix();
cameraHelper.update();
});
shadowFolder.add(cam, "top", 0, 500).onChange(function (v) {
cam.updateProjectionMatrix();
cameraHelper.update();
});
shadowFolder.add(cam, "bottom", -500, 0).onChange(function (v) {
cam.updateProjectionMatrix();
cameraHelper.update();
});
shadowFolder.add(cam, "far", 0, 1000).onChange(function (v) {
cam.updateProjectionMatrix();
cameraHelper.update();
});
示例代码如下:
vue
<template>
<div ref="lightDom"></div>
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from "vue";
import * as THREE from "three";
import model from "./model.js";
import gui from "./gui.js";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
const lightDom = ref(null);
// 场景
const scene = new THREE.Scene();
scene.add(model);
// 辅助观察坐标系
const axesHelper = new THREE.AxesHelper(500);
scene.add(axesHelper);
// 环境光
const ambientLight = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(ambientLight);
// 平行光
const directionalLight = new THREE.DirectionalLight(0xffffff, 4);
directionalLight.position.set(200, 160, 150);
scene.add(directionalLight);
// gui控制环境光光照强度`.intensity`
gui.add(ambientLight, "intensity", 0, 2).name("环境光.intensity");
const dirHelper = new THREE.DirectionalLightHelper(directionalLight, 5);
scene.add(dirHelper);
// 平行光子菜单
const dirFolder = gui.addFolder("平行光");
dirFolder.add(directionalLight, "intensity", 0, 2);
dirFolder
.add(directionalLight.position, "y", 0, 300)
.onChange(function (value) {
dirHelper.update();
});
const obj = {
R: 100,
angle: 0,
};
dirFolder.add(obj, "R", 0, 300).onChange(function (value) {
directionalLight.position.x = value * Math.cos(obj.angle);
directionalLight.position.z = value * Math.sin(obj.angle);
dirHelper.update();
});
dirFolder.add(obj, "angle", 0, Math.PI * 2).onChange(function (value) {
directionalLight.position.x = obj.R * Math.cos(value);
directionalLight.position.z = obj.R * Math.sin(value);
dirHelper.update();
});
// mapSize属性默认 512x512
// console.log('阴影默认像素', directionalLight.shadow.mapSize);
// directionalLight.shadow.mapSize.set(128, 128);
directionalLight.shadow.mapSize.set(1024, 1024);
// 模糊弱化阴影边缘
// console.log('.shadow.radius', directionalLight.shadow.radius); // 1
// directionalLight.shadow.radius = 3;
// 2、平行光设置产生阴影的光源对象,开启光源阴影的计算功能
directionalLight.castShadow = true;
// 5、设置三维场景计算阴影的范围
directionalLight.shadow.camera.left = -50 * 6;
directionalLight.shadow.camera.right = 50 * 6;
directionalLight.shadow.camera.top = 200 * 2;
directionalLight.shadow.camera.bottom = -100 * 2;
directionalLight.shadow.camera.near = 0.5;
directionalLight.shadow.camera.far = 400 * 10;
// 可视化平行光阴影对应的正投影相机对象
const cameraHelper = new THREE.CameraHelper(directionalLight.shadow.camera);
scene.add(cameraHelper);
// 阴影子菜单
const shadowFolder = gui.addFolder("平行光阴影");
const cam = directionalLight.shadow.camera;
// 相机left、right等属性变化执行.updateProjectionMatrix();
// 相机变化了,执行CameraHelper的更新方法.update();
shadowFolder.add(cam, "left", -500, 0).onChange(function (v) {
cam.updateProjectionMatrix(); //相机更新投影矩阵
cameraHelper.update(); //相机范围变化了,相机辅助对象更新
});
shadowFolder.add(cam, "right", 0, 500).onChange(function (v) {
cam.updateProjectionMatrix();
cameraHelper.update();
});
shadowFolder.add(cam, "top", 0, 500).onChange(function (v) {
cam.updateProjectionMatrix();
cameraHelper.update();
});
shadowFolder.add(cam, "bottom", -500, 0).onChange(function (v) {
cam.updateProjectionMatrix();
cameraHelper.update();
});
shadowFolder.add(cam, "far", 0, 1000).onChange(function (v) {
cam.updateProjectionMatrix();
cameraHelper.update();
});
// const spotLight = new THREE.SpotLight(0xffffff, 1.0);
// scene.add(spotLight);
// spotLight.angle = Math.PI / 6;
// spotLight.decay = 0.0;
// spotLight.position.set(0, 50, 0);
// const spotLightHelper = new THREE.SpotLightHelper(spotLight, 0xff0000);
// scene.add(spotLightHelper);
// spotLight.target是一个模型对象Object3D,默认在坐标原点
// spotLight.target.position.set(50, 0, 0);
//spotLight.target添加到场景中.target.position才会起作用
// scene.add(spotLight.target);
// 相机
const width = window.innerWidth - 296;
const height = window.innerHeight - 136;
const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);
// camera.position.set(40, 122, 390);
camera.position.set(153, 697, 676);
camera.lookAt(0, 0, 0);
// webgl 渲染器
const renderer = new THREE.WebGLRenderer({
antialias: true,
});
renderer.setSize(width, height);
// 防止输出模糊
renderer.setPixelRatio(window.devicePixelRatio);
// 4、设置渲染器,允许光源阴影渲染
renderer.shadowMap.enabled = true;
// 模型表面产生条纹影响渲染效果,可以改变.shadowMap.type默认值优化
renderer.shadowMap.type = THREE.VSMShadowMap;
// 相机轨道控制器
const controls = new OrbitControls(camera, renderer.domElement);
controls.addEventListener("change", () => {
renderer.render(scene, camera);
});
// resize 事件会在窗口被调整大小时发生
window.addEventListener("resize", () => {
const w = window.innerWidth - 296;
const h = window.innerHeight - 136;
renderer.setSize(w, h);
camera.aspect = w / h;
// 如果相机的一些属性发生了变化,需要执行 updateProjectionMatrix ()方法更新相机的投影矩阵
camera.updateProjectionMatrix();
});
onMounted(() => {
// renderer.setClearColor(0x444544, 0.4);
lightDom.value?.appendChild(renderer.domElement);
});
onUnmounted(() => {
renderer.dispose();
});
// 渲染循环
const render = () => {
renderer.render(scene, camera);
requestAnimationFrame(render);
};
render();
</script>
js
// 引入Three.js
import * as THREE from "three";
// 引入gltf模型加载库GLTFLoader.js
import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
import gui from "./gui.js";
const loader = new GLTFLoader(); //创建一个GLTF加载器
const model = new THREE.Group(); //声明一个组对象,用来添加加载成功的三维场景
const textureCube = new THREE.CubeTextureLoader()
.setPath("/环境贴图/环境贴图0/")
.load(["px.jpg", "nx.jpg", "py.jpg", "ny.jpg", "pz.jpg", "nz.jpg"]);
textureCube.encoding = THREE.sRGBEncoding; //和renderer.outputEncoding一致
loader.load("/工厂建模数据/工厂.glb", function (gltf) {
//gltf加载成功后返回一个对象
// console.log('控制台查看gltf对象结构', gltf);
gltf.scene.traverse(function (obj) {
if (obj.isMesh) {
//判断是否是网格模型
obj.material.envMap = textureCube; //设置环境贴图
// envMapIntensity:控制环境贴图对mesh表面影响程度
obj.material.envMapIntensity = 1.0; //默认值1, 设置为0.0,相当于没有环境贴图
// 批量设置所有Mesh都可以产生阴影和接收阴影
obj.castShadow = true;
// 设置接收阴影的投影面
obj.receiveShadow = true;
}
});
model.add(gltf.scene); //三维场景添加到model组对象中
const obj = {
envMapIntensity: 1.0,
};
gui.add(obj, "envMapIntensity", 0, 2).onChange(function (value) {
gltf.scene.traverse(function (obj) {
if (obj.isMesh) {
obj.material.envMapIntensity = value;
}
});
});
});
export default model;
js
// 从threejs扩展库引入gui.js
import { GUI } from "three/addons/libs/lil-gui.module.min.js";
const gui = new GUI(); //创建GUI对象
gui.domElement.style.right = "0px";
gui.domElement.style.width = "300px";
export default gui;