Object3D.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862
  1. import {
  2. Quaternion
  3. } from '../math/Quaternion.js';
  4. import {
  5. Vector3
  6. } from '../math/Vector3.js';
  7. import {
  8. Matrix4
  9. } from '../math/Matrix4.js';
  10. import {
  11. EventDispatcher
  12. } from './EventDispatcher.js';
  13. import {
  14. Euler
  15. } from '../math/Euler.js';
  16. import {
  17. Layers
  18. } from './Layers.js';
  19. import {
  20. Matrix3
  21. } from '../math/Matrix3.js';
  22. import {
  23. _Math
  24. } from '../math/Math.js';
  25. /**
  26. * @author mrdoob / http://mrdoob.com/
  27. * @author mikael emtinger / http://gomo.se/
  28. * @author alteredq / http://alteredqualia.com/
  29. * @author WestLangley / http://github.com/WestLangley
  30. * @author elephantatwork / www.elephantatwork.ch
  31. */
  32. //局部的全局变量
  33. var object3DId = 0;
  34. function Object3D() {
  35. // 每次执行该构造函数创建对象的时候,都会给该对象设置一个id属性,并且他一个全局变量加1赋值给id属性
  36. Object.defineProperty(this, 'id', {
  37. value: object3DId++
  38. });
  39. // generate :生成
  40. this.uuid = _Math.generateUUID();
  41. this.name = '';
  42. this.type = 'Object3D';
  43. this.parent = null;
  44. this.children = [];
  45. this.up = Object3D.DefaultUp.clone();
  46. var position = new Vector3();
  47. var rotation = new Euler();
  48. var quaternion = new Quaternion();
  49. var scale = new Vector3(1, 1, 1);
  50. function onRotationChange() {
  51. quaternion.setFromEuler(rotation, false);
  52. }
  53. function onQuaternionChange() {
  54. rotation.setFromQuaternion(quaternion, undefined, false);
  55. }
  56. rotation.onChange(onRotationChange);
  57. quaternion.onChange(onQuaternionChange);
  58. Object.defineProperties(this, {
  59. position: {
  60. enumerable: true,
  61. value: position
  62. },
  63. rotation: {
  64. enumerable: true,
  65. value: rotation
  66. },
  67. quaternion: {
  68. enumerable: true,
  69. value: quaternion
  70. },
  71. scale: {
  72. enumerable: true,
  73. value: scale
  74. },
  75. modelViewMatrix: {
  76. value: new Matrix4()
  77. },
  78. normalMatrix: {
  79. value: new Matrix3()
  80. }
  81. });
  82. this.matrix = new Matrix4();
  83. this.matrixWorld = new Matrix4();
  84. this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate;
  85. this.matrixWorldNeedsUpdate = false;
  86. // 创建obj3对象的时候,已经默认创建Layers,并且带对象创建的时候默认相当于初始化执行set(0)
  87. this.layers = new Layers();
  88. this.visible = true;
  89. this.castShadow = false;
  90. this.receiveShadow = false;
  91. this.frustumCulled = true;
  92. this.renderOrder = 0;
  93. this.userData = {};
  94. }
  95. Object3D.DefaultUp = new Vector3(0, 1, 0);
  96. Object3D.DefaultMatrixAutoUpdate = true;
  97. Object3D.prototype = Object.assign(Object.create(EventDispatcher.prototype), {
  98. constructor: Object3D,
  99. isObject3D: true,
  100. onBeforeRender: function() {},
  101. onAfterRender: function() {},
  102. applyMatrix: function(matrix) {
  103. this.matrix.multiplyMatrices(matrix, this.matrix);
  104. this.matrix.decompose(this.position, this.quaternion, this.scale);
  105. },
  106. applyQuaternion: function(q) {
  107. this.quaternion.premultiply(q);
  108. return this;
  109. },
  110. setRotationFromAxisAngle: function(axis, angle) {
  111. // assumes axis is normalized
  112. this.quaternion.setFromAxisAngle(axis, angle);
  113. },
  114. setRotationFromEuler: function(euler) {
  115. this.quaternion.setFromEuler(euler, true);
  116. },
  117. setRotationFromMatrix: function(m) {
  118. // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
  119. this.quaternion.setFromRotationMatrix(m);
  120. },
  121. setRotationFromQuaternion: function(q) {
  122. // assumes q is normalized
  123. this.quaternion.copy(q);
  124. },
  125. rotateOnAxis: function() {
  126. // rotate object on axis in object space
  127. // axis is assumed to be normalized
  128. var q1 = new Quaternion();
  129. return function rotateOnAxis(axis, angle) {
  130. q1.setFromAxisAngle(axis, angle);
  131. this.quaternion.multiply(q1);
  132. return this;
  133. };
  134. }(),
  135. rotateOnWorldAxis: function() {
  136. // rotate object on axis in world space
  137. // axis is assumed to be normalized
  138. // method assumes no rotated parent
  139. var q1 = new Quaternion();
  140. return function rotateOnWorldAxis(axis, angle) {
  141. q1.setFromAxisAngle(axis, angle);
  142. this.quaternion.premultiply(q1);
  143. return this;
  144. };
  145. }(),
  146. rotateX: function() {
  147. var v1 = new Vector3(1, 0, 0);
  148. return function rotateX(angle) {
  149. return this.rotateOnAxis(v1, angle);
  150. };
  151. }(),
  152. rotateY: function() {
  153. var v1 = new Vector3(0, 1, 0);
  154. return function rotateY(angle) {
  155. return this.rotateOnAxis(v1, angle);
  156. };
  157. }(),
  158. rotateZ: function() {
  159. var v1 = new Vector3(0, 0, 1);
  160. return function rotateZ(angle) {
  161. return this.rotateOnAxis(v1, angle);
  162. };
  163. }(),
  164. translateOnAxis: function() {
  165. // translate object by distance along axis in object space
  166. // axis is assumed to be normalized
  167. var v1 = new Vector3();
  168. return function translateOnAxis(axis, distance) {
  169. v1.copy(axis).applyQuaternion(this.quaternion);
  170. this.position.add(v1.multiplyScalar(distance));
  171. return this;
  172. };
  173. }(),
  174. translateX: function() {
  175. var v1 = new Vector3(1, 0, 0);
  176. return function translateX(distance) {
  177. return this.translateOnAxis(v1, distance);
  178. };
  179. }(),
  180. translateY: function() {
  181. var v1 = new Vector3(0, 1, 0);
  182. return function translateY(distance) {
  183. return this.translateOnAxis(v1, distance);
  184. };
  185. }(),
  186. translateZ: function() {
  187. var v1 = new Vector3(0, 0, 1);
  188. return function translateZ(distance) {
  189. return this.translateOnAxis(v1, distance);
  190. };
  191. }(),
  192. localToWorld: function(vector) {
  193. return vector.applyMatrix4(this.matrixWorld);
  194. },
  195. worldToLocal: function() {
  196. var m1 = new Matrix4();
  197. return function worldToLocal(vector) {
  198. return vector.applyMatrix4(m1.getInverse(this.matrixWorld));
  199. };
  200. }(),
  201. lookAt: function() {
  202. // This method does not support objects with rotated and/or translated parent(s)
  203. var m1 = new Matrix4();
  204. var vector = new Vector3();
  205. // 参数可以是一个向量,也可以是向量的三个分量
  206. return function lookAt(x, y, z) {
  207. // 判断x是不是向量v3,如果是,说明程序员使用的是三维向量
  208. if (x.isVector3) {
  209. vector.copy(x);
  210. } else {
  211. vector.set(x, y, z);
  212. }
  213. if (this.isCamera) {
  214. m1.lookAt(this.position, vector, this.up);
  215. } else {
  216. m1.lookAt(vector, this.position, this.up);
  217. }
  218. this.quaternion.setFromRotationMatrix(m1);
  219. };
  220. }(),
  221. add: function(object) {
  222. if (arguments.length > 1) {
  223. for (var i = 0; i < arguments.length; i++) {
  224. this.add(arguments[i]);
  225. }
  226. return this;
  227. }
  228. if (object === this) {
  229. console.error("THREE.Object3D.add: object can't be added as a child of itself.", object);
  230. return this;
  231. }
  232. if ((object && object.isObject3D)) {
  233. if (object.parent !== null) {
  234. object.parent.remove(object);
  235. }
  236. object.parent = this;
  237. object.dispatchEvent({
  238. type: 'added'
  239. });
  240. this.children.push(object);
  241. } else {
  242. console.error("THREE.Object3D.add: object not an instance of THREE.Object3D.", object);
  243. }
  244. return this;
  245. },
  246. // 参数:.remove ( object : Object3D, ... )
  247. // 将对象作为对象的子对象移除。可以删除任意数量的对象。
  248. remove: function(object) {
  249. // arguments对象表示所有参数组成的数组
  250. if (arguments.length > 1) {
  251. // 循环遍历 每一个参数对象执行remove删除方法
  252. for (var i = 0; i < arguments.length; i++) {
  253. this.remove(arguments[i]);
  254. }
  255. return this;
  256. }
  257. // 获得object在children数组中的索引
  258. var index = this.children.indexOf(object);
  259. if (index !== -1) {
  260. // 设置object的父对象属性parent为null空
  261. object.parent = null;
  262. object.dispatchEvent({
  263. type: 'removed'
  264. });
  265. // 删除children数组中索引是index的元素
  266. this.children.splice(index, 1);
  267. }
  268. return this;
  269. },
  270. // 通过id获得对象
  271. getObjectById: function(id) {
  272. // 浏览器通过id选择的生层原理
  273. return this.getObjectByProperty('id', id);
  274. },
  275. getObjectByName: function(name) {
  276. return this.getObjectByProperty('name', name);
  277. },
  278. getObjectByProperty: function(name, value) {
  279. if (this[name] === value) return this;
  280. for (var i = 0, l = this.children.length; i < l; i++) {
  281. var child = this.children[i];
  282. var object = child.getObjectByProperty(name, value);
  283. if (object !== undefined) {
  284. return object;
  285. }
  286. }
  287. return undefined;
  288. },
  289. getWorldPosition: function(target) {
  290. if (target === undefined) {
  291. console.warn('THREE.Object3D: .getWorldPosition() target is now required');
  292. target = new Vector3();
  293. }
  294. this.updateMatrixWorld(true);
  295. return target.setFromMatrixPosition(this.matrixWorld);
  296. },
  297. getWorldQuaternion: function() {
  298. var position = new Vector3();
  299. var scale = new Vector3();
  300. return function getWorldQuaternion(target) {
  301. if (target === undefined) {
  302. console.warn('THREE.Object3D: .getWorldQuaternion() target is now required');
  303. target = new Quaternion();
  304. }
  305. this.updateMatrixWorld(true);
  306. this.matrixWorld.decompose(position, target, scale);
  307. return target;
  308. };
  309. }(),
  310. getWorldScale: function() {
  311. var position = new Vector3();
  312. var quaternion = new Quaternion();
  313. return function getWorldScale(target) {
  314. if (target === undefined) {
  315. console.warn('THREE.Object3D: .getWorldScale() target is now required');
  316. target = new Vector3();
  317. }
  318. this.updateMatrixWorld(true);
  319. this.matrixWorld.decompose(position, quaternion, target);
  320. return target;
  321. };
  322. }(),
  323. getWorldDirection: function() {
  324. var quaternion = new Quaternion();
  325. return function getWorldDirection(target) {
  326. if (target === undefined) {
  327. console.warn('THREE.Object3D: .getWorldDirection() target is now required');
  328. target = new Vector3();
  329. }
  330. this.getWorldQuaternion(quaternion);
  331. return target.set(0, 0, 1).applyQuaternion(quaternion);
  332. };
  333. }(),
  334. raycast: function() {},
  335. traverse: function(callback) {
  336. callback(this);
  337. var children = this.children;
  338. for (var i = 0, l = children.length; i < l; i++) {
  339. children[i].traverse(callback);
  340. }
  341. },
  342. traverseVisible: function(callback) {
  343. if (this.visible === false) return;
  344. callback(this);
  345. var children = this.children;
  346. for (var i = 0, l = children.length; i < l; i++) {
  347. children[i].traverseVisible(callback);
  348. }
  349. },
  350. traverseAncestors: function(callback) {
  351. var parent = this.parent;
  352. if (parent !== null) {
  353. callback(parent);
  354. parent.traverseAncestors(callback);
  355. }
  356. },
  357. updateMatrix: function() {
  358. this.matrix.compose(this.position, this.quaternion, this.scale);
  359. this.matrixWorldNeedsUpdate = true;
  360. },
  361. updateMatrixWorld: function(force) {
  362. if (this.matrixAutoUpdate) this.updateMatrix();
  363. if (this.matrixWorldNeedsUpdate || force) {
  364. if (this.parent === null) {
  365. this.matrixWorld.copy(this.matrix);
  366. } else {
  367. this.matrixWorld.multiplyMatrices(this.parent.matrixWorld, this.matrix);
  368. }
  369. this.matrixWorldNeedsUpdate = false;
  370. force = true;
  371. }
  372. // update children
  373. var children = this.children;
  374. for (var i = 0, l = children.length; i < l; i++) {
  375. children[i].updateMatrixWorld(force);
  376. }
  377. },
  378. toJSON: function(meta) {
  379. // meta is a string when called from JSON.stringify
  380. var isRootObject = (meta === undefined || typeof meta === 'string');
  381. var output = {};
  382. // meta is a hash used to collect geometries, materials.
  383. // not providing it implies that this is the root object
  384. // being serialized.
  385. if (isRootObject) {
  386. // initialize meta obj
  387. meta = {
  388. geometries: {},
  389. materials: {},
  390. textures: {},
  391. images: {},
  392. shapes: {}
  393. };
  394. output.metadata = {
  395. version: 4.5,
  396. type: 'Object',
  397. generator: 'Object3D.toJSON'
  398. };
  399. }
  400. // standard Object3D serialization
  401. var object = {};
  402. object.uuid = this.uuid;
  403. object.type = this.type;
  404. if (this.name !== '') object.name = this.name;
  405. if (this.castShadow === true) object.castShadow = true;
  406. if (this.receiveShadow === true) object.receiveShadow = true;
  407. if (this.visible === false) object.visible = false;
  408. if (this.frustumCulled === false) object.frustumCulled = false;
  409. if (this.renderOrder !== 0) object.renderOrder = this.renderOrder;
  410. if (JSON.stringify(this.userData) !== '{}') object.userData = this.userData;
  411. object.matrix = this.matrix.toArray();
  412. //
  413. function serialize(library, element) {
  414. if (library[element.uuid] === undefined) {
  415. library[element.uuid] = element.toJSON(meta);
  416. }
  417. return element.uuid;
  418. }
  419. if (this.geometry !== undefined) {
  420. object.geometry = serialize(meta.geometries, this.geometry);
  421. var parameters = this.geometry.parameters;
  422. if (parameters !== undefined && parameters.shapes !== undefined) {
  423. var shapes = parameters.shapes;
  424. if (Array.isArray(shapes)) {
  425. for (var i = 0, l = shapes.length; i < l; i++) {
  426. var shape = shapes[i];
  427. serialize(meta.shapes, shape);
  428. }
  429. } else {
  430. serialize(meta.shapes, shapes);
  431. }
  432. }
  433. }
  434. if (this.material !== undefined) {
  435. if (Array.isArray(this.material)) {
  436. var uuids = [];
  437. for (var i = 0, l = this.material.length; i < l; i++) {
  438. uuids.push(serialize(meta.materials, this.material[i]));
  439. }
  440. object.material = uuids;
  441. } else {
  442. object.material = serialize(meta.materials, this.material);
  443. }
  444. }
  445. //
  446. if (this.children.length > 0) {
  447. object.children = [];
  448. for (var i = 0; i < this.children.length; i++) {
  449. object.children.push(this.children[i].toJSON(meta).object);
  450. }
  451. }
  452. if (isRootObject) {
  453. var geometries = extractFromCache(meta.geometries);
  454. var materials = extractFromCache(meta.materials);
  455. var textures = extractFromCache(meta.textures);
  456. var images = extractFromCache(meta.images);
  457. var shapes = extractFromCache(meta.shapes);
  458. if (geometries.length > 0) output.geometries = geometries;
  459. if (materials.length > 0) output.materials = materials;
  460. if (textures.length > 0) output.textures = textures;
  461. if (images.length > 0) output.images = images;
  462. if (shapes.length > 0) output.shapes = shapes;
  463. }
  464. output.object = object;
  465. return output;
  466. // extract data from the cache hash
  467. // remove metadata on each item
  468. // and return as array
  469. function extractFromCache(cache) {
  470. var values = [];
  471. for (var key in cache) {
  472. var data = cache[key];
  473. delete data.metadata;
  474. values.push(data);
  475. }
  476. return values;
  477. }
  478. },
  479. clone: function(recursive) {
  480. return new this.constructor().copy(this, recursive);
  481. },
  482. copy: function(source, recursive) {
  483. if (recursive === undefined) recursive = true;
  484. this.name = source.name;
  485. this.up.copy(source.up);
  486. this.position.copy(source.position);
  487. this.quaternion.copy(source.quaternion);
  488. this.scale.copy(source.scale);
  489. this.matrix.copy(source.matrix);
  490. this.matrixWorld.copy(source.matrixWorld);
  491. this.matrixAutoUpdate = source.matrixAutoUpdate;
  492. this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;
  493. this.layers.mask = source.layers.mask;
  494. this.visible = source.visible;
  495. this.castShadow = source.castShadow;
  496. this.receiveShadow = source.receiveShadow;
  497. this.frustumCulled = source.frustumCulled;
  498. this.renderOrder = source.renderOrder;
  499. this.userData = JSON.parse(JSON.stringify(source.userData));
  500. if (recursive === true) {
  501. for (var i = 0; i < source.children.length; i++) {
  502. var child = source.children[i];
  503. this.add(child.clone());
  504. }
  505. }
  506. return this;
  507. }
  508. });
  509. export {
  510. Object3D
  511. };