webgl_marchingcubes.html 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <title>three.js webgl - marching cubes</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. <meta property="og:title" content="three.js webgl - marching cubes">
  8. <meta property="og:type" content="website">
  9. <meta property="og:url" content="https://threejs.org/examples/webgl_marchingcubes.html">
  10. <meta property="og:image" content="https://threejs.org/examples/screenshots/webgl_marchingcubes.jpg">
  11. <link type="text/css" rel="stylesheet" href="main.css">
  12. </head>
  13. <body>
  14. <div id="container"></div>
  15. <div id="info">
  16. <a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> -
  17. marching cubes<br/>
  18. based on greggman's <a href="https://webglsamples.org/blob/blob.html">blob</a>, original code by Henrik Rydgård
  19. </div>
  20. <script type="importmap">
  21. {
  22. "imports": {
  23. "three": "../build/three.module.js",
  24. "three/addons/": "./jsm/"
  25. }
  26. }
  27. </script>
  28. <script type="module">
  29. import * as THREE from 'three';
  30. import Stats from 'three/addons/libs/stats.module.js';
  31. import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
  32. import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
  33. import { MarchingCubes } from 'three/addons/objects/MarchingCubes.js';
  34. import { ToonShader1, ToonShader2, ToonShaderHatching, ToonShaderDotted } from 'three/addons/shaders/ToonShader.js';
  35. let container, stats;
  36. let camera, scene, renderer;
  37. let materials, current_material;
  38. let light, pointLight, ambientLight;
  39. let effect, resolution;
  40. let effectController;
  41. let time = 0;
  42. const timer = new THREE.Timer();
  43. timer.connect( document );
  44. init();
  45. function init() {
  46. container = document.getElementById( 'container' );
  47. // CAMERA
  48. camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 10000 );
  49. camera.position.set( - 500, 500, 1500 );
  50. // SCENE
  51. scene = new THREE.Scene();
  52. scene.background = new THREE.Color( 0x050505 );
  53. // LIGHTS
  54. light = new THREE.DirectionalLight( 0xffffff, 3 );
  55. light.position.set( 0.5, 0.5, 1 );
  56. scene.add( light );
  57. pointLight = new THREE.PointLight( 0xff7c00, 3, 0, 0 );
  58. pointLight.position.set( 0, 0, 100 );
  59. scene.add( pointLight );
  60. ambientLight = new THREE.AmbientLight( 0x323232, 3 );
  61. scene.add( ambientLight );
  62. // MATERIALS
  63. materials = generateMaterials();
  64. current_material = 'shiny';
  65. // MARCHING CUBES
  66. resolution = 28;
  67. effect = new MarchingCubes( resolution, materials[ current_material ], true, true, 100000 );
  68. effect.position.set( 0, 0, 0 );
  69. effect.scale.set( 700, 700, 700 );
  70. effect.enableUvs = false;
  71. effect.enableColors = false;
  72. scene.add( effect );
  73. // RENDERER
  74. renderer = new THREE.WebGLRenderer();
  75. renderer.setPixelRatio( window.devicePixelRatio );
  76. renderer.setSize( window.innerWidth, window.innerHeight );
  77. renderer.setAnimationLoop( animate );
  78. container.appendChild( renderer.domElement );
  79. // CONTROLS
  80. const controls = new OrbitControls( camera, renderer.domElement );
  81. controls.minDistance = 500;
  82. controls.maxDistance = 5000;
  83. // STATS
  84. stats = new Stats();
  85. container.appendChild( stats.dom );
  86. // GUI
  87. setupGui();
  88. // EVENTS
  89. window.addEventListener( 'resize', onWindowResize );
  90. }
  91. //
  92. function onWindowResize() {
  93. camera.aspect = window.innerWidth / window.innerHeight;
  94. camera.updateProjectionMatrix();
  95. renderer.setSize( window.innerWidth, window.innerHeight );
  96. }
  97. function generateMaterials() {
  98. // environment map
  99. const path = 'textures/cube/SwedishRoyalCastle/';
  100. const format = '.jpg';
  101. const urls = [
  102. path + 'px' + format, path + 'nx' + format,
  103. path + 'py' + format, path + 'ny' + format,
  104. path + 'pz' + format, path + 'nz' + format
  105. ];
  106. const cubeTextureLoader = new THREE.CubeTextureLoader();
  107. const reflectionCube = cubeTextureLoader.load( urls );
  108. const refractionCube = cubeTextureLoader.load( urls );
  109. refractionCube.mapping = THREE.CubeRefractionMapping;
  110. // toons
  111. const toonMaterial1 = createShaderMaterial( ToonShader1, light, ambientLight );
  112. const toonMaterial2 = createShaderMaterial( ToonShader2, light, ambientLight );
  113. const hatchingMaterial = createShaderMaterial( ToonShaderHatching, light, ambientLight );
  114. const dottedMaterial = createShaderMaterial( ToonShaderDotted, light, ambientLight );
  115. const texture = new THREE.TextureLoader().load( 'textures/uv_grid_opengl.jpg' );
  116. texture.wrapS = THREE.RepeatWrapping;
  117. texture.wrapT = THREE.RepeatWrapping;
  118. texture.colorSpace = THREE.SRGBColorSpace;
  119. const materials = {
  120. 'shiny': new THREE.MeshStandardMaterial( { color: 0x9c0000, envMap: reflectionCube, roughness: 0.1, metalness: 1.0 } ),
  121. 'chrome': new THREE.MeshLambertMaterial( { color: 0xffffff, envMap: reflectionCube } ),
  122. 'liquid': new THREE.MeshLambertMaterial( { color: 0xffffff, envMap: refractionCube, refractionRatio: 0.85 } ),
  123. 'matte': new THREE.MeshPhongMaterial( { specular: 0x494949, shininess: 1 } ),
  124. 'flat': new THREE.MeshLambertMaterial( { /*TODO flatShading: true */ } ),
  125. 'textured': new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0x111111, shininess: 1, map: texture } ),
  126. 'colors': new THREE.MeshPhongMaterial( { color: 0xffffff, specular: 0xffffff, shininess: 2, vertexColors: true } ),
  127. 'multiColors': new THREE.MeshPhongMaterial( { shininess: 2, vertexColors: true } ),
  128. 'plastic': new THREE.MeshPhongMaterial( { specular: 0xc1c1c1, shininess: 250 } ),
  129. 'toon1': toonMaterial1,
  130. 'toon2': toonMaterial2,
  131. 'hatching': hatchingMaterial,
  132. 'dotted': dottedMaterial
  133. };
  134. return materials;
  135. }
  136. function createShaderMaterial( shader, light, ambientLight ) {
  137. const u = THREE.UniformsUtils.clone( shader.uniforms );
  138. const vs = shader.vertexShader;
  139. const fs = shader.fragmentShader;
  140. const material = new THREE.ShaderMaterial( { uniforms: u, vertexShader: vs, fragmentShader: fs } );
  141. material.uniforms[ 'uDirLightPos' ].value = light.position;
  142. material.uniforms[ 'uDirLightColor' ].value = light.color;
  143. material.uniforms[ 'uAmbientLightColor' ].value = ambientLight.color;
  144. return material;
  145. }
  146. //
  147. function setupGui() {
  148. const createHandler = function ( id ) {
  149. return function () {
  150. current_material = id;
  151. effect.material = materials[ id ];
  152. effect.enableUvs = ( current_material === 'textured' ) ? true : false;
  153. effect.enableColors = ( current_material === 'colors' || current_material === 'multiColors' ) ? true : false;
  154. };
  155. };
  156. effectController = {
  157. material: 'shiny',
  158. speed: 1.0,
  159. numBlobs: 10,
  160. resolution: 28,
  161. isolation: 80,
  162. floor: true,
  163. wallx: false,
  164. wallz: false,
  165. dummy: function () {}
  166. };
  167. let h;
  168. const gui = new GUI();
  169. // material (type)
  170. h = gui.addFolder( 'Materials' );
  171. for ( const m in materials ) {
  172. effectController[ m ] = createHandler( m );
  173. h.add( effectController, m ).name( m );
  174. }
  175. // simulation
  176. h = gui.addFolder( 'Simulation' );
  177. h.add( effectController, 'speed', 0.1, 8.0, 0.05 );
  178. h.add( effectController, 'numBlobs', 1, 50, 1 );
  179. h.add( effectController, 'resolution', 14, 100, 1 );
  180. h.add( effectController, 'isolation', 10, 300, 1 );
  181. h.add( effectController, 'floor' );
  182. h.add( effectController, 'wallx' );
  183. h.add( effectController, 'wallz' );
  184. }
  185. // this controls content of marching cubes voxel field
  186. function updateCubes( object, time, numblobs, floor, wallx, wallz ) {
  187. object.reset();
  188. // fill the field with some metaballs
  189. const rainbow = [
  190. new THREE.Color( 0xff0000 ),
  191. new THREE.Color( 0xffbb00 ),
  192. new THREE.Color( 0xffff00 ),
  193. new THREE.Color( 0x00ff00 ),
  194. new THREE.Color( 0x0000ff ),
  195. new THREE.Color( 0x9400bd ),
  196. new THREE.Color( 0xc800eb )
  197. ];
  198. const subtract = 12;
  199. const strength = 1.2 / ( ( Math.sqrt( numblobs ) - 1 ) / 4 + 1 );
  200. for ( let i = 0; i < numblobs; i ++ ) {
  201. const ballx = Math.sin( i + 1.26 * time * ( 1.03 + 0.5 * Math.cos( 0.21 * i ) ) ) * 0.27 + 0.5;
  202. const bally = Math.abs( Math.cos( i + 1.12 * time * Math.cos( 1.22 + 0.1424 * i ) ) ) * 0.77; // dip into the floor
  203. const ballz = Math.cos( i + 1.32 * time * 0.1 * Math.sin( ( 0.92 + 0.53 * i ) ) ) * 0.27 + 0.5;
  204. if ( current_material === 'multiColors' ) {
  205. object.addBall( ballx, bally, ballz, strength, subtract, rainbow[ i % 7 ] );
  206. } else {
  207. object.addBall( ballx, bally, ballz, strength, subtract );
  208. }
  209. }
  210. if ( floor ) object.addPlaneY( 2, 12 );
  211. if ( wallz ) object.addPlaneZ( 2, 12 );
  212. if ( wallx ) object.addPlaneX( 2, 12 );
  213. object.update();
  214. }
  215. //
  216. function animate() {
  217. timer.update();
  218. render();
  219. stats.update();
  220. }
  221. function render() {
  222. const delta = timer.getDelta();
  223. time += delta * effectController.speed * 0.5;
  224. // marching cubes
  225. if ( effectController.resolution !== resolution ) {
  226. resolution = effectController.resolution;
  227. effect.init( Math.floor( resolution ) );
  228. }
  229. if ( effectController.isolation !== effect.isolation ) {
  230. effect.isolation = effectController.isolation;
  231. }
  232. updateCubes( effect, time, effectController.numBlobs, effectController.floor, effectController.wallx, effectController.wallz );
  233. // render
  234. renderer.render( scene, camera );
  235. }
  236. </script>
  237. </body>
  238. </html>
粤ICP备19079148号