ThreeApplication.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. /* Copyright© 2000 - 2021 SuperMap Software Co.Ltd. All rights reserved.*/
  2. var ThreeApplication = {
  3. data: null,
  4. buildingMesh: null,
  5. buildingRoofMesh: null,
  6. terrainMesh: null,
  7. rooms: [],
  8. buildingView: null,
  9. modelOpacity: 0.4,
  10. register: function (renderer, scene, camera) {
  11. this.renderer = renderer;
  12. this.scene = scene;
  13. this.camera = camera;
  14. return this;
  15. },
  16. //threeLayer主要用来设置模型在地图上位置
  17. setTargetLayer: function (threeLayer) {
  18. this.threeLayer = threeLayer;
  19. return this;
  20. },
  21. setPosition: function (position) {
  22. this.position = position;
  23. return this;
  24. },
  25. start: function () {
  26. //程序入口开始
  27. SceneBuilder.preLoader(ThreeApplication).load();
  28. }
  29. };
  30. var SceneBuilder = {
  31. //预加载模型数据
  32. preLoader: function (app) {
  33. var manager, slowLoopIntervalId, is3DDataLoaded = false;
  34. function loadData(onComplete) {
  35. var url = '../data/ThreeBuildingData.json';
  36. $.ajax({
  37. dataType: 'json',
  38. url: url,
  39. success: function (result) {
  40. app.data = new DataProcessor(result);
  41. onComplete();
  42. },
  43. error: function (jqXHR, status, errorThrown) {
  44. console.log(status, errorThrown);
  45. }
  46. });
  47. }
  48. function loadResources() {
  49. manager = new THREE.LoadingManager();
  50. manager.onProgress = function (item, loaded, total) {
  51. };
  52. manager.onLoad = function () {
  53. is3DDataLoaded = true;
  54. };
  55. loadBuildingModel();
  56. loadRooms();
  57. }
  58. function loadBuildingModel() {
  59. var loader = new THREE.LegacyJSONLoader(manager);
  60. // loader.setResourcePath()('./js/obj/building/maps/');
  61. loader.load('./js/obj/building/building.js', function (geometry, materials) {
  62. var material = new THREE.MultiMaterial(materials);
  63. for (var i = 0; i < materials.length; i++) {
  64. materials[i].transparent = true;
  65. materials[i].vertexColors = THREE.FaceColors;
  66. }
  67. scaleGeometry(geometry);
  68. for (var i = 0; i < geometry.faces.length; i++) {
  69. geometry.faces[i].color = new THREE.Color(0x08acff);
  70. geometry.colorsNeedUpdate = true;
  71. }
  72. app.buildingMesh = new THREE.Mesh(geometry, material);
  73. app.buildingMesh.geometry.computeBoundingSphere();
  74. }
  75. );
  76. var loader = new THREE.LegacyJSONLoader(manager);
  77. loader.load('./js/obj/building/building-roof.js', function (geometry, materials) {
  78. var material = new THREE.MultiMaterial(materials);
  79. for (var i = 0; i < materials.length; i++) {
  80. materials[i] = new THREE.MeshPhongMaterial({
  81. color: 0xffffff,
  82. transparent: true,
  83. polygonOffset: true,
  84. polygonOffsetFactor: 1,
  85. polygonOffsetUnits: 1
  86. });
  87. }
  88. scaleGeometry(geometry);
  89. app.buildingRoofMesh = new THREE.Mesh(geometry, material);
  90. });
  91. }
  92. function loadRooms() {
  93. var roomData = app.data.locations;
  94. for (var i = 0; i < roomData.length; i++) {
  95. loadRoom(roomData[i]);
  96. }
  97. function loadRoom(data) {
  98. var name = data.name,
  99. slug = data.slug,
  100. loader = new THREE.LegacyJSONLoader(manager);
  101. loader.load("./js/" + data.objRoom, function (geometry, materials) {
  102. var material = new THREE.MeshPhongMaterial({
  103. color: 0xffffff
  104. });
  105. scaleGeometry(geometry);
  106. var mesh = new THREE.Mesh(geometry, material);
  107. var room = new InteractiveModel(mesh, name, slug);
  108. room.setEmissiveDefault(0x333333);
  109. room.unmark();
  110. app.rooms.push(room);
  111. });
  112. }
  113. }
  114. function scaleGeometry(geometry) {
  115. var transform = new THREE.Matrix4(),
  116. scale = new THREE.Matrix4(),
  117. translate = new THREE.Matrix4();
  118. scale.makeScale(0.2, 0.2, 0.2);
  119. translate.makeTranslation(32.57, 0, 30);
  120. transform.multiplyMatrices(scale, translate);
  121. geometry.applyMatrix(transform);
  122. }
  123. function waitForLoading() {
  124. slowLoopIntervalId = setInterval(function () {
  125. if (is3DDataLoaded) {
  126. is3DDataLoaded = false;
  127. SceneBuilder.viewBuilder(app).build();
  128. clearInterval(slowLoopIntervalId);
  129. }
  130. }, 500);
  131. }
  132. this.load = function () {
  133. loadData(function () {
  134. loadResources();
  135. });
  136. waitForLoading();
  137. };
  138. return this;
  139. },
  140. //构建模型场景
  141. viewBuilder: function (app) {
  142. this.build = function () {
  143. app.buildingView = app.buildingView || new BuildingView(app);
  144. var buildingView = app.buildingView;
  145. buildingView.setOpacity(app.modelOpacity);
  146. };
  147. return this;
  148. }
  149. };
  150. //数据处理器
  151. function DataProcessor(data) {
  152. var locationBySlug = {},
  153. witnessBySlug = {},
  154. locations = data.locations,
  155. witnesses = data.witnesses,
  156. location,
  157. witness,
  158. i;
  159. for (i = 0; i < locations.length; i++) {
  160. location = locations[i];
  161. locationBySlug[location.slug] = location;
  162. }
  163. for (i = 0; i < witnesses.length; i++) {
  164. witness = witnesses[i];
  165. witnessBySlug[witness.slug] = witness;
  166. }
  167. return {
  168. locations: locations,
  169. witnesses: witnesses,
  170. locationBySlug: locationBySlug,
  171. witnessBySlug: witnessBySlug
  172. }
  173. }
  174. //可交互对象(建筑和房间)
  175. function InteractiveModel(mesh, name, slug, labelOffset) {
  176. var object3D = null,
  177. center = null;
  178. var scale = 1;
  179. var emissiveDefault = 0x000000,
  180. emissiveHighlight = 0xff0000,
  181. isDoubleSide = true,
  182. opacityDefault = 1.0,
  183. opacityHighLight = 1.0;
  184. build3D();
  185. calculateCenter();
  186. function build3D() {
  187. object3D = mesh;
  188. object3D.name = slug;
  189. opacityDefault = object3D.material.opacity;
  190. opacityHighLight = object3D.material.opacity;
  191. if (object3D.material.length > 1) {
  192. for (var i = 0; i < object3D.material.length; i++) {
  193. setMaterial(object3D.material[i]);
  194. }
  195. } else {
  196. setMaterial(object3D.material);
  197. }
  198. function setMaterial(material) {
  199. material.side = THREE.DoubleSide;
  200. material.emissive.setHex(emissiveDefault);
  201. material.polygonOffset = true;
  202. material.polygonOffsetFactor = -2;
  203. material.polygonOffsetUnits = 1;
  204. material.needsUpdate = true;
  205. }
  206. }
  207. function calculateCenter() {
  208. mesh.geometry.computeBoundingBox();
  209. center = new THREE.Vector3();
  210. center.addVectors(
  211. mesh.geometry.boundingBox.min,
  212. mesh.geometry.boundingBox.max
  213. );
  214. center.divideScalar(2);
  215. }
  216. function getName() {
  217. return name;
  218. }
  219. function getSlug() {
  220. return slug;
  221. }
  222. function getCenter() {
  223. calculateCenter();
  224. return center;
  225. }
  226. function mark() {
  227. object3D.material.emissive.setHex(emissiveHighlight);
  228. object3D.material.opacity = opacityHighLight;
  229. object3D.material.needsUpdate = true;
  230. }
  231. function unmark() {
  232. object3D.material.emissive.setHex(emissiveDefault);
  233. object3D.material.opacity = opacityDefault;
  234. object3D.material.needsUpdate = true;
  235. }
  236. function setEmissiveDefault(hex) {
  237. emissiveDefault = hex;
  238. }
  239. function setDoubleSide(bool) {
  240. isDoubleSide = bool;
  241. object3D.material.side = (bool) ? THREE.DoubleSide : THREE.FrontSide;
  242. object3D.material.needsUpdate = true;
  243. }
  244. function setHighlightOpacity(val) {
  245. opacityHighLight = val;
  246. }
  247. return {
  248. object3D: object3D,
  249. getCenter: getCenter,
  250. getName: getName,
  251. mark: mark,
  252. unmark: unmark,
  253. scale: scale,
  254. setEmissiveDefault: setEmissiveDefault,
  255. setDoubleSide: setDoubleSide,
  256. setHighlightOpacity: setHighlightOpacity
  257. }
  258. }
  259. //添加three场景,添加模型
  260. function BuildingView(app) {
  261. var renderer, camera, scene,
  262. buildingMesh,
  263. roofMesh,
  264. roofEdgeHelper,
  265. rooms, roomsGroup,
  266. raycaster;
  267. init();
  268. function init() {
  269. renderer = app.renderer;
  270. camera = app.camera;
  271. scene = app.scene;
  272. buildingMesh = app.buildingMesh;
  273. roofMesh = app.buildingRoofMesh;
  274. rooms = app.rooms;
  275. initScene();
  276. addObjects();
  277. }
  278. function initScene() {
  279. raycaster = app.raycaster = new THREE.Raycaster();
  280. }
  281. function addObjects() {
  282. // building
  283. correctionObject3D(buildingMesh);
  284. scene.add(buildingMesh);
  285. // line helper (building)
  286. var edgeHelper = new THREE.EdgesHelper(buildingMesh, 0x02f7f8, 1);
  287. edgeHelper.material.linewidth = 10;
  288. correctionObject3D(edgeHelper);
  289. scene.add(edgeHelper);
  290. // roof
  291. var materials = roofMesh.material.materials;
  292. for (var i = 0; i < materials.length; i++) {
  293. materials[i].transparent = true;
  294. }
  295. roofMesh.renderOrder = 1;
  296. correctionObject3D(roofMesh);
  297. scene.add(roofMesh);
  298. // line helper (roof)
  299. roofEdgeHelper = new THREE.EdgesHelper(roofMesh, 0x02f7f8, 20);
  300. roofEdgeHelper.material.transparent = true;
  301. roofEdgeHelper.material.opacity = 0.2;
  302. roofEdgeHelper.material.linewidth = 1;
  303. roofEdgeHelper.renderOrder = 1;
  304. correctionObject3D(roofEdgeHelper);
  305. scene.add(roofEdgeHelper);
  306. // rooms
  307. roomsGroup = new THREE.Object3D();
  308. for (var i = 0; i < rooms.length; i++) {
  309. roomsGroup.add(rooms[i].object3D);
  310. }
  311. correctionObject3D(roomsGroup);
  312. scene.add(roomsGroup);
  313. }
  314. function correctionObject3D(obj3D) {
  315. obj3D.rotation.x = -Math.PI / 2;
  316. obj3D.rotation.y = Math.PI / 7;
  317. obj3D.scale.set(16, 16, 16);
  318. app.threeLayer.setPosition(obj3D, app.position);
  319. }
  320. this.setOpacity = function (val) {
  321. var materials = buildingMesh.material.materials;
  322. for (var i = 0; i < materials.length; i++) {
  323. materials[i].opacity = 0.1 + val * (1 - 0.15);
  324. materials[i].needsUpdate = true;
  325. }
  326. // roof
  327. materials = roofMesh.material.materials;
  328. for (var i = 0; i < materials.length; i++) {
  329. materials[i].opacity = val * val * 1.1;
  330. materials[i].needsUpdate = true;
  331. }
  332. roofEdgeHelper.material.opacity = val * val * 0.2;
  333. roofEdgeHelper.material.needsUpdate = true;
  334. };
  335. }