文章目录
在 Vue 3 中使用 Three.js 模拟楼栋阳光照射时长
本文将介绍如何在 Vue 3 应用程序中使用 Three.js 创建一个三维场景,模拟一天中不同时段楼栋落地窗接收到的阳光照射时长。
技术要点
- Three.js 场景搭建:通过
THREE.Scene
、THREE.PerspectiveCamera
和THREE.WebGLRenderer
构建基础三维场景。 - 光源与阴影:使用
THREE.AmbientLight
提供环境光和THREE.DirectionalLight
模拟太阳光,并启用阴影映射以增强光照效果的真实性。 - 相机控制:利用 [OrbitControls](file://h:\project_induce\24\project\vue3-demo\public\jsm\controls\OrbitControls.js#L42-L1113) 实现交互式视角控制,便于观察整个建筑群。
- 建筑模型创建:定义
createBuilding
函数生成具有多楼层结构的楼体及其窗户,采用THREE.BoxGeometry
结合材质对象创建几何形状并设置位置信息。 - 日照时间计算:
- 使用
THREE.Raycaster
对象检测每个窗户是否被其他建筑物遮挡。 - 遍历指定时间段内的每一分钟,更新太阳的位置,并记录未被遮挡的窗户所接收到的日光时数。
- 使用
- 动画循环:通过
requestAnimationFrame
实现持续渲染,动态调整太阳位置模拟日升日落过程。
整体代码
以下为完整的实现代码:
<template>
<div ref="container"></div>
</template>
<script setup>
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { ref, onMounted } from 'vue';
const container = ref(null);
onMounted(() => {
// 初始化场景、相机和渲染器
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 30;
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
container.value.appendChild(renderer.domElement);
// 添加环境光和方向光
const ambientLight = new THREE.AmbientLight(0x404040);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.5);
directionalLight.castShadow = true;
directionalLight.shadow.camera.left = -20;
directionalLight.shadow.camera.right = 20;
directionalLight.shadow.camera.top = 20;
directionalLight.shadow.camera.bottom = -20;
directionalLight.shadow.camera.near = 0.1;
directionalLight.shadow.camera.far = 50;
directionalLight.shadow.mapSize.width = 1024;
directionalLight.shadow.mapSize.height = 1024;
scene.add(directionalLight);
// 控制器
const controls = new OrbitControls(camera, renderer.domElement);
// 定义楼层参数
const floorHeight = 3.3;
const floorCount = 5;
const frontBackDistance = 10;
const leftRightDistance = 7;
// 创建楼栋函数
function createBuilding(xOffset, zOffset) {
const buildingGroup = new THREE.Group();
for (let i = 0; i < floorCount; i++) {
// 楼栋
const buildingGeometry = new THREE.BoxGeometry(5, floorHeight, 3);
const buildingMaterial = new THREE.MeshPhongMaterial({ color