webgl_geometry_sdf.html 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <title>three.js webgl - SDF Geometry</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="https://threejs.org" target="_blank" rel="noopener">three.js</a> -SDF to Mesh-<br/>
  12. a wrapper of <a href="https://www.npmjs.com/package/isosurface" target="_blank" > Mikola Lysenko's Isosurface</a><br/>
  13. Mandelbrot by <a href="https://www.shadertoy.com/view/MdXSWn" target="_blank" > EvilRyu</a><br/>
  14. </div>
  15. <script type="importmap">
  16. {
  17. "imports": {
  18. "three": "../build/three.module.js",
  19. "three/addons/": "./jsm/"
  20. }
  21. }
  22. </script>
  23. <script type="module">
  24. import * as THREE from 'three';
  25. import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
  26. import { SDFGeometryGenerator } from 'three/addons/geometries/SDFGeometryGenerator.js';
  27. import Stats from 'three/addons/libs/stats.module.js';
  28. import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
  29. let renderer, stats, meshFromSDF, scene, camera, clock, controls;
  30. const settings = {
  31. res: 4,
  32. bounds: 1,
  33. autoRotate: true,
  34. wireframe: true,
  35. material: 'depth',
  36. vertexCount: '0'
  37. };
  38. // Example SDF from https://www.shadertoy.com/view/MdXSWn -->
  39. const shader = /* glsl */`
  40. float dist(vec3 p) {
  41. p.xyz = p.xzy;
  42. p *= 1.2;
  43. vec3 z = p;
  44. vec3 dz=vec3(0.0);
  45. float power = 8.0;
  46. float r, theta, phi;
  47. float dr = 1.0;
  48. float t0 = 1.0;
  49. for(int i = 0; i < 7; ++i) {
  50. r = length(z);
  51. if(r > 2.0) continue;
  52. theta = atan(z.y / z.x);
  53. #ifdef phase_shift_on
  54. phi = asin(z.z / r) ;
  55. #else
  56. phi = asin(z.z / r);
  57. #endif
  58. dr = pow(r, power - 1.0) * dr * power + 1.0;
  59. r = pow(r, power);
  60. theta = theta * power;
  61. phi = phi * power;
  62. z = r * vec3(cos(theta)*cos(phi), sin(theta)*cos(phi), sin(phi)) + p;
  63. t0 = min(t0, r);
  64. }
  65. return 0.5 * log(r) * r / dr;
  66. }
  67. `;
  68. init();
  69. function init() {
  70. const w = window.innerWidth;
  71. const h = window.innerHeight;
  72. camera = new THREE.OrthographicCamera( w / - 2, w / 2, h / 2, h / - 2, 0.01, 1600 );
  73. camera.position.z = 1100;
  74. scene = new THREE.Scene();
  75. clock = new THREE.Clock();
  76. renderer = new THREE.WebGLRenderer( { antialias: true } );
  77. renderer.setPixelRatio( window.devicePixelRatio );
  78. renderer.setSize( window.innerWidth, window.innerHeight );
  79. renderer.setAnimationLoop( animate );
  80. document.body.appendChild( renderer.domElement );
  81. stats = new Stats();
  82. document.body.appendChild( stats.dom );
  83. controls = new OrbitControls( camera, renderer.domElement );
  84. controls.enableDamping = true;
  85. window.addEventListener( 'resize', onWindowResize );
  86. //
  87. const panel = new GUI( );
  88. panel.add( settings, 'res', 1, 6, 1 ).name( 'Res' ).onFinishChange( compile );
  89. panel.add( settings, 'bounds', 1, 10, 1 ).name( 'Bounds' ).onFinishChange( compile );
  90. panel.add( settings, 'material', [ 'depth', 'normal' ] ).name( 'Material' ).onChange( setMaterial );
  91. panel.add( settings, 'wireframe' ).name( 'Wireframe' ).onChange( setMaterial );
  92. panel.add( settings, 'autoRotate' ).name( 'Auto Rotate' );
  93. panel.add( settings, 'vertexCount' ).name( 'Vertex count' ).listen().disable();
  94. //
  95. compile();
  96. }
  97. function compile() {
  98. const generator = new SDFGeometryGenerator( renderer );
  99. const geometry = generator.generate( Math.pow( 2, settings.res + 2 ), shader, settings.bounds );
  100. geometry.computeVertexNormals();
  101. if ( meshFromSDF ) { // updates mesh
  102. meshFromSDF.geometry.dispose();
  103. meshFromSDF.geometry = geometry;
  104. } else { // inits meshFromSDF : THREE.Mesh
  105. meshFromSDF = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial() );
  106. scene.add( meshFromSDF );
  107. const scale = Math.min( window.innerWidth, window.innerHeight ) / 2 * 0.66;
  108. meshFromSDF.scale.set( scale, scale, scale );
  109. setMaterial();
  110. }
  111. settings.vertexCount = geometry.attributes.position.count;
  112. }
  113. function setMaterial() {
  114. meshFromSDF.material.dispose();
  115. if ( settings.material == 'depth' ) {
  116. meshFromSDF.material = new THREE.MeshDepthMaterial();
  117. } else if ( settings.material == 'normal' ) {
  118. meshFromSDF.material = new THREE.MeshNormalMaterial();
  119. }
  120. meshFromSDF.material.wireframe = settings.wireframe;
  121. }
  122. function onWindowResize() {
  123. const w = window.innerWidth;
  124. const h = window.innerHeight;
  125. renderer.setSize( w, h );
  126. camera.left = w / - 2;
  127. camera.right = w / 2;
  128. camera.top = h / 2;
  129. camera.bottom = h / - 2;
  130. camera.updateProjectionMatrix();
  131. }
  132. function render() {
  133. renderer.render( scene, camera );
  134. }
  135. function animate() {
  136. controls.update();
  137. if ( settings.autoRotate ) {
  138. meshFromSDF.rotation.y += Math.PI * 0.05 * clock.getDelta();
  139. }
  140. render();
  141. stats.update();
  142. }
  143. </script>
  144. </body>
  145. </html>