四时宝库

程序员的知识宝库

如何使用ThreeJS实现3D小区模型?(threejs制作3d户型图)

使用Three.js实现3D小区模型,需要涉及到对于小区场景的设置、建筑物的创建、道路信息、绿化信息、灯光信息等各种不同的元素创建。下面我们就来通过一个简单的例子来实现一个简单的小区3D模型。

准备工作

首先需要安装Three.js,可以通过CDN或npm安装Three.js

CDN方式: 在HTML文件中引入Three.js库

<script src="https://cdn.jsdelivr.net/npm/three@0.146.0/build/three.min.js"></script>

npm方式: 在项目目录中运行npm install three,然后在JavaScript中导入。

接下来,就是创建一个基本的HTML文件,包含一个<canvas>元素用于渲染3D模型。下面我们就来按照步骤一步一步的搭建相关的场景。

创建场景、相机和渲染器

首先,就需要我们去创建一个Three.js的基本场景,在这个场景中主要包括了场景、相机和渲染器信息。

// 创建场景
const scene = new THREE.Scene();

// 创建相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 10, 20);

// 创建渲染器
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

添加地面

创建完场景之后,接下来就是创建地面信息,可以通过PlaneGeometry来进行创建,如下所示。

// 创建地面
const geometry = new THREE.PlaneGeometry(100, 100);
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00, side: THREE.DoubleSide });
const plane = new THREE.Mesh(geometry, material);
plane.rotation.x = - Math.PI / 2;  // 将平面旋转到水平
scene.add(plane);

创建建筑物

地面创建好之后,接下来就是创建地面上的建筑物信息,通过BoxGeometry来表示建筑物的信息,然后通过根据需要创建不同大小的盒子代表不同的楼宇,如下所示。

// 创建建筑物
function createBuilding(x, y, z, width, height, depth, color) {
    const geometry = new THREE.BoxGeometry(width, height, depth);
    const material = new THREE.MeshBasicMaterial({ color: color });
    const building = new THREE.Mesh(geometry, material);
    building.position.set(x, y + height / 2, z); // 确保建筑物底部位于地面上
    scene.add(building);
}

// 创建几个建筑物
createBuilding(-10, 0, -10, 5, 10, 5, 0xff0000);  // 红色建筑
createBuilding(10, 0, -10, 6, 15, 6, 0x0000ff);  // 蓝色建筑

添加道路

道路可以使用PlaneGeometry并设置为灰色或黑色来表示。

// 创建道路
function createRoad(x, z, width, depth) {
    const geometry = new THREE.PlaneGeometry(width, depth);
    const material = new THREE.MeshBasicMaterial({ color: 0x333333 });
    const road = new THREE.Mesh(geometry, material);
    road.rotation.x = -Math.PI / 2;
    road.position.set(x, 0.01, z);  // 稍微抬高道路,以避免与地面重叠
    scene.add(road);
}

// 创建一条道路
createRoad(0, 0, 4, 50);  // 贯穿小区的主干道

添加绿化

绿化可以用SphereGeometry和CylinderGeometry来表示树木。

// 创建树木
function createTree(x, z) {
    const trunkGeometry = new THREE.CylinderGeometry(0.5, 0.5, 3);
    const trunkMaterial = new THREE.MeshBasicMaterial({ color: 0x8B4513 });
    const trunk = new THREE.Mesh(trunkGeometry, trunkMaterial);
    trunk.position.set(x, 1.5, z);
    
    const crownGeometry = new THREE.SphereGeometry(2);
    const crownMaterial = new THREE.MeshBasicMaterial({ color: 0x228B22 });
    const crown = new THREE.Mesh(crownGeometry, crownMaterial);
    crown.position.set(x, 5, z);
    
    scene.add(trunk);
    scene.add(crown);
}

// 创建几棵树
createTree(-5, 10);
createTree(5, 15);

添加灯光

通过DirectionalLight或PointLight,来表示灯光效果。

// 添加环境光
const ambientLight = new THREE.AmbientLight(0x404040);  // 环境光
scene.add(ambientLight);

// 添加方向光
const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
directionalLight.position.set(10, 20, 10);
scene.add(directionalLight);

渲染循环

最后,创建一个渲染循环来渲染场景。

function animate() {
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
}

animate();

交互与控制

为了更好地查看模型,可以添加OrbitControls。

// 添加轨道控制器
const controls = new THREE.OrbitControls(camera, renderer.domElement);

当然我们也可以根据需要进一步丰富模型,比如添加更多细节、纹理、交互等。也可以使用工具如Blender制作复杂的建筑模型,并导入到Three.js中。

全量代码实现

下面是全量代码实现,可以根据自己的需求来调整相关的布局实现一个好看的3D小区地图

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<title>3D 小区模型 - 十字路口</title>
		<style>
			body {
				margin: 0;
			}

			canvas {
				display: block;
			}
		</style>
	</head>
	<body>
		<script src="https://cdn.jsdelivr.net/npm/three@0.146.0/build/three.min.js"></script>
		<script src="https://cdn.jsdelivr.net/npm/three@0.146.0/examples/js/controls/OrbitControls.js"></script>
		<script>
			// 创建场景
			const scene = new THREE.Scene();

			// 创建相机
			const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
			camera.position.set(0, 30, 70);

			// 创建渲染器
			const renderer = new THREE.WebGLRenderer();
			renderer.setSize(window.innerWidth, window.innerHeight);
			document.body.appendChild(renderer.domElement);

			// 创建地面
			const groundGeometry = new THREE.PlaneGeometry(100, 100);
			const groundMaterial = new THREE.MeshStandardMaterial({
				color: 0x8B4513
			}); // 土壤色
			const ground = new THREE.Mesh(groundGeometry, groundMaterial);
			ground.rotation.x = -Math.PI / 2; // 将平面旋转到水平
			scene.add(ground);

			// 创建建筑物
			function createBuilding(x, y, z, width, height, depth, color) {
				const geometry = new THREE.BoxGeometry(width, height, depth);
				const material = new THREE.MeshStandardMaterial({
					color: color
				});
				const building = new THREE.Mesh(geometry, material);
				building.position.set(x, y + height / 2, z); // 确保建筑物底部位于地面上
				scene.add(building);
			}

			// 添加建筑物,避免放置在十字路口的中心区域
			createBuilding(-25, 0, -15, 6, 12, 6, 0xd3d3d3); // 浅灰色建筑
			createBuilding(25, 0, -15, 6, 12, 6, 0xadd8e6); // 浅蓝色建筑
			createBuilding(-15, 0, 25, 8, 20, 8, 0xffe4b5); // 米色建筑

			// 创建道路
			function createRoad(x, z, width, depth) {
				const geometry = new THREE.PlaneGeometry(width, depth);
				const material = new THREE.MeshStandardMaterial({
					color: 0x696969
				}); // 深灰色
				const road = new THREE.Mesh(geometry, material);
				road.rotation.x = -Math.PI / 2;
				road.position.set(x, 0.01, z); // 稍微抬高道路,以避免与地面重叠
				scene.add(road);
			}

			// 添加道路,形成十字路口
			createRoad(0, 0, 10, 100); // 横向主干道
			createRoad(0, 0, 100, 10); // 纵向主干道

			// 创建树木
			function createTree(x, z) {
				const trunkGeometry = new THREE.CylinderGeometry(0.5, 0.5, 3);
				const trunkMaterial = new THREE.MeshStandardMaterial({
					color: 0x8b4513
				}); // 深棕色
				const trunk = new THREE.Mesh(trunkGeometry, trunkMaterial);
				trunk.position.set(x, 1.5, z);

				const crownGeometry = new THREE.SphereGeometry(2);
				const crownMaterial = new THREE.MeshStandardMaterial({
					color: 0x228b22
				}); // 绿色
				const crown = new THREE.Mesh(crownGeometry, crownMaterial);
				crown.position.set(x, 5, z);

				scene.add(trunk);
				scene.add(crown);
			}

			// 添加树木
			createTree(-30, -30);
			createTree(30, -30);
			createTree(-30, 30);
			createTree(30, 30);

			// 添加环境光
			const ambientLight = new THREE.AmbientLight(0x404040); // 环境光
			scene.add(ambientLight);

			// 添加方向光
			const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
			directionalLight.position.set(10, 50, 30);
			scene.add(directionalLight);

			// 添加轨道控制器
			const controls = new THREE.OrbitControls(camera, renderer.domElement);

			// 渲染循环
			function animate() {
				requestAnimationFrame(animate);
				controls.update();
				renderer.render(scene, camera);
			}

			animate();

			// 处理窗口大小变化
			window.addEventListener('resize', () => {
				camera.aspect = window.innerWidth / window.innerHeight;
				camera.updateProjectionMatrix();
				renderer.setSize(window.innerWidth, window.innerHeight);
			});
		</script>
	</body>
</html>

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言
    友情链接