Three.js实现简单3D房间布局

本文实例为大家分享了Three.js实现简单3D房间布局的具体代码,供大家参考,具体内容如下

废话不说了,直接上成果图。

代码如下

<!doctype html>
<html lang="en">
<head>
<title>房间布局</title>
<meta charset="utf-8">
<meta name="viewport"
 content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
</head>
<body>

 <script src="js/jquery-1.9.1.js"></script>
 <script src="js/Three.min.js"></script>
 <script src="js/OrbitControls.js"></script>
 <script src="js/ThreeBSP.js"></script>
 <script src="js/Detector.js"></script>
 <script src="js/Stats.js"></script>

 <script src="js/THREEx.KeyboardState.js"></script>
 <script src="js/THREEx.FullScreen.js"></script>
 <script src="js/THREEx.WindowResize.js"></script>

 <!-- people -->
 <script src="people/js/three.js"></script>
 <script src="people/js/DDSLoader.js"></script>
 <script src="people/js/MTLLoader.js"></script>
 <script src="people/js/OBJLoader.js"></script>
 <script src="people/js/Detector.js"></script>
 <script src="people/js/stats.min.js"></script>
 <script src="people/js/PathControls.js"></script>
 <script src="people/js/Tween.js"></script>
 <script src="people/js/RequestAnimationFrame.js"></script>

 <div id="ThreeJS" style="position: absolute; left: 0px; top: 0px"></div>

 <script>
 // 设置全局变量
 var scene, camera, renderer, controls, tween, door;
 var keyboard = new THREEx.KeyboardState();//保持键盘的当前状态,可以随时查询
 var clock = new THREE.Clock();
 var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight;
 //var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 20000;
 var VIEW_ANGLE = 75, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 0.1, FAR = 10000;
 var materialArrayA = [];
 var materialArrayB = [];
 var matArrayA = [];//内墙
 var matArrayB = [];//外墙
 var dummy = new THREE.Object3D();//仿制品
 init();
 animate();

 //1.场景
 function initScene() {
 scene = new THREE.Scene();
 }

 //2.相机
 function initCamera() {
 camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR);
 camera.position.set(0, 1000, 1800);
 camera.lookAt(scene.position);
 camera.lookAt(0, 0, 0);
 scene.add(camera);
 }

 //3.渲染器
 function initRender() {
 if (Detector.webgl)
 renderer = new THREE.WebGLRenderer({
  antialias : true
 });
 else
 renderer = new THREE.CanvasRenderer();
 //设置渲染器的大小为窗口的内宽度,也就是内容区的宽度。
 renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
 container = document.getElementById('ThreeJS');
 container.appendChild(renderer.domElement);
 renderer.setClearColor(0x4682B4, 1.0);
 }

 //4.事件
 function initEvent() {
 THREEx.WindowResize(renderer, camera);
 THREEx.FullScreen.bindKey({
 charCode : 'm'.charCodeAt(0)
 });
 }

 //5.控制
 function initControls() {
 controls = new THREE.OrbitControls(camera, renderer.domElement);
 }

 //6.光源
 function initLight() {
 // 位置不同,方向光作用于物体的面也不同,看到的物体各个面的颜色也不同
 // A start, 第二个参数是光源强度
 var directionalLight = new THREE.DirectionalLight(0xffffff, 1);//模拟远处类似太阳的光源
 directionalLight.position.set(0, 100, 0).normalize();
 scene.add(directionalLight);
 //A end
 var ambient = new THREE.AmbientLight(0xffffff, 1); //AmbientLight,影响整个场景的光源
 ambient.position.set(0, 0, 0);
 scene.add(ambient);
 //var pointlight = new THREE.PointLight(0x000000,1.5,2000);
 //scene.add(pointlight);
 }

 //创建地板
 function createFloor() {
 var loader = new THREE.TextureLoader();
 loader.load("images/floor.jpg", function(texture) {
 texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
 texture.repeat.set(10, 10);
 var floorGeometry = new THREE.BoxGeometry(1600, 1100, 1);
 var floorMaterial = new THREE.MeshBasicMaterial({
  map : texture,
  side : THREE.DoubleSide
 });
 var floor = new THREE.Mesh(floorGeometry, floorMaterial);
 floor.position.y = -0.5;
 floor.rotation.x = Math.PI / 2;
 scene.add(floor);
 });

 //茶色:0x58ACFA 透明玻璃色:0XECF1F3
 var glass_material = new THREE.MeshBasicMaterial({
 color : 0XECF1F3
 });
 glass_material.opacity = 0.4;
 glass_material.transparent = true;

 var left_wall = returnWallObject(20, 200, 1100, 0, matArrayB, -801,
  100, 0);
 var left_cube = returnWallObject(20, 110, 1100, 0, matArrayB, -801,
  100, 0);
 createResultBsp(left_wall, left_cube, 1);
 createCubeWall(1, 110, 1100, 0, glass_material, -801, 100, 0);

 var right_wall = returnWallObject(20, 200, 1100, 1, matArrayB, 801,
  100, 0);
 var right_cube = returnWallObject(20, 110, 1100, 0, matArrayB, 801,
  100, 0);
 createResultBsp(right_wall, right_cube, 1);
 createCubeWall(1, 110, 1100, 0, glass_material, 801, 100, 0);
 }

 //墙上挖门,通过两个几何体生成BSP对象
 function createResultBsp(bsp, less_bsp, mat) {
 switch (mat) {
 case 1:
 var material = new THREE.MeshPhongMaterial({
  color : 0x9cb2d1,
  specular : 0x9cb2d1,
  shininess : 30,
  transparent : true,
  opacity : 1
 });
 break;
 case 2:
 var material = new THREE.MeshPhongMaterial({
  color : 0xafc0ca,
  specular : 0xafc0ca,
  shininess : 30,
  transparent : true,
  opacity : 1
 });
 break;
 default:
 }

 var sphere1BSP = new ThreeBSP(bsp);
 var cube2BSP = new ThreeBSP(less_bsp);//0x9cb2d1 淡紫,0xC3C3C3 白灰 , 0xafc0ca灰
 var resultBSP = sphere1BSP.subtract(cube2BSP);
 var result = resultBSP.toMesh(material);
 result.material.flatshading = THREE.FlatShading;
 result.geometry.computeFaceNormals(); //重新计算几何体侧面法向量
 result.geometry.computeVertexNormals();
 result.material.needsUpdate = true; //更新纹理
 result.geometry.buffersNeedUpdate = true;
 result.geometry.uvsNeedUpdate = true;
 scene.add(result);
 }

 //创建墙
 function createCubeWall(width, height, depth, angle, material, x, y, z) {
 var cubeGeometry = new THREE.BoxGeometry(width, height, depth);
 var cube = new THREE.Mesh(cubeGeometry, material);
 cube.position.x = x;
 cube.position.y = y;
 cube.position.z = z;
 cube.rotation.y += angle * Math.PI; //-逆时针旋转,+顺时针
 scene.add(cube);
 }

 //返回墙对象
 function returnWallObject(width, height, depth, angle, material, x, y,
 z) {
 var cubeGeometry = new THREE.BoxGeometry(width, height, depth);
 var cube = new THREE.Mesh(cubeGeometry, material);
 cube.position.x = x;
 cube.position.y = y;
 cube.position.z = z;
 cube.rotation.y += angle * Math.PI;
 return cube;
 }

 //创建墙纹理
 function createWallMaterail() {
 matArrayA.push(new THREE.MeshPhongMaterial({
 color : 0xafc0ca
 })); //前 0xafc0ca :灰色
 matArrayA.push(new THREE.MeshPhongMaterial({
 color : 0xafc0ca
 })); //后
 matArrayA.push(new THREE.MeshPhongMaterial({
 color : 0xd6e4ec
 })); //上 0xd6e4ec: 偏白色
 matArrayA.push(new THREE.MeshPhongMaterial({
 color : 0xd6e4ec
 })); //下
 matArrayA.push(new THREE.MeshPhongMaterial({
 color : 0xafc0ca
 })); //左 0xafc0ca :灰色
 matArrayA.push(new THREE.MeshPhongMaterial({
 color : 0xafc0ca
 })); //右

 matArrayB.push(new THREE.MeshPhongMaterial({
 color : 0xafc0ca
 })); //前 0xafc0ca :灰色
 matArrayB.push(new THREE.MeshPhongMaterial({
 color : 0x9cb2d1
 })); //后 0x9cb2d1:淡紫
 matArrayB.push(new THREE.MeshPhongMaterial({
 color : 0xd6e4ec
 })); //上 0xd6e4ec: 偏白色
 matArrayB.push(new THREE.MeshPhongMaterial({
 color : 0xd6e4ec
 })); //下
 matArrayB.push(new THREE.MeshPhongMaterial({
 color : 0xafc0ca
 })); //左 0xafc0ca :灰色
 matArrayB.push(new THREE.MeshPhongMaterial({
 color : 0xafc0ca
 })); //右

 }

 //创建房间布局
 function createLayout() {

 // 墙面1 立方体比较长的面 左一
 createCubeWall(10, 200, 900, 0, matArrayB, -651, 100, 0);
 // 墙面2 立方体比较长的面 右一
 createCubeWall(10, 200, 900, 1, matArrayB, 651, 100, 0);
 // 墙面3 门对面的墙 立方体比较短的面
 createCubeWall(10, 200, 1310, 1.5, matArrayB, 0, 100, -451);

 // 墙面4 带门的面
 var wall = returnWallObject(1310, 200, 10, 0, matArrayB, 0, 100,
  455);
 // 门框
 var door_cube = returnWallObject(100, 180, 10, 0, matArrayB, 0, 90,
  455);
 createResultBsp(wall, door_cube, 1);

 //为墙面安装门,右门
 var loader = new THREE.TextureLoader();
 loader.load("images/door_right.png", function(texture) {
 var doorgeometry = new THREE.BoxGeometry(100, 180, 2);
 var doormaterial = new THREE.MeshBasicMaterial({
  map : texture,
  color : 0xffffff
 });
 doormaterial.opacity = 1.0;
 doormaterial.transparent = true;
 door = new THREE.Mesh(doorgeometry, doormaterial);
 door.position.set(-50, 0, 0);
 var door1 = door.clone();
 door1.position.set(50, 0, 0);
 door1.visible = false;
 dummy.add(door);
 dummy.add(door1);
 dummy.position.set(50, 90, 451)
 scene.add(dummy);
 });

 // 房间A:隔墙1
 createCubeWall(10, 200, 250, 0, matArrayA, -151, 100, 325);
 //房间A:隔墙2 无门
 createCubeWall(10, 200, 220, 0.5, matArrayA, -256, 100, 201);
 // 厨房:隔墙3
 createCubeWall(350, 200, 10, 0, matArrayA, 481, 100, 131);
 // 厨房:隔墙4 无门
 createCubeWall(10, 200, 200, 0, matArrayA, 301, 100, 225);
 // 房间B
 createCubeWall(350, 200, 10, 0, matArrayA, -471, 100, -50);
 //房间B 无门
 createCubeWall(200, 200, 10, 0.5, matArrayA, 0, 100, -350);
 // 房间C
 createCubeWall(220, 200, 10, 0, matArrayA, 540, 100, -50);
 //房间C 无门
 createCubeWall(200, 200, 10, 0.5, matArrayA, 250, 100, -350);
 //厕所
 var cube = returnWallObject(10, 200, 260, 0.5, matArrayA, 125, 100,
  -250);
 //厕所门框
 var door_cube1 = returnWallObject(10, 160, 80, 0.5, matArrayA, 155,
  90, -250);
 createResultBsp(cube, door_cube1, 2);

 //茶色:0x58ACFA 透明玻璃色:0XECF1F3
 var glass_material = new THREE.MeshBasicMaterial({
 color : 0x58ACFA
 });
 glass_material.opacity = 0.6;
 glass_material.transparent = true;
 createCubeWall(1, 180, 80, 0.5, glass_material, 155, 90, -250);
 }

 //7.初始化OBJ对象
 function initObject() {
 //墙纹理
 createWallMaterail();
 createFloor();
 createLayout();
 }

 //初始化函数
 function init() {
 initScene();
 initCamera();
 initRender();
 initEvent();
 initControls();
 initLight();
 initObject();
 //监听键盘按键
 document.addEventListener("keydown", onkeyDown, false);
 }

 var door_state = true;//默认是门是关闭的
 //Enter=13,Space=32;
 function onkeyDown(event) {
 switch (event.keyCode) {
 case 13:
 console.log(event.keyCode);
 if (door_state) {
  dummy.rotation.y += 0.5 * Math.PI;
  door_state = false;
 } else {
  dummy.rotation.y -= 0.5 * Math.PI;
  door_state = true;
 }
 break;
 default:
 console.log(event.keyCode);
 break;
 }
 }

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

 function update() {
 var delta = clock.getDelta();
 var moveDistance = 200 * delta;
 var rotateAngle = Math.PI / 2 * delta;
 controls.update();
 }
 </script>
</body>
</html>

通过Enter键可控制开门和关门动作。门的旋转是通过,把门克隆一份,把克隆的那个设置为不可见,然后把两个门打个组 ,这个时候中旋转组就可以了。

此时的旋转中心实际是在组的中心,但设置一半不可见 ,看起来就像是门在旋转了。注意的是,组内的东西的坐标是相对于组的组内,两个门的坐标应该分别是x轴的正负轴上,整个组的位置应该是原来门应该在的位置。

这也是我向一位大神请教的,真的很感谢他那么耐心的教我。

运行方式:

在支持webgl的浏览器上打开room.html,即可看到效果图。如果加载不出来,打开Chrome快捷方式的属性中设置:右击Chrome浏览器快捷方式, 选择“属性”,在“目标”中加上"--allow-file-access-from-files",注意前面有个空格。修改完成,点击应用,确定后,关闭所有chrome上的窗口,重启chrome。再找到该资源room.html文件,以Google Chrome浏览器方式打开即可。

错误解决。

如果出现地板和门的两张图片加载不出来时,提示已被跨源资源共享策略阻止加载。解决办法第一种是如上图所示在Chrome的属性加"--allow-file-access-from-files";第二种就是把图片位置的相对路径改成绝对路径。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • three.js实现3D模型展示的示例代码

    由于项目需要展示3d模型,所以对three做了点研究,分享出来 希望能帮到大家 先看看效果: three.js整体来说 不是很难 只要你静下心来研究研究 很快就会上手的 首先我们在页面上需要创建一个能够放置3D模型的画布 也可以说是初始化 Three var WIDTH,HEIGHT; var renderer; function initThree() { WIDTH = document.documentElement.clientWidth/2; <!--{foreach from=$re

  • three.js实现3D影院的原理的代码分析

    本篇文章我们通过介绍3D影院的视觉原理,并介绍了three.js事件处理过程,全面分析了实现3D影院的基础知识. 1.创建一个3d的空间 可以想象一下我们在房间内,房间是一个立方体,如果你有生活品味,可能会在房间内贴上壁纸,three.js可以很方便的创建一个立方体,并且给它的周围贴上纹理,让照相机在立方体之中,照相机可以360旋转,就模拟了一个真实的场景. 转换为代码: const path = 'assets/image/' const format = '.jpg' const urls

  • Three.js源码阅读笔记(Object3D类)

    这是Three.js源码阅读笔记的第二篇,直接开始. Core::Object3D Object3D似乎是Three.js框架中最重要的类,相当一部分其他的类都是继承自Object3D类,比如场景类.几何形体类.相机类.光照类等等:他们都是3D空间中的对象,所以称为Object3D类.Object3D构造函数如下: 复制代码 代码如下: THREE.Object3D = function () { THREE.Object3DLibrary.push( this ); this.id = THR

  • Three.JS实现三维场景

    最近在看一些Web3D的内容,觉得如果用纯openGLes写一个简单的3D场景太难了:不过还好,有很多现成的库可以使用. (个人感觉):我知道的经常的是Three.JS和SceneJS.感觉Three.JS资料比较多,貌似好学一些吧:另一个是ScenenJS,感觉官方介绍比较好,适合做一些工程和医学上的模拟,实时性比较好,但是中文资料感觉比较少,不太好学习.我个人看的是Three.JS 学习中用到的一些工具和库:学习中用到一些库,也费了不少时间去整理,下载: 用到的工具:WebStorm,个人感

  • Three.js开发实现3D地图的实践过程总结

    前言 本文主要介绍Three.js的开发基础和基本原理,以及如何实现3D全景图.想在web端实现3D全景图的效果,除了全景图片.WebGL外,还需要处理很多细节.据我所知,目前国外3D全景图比较好的是KrPano,国内很多3D全景服务是在使用krpano的工具. 前段时间连续上了一个月班,加班加点完成了一个3D攻坚项目.也算是由传统web转型到webgl图形学开发中,坑不少,做了一下总结分享. Three.js 基于简化WebGL开发复杂度和降低入门难度的目的,mrdoob)在WebGL标准基础

  • 利用three.js画一个3D立体的正方体示例代码

    简介 three.js 是一款WebGL框架,WebGL可以让我们在canvas上实现3D效果.实现3D效果在国内来说还算是比较新的东西,可供查阅的资料也不多.这篇文章仅是一个入门篇,介绍如何绘制一个3D正方体. Three.js中的基本概念 Three.js包含3个基本概念:场景(Scene).相机(Camera)和渲染器(Renderer). 场景就是需要绘制的对象,相机代表取景的视角,渲染器是绘制的载体(可以挂靠到浏览器的DOM元素中), 也就是我们通过相机拍摄场景然后绘制到目标介质中去.

  • three.js实现3D视野缩放效果

    首先,不再废话了,什么是three.js,是干什么的,知道的就是知道,不知道的就百度吧. 小编为大家推荐一篇:Three.js快速入门教程 昨儿发现three.js中的3D视野的缩小和放大效果可以用照相机的远近焦来实现. 缩小后: 这里采用的是透视照相机: //照相机配置 var fov = 40;//拍摄距离 var near = 1;//最小范围 var far = 1000;//最大范围 var camera = new THREE.PerspectiveCamera(fov, windo

  • Three.js的使用及绘制基础3D图形详解

    一. 前言 Three.js 是一款 webGL(3D绘图标准,在此不赘述)引擎,可以运行于所有支持 webGL 的浏览器.Three.js 封装了 webGL 底层的 API ,为我们提供了高级的开发接口,可以使用简单的代码去实现 3D 渲染.(官网:https://threejs.org/) 二. 为什么要选择Three.js? Three.js 作为原生 web3D 引擎,对插件式 web3D 引擎的优势不言而喻:不需要安装插件.在移动端支持好. Three.js 与其他原生 web3D

  • Three.js实现3D机房效果

    3D机房系统是最近用户的需求,通过相关了解最后使用Three.js,也发现最近有东西可以写出来分享: webGL可以让我们在canvas上实现3D效果.而three.js是一款webGL框架,由于其易用性被广泛应用 Three.js是通过对WebGL接口的封装与简化而形成的一个易用的图形库 分步实现3D效果 初始化3D模型参数 开始搭建场景 初始化渲染器 初始化摄像机 创建场景 灯光布置 创建网格线 循环渲染界面 创建鼠标控制器 添加对象到场景中 一 . 初始化3D模型参数 //参数处理 thi

  • three.js中3D视野的缩放实现代码

    通过Threejs基础学习--修改版知道创建一个相机的相关知识点 var camera = new THREE.PerspectiveCamera( fov, aspect , near,far ); 视野角:fov 这里视野角(有的地方叫拍摄距离)越大,场景中的物体越小,视野角越小,场景中的物体越大 纵横比:aspect   (3d物体的宽/高比例) 相机离视体积最近的距离:near 相机离视体积最远的距离:far 其中fov视野角(拍摄距离)越大,场景中的物体越小.fov视野角(拍摄距离)越

随机推荐