webgl_loader_pdb.html 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <title>three.js webgl - molecules</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. <style>
  9. #menu {
  10. position: absolute;
  11. bottom: 20px;
  12. width: 100%;
  13. text-align: center;
  14. padding: 0;
  15. margin: 0;
  16. }
  17. button {
  18. color: rgb(255,255,255);
  19. background: transparent;
  20. border: 0px;
  21. padding: 5px 10px;
  22. cursor: pointer;
  23. }
  24. button:hover {
  25. background-color: rgba(0,255,255,0.5);
  26. }
  27. button:active {
  28. color: #000000;
  29. background-color: rgba(0,255,255,1);
  30. }
  31. .label {
  32. text-shadow: -1px 1px 1px rgb(0,0,0);
  33. margin-left: 25px;
  34. font-size: 20px;
  35. }
  36. </style>
  37. </head>
  38. <body>
  39. <div id="container"></div>
  40. <div id="info"><a href="http://threejs.org" target="_blank" rel="noopener">three.js webgl</a> - molecules</div>
  41. <div id="menu"></div>
  42. <script type="module">
  43. import {
  44. BoxBufferGeometry,
  45. Color,
  46. DirectionalLight,
  47. Group,
  48. IcosahedronBufferGeometry,
  49. Mesh,
  50. MeshPhongMaterial,
  51. PerspectiveCamera,
  52. Scene,
  53. Vector3,
  54. WebGLRenderer,
  55. } from "../build/three.module.js";
  56. import { TrackballControls } from './jsm/controls/TrackballControls.js';
  57. import { PDBLoader } from './jsm/loaders/PDBLoader.js';
  58. import { CSS2DRenderer, CSS2DObject } from './jsm/renderers/CSS2DRenderer.js';
  59. var camera, scene, renderer, labelRenderer;
  60. var controls;
  61. var root;
  62. var MOLECULES = {
  63. "Ethanol": "ethanol.pdb",
  64. "Aspirin": "aspirin.pdb",
  65. "Caffeine": "caffeine.pdb",
  66. "Nicotine": "nicotine.pdb",
  67. "LSD": "lsd.pdb",
  68. "Cocaine": "cocaine.pdb",
  69. "Cholesterol": "cholesterol.pdb",
  70. "Lycopene": "lycopene.pdb",
  71. "Glucose": "glucose.pdb",
  72. "Aluminium oxide": "Al2O3.pdb",
  73. "Cubane": "cubane.pdb",
  74. "Copper": "cu.pdb",
  75. "Fluorite": "caf2.pdb",
  76. "Salt": "nacl.pdb",
  77. "YBCO superconductor": "ybco.pdb",
  78. "Buckyball": "buckyball.pdb",
  79. "Graphite": "graphite.pdb"
  80. };
  81. var loader = new PDBLoader();
  82. var offset = new Vector3();
  83. var menu = document.getElementById( 'menu' );
  84. init();
  85. animate();
  86. function init() {
  87. scene = new Scene();
  88. scene.background = new Color( 0x050505 );
  89. camera = new PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 5000 );
  90. camera.position.z = 1000;
  91. scene.add( camera );
  92. var light = new DirectionalLight( 0xffffff, 0.8 );
  93. light.position.set( 1, 1, 1 );
  94. scene.add( light );
  95. var light = new DirectionalLight( 0xffffff, 0.5 );
  96. light.position.set( - 1, - 1, 1 );
  97. scene.add( light );
  98. root = new Group();
  99. scene.add( root );
  100. //
  101. renderer = new WebGLRenderer( { antialias: true } );
  102. renderer.setPixelRatio( window.devicePixelRatio );
  103. renderer.setSize( window.innerWidth, window.innerHeight );
  104. document.getElementById( 'container' ).appendChild( renderer.domElement );
  105. labelRenderer = new CSS2DRenderer();
  106. labelRenderer.setSize( window.innerWidth, window.innerHeight );
  107. labelRenderer.domElement.style.position = 'absolute';
  108. labelRenderer.domElement.style.top = '0';
  109. labelRenderer.domElement.style.pointerEvents = 'none';
  110. document.getElementById( 'container' ).appendChild( labelRenderer.domElement );
  111. //
  112. controls = new TrackballControls( camera, renderer.domElement );
  113. controls.minDistance = 500;
  114. controls.maxDistance = 2000;
  115. //
  116. loadMolecule( 'models/molecules/caffeine.pdb' );
  117. createMenu();
  118. //
  119. window.addEventListener( 'resize', onWindowResize, false );
  120. }
  121. //
  122. function generateButtonCallback( url ) {
  123. return function () {
  124. loadMolecule( url );
  125. };
  126. }
  127. function createMenu() {
  128. for ( var m in MOLECULES ) {
  129. var button = document.createElement( 'button' );
  130. button.innerHTML = m;
  131. menu.appendChild( button );
  132. var url = 'models/molecules/' + MOLECULES[ m ];
  133. button.addEventListener( 'click', generateButtonCallback( url ), false );
  134. }
  135. }
  136. //
  137. function loadMolecule( url ) {
  138. while ( root.children.length > 0 ) {
  139. var object = root.children[ 0 ];
  140. object.parent.remove( object );
  141. }
  142. loader.load( url, function ( pdb ) {
  143. var geometryAtoms = pdb.geometryAtoms;
  144. var geometryBonds = pdb.geometryBonds;
  145. var json = pdb.json;
  146. var boxGeometry = new BoxBufferGeometry( 1, 1, 1 );
  147. var sphereGeometry = new IcosahedronBufferGeometry( 1, 2 );
  148. geometryAtoms.computeBoundingBox();
  149. geometryAtoms.boundingBox.getCenter( offset ).negate();
  150. geometryAtoms.translate( offset.x, offset.y, offset.z );
  151. geometryBonds.translate( offset.x, offset.y, offset.z );
  152. var positions = geometryAtoms.getAttribute( 'position' );
  153. var colors = geometryAtoms.getAttribute( 'color' );
  154. var position = new Vector3();
  155. var color = new Color();
  156. for ( var i = 0; i < positions.count; i ++ ) {
  157. position.x = positions.getX( i );
  158. position.y = positions.getY( i );
  159. position.z = positions.getZ( i );
  160. color.r = colors.getX( i );
  161. color.g = colors.getY( i );
  162. color.b = colors.getZ( i );
  163. var material = new MeshPhongMaterial( { color: color } );
  164. var object = new Mesh( sphereGeometry, material );
  165. object.position.copy( position );
  166. object.position.multiplyScalar( 75 );
  167. object.scale.multiplyScalar( 25 );
  168. root.add( object );
  169. var atom = json.atoms[ i ];
  170. var text = document.createElement( 'div' );
  171. text.className = 'label';
  172. text.style.color = 'rgb(' + atom[ 3 ][ 0 ] + ',' + atom[ 3 ][ 1 ] + ',' + atom[ 3 ][ 2 ] + ')';
  173. text.textContent = atom[ 4 ];
  174. var label = new CSS2DObject( text );
  175. label.position.copy( object.position );
  176. root.add( label );
  177. }
  178. positions = geometryBonds.getAttribute( 'position' );
  179. var start = new Vector3();
  180. var end = new Vector3();
  181. for ( var i = 0; i < positions.count; i += 2 ) {
  182. start.x = positions.getX( i );
  183. start.y = positions.getY( i );
  184. start.z = positions.getZ( i );
  185. end.x = positions.getX( i + 1 );
  186. end.y = positions.getY( i + 1 );
  187. end.z = positions.getZ( i + 1 );
  188. start.multiplyScalar( 75 );
  189. end.multiplyScalar( 75 );
  190. var object = new Mesh( boxGeometry, new MeshPhongMaterial( 0xffffff ) );
  191. object.position.copy( start );
  192. object.position.lerp( end, 0.5 );
  193. object.scale.set( 5, 5, start.distanceTo( end ) );
  194. object.lookAt( end );
  195. root.add( object );
  196. }
  197. render();
  198. } );
  199. }
  200. //
  201. function onWindowResize() {
  202. camera.aspect = window.innerWidth / window.innerHeight;
  203. camera.updateProjectionMatrix();
  204. renderer.setSize( window.innerWidth, window.innerHeight );
  205. labelRenderer.setSize( window.innerWidth, window.innerHeight );
  206. render();
  207. }
  208. function animate() {
  209. requestAnimationFrame( animate );
  210. controls.update();
  211. var time = Date.now() * 0.0004;
  212. root.rotation.x = time;
  213. root.rotation.y = time * 0.7;
  214. render();
  215. }
  216. function render() {
  217. renderer.render( scene, camera );
  218. labelRenderer.render( scene, camera );
  219. }
  220. </script>
  221. </body>
  222. </html>