webgl_geometry_compression.html 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <title>three.js webgl - materials - standard</title>
  5. <meta charset="utf-8">
  6. <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
  7. <link type="text/css" rel="stylesheet" href="main.css">
  8. </head>
  9. <body>
  10. <div id="info">
  11. <a href="http://threejs.org" target="_blank" rel="noopener">three.js</a> - Geometry Compression Example<br />
  12. Octahedron and Quantization encoding methods from <a>Tarek Sherif @tsherif</a>
  13. </div>
  14. <script type="module">
  15. import * as THREE from '../build/three.module.js';
  16. import Stats from './jsm/libs/stats.module.js';
  17. import { OrbitControls } from './jsm/controls/OrbitControls.js';
  18. import { GeometryCompressionUtils, PackedPhongMaterial } from './jsm/utils/GeometryCompressionUtils.js';
  19. import { GUI } from './jsm/libs/dat.gui.module.js';
  20. var statsEnabled = true;
  21. var container, stats, gui;
  22. var camera, scene, renderer, controls;
  23. var lights = [];
  24. // options
  25. var data = {
  26. "wireframe": false,
  27. "texture": false,
  28. "detail": 4,
  29. "rotationSpeed": 0.1,
  30. "quantizeEncodePos": false,
  31. "defaultEncodeNormal": false,
  32. "anglesEncodeNormal": false,
  33. "oct1bytesEncode": false,
  34. "oct2bytesEncode": false,
  35. "defaultEncodeUV": false,
  36. "totalGPUMemory": "0 bytes"
  37. };
  38. var memoryDisplay;
  39. // geometry params
  40. var radius = 100;
  41. // materials
  42. var lineMaterial = new THREE.LineBasicMaterial({ color: 0xaaaaaa, transparent: true, opacity: 0.8 });
  43. var meshMaterial = new THREE.MeshPhongMaterial({ color: 0xffffff, emissive: 0x111111 });
  44. // texture
  45. var texture = new THREE.TextureLoader().load("textures/uv_grid_opengl.jpg");
  46. texture.wrapS = THREE.RepeatWrapping;
  47. texture.wrapT = THREE.RepeatWrapping;
  48. //
  49. init();
  50. animate();
  51. function init() {
  52. //
  53. container = document.createElement('div');
  54. document.body.appendChild(container);
  55. renderer = new THREE.WebGLRenderer({ antialias: true });
  56. renderer.setPixelRatio(window.devicePixelRatio);
  57. renderer.setSize(window.innerWidth, window.innerHeight);
  58. container.appendChild(renderer.domElement);
  59. //
  60. scene = new THREE.Scene();
  61. camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.01, 10000000);
  62. camera.position.x = 2 * radius;
  63. camera.position.y = 2 * radius;
  64. camera.position.z = 2 * radius;
  65. controls = new OrbitControls(camera, renderer.domElement);
  66. //
  67. lights[0] = new THREE.PointLight(0xffffff, 1, 0);
  68. lights[1] = new THREE.PointLight(0xffffff, 1, 0);
  69. lights[2] = new THREE.PointLight(0xffffff, 1, 0);
  70. lights[0].position.set(0, 2 * radius, 0);
  71. lights[1].position.set(2 * radius, - 2 * radius, 2 * radius);
  72. lights[2].position.set(- 2 * radius, - 2 * radius, - 2 * radius);
  73. scene.add(lights[0]);
  74. scene.add(lights[1]);
  75. scene.add(lights[2]);
  76. //
  77. scene.add(new THREE.AxesHelper(radius * 5));
  78. //
  79. var ballGeom = newGeometry();
  80. var ballMesh = new THREE.Mesh(ballGeom, meshMaterial);
  81. var ballLineSegments = new THREE.LineSegments(new THREE.WireframeGeometry(ballGeom), lineMaterial);
  82. ballLineSegments.visible = data.wireframe;
  83. scene.add(ballMesh);
  84. scene.add(ballLineSegments);
  85. //
  86. gui = new GUI();
  87. gui.width = 350;
  88. // generateGeometry
  89. function newGeometry() {
  90. var geom = new THREE.IcosahedronBufferGeometry(radius, data.detail);
  91. // var geom = new THREE.CylinderBufferGeometry( 5, 5, 20, 32 );
  92. // var geom = new THREE.OctahedronBufferGeometry( radius, data.detail );
  93. // var geom = new THREE.BoxBufferGeometry(radius, radius, radius, data.detail, data.detail, data.detail);
  94. return geom;
  95. }
  96. function generateGeometry() {
  97. updateGroupGeometry(
  98. ballMesh,
  99. ballLineSegments,
  100. newGeometry(),
  101. data);
  102. }
  103. // updateLineSegments
  104. function updateLineSegments() {
  105. ballLineSegments.visible = data.wireframe;
  106. }
  107. var folder = gui.addFolder('Scene');
  108. folder.open();
  109. folder.add(data, 'wireframe', false).onChange(updateLineSegments);
  110. folder.add(data, 'texture', false).onChange(generateGeometry);
  111. folder.add(data, 'detail', 0, 6, 1).onChange(generateGeometry);
  112. folder.add(data, 'rotationSpeed', 0, 0.5, 0.1);
  113. folder = gui.addFolder('Position Compression');
  114. folder.open();
  115. folder.add(data, 'quantizeEncodePos', false).onChange(generateGeometry);
  116. folder = gui.addFolder('Normal Compression');
  117. folder.open();
  118. folder.add(data, 'defaultEncodeNormal', false).onChange(generateGeometry);
  119. folder.add(data, 'anglesEncodeNormal', false).onChange(generateGeometry);
  120. folder.add(data, 'oct1bytesEncode', false).onChange(generateGeometry);
  121. folder.add(data, 'oct2bytesEncode', false).onChange(generateGeometry);
  122. folder = gui.addFolder('UV Compression');
  123. folder.open();
  124. folder.add(data, 'defaultEncodeUV', false).onChange(generateGeometry);
  125. folder = gui.addFolder('Memory Info');
  126. folder.open();
  127. memoryDisplay = folder.add(data, 'totalGPUMemory', "0 bytes");
  128. computeGPUMemory(ballMesh);
  129. //
  130. if (statsEnabled) {
  131. stats = new Stats();
  132. container.appendChild(stats.dom);
  133. }
  134. window.addEventListener('resize', onWindowResize, false);
  135. }
  136. //
  137. function onWindowResize() {
  138. renderer.setSize(window.innerWidth, window.innerHeight);
  139. camera.aspect = window.innerWidth / window.innerHeight;
  140. camera.updateProjectionMatrix();
  141. }
  142. //
  143. function updateLightsPossition() {
  144. lights.forEach(light => {
  145. var direction = light.position.clone();
  146. direction.applyAxisAngle(new THREE.Vector3(1, 1, 0), data.rotationSpeed / 180 * Math.PI);
  147. light.position.add(direction.sub(light.position));
  148. });
  149. }
  150. //
  151. function animate() {
  152. requestAnimationFrame(animate);
  153. controls.update();
  154. updateLightsPossition();
  155. renderer.render(scene, camera);
  156. if (statsEnabled) stats.update();
  157. }
  158. //
  159. function updateGroupGeometry(mesh, lineSegments, geometry, data) {
  160. if (geometry.isGeometry) {
  161. geometry = new THREE.BufferGeometry().fromGeometry(geometry);
  162. console.warn('THREE.GeometryBrowser: Converted Geometry to BufferGeometry.');
  163. }
  164. lineSegments.geometry.dispose();
  165. mesh.geometry.dispose();
  166. lineSegments.geometry = new THREE.WireframeGeometry(geometry);
  167. mesh.geometry = geometry;
  168. mesh.material = new THREE.MeshPhongMaterial({ color: 0xffffff, emissive: 0x111111 });
  169. mesh.material.map = data.texture ? texture : null;
  170. var normalEncode = "";
  171. if (data.oct1bytesEncode) {
  172. /**
  173. * It is not recommended to use 1-byte octahedron normals encoding unless you want to extremely reduce the memory usage
  174. * As it makes vertex data not aligned to a 4 byte boundary which may harm some WebGL implementations and sometimes the normal distortion is visible
  175. * Please refer to @zeux 's comments in https://github.com/mrdoob/three.js/pull/18208
  176. */
  177. normalEncode = "OCT1Byte";
  178. } else if (data.oct2bytesEncode) {
  179. normalEncode = "OCT2Byte";
  180. } else if (data.anglesEncodeNormal) {
  181. normalEncode = "ANGLES";
  182. } else if (data.defaultEncodeNormal) {
  183. normalEncode = "DEFAULT";
  184. }
  185. if (normalEncode != "") {
  186. GeometryCompressionUtils.compressNormals(mesh, normalEncode);
  187. }
  188. if (data.quantizeEncodePos) {
  189. GeometryCompressionUtils.compressPositions(mesh);
  190. }
  191. if (data.defaultEncodeUV) {
  192. GeometryCompressionUtils.compressUvs(mesh);
  193. }
  194. computeGPUMemory(mesh);
  195. }
  196. function computeGPUMemory(mesh) {
  197. let posBytes = mesh.geometry.attributes.position.bytes || mesh.geometry.attributes.position.array.length * 4;
  198. let normBytes = mesh.geometry.attributes.normal.bytes || mesh.geometry.attributes.normal.array.length * 4;
  199. let uvBytes = mesh.geometry.attributes.uv.bytes || mesh.geometry.attributes.uv.array.length * 4;
  200. memoryDisplay.setValue(posBytes + normBytes + uvBytes + " bytes");
  201. }
  202. </script>
  203. </body>
  204. </html>