attributes.tests.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. import { ObjectLoader } from '../../../src/loaders/ObjectLoader.js';
  2. export default QUnit.module( 'JSON4 Format', () => {
  3. QUnit.module( 'Attributes', () => {
  4. QUnit.test( 'Float32BufferAttribute', ( assert ) => {
  5. const json = {
  6. metadata: { version: 4.7, type: 'Object', generator: 'Object3D.toJSON' },
  7. geometries: [ {
  8. uuid: 'geom-1',
  9. type: 'BufferGeometry',
  10. data: {
  11. attributes: {
  12. position: {
  13. itemSize: 3,
  14. type: 'Float32Array',
  15. array: [ 0, 0, 0, 1, 0, 0, 0, 1, 0 ],
  16. normalized: false
  17. }
  18. }
  19. }
  20. } ],
  21. materials: [ {
  22. uuid: 'mat-1',
  23. type: 'MeshBasicMaterial',
  24. color: 16711680
  25. } ],
  26. object: {
  27. uuid: 'mesh-1',
  28. type: 'Mesh',
  29. geometry: 'geom-1',
  30. material: 'mat-1',
  31. matrix: [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ],
  32. layers: 1
  33. }
  34. };
  35. const loader = new ObjectLoader();
  36. const mesh = loader.parse( json );
  37. const attr = mesh.geometry.attributes.position;
  38. assert.ok( attr.array instanceof Float32Array, 'Array is Float32Array' );
  39. assert.strictEqual( attr.itemSize, 3, 'ItemSize is 3' );
  40. assert.strictEqual( attr.count, 3, 'Count is 3' );
  41. } );
  42. QUnit.test( 'Int8BufferAttribute', ( assert ) => {
  43. const json = {
  44. metadata: { version: 4.7, type: 'Object', generator: 'Object3D.toJSON' },
  45. geometries: [ {
  46. uuid: 'geom-1',
  47. type: 'BufferGeometry',
  48. data: {
  49. attributes: {
  50. position: {
  51. itemSize: 3,
  52. type: 'Float32Array',
  53. array: [ 0, 0, 0, 1, 0, 0, 0, 1, 0 ],
  54. normalized: false
  55. },
  56. custom: {
  57. itemSize: 1,
  58. type: 'Int8Array',
  59. array: [ - 128, 0, 127 ],
  60. normalized: false
  61. }
  62. }
  63. }
  64. } ],
  65. materials: [ {
  66. uuid: 'mat-1',
  67. type: 'MeshBasicMaterial',
  68. color: 16711680
  69. } ],
  70. object: {
  71. uuid: 'mesh-1',
  72. type: 'Mesh',
  73. geometry: 'geom-1',
  74. material: 'mat-1',
  75. matrix: [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ],
  76. layers: 1
  77. }
  78. };
  79. const loader = new ObjectLoader();
  80. const mesh = loader.parse( json );
  81. const attr = mesh.geometry.attributes.custom;
  82. assert.ok( attr.array instanceof Int8Array, 'Array is Int8Array' );
  83. assert.strictEqual( attr.array[ 0 ], - 128, 'First value is -128' );
  84. assert.strictEqual( attr.array[ 2 ], 127, 'Last value is 127' );
  85. } );
  86. QUnit.test( 'Int16BufferAttribute', ( assert ) => {
  87. const json = {
  88. metadata: { version: 4.7, type: 'Object', generator: 'Object3D.toJSON' },
  89. geometries: [ {
  90. uuid: 'geom-1',
  91. type: 'BufferGeometry',
  92. data: {
  93. attributes: {
  94. position: {
  95. itemSize: 3,
  96. type: 'Float32Array',
  97. array: [ 0, 0, 0, 1, 0, 0, 0, 1, 0 ],
  98. normalized: false
  99. },
  100. custom: {
  101. itemSize: 1,
  102. type: 'Int16Array',
  103. array: [ - 32768, 0, 32767 ],
  104. normalized: false
  105. }
  106. }
  107. }
  108. } ],
  109. materials: [ {
  110. uuid: 'mat-1',
  111. type: 'MeshBasicMaterial',
  112. color: 16711680
  113. } ],
  114. object: {
  115. uuid: 'mesh-1',
  116. type: 'Mesh',
  117. geometry: 'geom-1',
  118. material: 'mat-1',
  119. matrix: [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ],
  120. layers: 1
  121. }
  122. };
  123. const loader = new ObjectLoader();
  124. const mesh = loader.parse( json );
  125. const attr = mesh.geometry.attributes.custom;
  126. assert.ok( attr.array instanceof Int16Array, 'Array is Int16Array' );
  127. assert.strictEqual( attr.array[ 0 ], - 32768, 'First value is -32768' );
  128. assert.strictEqual( attr.array[ 2 ], 32767, 'Last value is 32767' );
  129. } );
  130. QUnit.test( 'Int32BufferAttribute', ( assert ) => {
  131. const json = {
  132. metadata: { version: 4.7, type: 'Object', generator: 'Object3D.toJSON' },
  133. geometries: [ {
  134. uuid: 'geom-1',
  135. type: 'BufferGeometry',
  136. data: {
  137. attributes: {
  138. position: {
  139. itemSize: 3,
  140. type: 'Float32Array',
  141. array: [ 0, 0, 0, 1, 0, 0, 0, 1, 0 ],
  142. normalized: false
  143. },
  144. custom: {
  145. itemSize: 1,
  146. type: 'Int32Array',
  147. array: [ - 2147483648, 0, 2147483647 ],
  148. normalized: false
  149. }
  150. }
  151. }
  152. } ],
  153. materials: [ {
  154. uuid: 'mat-1',
  155. type: 'MeshBasicMaterial',
  156. color: 16711680
  157. } ],
  158. object: {
  159. uuid: 'mesh-1',
  160. type: 'Mesh',
  161. geometry: 'geom-1',
  162. material: 'mat-1',
  163. matrix: [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ],
  164. layers: 1
  165. }
  166. };
  167. const loader = new ObjectLoader();
  168. const mesh = loader.parse( json );
  169. const attr = mesh.geometry.attributes.custom;
  170. assert.ok( attr.array instanceof Int32Array, 'Array is Int32Array' );
  171. assert.strictEqual( attr.array[ 0 ], - 2147483648, 'First value' );
  172. assert.strictEqual( attr.array[ 2 ], 2147483647, 'Last value' );
  173. } );
  174. QUnit.test( 'Uint8BufferAttribute', ( assert ) => {
  175. const json = {
  176. metadata: { version: 4.7, type: 'Object', generator: 'Object3D.toJSON' },
  177. geometries: [ {
  178. uuid: 'geom-1',
  179. type: 'BufferGeometry',
  180. data: {
  181. attributes: {
  182. position: {
  183. itemSize: 3,
  184. type: 'Float32Array',
  185. array: [ 0, 0, 0, 1, 0, 0, 0, 1, 0 ],
  186. normalized: false
  187. },
  188. custom: {
  189. itemSize: 1,
  190. type: 'Uint8Array',
  191. array: [ 0, 128, 255 ],
  192. normalized: false
  193. }
  194. }
  195. }
  196. } ],
  197. materials: [ {
  198. uuid: 'mat-1',
  199. type: 'MeshBasicMaterial',
  200. color: 16711680
  201. } ],
  202. object: {
  203. uuid: 'mesh-1',
  204. type: 'Mesh',
  205. geometry: 'geom-1',
  206. material: 'mat-1',
  207. matrix: [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ],
  208. layers: 1
  209. }
  210. };
  211. const loader = new ObjectLoader();
  212. const mesh = loader.parse( json );
  213. const attr = mesh.geometry.attributes.custom;
  214. assert.ok( attr.array instanceof Uint8Array, 'Array is Uint8Array' );
  215. assert.strictEqual( attr.array[ 0 ], 0, 'First value is 0' );
  216. assert.strictEqual( attr.array[ 2 ], 255, 'Last value is 255' );
  217. } );
  218. QUnit.test( 'Uint16BufferAttribute', ( assert ) => {
  219. const json = {
  220. metadata: { version: 4.7, type: 'Object', generator: 'Object3D.toJSON' },
  221. geometries: [ {
  222. uuid: 'geom-1',
  223. type: 'BufferGeometry',
  224. data: {
  225. attributes: {
  226. position: {
  227. itemSize: 3,
  228. type: 'Float32Array',
  229. array: [ 0, 0, 0, 1, 0, 0, 0, 1, 0 ],
  230. normalized: false
  231. },
  232. custom: {
  233. itemSize: 1,
  234. type: 'Uint16Array',
  235. array: [ 0, 32768, 65535 ],
  236. normalized: false
  237. }
  238. }
  239. }
  240. } ],
  241. materials: [ {
  242. uuid: 'mat-1',
  243. type: 'MeshBasicMaterial',
  244. color: 16711680
  245. } ],
  246. object: {
  247. uuid: 'mesh-1',
  248. type: 'Mesh',
  249. geometry: 'geom-1',
  250. material: 'mat-1',
  251. matrix: [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ],
  252. layers: 1
  253. }
  254. };
  255. const loader = new ObjectLoader();
  256. const mesh = loader.parse( json );
  257. const attr = mesh.geometry.attributes.custom;
  258. assert.ok( attr.array instanceof Uint16Array, 'Array is Uint16Array' );
  259. assert.strictEqual( attr.array[ 0 ], 0, 'First value is 0' );
  260. assert.strictEqual( attr.array[ 2 ], 65535, 'Last value is 65535' );
  261. } );
  262. QUnit.test( 'Uint32BufferAttribute', ( assert ) => {
  263. const json = {
  264. metadata: { version: 4.7, type: 'Object', generator: 'Object3D.toJSON' },
  265. geometries: [ {
  266. uuid: 'geom-1',
  267. type: 'BufferGeometry',
  268. data: {
  269. attributes: {
  270. position: {
  271. itemSize: 3,
  272. type: 'Float32Array',
  273. array: [ 0, 0, 0, 1, 0, 0, 0, 1, 0 ],
  274. normalized: false
  275. },
  276. custom: {
  277. itemSize: 1,
  278. type: 'Uint32Array',
  279. array: [ 0, 2147483648, 4294967295 ],
  280. normalized: false
  281. }
  282. }
  283. }
  284. } ],
  285. materials: [ {
  286. uuid: 'mat-1',
  287. type: 'MeshBasicMaterial',
  288. color: 16711680
  289. } ],
  290. object: {
  291. uuid: 'mesh-1',
  292. type: 'Mesh',
  293. geometry: 'geom-1',
  294. material: 'mat-1',
  295. matrix: [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ],
  296. layers: 1
  297. }
  298. };
  299. const loader = new ObjectLoader();
  300. const mesh = loader.parse( json );
  301. const attr = mesh.geometry.attributes.custom;
  302. assert.ok( attr.array instanceof Uint32Array, 'Array is Uint32Array' );
  303. assert.strictEqual( attr.array[ 0 ], 0, 'First value is 0' );
  304. assert.strictEqual( attr.array[ 2 ], 4294967295, 'Last value is 4294967295' );
  305. } );
  306. QUnit.test( 'Normalized attribute', ( assert ) => {
  307. const json = {
  308. metadata: { version: 4.7, type: 'Object', generator: 'Object3D.toJSON' },
  309. geometries: [ {
  310. uuid: 'geom-1',
  311. type: 'BufferGeometry',
  312. data: {
  313. attributes: {
  314. position: {
  315. itemSize: 3,
  316. type: 'Float32Array',
  317. array: [ 0, 0, 0, 1, 0, 0, 0, 1, 0 ],
  318. normalized: false
  319. },
  320. color: {
  321. itemSize: 3,
  322. type: 'Uint8Array',
  323. array: [ 255, 0, 0, 0, 255, 0, 0, 0, 255 ],
  324. normalized: true
  325. }
  326. }
  327. }
  328. } ],
  329. materials: [ {
  330. uuid: 'mat-1',
  331. type: 'MeshBasicMaterial',
  332. color: 16711680,
  333. vertexColors: true
  334. } ],
  335. object: {
  336. uuid: 'mesh-1',
  337. type: 'Mesh',
  338. geometry: 'geom-1',
  339. material: 'mat-1',
  340. matrix: [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ],
  341. layers: 1
  342. }
  343. };
  344. const loader = new ObjectLoader();
  345. const mesh = loader.parse( json );
  346. const attr = mesh.geometry.attributes.color;
  347. assert.ok( attr.array instanceof Uint8Array, 'Array is Uint8Array' );
  348. assert.strictEqual( attr.normalized, true, 'Attribute is normalized' );
  349. } );
  350. QUnit.test( 'InterleavedBuffer + InterleavedBufferAttribute', ( assert ) => {
  351. // Create Float32Array data and convert to Uint32 representation for arrayBuffers
  352. const floatData = new Float32Array( [
  353. 0, 0, 0, 0, 0,
  354. 1, 0, 0, 1, 0,
  355. 0, 1, 0, 0.5, 1
  356. ] );
  357. const arrayBufferData = Array.from( new Uint32Array( floatData.buffer ) );
  358. const json = {
  359. metadata: { version: 4.7, type: 'Object', generator: 'Object3D.toJSON' },
  360. geometries: [ {
  361. uuid: 'geom-1',
  362. type: 'BufferGeometry',
  363. data: {
  364. arrayBuffers: {
  365. 'arraybuffer-1': arrayBufferData
  366. },
  367. interleavedBuffers: {
  368. 'buffer-1': {
  369. uuid: 'buffer-1',
  370. buffer: 'arraybuffer-1',
  371. type: 'Float32Array',
  372. stride: 5
  373. }
  374. },
  375. attributes: {
  376. position: {
  377. isInterleavedBufferAttribute: true,
  378. itemSize: 3,
  379. data: 'buffer-1',
  380. offset: 0,
  381. normalized: false
  382. },
  383. uv: {
  384. isInterleavedBufferAttribute: true,
  385. itemSize: 2,
  386. data: 'buffer-1',
  387. offset: 3,
  388. normalized: false
  389. }
  390. }
  391. }
  392. } ],
  393. materials: [ {
  394. uuid: 'mat-1',
  395. type: 'MeshBasicMaterial',
  396. color: 16711680
  397. } ],
  398. object: {
  399. uuid: 'mesh-1',
  400. type: 'Mesh',
  401. geometry: 'geom-1',
  402. material: 'mat-1',
  403. matrix: [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ],
  404. layers: 1
  405. }
  406. };
  407. const loader = new ObjectLoader();
  408. const mesh = loader.parse( json );
  409. const posAttr = mesh.geometry.attributes.position;
  410. const uvAttr = mesh.geometry.attributes.uv;
  411. assert.ok( posAttr.isInterleavedBufferAttribute, 'Position is InterleavedBufferAttribute' );
  412. assert.ok( uvAttr.isInterleavedBufferAttribute, 'UV is InterleavedBufferAttribute' );
  413. assert.strictEqual( posAttr.data, uvAttr.data, 'Share same InterleavedBuffer' );
  414. assert.strictEqual( posAttr.itemSize, 3, 'Position itemSize is 3' );
  415. assert.strictEqual( uvAttr.itemSize, 2, 'UV itemSize is 2' );
  416. assert.strictEqual( posAttr.offset, 0, 'Position offset is 0' );
  417. assert.strictEqual( uvAttr.offset, 3, 'UV offset is 3' );
  418. } );
  419. QUnit.test( 'Multiple attributes sharing InterleavedBuffer', ( assert ) => {
  420. // Create Float32Array data and convert to Uint32 representation for arrayBuffers
  421. const floatData = new Float32Array( [
  422. 0, 0, 0, 0, 0, 1, 0, 0,
  423. 1, 0, 0, 1, 0, 0, 0, 1,
  424. 0, 1, 0, 0.5, 1, 0, 0, 1
  425. ] );
  426. const arrayBufferData = Array.from( new Uint32Array( floatData.buffer ) );
  427. const json = {
  428. metadata: { version: 4.7, type: 'Object', generator: 'Object3D.toJSON' },
  429. geometries: [ {
  430. uuid: 'geom-1',
  431. type: 'BufferGeometry',
  432. data: {
  433. arrayBuffers: {
  434. 'arraybuffer-1': arrayBufferData
  435. },
  436. interleavedBuffers: {
  437. 'buffer-1': {
  438. uuid: 'buffer-1',
  439. buffer: 'arraybuffer-1',
  440. type: 'Float32Array',
  441. stride: 8
  442. }
  443. },
  444. attributes: {
  445. position: {
  446. isInterleavedBufferAttribute: true,
  447. itemSize: 3,
  448. data: 'buffer-1',
  449. offset: 0,
  450. normalized: false
  451. },
  452. uv: {
  453. isInterleavedBufferAttribute: true,
  454. itemSize: 2,
  455. data: 'buffer-1',
  456. offset: 3,
  457. normalized: false
  458. },
  459. normal: {
  460. isInterleavedBufferAttribute: true,
  461. itemSize: 3,
  462. data: 'buffer-1',
  463. offset: 5,
  464. normalized: false
  465. }
  466. }
  467. }
  468. } ],
  469. materials: [ {
  470. uuid: 'mat-1',
  471. type: 'MeshBasicMaterial',
  472. color: 16711680
  473. } ],
  474. object: {
  475. uuid: 'mesh-1',
  476. type: 'Mesh',
  477. geometry: 'geom-1',
  478. material: 'mat-1',
  479. matrix: [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ],
  480. layers: 1
  481. }
  482. };
  483. const loader = new ObjectLoader();
  484. const mesh = loader.parse( json );
  485. const posAttr = mesh.geometry.attributes.position;
  486. const uvAttr = mesh.geometry.attributes.uv;
  487. const normalAttr = mesh.geometry.attributes.normal;
  488. assert.strictEqual( posAttr.data, uvAttr.data, 'Position and UV share same buffer' );
  489. assert.strictEqual( uvAttr.data, normalAttr.data, 'UV and Normal share same buffer' );
  490. assert.strictEqual( posAttr.data.stride, 8, 'Buffer stride is 8' );
  491. } );
  492. QUnit.test( 'InstancedBufferAttribute with meshPerAttribute', ( assert ) => {
  493. const json = {
  494. metadata: { version: 4.7, type: 'Object', generator: 'Object3D.toJSON' },
  495. geometries: [ {
  496. uuid: 'geom-1',
  497. type: 'InstancedBufferGeometry',
  498. data: {
  499. attributes: {
  500. position: {
  501. itemSize: 3,
  502. type: 'Float32Array',
  503. array: [ 0, 0, 0, 1, 0, 0, 0, 1, 0 ],
  504. normalized: false
  505. },
  506. instanceOffset: {
  507. itemSize: 3,
  508. type: 'Float32Array',
  509. array: [ 0, 0, 0, 2, 0, 0, 4, 0, 0 ],
  510. normalized: false,
  511. isInstancedBufferAttribute: true,
  512. meshPerAttribute: 1
  513. }
  514. }
  515. },
  516. instanceCount: 3
  517. } ],
  518. materials: [ {
  519. uuid: 'mat-1',
  520. type: 'MeshBasicMaterial',
  521. color: 16711680
  522. } ],
  523. object: {
  524. uuid: 'mesh-1',
  525. type: 'Mesh',
  526. geometry: 'geom-1',
  527. material: 'mat-1',
  528. matrix: [ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ],
  529. layers: 1
  530. }
  531. };
  532. const loader = new ObjectLoader();
  533. const mesh = loader.parse( json );
  534. const attr = mesh.geometry.attributes.instanceOffset;
  535. assert.ok( attr.isInstancedBufferAttribute, 'Is InstancedBufferAttribute' );
  536. assert.strictEqual( attr.meshPerAttribute, 1, 'meshPerAttribute is 1' );
  537. } );
  538. } );
  539. } );
粤ICP备19079148号