第一人称房屋 ·House Scene· ▶ 在线运行案例
- 案例合集:三维可视化功能案例(threehub.cn)
- 开源仓库github地址:https://github.com/z2586300277/three-cesium-examples
- 400个案例代码:网盘链接
你将学到什么
- FBXLoader 加载 FBX 城市/角色模型
- 场景雾效增强纵深
requestAnimationFrame渲染循环与resize自适应
效果说明
本案例演示第一人称房屋效果:基于 WebGL 实现「第一人称房屋」可视化效果,附完整可运行源码;核心用到 FBXLoader、场景雾效增强纵深。建议先打开文首在线案例查看动态画面,再对照下方源码逐步理解。
核心概念
- Loader异步加载模型;glTF 返回
gltf.scene,加载后注意scale与坐标系。Draco 需配置DRACOLoader。
实现步骤
- 搭建 Scene / Camera / Renderer 与 OrbitControls
- Loader 异步加载模型/纹理资源
- rAF 循环中 update 并 render
代码要点
import * as THREE from 'three';import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader.js'; import { FirstPersonControls } from 'three/examples/jsm/controls/FirstPersonControls.js';
const host = FILE_HOST + 'examples/flowerAndHouse';
const box = document.getElementById('box');
const width = box.clientWidth; const height = box.clientHeight; const camera = new THREE.PerspectiveCamera(60, width / height, 0.1, 1000);
const scene = new THREE.Scene();
const house = new THREE.Group();
const renderer = new THREE.WebGLRenderer();
function create() { renderer.setSize(width, height); //设置背景颜色 renderer.setClearColor(0xcce0ff, 1); box.appendChild(renderer.domElement);
camera.position.set(-500, 60, 0) camera.lookAt(scene.position);
const light = new THREE.AmbientLight(0xCCCCCC); scene.add(light);
const axisHelper = new THREE.AxesHelper(1000); scene.add(axisHelper);
createGrass(); createHouse();
function createHouse() { createFloor(); const sideWall = createSideWall(); const sideWall2 = createSideWall(); sideWall2.position.z = 300;
createFrontWall(); createBackWall();
const roof = createRoof(); const roof2 = createRoof(); roof2.rotation.x = Math.PI / 2; roof2.rotation.y = Math.PI / 4 * 0.6; roof2.position.y = 130; roof2.position.x = -50; roof2.position.z = 155;
createWindow(); createDoor();
createBed(); } scene.add(house);
scene.fog = new THREE.Fog(0xffffff, 10, 1500); }
function createGrass() { const geometry = new THREE.PlaneGeometry( 10000, 10000);
const texture = new THREE.TextureLoader().load(host+'/img/grass.jpg'); texture.wrapS = THREE.RepeatWrapping; texture.wrapT = THREE.RepeatWrapping; texture.repeat.set( 100, 100 );
const grassMaterial = new THREE.MeshBasicMaterial({map: texture});
const grass = new THREE.Mesh( geometry, grassMaterial );
grass.rotation.x = -0.5 * Math.PI;
scene.add( grass ); }
function createFloor() { const geometry = new THREE.PlaneGeometry( 200, 300);
const texture = new THREE.TextureLoader().load(host + '/img/wood.jpg'); texture.wrapS = THREE.RepeatWrapping; texture.wrapT = THREE.RepeatWrapping; texture.repeat.set( 2, 2 );
const material = new THREE.MeshBasicMaterial({map: texture});
const floor = new THREE.Mesh( geometry, material );
floor.rotation.x = -0.5 * Math.PI; floor.position.y = 1; floor.position.z = 150;
house.add(floor); }
function createSideWall() { const shape = new THREE.Shape(); shape.moveTo(-100, 0); shape.lineTo(100, 0); shape.lineTo(100,100); shape.lineTo(0,150); shape.lineTo(-100,100); shape.lineTo(-100,0);
const extrudeGeometry = new THREE.ExtrudeGeometry( shape );
const texture = new THREE.TextureLoader().load(host+'/img/wall.jpg'); texture.wrapS = texture.wrapT = THREE.RepeatWrapping; texture.repeat.set( 0.01, 0.005 );
var material = new THREE.MeshBasicMaterial( {map: texture} );
const sideWall = new THREE.Mesh( extrudeGeometry, material ) ;
house.add(sideWall);
return sideWall; }
function createFrontWall() { const shape = new THREE.Shape(); shape.moveTo(-150, 0); shape.lineTo(150, 0); shape.lineTo(150,100); shape.lineTo(-150,100); shape.lineTo(-150,0);
const window = new THREE.Path(); window.moveTo(30,30) window.lineTo(80, 30) window.lineTo(80, 80) window.lineTo(30, 80); window.lineTo(30, 30); shape.holes.push(window);
const door = new THREE.Path(); door.moveTo(-30, 0) door.lineTo(-30, 80) door.lineTo(-80, 80) door.lineTo(-80, 0); door.lineTo(-30, 0); shape.holes.push(door);
const extrudeGeometry = new THREE.ExtrudeGeometry( shape )
const texture = new THREE.TextureLoader().load(host+'/img/wall.jpg'); texture.wrapS = texture.wrapT = THREE.RepeatWrapping; texture.repeat.set( 0.01, 0.005 );
const material = new THREE.MeshBasicMaterial({map: texture} );
const frontWall = new THREE.Mesh( extrudeGeometry, material ) ;
frontWall.position.z = 150; frontWall.position.x = 100; frontWall.rotation.y = Math.PI * 0.5;
house.add(frontWall); }
function createBackWall() { const shape = new THREE.Shape(); shape.moveTo(-150, 0) shape.lineTo(150, 0) shape.lineTo(150,100) shape.lineTo(-150,100);
const extrudeGeometry = new THREE.ExtrudeGeometry( shape )
const texture = new THREE.TextureLoader().load(host+'/img/wall.jpg'); texture.wrapS = texture.wrapT = THREE.RepeatWrapping; texture.repeat.set( 0.01, 0.005 );
const material = new THREE.MeshBasicMaterial({map: texture});
const backWall = new THREE.Mesh( extrudeGeometry, material) ;
backWall.position.z = 150; backWall.position.x = -100; backWall.rotation.y = Math.PI * 0.5;
house.add(backWall); }
function createRoof() { const geometry = new THREE.BoxGeometry( 120, 320, 10 );
const texture = new THREE.TextureLoader().load(host+'/img/tile.jpg'); texture.wrapS = texture.wrapT = THREE.RepeatWrapping; texture.repeat.set( 5, 1); texture.rotation = Math.PI / 2; const textureMaterial = new THREE.MeshBasicMaterial({ map: texture});
const colorMaterial = new THREE.MeshBasicMaterial({ color: 'grey' });
const materials = [ colorMaterial, colorMaterial, colorMaterial, colorMaterial, colorMaterial, textureMaterial ];
const roof = new THREE.Mesh( geometry, materials );
house.add(roof);
roof.rotation.x = Math.PI / 2; roof.rotation.y = - Math.PI / 4 * 0.6; roof.position.y = 130; roof.position.x = 50; roof.position.z = 155; return roof; }
function createWindow() { const shape = new THREE.Shape(); shape.moveTo(0, 0); shape.lineTo(0, 50) shape.lineTo(50,50) shape.lineTo(50,0); shape.lineTo(0, 0);
const hole = new THREE.Path(); hole.moveTo(5,5) hole.lineTo(5, 45) hole.lineTo(45, 45) hole.lineTo(45, 5); hole.lineTo(5, 5); shape.holes.push(hole);
const extrudeGeometry = new THREE.ExtrudeGeometry(shape);
var extrudeMaterial = new THREE.MeshBasicMaterial({ color: 'silver' });
var mesh = new THREE.Mesh( extrudeGeometry, extrudeMaterial ) ; mesh.rotation.y = Math.PI / 2; mesh.position.y = 30; mesh.position.x = 100; mesh.position.z = 120;
house.add(mesh);
return mesh; }
function createDoor() { const shape = new THREE.Shape(); shape.moveTo(0, 0); shape.lineTo(0, 80); shape.lineTo(50,80); shape.lineTo(50,0); shape.lineTo(0, 0);
const hole = new THREE.Path(); hole.moveTo(5,5); hole.lineTo(5, 75); hole.lineTo(45, 75); hole.lineTo(45, 5); hole.lineTo(5, 5); shape.holes.push(hole);
const extrudeGeometry = new THREE.ExtrudeGeometry( shape );
const material = new THREE.MeshBasicMaterial( { color: 'silver' } );
const door = new THREE.Mesh( extrudeGeometry, material ) ;
door.rotation.y = Math.PI / 2; door.position.y = 0; door.position.x = 100; door.position.z = 230;
house.add(door); }
function createBed() { var loader = new FBXLoader(); loader.load(host + '/bed.fbx', function ( object ) { object.position.x = 40; object.position.z = 80; object.position.y = 20;
house.add( object ); } ); }
const clock = new THREE.Clock();
const controls = new FirstPersonControls(camera, renderer.domElement); controls.lookSpeed = 0.05; controls.movementSpeed = 100; controls.lookVertical = false;
create() render()
function render() { const delta = clock.getDelta(); controls.update(delta);
renderer.render(scene, camera); requestAnimationFrame(render) }完整源码:GitHub
小结
- 本文提供第一人称房屋完整 Three.js 源码与在线 Demo,建议先运行案例再改 uniform/参数做二次实验
- 更多 Three.js 实战案例见 three-cesium-examples 合集 与 GitHub 开源仓库