1
0

roundtrip.tests.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. import { ObjectLoader } from '../../../src/loaders/ObjectLoader.js';
  2. import { Scene } from '../../../src/scenes/Scene.js';
  3. import { Mesh } from '../../../src/objects/Mesh.js';
  4. import { Group } from '../../../src/objects/Group.js';
  5. import { BoxGeometry } from '../../../src/geometries/BoxGeometry.js';
  6. import { SphereGeometry } from '../../../src/geometries/SphereGeometry.js';
  7. import { BufferGeometry } from '../../../src/core/BufferGeometry.js';
  8. import { Float32BufferAttribute } from '../../../src/core/BufferAttribute.js';
  9. import { MeshBasicMaterial } from '../../../src/materials/MeshBasicMaterial.js';
  10. import { MeshStandardMaterial } from '../../../src/materials/MeshStandardMaterial.js';
  11. import { AmbientLight } from '../../../src/lights/AmbientLight.js';
  12. import { DirectionalLight } from '../../../src/lights/DirectionalLight.js';
  13. import { PointLight } from '../../../src/lights/PointLight.js';
  14. import { PerspectiveCamera } from '../../../src/cameras/PerspectiveCamera.js';
  15. import { OrthographicCamera } from '../../../src/cameras/OrthographicCamera.js';
  16. import { Color } from '../../../src/math/Color.js';
  17. import { Fog } from '../../../src/scenes/Fog.js';
  18. export default QUnit.module( 'JSON4 Format', () => {
  19. QUnit.module( 'Round-trip', () => {
  20. QUnit.test( 'Simple Mesh round-trip', ( assert ) => {
  21. const geometry = new BoxGeometry( 2, 3, 4 );
  22. const material = new MeshBasicMaterial( { color: 0xff0000 } );
  23. const mesh = new Mesh( geometry, material );
  24. mesh.position.set( 1, 2, 3 );
  25. mesh.name = 'TestMesh';
  26. mesh.updateMatrix();
  27. const json = mesh.toJSON();
  28. const loader = new ObjectLoader();
  29. const restored = loader.parse( json );
  30. assert.ok( restored.isMesh, 'Restored is Mesh' );
  31. assert.strictEqual( restored.name, 'TestMesh', 'Name preserved' );
  32. assert.strictEqual( restored.position.x, 1, 'Position.x preserved' );
  33. assert.strictEqual( restored.position.y, 2, 'Position.y preserved' );
  34. assert.strictEqual( restored.position.z, 3, 'Position.z preserved' );
  35. assert.strictEqual( restored.geometry.parameters.width, 2, 'Geometry width preserved' );
  36. assert.strictEqual( restored.material.color.getHex(), 0xff0000, 'Material color preserved' );
  37. } );
  38. QUnit.test( 'Scene with multiple objects round-trip', ( assert ) => {
  39. const scene = new Scene();
  40. scene.name = 'TestScene';
  41. scene.background = new Color( 0x87ceeb );
  42. const geometry = new BoxGeometry( 1, 1, 1 );
  43. const material = new MeshBasicMaterial( { color: 0xff0000 } );
  44. const mesh1 = new Mesh( geometry, material );
  45. mesh1.name = 'Mesh1';
  46. mesh1.position.set( 0, 0, 0 );
  47. const mesh2 = new Mesh( geometry, material );
  48. mesh2.name = 'Mesh2';
  49. mesh2.position.set( 2, 0, 0 );
  50. scene.add( mesh1, mesh2 );
  51. const json = scene.toJSON();
  52. const loader = new ObjectLoader();
  53. const restored = loader.parse( json );
  54. assert.ok( restored.isScene, 'Restored is Scene' );
  55. assert.strictEqual( restored.name, 'TestScene', 'Scene name preserved' );
  56. assert.strictEqual( restored.background.getHex(), 0x87ceeb, 'Background preserved' );
  57. assert.strictEqual( restored.children.length, 2, 'Has 2 children' );
  58. assert.strictEqual( restored.children[ 0 ].name, 'Mesh1', 'First child name' );
  59. assert.strictEqual( restored.children[ 1 ].name, 'Mesh2', 'Second child name' );
  60. } );
  61. QUnit.test( 'Hierarchy round-trip', ( assert ) => {
  62. const scene = new Scene();
  63. const parent = new Group();
  64. parent.name = 'Parent';
  65. parent.position.set( 1, 0, 0 );
  66. const child = new Group();
  67. child.name = 'Child';
  68. child.position.set( 0, 1, 0 );
  69. const grandchild = new Mesh(
  70. new BoxGeometry( 1, 1, 1 ),
  71. new MeshBasicMaterial( { color: 0xff0000 } )
  72. );
  73. grandchild.name = 'Grandchild';
  74. grandchild.position.set( 0, 0, 1 );
  75. child.add( grandchild );
  76. parent.add( child );
  77. scene.add( parent );
  78. const json = scene.toJSON();
  79. const loader = new ObjectLoader();
  80. const restored = loader.parse( json );
  81. const restoredParent = restored.children[ 0 ];
  82. const restoredChild = restoredParent.children[ 0 ];
  83. const restoredGrandchild = restoredChild.children[ 0 ];
  84. assert.strictEqual( restoredParent.name, 'Parent', 'Parent name' );
  85. assert.strictEqual( restoredChild.name, 'Child', 'Child name' );
  86. assert.strictEqual( restoredGrandchild.name, 'Grandchild', 'Grandchild name' );
  87. assert.strictEqual( restoredGrandchild.parent, restoredChild, 'Parent-child relation' );
  88. } );
  89. QUnit.test( 'BufferGeometry with custom attributes round-trip', ( assert ) => {
  90. const geometry = new BufferGeometry();
  91. geometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 1, 0, 0, 0, 1, 0 ], 3 ) );
  92. geometry.setAttribute( 'normal', new Float32BufferAttribute( [ 0, 0, 1, 0, 0, 1, 0, 0, 1 ], 3 ) );
  93. geometry.setAttribute( 'uv', new Float32BufferAttribute( [ 0, 0, 1, 0, 0.5, 1 ], 2 ) );
  94. const material = new MeshBasicMaterial( { color: 0xff0000 } );
  95. const mesh = new Mesh( geometry, material );
  96. const json = mesh.toJSON();
  97. const loader = new ObjectLoader();
  98. const restored = loader.parse( json );
  99. assert.ok( restored.geometry.attributes.position, 'Has position' );
  100. assert.ok( restored.geometry.attributes.normal, 'Has normal' );
  101. assert.ok( restored.geometry.attributes.uv, 'Has uv' );
  102. assert.strictEqual( restored.geometry.attributes.position.count, 3, 'Position count' );
  103. assert.strictEqual( restored.geometry.attributes.uv.itemSize, 2, 'UV itemSize' );
  104. } );
  105. QUnit.test( 'MeshStandardMaterial round-trip', ( assert ) => {
  106. const material = new MeshStandardMaterial( {
  107. color: 0xff0000,
  108. roughness: 0.3,
  109. metalness: 0.8,
  110. emissive: 0x00ff00,
  111. emissiveIntensity: 0.5
  112. } );
  113. const mesh = new Mesh( new BoxGeometry( 1, 1, 1 ), material );
  114. const json = mesh.toJSON();
  115. const loader = new ObjectLoader();
  116. const restored = loader.parse( json );
  117. assert.ok( restored.material.isMeshStandardMaterial, 'Is MeshStandardMaterial' );
  118. assert.strictEqual( restored.material.color.getHex(), 0xff0000, 'Color preserved' );
  119. assert.strictEqual( restored.material.roughness, 0.3, 'Roughness preserved' );
  120. assert.strictEqual( restored.material.metalness, 0.8, 'Metalness preserved' );
  121. assert.strictEqual( restored.material.emissive.getHex(), 0x00ff00, 'Emissive preserved' );
  122. assert.strictEqual( restored.material.emissiveIntensity, 0.5, 'EmissiveIntensity preserved' );
  123. } );
  124. QUnit.test( 'Lights round-trip', ( assert ) => {
  125. const scene = new Scene();
  126. const ambient = new AmbientLight( 0xffffff, 0.5 );
  127. ambient.name = 'Ambient';
  128. const directional = new DirectionalLight( 0xffffff, 1 );
  129. directional.name = 'Directional';
  130. directional.position.set( 5, 10, 5 );
  131. const point = new PointLight( 0xff0000, 2, 50, 2 );
  132. point.name = 'Point';
  133. point.position.set( 0, 5, 0 );
  134. scene.add( ambient, directional, point );
  135. scene.updateMatrixWorld( true );
  136. const json = scene.toJSON();
  137. const loader = new ObjectLoader();
  138. const restored = loader.parse( json );
  139. const restoredAmbient = restored.getObjectByName( 'Ambient' );
  140. const restoredDirectional = restored.getObjectByName( 'Directional' );
  141. const restoredPoint = restored.getObjectByName( 'Point' );
  142. assert.ok( restoredAmbient.isAmbientLight, 'Ambient is AmbientLight' );
  143. assert.strictEqual( restoredAmbient.intensity, 0.5, 'Ambient intensity' );
  144. assert.ok( restoredDirectional.isDirectionalLight, 'Directional is DirectionalLight' );
  145. assert.strictEqual( restoredDirectional.position.x, 5, 'Directional position.x' );
  146. assert.ok( restoredPoint.isPointLight, 'Point is PointLight' );
  147. assert.strictEqual( restoredPoint.color.getHex(), 0xff0000, 'Point color' );
  148. assert.strictEqual( restoredPoint.distance, 50, 'Point distance' );
  149. assert.strictEqual( restoredPoint.decay, 2, 'Point decay' );
  150. } );
  151. QUnit.test( 'Cameras round-trip', ( assert ) => {
  152. const scene = new Scene();
  153. const perspective = new PerspectiveCamera( 75, 16 / 9, 0.1, 1000 );
  154. perspective.name = 'Perspective';
  155. perspective.position.set( 0, 0, 5 );
  156. perspective.zoom = 1.5;
  157. const ortho = new OrthographicCamera( - 10, 10, 10, - 10, 0.1, 100 );
  158. ortho.name = 'Ortho';
  159. ortho.position.set( 0, 10, 0 );
  160. scene.add( perspective, ortho );
  161. const json = scene.toJSON();
  162. const loader = new ObjectLoader();
  163. const restored = loader.parse( json );
  164. const restoredPerspective = restored.getObjectByName( 'Perspective' );
  165. const restoredOrtho = restored.getObjectByName( 'Ortho' );
  166. assert.ok( restoredPerspective.isPerspectiveCamera, 'Is PerspectiveCamera' );
  167. assert.strictEqual( restoredPerspective.fov, 75, 'FOV preserved' );
  168. assert.strictEqual( restoredPerspective.zoom, 1.5, 'Zoom preserved' );
  169. assert.ok( restoredOrtho.isOrthographicCamera, 'Is OrthographicCamera' );
  170. assert.strictEqual( restoredOrtho.left, - 10, 'Left preserved' );
  171. assert.strictEqual( restoredOrtho.right, 10, 'Right preserved' );
  172. } );
  173. QUnit.test( 'Scene with Fog round-trip', ( assert ) => {
  174. const scene = new Scene();
  175. scene.fog = new Fog( 0xffffff, 10, 100 );
  176. scene.fog.name = 'TestFog';
  177. const json = scene.toJSON();
  178. const loader = new ObjectLoader();
  179. const restored = loader.parse( json );
  180. assert.ok( restored.fog.isFog, 'Has Fog' );
  181. assert.strictEqual( restored.fog.color.getHex(), 0xffffff, 'Fog color' );
  182. assert.strictEqual( restored.fog.near, 10, 'Fog near' );
  183. assert.strictEqual( restored.fog.far, 100, 'Fog far' );
  184. assert.strictEqual( restored.fog.name, 'TestFog', 'Fog name' );
  185. } );
  186. QUnit.test( 'Object transforms round-trip', ( assert ) => {
  187. const mesh = new Mesh(
  188. new BoxGeometry( 1, 1, 1 ),
  189. new MeshBasicMaterial( { color: 0xff0000 } )
  190. );
  191. mesh.position.set( 1, 2, 3 );
  192. mesh.rotation.set( Math.PI / 4, Math.PI / 2, 0 );
  193. mesh.scale.set( 2, 2, 2 );
  194. mesh.updateMatrix();
  195. const json = mesh.toJSON();
  196. const loader = new ObjectLoader();
  197. const restored = loader.parse( json );
  198. assert.ok( Math.abs( restored.position.x - 1 ) < 0.0001, 'Position.x' );
  199. assert.ok( Math.abs( restored.position.y - 2 ) < 0.0001, 'Position.y' );
  200. assert.ok( Math.abs( restored.position.z - 3 ) < 0.0001, 'Position.z' );
  201. assert.ok( Math.abs( restored.scale.x - 2 ) < 0.0001, 'Scale.x' );
  202. assert.ok( Math.abs( restored.scale.y - 2 ) < 0.0001, 'Scale.y' );
  203. assert.ok( Math.abs( restored.scale.z - 2 ) < 0.0001, 'Scale.z' );
  204. } );
  205. QUnit.test( 'userData round-trip', ( assert ) => {
  206. const mesh = new Mesh(
  207. new BoxGeometry( 1, 1, 1 ),
  208. new MeshBasicMaterial( { color: 0xff0000 } )
  209. );
  210. mesh.userData = {
  211. customString: 'hello',
  212. customNumber: 42,
  213. customBool: true,
  214. customArray: [ 1, 2, 3 ],
  215. customObject: { nested: 'value' }
  216. };
  217. const json = mesh.toJSON();
  218. const loader = new ObjectLoader();
  219. const restored = loader.parse( json );
  220. assert.strictEqual( restored.userData.customString, 'hello', 'String preserved' );
  221. assert.strictEqual( restored.userData.customNumber, 42, 'Number preserved' );
  222. assert.strictEqual( restored.userData.customBool, true, 'Bool preserved' );
  223. assert.deepEqual( restored.userData.customArray, [ 1, 2, 3 ], 'Array preserved' );
  224. assert.deepEqual( restored.userData.customObject, { nested: 'value' }, 'Object preserved' );
  225. } );
  226. QUnit.test( 'Object properties round-trip', ( assert ) => {
  227. const mesh = new Mesh(
  228. new BoxGeometry( 1, 1, 1 ),
  229. new MeshBasicMaterial( { color: 0xff0000 } )
  230. );
  231. mesh.visible = false;
  232. mesh.castShadow = true;
  233. mesh.receiveShadow = true;
  234. mesh.frustumCulled = false;
  235. mesh.renderOrder = 5;
  236. const json = mesh.toJSON();
  237. const loader = new ObjectLoader();
  238. const restored = loader.parse( json );
  239. assert.strictEqual( restored.visible, false, 'Visible' );
  240. assert.strictEqual( restored.castShadow, true, 'CastShadow' );
  241. assert.strictEqual( restored.receiveShadow, true, 'ReceiveShadow' );
  242. assert.strictEqual( restored.frustumCulled, false, 'FrustumCulled' );
  243. assert.strictEqual( restored.renderOrder, 5, 'RenderOrder' );
  244. } );
  245. QUnit.test( 'Shared geometry/material round-trip', ( assert ) => {
  246. const scene = new Scene();
  247. const geometry = new BoxGeometry( 1, 1, 1 );
  248. const material = new MeshBasicMaterial( { color: 0xff0000 } );
  249. const mesh1 = new Mesh( geometry, material );
  250. mesh1.name = 'Mesh1';
  251. const mesh2 = new Mesh( geometry, material );
  252. mesh2.name = 'Mesh2';
  253. mesh2.position.x = 2;
  254. scene.add( mesh1, mesh2 );
  255. const json = scene.toJSON();
  256. const loader = new ObjectLoader();
  257. const restored = loader.parse( json );
  258. const restoredMesh1 = restored.getObjectByName( 'Mesh1' );
  259. const restoredMesh2 = restored.getObjectByName( 'Mesh2' );
  260. assert.strictEqual( restoredMesh1.geometry, restoredMesh2.geometry, 'Geometry shared' );
  261. assert.strictEqual( restoredMesh1.material, restoredMesh2.material, 'Material shared' );
  262. } );
  263. QUnit.test( 'Complex scene round-trip', ( assert ) => {
  264. const scene = new Scene();
  265. scene.name = 'ComplexScene';
  266. scene.background = new Color( 0x333333 );
  267. scene.fog = new Fog( 0x333333, 10, 100 );
  268. const group = new Group();
  269. group.name = 'ObjectsGroup';
  270. const geometry1 = new BoxGeometry( 1, 1, 1 );
  271. const geometry2 = new SphereGeometry( 0.5, 16, 8 );
  272. const material1 = new MeshBasicMaterial( { color: 0xff0000 } );
  273. const material2 = new MeshStandardMaterial( { color: 0x00ff00, roughness: 0.5 } );
  274. const box = new Mesh( geometry1, material1 );
  275. box.name = 'Box';
  276. box.position.set( - 2, 0, 0 );
  277. const sphere = new Mesh( geometry2, material2 );
  278. sphere.name = 'Sphere';
  279. sphere.position.set( 2, 0, 0 );
  280. group.add( box, sphere );
  281. scene.add( group );
  282. const ambient = new AmbientLight( 0xffffff, 0.3 );
  283. scene.add( ambient );
  284. const directional = new DirectionalLight( 0xffffff, 1 );
  285. directional.position.set( 5, 10, 5 );
  286. scene.add( directional );
  287. const camera = new PerspectiveCamera( 75, 1, 0.1, 1000 );
  288. camera.name = 'MainCamera';
  289. camera.position.set( 0, 0, 10 );
  290. scene.add( camera );
  291. const json = scene.toJSON();
  292. const loader = new ObjectLoader();
  293. const restored = loader.parse( json );
  294. assert.ok( restored.isScene, 'Is Scene' );
  295. assert.strictEqual( restored.name, 'ComplexScene', 'Scene name' );
  296. assert.strictEqual( restored.background.getHex(), 0x333333, 'Background' );
  297. assert.ok( restored.fog.isFog, 'Has Fog' );
  298. const restoredGroup = restored.getObjectByName( 'ObjectsGroup' );
  299. assert.ok( restoredGroup.isGroup, 'Group found' );
  300. assert.strictEqual( restoredGroup.children.length, 2, 'Group has 2 children' );
  301. const restoredBox = restored.getObjectByName( 'Box' );
  302. const restoredSphere = restored.getObjectByName( 'Sphere' );
  303. assert.ok( restoredBox.isMesh, 'Box found' );
  304. assert.ok( restoredSphere.isMesh, 'Sphere found' );
  305. const restoredCamera = restored.getObjectByName( 'MainCamera' );
  306. assert.ok( restoredCamera.isPerspectiveCamera, 'Camera found' );
  307. } );
  308. } );
  309. } );
粤ICP备19079148号