近段时间由于项目需求,要在页面中插入3d的室内布局概念图,开始从零学习three.js的知识,下面记录一下这两周研究的结果,本人也是小白一枚,不足之处,还望批评指正!

第一个遇到的问题是室内地图块的渲染效果问题,使用一个光源时,效果总是不尽如人意,总有光照不到的一面是有黑色阴影,后来想到使用两个光源,两侧打光,渲染效果好了很多。

var ambiColor = "#f2f2f2";
var spotLight = new THREE.SpotLight(ambiColor);
spotLight.position.set( -100, 100, -100);
scene.add(spotLight);
var spotLight2 = new THREE.SpotLight(ambiColor);
spotLight2.position.set( 100, 100, 150);
scene.add(spotLight2);

第二个问题是cube的材质问题,在研究threejs之前看到一篇有关室内地图的博文,由于实现效果相似,于是引用了博主对cube材质的思路:顶面和侧面使用不同的材质,我的第一想法就是在cube上面加一个plane,覆盖cube原先顶面的MeshLambertMaterial材质,但是这个想法在后来实现旋转时被否决了,因为plane的高度和cube重合时,会使的顶面和plane的颜色冲突,形成一条条的线,如果y轴方向稍微高出0.2,在俯视图上看不出上面问题,但是当相机的视角一调节,立马便看出问题,找了官方文档的案例,发现可以用MeshFaceMaterial自定义cube的六个面的颜色和材质。

var yellow = [];
// 右侧面
yellow.push(new THREE.MeshLambertMaterial({color: "#F8D3A5"}));
// 左侧面
yellow.push(new THREE.MeshLambertMaterial({color: "#F8D3A5"}));
// 顶侧面
yellow.push(new THREE.MeshBasicMaterial({color: "#F8D3A5",transparent:true,opacity:0.8}));
// 地侧面
yellow.push(new THREE.MeshLambertMaterial({color: "#F8D3A5"}));
// 前侧面
yellow.push(new THREE.MeshLambertMaterial({color: "#F8D3A5"}));
// 后侧面
yellow.push(new THREE.MeshLambertMaterial({color: "#F8D3A5"}));
var face1Material = new THREE.MeshFaceMaterial(yellow);
var cube1Geom = new THREE.BoxGeometry(3,2,12);
var cube1 = new THREE.Mesh(cube1Geom, face1Material);

顶侧使用MeshBasicMaterial可以不受光照的影响,并且可以设置透明度,侧面可以形成阴影,显得真实一点。

第三步是实现相机角度的旋转,这个是直接拿的官方文档的案例里面的方法,比较生硬,还有待优化,因为是上下360度旋转,稍微一转地图的底面便翘起来。

<script src="libs/TrackballControls.js"></script>
controls = new THREE.TrackballControls( camera );
controls.rotateSpeed = 1.0;
controls.zoomSpeed = 1.2;
controls.panSpeed = 0.8;
controls.noZoom = false;
controls.noPan = false;
controls.staticMoving = true;
controls.dynamicDampingFactor = 0.3;
function render() {controls.update();}

只需要引入一个官方的js包,就可以实现了。

第四步是考虑了最久的一个,实现用户的交互,在点击cube之后,cube可以变色,用以提示用户,该cube被点击了,看了网上很多demo,都是使用射线原理,将鼠标点击屏幕中的点垂直射一条光线,如果触碰到多个对象,取第一个对象即为当前点击的cube。这个原理是很简单,但是实现将cube变色却把我难住了,后来又找了很多博客,找到一个可以使cube变色的案例,但是每次把代码搬到我这里就失灵了,总是报一个getHex()和set()未定义的错误,我以为是版本的问题,后来想了很久,试了好久,终于发现,原来是我定义材质的问题,我定义的材质是一个数组,六个面需要改色的话,需要分别改色,而案例中cube的六个面的材质颜色完全一样,所以只需要直接获取再修改便可以了。

function onDocumentMouseClick(event) {event.preventDefault();mouse.x = (event.clientX / window.innerWidth) * 2 - 1;mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
}
raycaster.setFromCamera(mouse, camera);
var intersects = raycaster.intersectObjects(scene.children);
if (intersects.length > 0) {if (INTERSECTED !== intersects[0].object) {if (INTERSECTED && INTERSECTED instanceof THREE.Mesh && INTERSECTED.material.length === 6) {for(var i = 0; i < 6; i++){INTERSECTED.material[i].color.setHex(INTERSECTED.currentHex);}}INTERSECTED = intersects[0].object;if(INTERSECTED instanceof THREE.Mesh && INTERSECTED.material.length === 6){for(var i = 0; i < 6; i++){INTERSECTED.currentHex = INTERSECTED.material[i].color.getHex();if(INTERSECTED.currentHex !== 16777215)INTERSECTED.material[i].color.set( "#FFC965" );}}}
} else {if (INTERSECTED && INTERSECTED instanceof THREE.Mesh && INTERSECTED.material.length === 6) {for(var i = 0; i < 6; i++){INTERSECTED.material[i].color.set(INTERSECTED.currentHex);}}INTERSECTED = null;
}

onmouseclick的方法确定鼠标点击的位置,下面部分是render()方法中的一部分。在整体上为了效果的美观,在所有cube的顶上加了一圈直线,这样cube看起来更加明显,但是这就又引起一个小麻烦,在点击物体时要判断是不是mesh,如果点击的直线应该是没有变色效果的,还有点击的是地板时,也不应该有变色效果。

经过一系列的探索,终于在零的基础上有了一些东西,虽然距离成品还很远(还有很多需要优化的地方),但也算threejs学习上的一小步,最后附上代码。

<!DOCTYPE html>
<html><head><meta charset="UTF-8"><title>Three.js</title><style>body {margin: 0;overflow: hidden;}</style>
</head><body>
<script type="text/javascript" src="libs/three.js"></script>
<script src="libs/TrackballControls.js"></script>
<script>var renderer, scene, camera;var INTERSECTED;var raycaster;var mouse;var controls ;// 边框线的高度
    var lineHeight = 1.75;// 块的高度
    var cubeHeight = 1.5;function init() {renderer = new THREE.WebGLRenderer({antialias: true
        });renderer.setClearColor(0xF1F2F7);renderer.setSize(window.innerWidth, window.innerHeight);scene = new THREE.Scene();scene.background = new THREE.Color( 0xF1F2F7 );camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);camera.lookAt(new THREE.Vector3(20, 0, 20));camera.position.set(0, 40, 50);// 光线的照射
        var ambiColor = "#f2f2f2";var spotLight = new THREE.SpotLight(ambiColor);spotLight.position.set( -100, 100, -100);scene.add(spotLight);var spotLight2 = new THREE.SpotLight(ambiColor);spotLight2.position.set( 100, 100, 150);scene.add(spotLight2);controls = new THREE.TrackballControls( camera );controls.rotateSpeed = 1.0;controls.zoomSpeed = 1.2;controls.panSpeed = 0.8;controls.noZoom = false;controls.noPan = false;controls.staticMoving = true;controls.dynamicDampingFactor = 0.3;raycaster = new THREE.Raycaster();mouse = new THREE.Vector2();document.body.appendChild(renderer.domElement);document.addEventListener('click', onDocumentMouseClick, false);creatCube();render();}function onDocumentMouseClick(event) {event.preventDefault();mouse.x = (event.clientX / window.innerWidth) * 2 - 1;mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;}function creatCube() {// 材质定义
        var yellow = [];// 右侧面
        yellow.push(new THREE.MeshLambertMaterial({color: "#F8D3A5"}));// 左侧面
        yellow.push(new THREE.MeshLambertMaterial({color: "#F8D3A5"}));// 顶侧面
        yellow.push(new THREE.MeshBasicMaterial({color: "#F8D3A5",transparent:true,opacity:0.8}));// 地侧面
        yellow.push(new THREE.MeshLambertMaterial({color: "#F8D3A5"}));// 前侧面
        yellow.push(new THREE.MeshLambertMaterial({color: "#F8D3A5"}));// 后侧面
        yellow.push(new THREE.MeshLambertMaterial({color: "#F8D3A5"}));var white = [];white.push(new THREE.MeshLambertMaterial({color: "#fff"}));white.push(new THREE.MeshLambertMaterial({color: "#fff"}));white.push(new THREE.MeshBasicMaterial({color: "#fff"}));white.push(new THREE.MeshLambertMaterial({color: "#fff"}));white.push(new THREE.MeshLambertMaterial({color: "#fff"}));white.push(new THREE.MeshLambertMaterial({color: "#fff"}));var purple = [];purple.push(new THREE.MeshLambertMaterial({color: "#E3B7F7"}));purple.push(new THREE.MeshLambertMaterial({color: "#E3B7F7"}));purple.push(new THREE.MeshBasicMaterial({color: "#E3B7F7",transparent:true,opacity:0.8}));purple.push(new THREE.MeshLambertMaterial({color: "#E3B7F7"}));purple.push(new THREE.MeshLambertMaterial({color: "#E3B7F7"}));purple.push(new THREE.MeshLambertMaterial({color: "#E3B7F7"}));var orange = [];orange.push(new THREE.MeshLambertMaterial({color: "#FFC965"}));orange.push(new THREE.MeshLambertMaterial({color: "#FFC965"}));orange.push(new THREE.MeshBasicMaterial({color: "#FFC965",transparent:true,opacity:0.5}));orange.push(new THREE.MeshLambertMaterial({color: "#FFC965"}));orange.push(new THREE.MeshLambertMaterial({color: "#FFC965"}));orange.push(new THREE.MeshLambertMaterial({color: "#FFC965"}));// 底部左侧的地板
        var cubeBottomLeftGeometry = new THREE.BoxGeometry(16,0.5,42);var cubeBottomLeftMaterial =  new THREE.MeshFaceMaterial(white);var cubeBottomLeft = new THREE.Mesh(cubeBottomLeftGeometry,cubeBottomLeftMaterial);cubeBottomLeft.position.x = -10;cubeBottomLeft.position.y = 0;cubeBottomLeft.position.z = 0;scene.add(cubeBottomLeft);// 底部右侧的地板
        var cubeBottomRightGeometry = new THREE.BoxGeometry(28,0.5,16);var cubeBottomRightMaterial =  new THREE.MeshFaceMaterial(white);var cubeBottomRight = new THREE.Mesh(cubeBottomRightGeometry,cubeBottomRightMaterial);cubeBottomRight.position.x = 12;cubeBottomRight.position.y = 0;cubeBottomRight.position.z = 13;scene.add(cubeBottomRight);// 方块1的下线1
        var line11Material = new THREE.LineBasicMaterial({color:"#F7A540"});var line11Geometry = new THREE.Geometry();line11Geometry.vertices.push(new THREE.Vector3(-17.5,lineHeight,20.5));line11Geometry.vertices.push(new THREE.Vector3(-14.5,lineHeight,20.5));var line11 = new THREE.Line(line11Geometry, line11Material);scene.add(line11);// 方块1的左线2
        var line12Material = new THREE.LineBasicMaterial({color:"#F7A540"});var line12Geometry = new THREE.Geometry();line12Geometry.vertices.push(new THREE.Vector3(-17.5,lineHeight,20.5));line12Geometry.vertices.push(new THREE.Vector3(-17.5,lineHeight,8.5));var line12 = new THREE.Line(line12Geometry, line12Material);scene.add(line12);// 方块1的右线3
        var line13Material = new THREE.LineBasicMaterial({color:"#F7A540"});var line13Geometry = new THREE.Geometry();line13Geometry.vertices.push(new THREE.Vector3(-14.5,lineHeight,8.5));line13Geometry.vertices.push(new THREE.Vector3(-14.5,lineHeight,20.5));var line13 = new THREE.Line(line13Geometry, line13Material);scene.add(line13);// 方块1的上线4
        var line14Material = new THREE.LineBasicMaterial({color:"#F7A540"});var line14Geometry = new THREE.Geometry();line14Geometry.vertices.push(new THREE.Vector3(-17.5,lineHeight,8.5));line14Geometry.vertices.push(new THREE.Vector3(-14.5,lineHeight,8.5));var line14 = new THREE.Line(line14Geometry, line14Material);scene.add(line14);// 方块2的下线1
        var line21Material = new THREE.LineBasicMaterial({color:"#B42EF7"});var line21Geometry = new THREE.Geometry();line21Geometry.vertices.push(new THREE.Vector3(-9.5,lineHeight,20.5));line21Geometry.vertices.push(new THREE.Vector3(-14.5,lineHeight,20.5));var line21 = new THREE.Line(line21Geometry, line21Material);scene.add(line21);// 方块2的右线3
        var line22Material = new THREE.LineBasicMaterial({color:"#B42EF7"});var line22Geometry = new THREE.Geometry();line22Geometry.vertices.push(new THREE.Vector3(-9.5,lineHeight,20.5));line22Geometry.vertices.push(new THREE.Vector3(-9.5,lineHeight,13.5));var line22 = new THREE.Line(line22Geometry, line22Material);scene.add(line22);// 方块2的左线2 与方块1右线重叠 取消
        /*var line23Material = new THREE.LineBasicMaterial({color:"#B42EF7"});
        var line23Geometry = new THREE.Geometry();
        line23Geometry.vertices.push(new THREE.Vector3(-13.7,lineHeight,15.3));
        line23Geometry.vertices.push(new THREE.Vector3(-13.7,lineHeight,22));
        var line23 = new THREE.Line(line23Geometry, line23Material);
        scene.add(line23);*/
        // 方块2的上线4
        var line24Material = new THREE.LineBasicMaterial({color:"#B42EF7"});var line24Geometry = new THREE.Geometry();line24Geometry.vertices.push(new THREE.Vector3(-9.5,lineHeight,13.5));line24Geometry.vertices.push(new THREE.Vector3(-14.5,lineHeight,13.5));var line24 = new THREE.Line(line24Geometry, line24Material);scene.add(line24);// 方块1
        var face1Material = new THREE.MeshFaceMaterial(yellow);var cube1Geom = new THREE.BoxGeometry(3,cubeHeight,12);var cube1 = new THREE.Mesh(cube1Geom, face1Material);cube1.position.x = -16;cube1.position.y = 1;cube1.position.z = 14.5;scene.add(cube1);// 方块2
        var face2Material = new THREE.MeshFaceMaterial(purple);var cube2Geom = new THREE.BoxGeometry(5,cubeHeight,7);var cube2 = new THREE.Mesh(cube2Geom, face2Material);cube2.position.x = -12;cube2.position.y = 1.;cube2.position.z = 17;scene.add(cube2);}function render() {controls.update();requestAnimationFrame(render);renderer.render(scene, camera);raycaster.setFromCamera(mouse, camera);var intersects = raycaster.intersectObjects(scene.children);if (intersects.length > 0) {if (INTERSECTED !== intersects[0].object) {// 判断对象是否是mesh 并且是有六个面材质的
                if (INTERSECTED && INTERSECTED instanceof THREE.Mesh && INTERSECTED.material.length === 6) {for(var i = 0; i < 6; i++){INTERSECTED.material[i].color.setHex(INTERSECTED.currentHex);}}INTERSECTED = intersects[0].object;if(INTERSECTED instanceof THREE.Mesh && INTERSECTED.material.length === 6){for(var i = 0; i < 6; i++){INTERSECTED.currentHex = INTERSECTED.material[i].color.getHex();// 如果是底面 因为底面的颜色获取后打印结果为:16777215
                        if(INTERSECTED.currentHex !== 16777215)INTERSECTED.material[i].color.set( "#FFC965" );}}}} else {if (INTERSECTED && INTERSECTED instanceof THREE.Mesh && INTERSECTED.material.length === 6) {for(var i = 0; i < 6; i++){INTERSECTED.material[i].color.set(INTERSECTED.currentHex);}}INTERSECTED = null;}}init();
</script>
</body></html>

原创作品,欢迎转载,备注出处。

ThreeJS逐步实现室内概念图的效果(渲染,交互)相关推荐

  1. 商汤提出手机端实时单目三维重建系统,实现逼真AR效果和交互

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 来源:商汤泰坦公开课 摘要 · 看点 商汤研究院和浙江大学 CAD&CG 国家重点实验室合作研 ...

  2. [html] 写一个类似刮刮卡效果的交互,即鼠标划过时显示号码

    [html] 写一个类似刮刮卡效果的交互,即鼠标划过时显示号码 <title>Document</title> <style> *{ margin:0; paddi ...

  3. H5实例教学--ThreeJs 实现粒子动画飘花效果

    粒子动画在ThreeJs可以用几种方式实现 本次样例使用Sprite类来构建粒子 官方对Sprite类的解释 Sprite A sprite is a plane that always faces ...

  4. threejs加载C4D模型及材质渲染实例

    最近在学习Threejs3D引擎使用,主要是为了实现web里面去实现3D模型的加载渲染,这样会比较直观的看到类似的效果,增加用户体验. 第一步:加载C4D模型.将模型和材质导出 二.加载主要插件模块 ...

  5. html 页面飘花,HTML5开发实例-ThreeJs实现粒子动画飘花效果代码分享

    粒子动画在ThreeJs可以用几种方式实现 本次样例使用Sprite类来构建粒子 大概意思:这个类创建的对象是一个始终面向相机的平面,可以把贴图应用在上面,Sprite对象无法添加阴影 ,所以cast ...

  6. threejs学习笔记:CSS2DObject 2d文字渲染

    import {CSS2DRenderer,CSS2DObject } from "three/examples/jsm/renderers/CSS2DRenderer.js";/ ...

  7. Threejs贴图为了更好的渲染(门)

    渲染结果图 门模型使用标准网格材质(MeshStandardMaterial),一种基于物理的渲染.使用PBR方式渲染. 思路: (1) 建立立方体模 (2)设置基本颜色.map属性添加颜色贴图 co ...

  8. 小白IT:炫彩的网页是怎么做的,什么是前端???Python前端基础CSS 效果渲染

    文章目录 一 认识HTML 1.web服务的本质 2.HTML是什么? 3.html文档格式 4.html标签格式 标签的语法 几个重要的属性 HTML注释 二.常用标签 1.!DOCTYPE标签 2 ...

  9. 高效真实的云效果渲染算法

    Realistic and Fast Cloud Rendering NinianeWang MicrosoftCorporation(nowatGoogleInc.) niniane@ofb.net ...

最新文章

  1. 如何使用深度学习训练聊天机器人
  2. Linux高级文本处理之gawk语法和基础命令(一)
  3. Calibre-免费开源的“一站式”的电子书管理阅读格式转换软件
  4. ssl1203-书的复制【dp】
  5. 学前儿童语言教育模拟试卷c卷,学前儿童语言教育模拟试卷参考答案.doc
  6. 游戏筑基之游戏菜单制作(C语言)
  7. FirstApp,iphone开发学习总结3,UIButton简单的操作
  8. 判断在ios系统中打开微信浏览器
  9. 航拍地形图转换成地形图_无人机航测生成地形图技术流程(Pix4D+ArcGIS+CASS)...
  10. 海豚蓝牙ASIO驱动程序使用说明
  11. 关于django的prefetch_related优化查询问题
  12. 混淆矩阵 Confusion Matrix
  13. c语言--余数正负判断,printf函数占位符
  14. matplotlib绘制三维图
  15. 2023年新自采集壁纸网页源码+简约大气
  16. Ubuntu16.04+ROS kinetic +Basler_camera环境配置以及相机标定
  17. 大数据之当传统产业遭遇互联网
  18. php下对中国内地身份证进行验证
  19. java 多线程 map_多线程Map并发读后修改
  20. ie visio 打开_Visio viewer 不能从IE打开vsd文件(转) | 学步园

热门文章

  1. DIV布局——人电影网站(5页) HTML+CSS+JavaScript 学生DW网页设计作业成品
  2. oracle11如何生成aw r,(Oracle)自定义调用AWRamp;ADDM
  3. 企业安全丨旧瓶新酒之ngx_lua fail2ban实现主动诱捕
  4. 财务报表分析:理论框架方法与案例
  5. 非侵入式负荷matlab程序,非侵入式负荷分解之BLUED数据集
  6. python英文字符串单词个数统计_Python实现统计英文单词个数及字符串分割代码
  7. 【好物推荐】LICEcap – 灵活好用,GIF 屏幕录制工具
  8. Android6.0 Sensor架构和问题分析
  9. python主要是干什么用的,python到底是干什么的
  10. 等保2.0 信息安全及等保标准体系概述