Three.js导入PDB格式的模型代码教程
程序员文章站
2022-04-03 20:21:35
简介
PDB是一种非常特殊的格式,由Protein Data Bank(蛋白质数据银行)创建,用于定义蛋白质的形状。蛋白质数据银行(www.rcsb.org)包含了很多分子和蛋白...
简介
PDB是一种非常特殊的格式,由Protein Data Bank(蛋白质数据银行)创建,用于定义蛋白质的形状。蛋白质数据银行(www.rcsb.org)包含了很多分子和蛋白质的详细信息,还可以用PDB格式下载这些分子的数据结构。在Three.js中有一种加载器可以加载PDB格式的文件。
实现案例
首先,引入script加载器,在这里需要再引入CSS2DRenderer渲染器来绘制每个原子的名称。
<script src="/lib/js/renderers/CSS2DRenderer.js"></script> <script src="/lib/js/loaders/PDBLoader.js"></script>
然后,我们实例化一个THREE.PDBLoader对象,将想要加载的模型文件传递给它,还提供了一个回调函数,该函数会在模型加载完成之后调用。在返回的对象里面,我们可以获得geometryAtoms原子的数据,geometryBonds原子之间的键的数据,和json每个原子名称的数据。
var loader = new THREE.PDBLoader(); loader.load("/lib/models/molecules/caffeine.pdb", function (pdb) { //创建一个模型组 var root = new THREE.Group(); var offset = new THREE.Vector3(); //获取到原子相关的数据 var geometryAtoms = pdb.geometryAtoms; //获取到原子间的键的数据 var geometryBonds = pdb.geometryBonds; //获取原子文字的数据 var json = pdb.json; var boxGeometry = new THREE.BoxBufferGeometry( 1, 1, 1 ); var sphereGeometry = new THREE.IcosahedronBufferGeometry( 1, 2 ); //让模型居中 geometryAtoms.computeBoundingBox(); geometryAtoms.boundingBox.getCenter( offset ).negate(); geometryAtoms.translate( offset.x, offset.y, offset.z ); geometryBonds.translate( offset.x, offset.y, offset.z ); //将原子和原子的文字添加到模型组当中 var positions = geometryAtoms.getAttribute( 'position' ); var colors = geometryAtoms.getAttribute( 'color' ); var position = new THREE.Vector3(); var color = new THREE.Color(); for ( var i = 0; i < positions.count; i ++ ) { position.x = positions.getX( i ); position.y = positions.getY( i ); position.z = positions.getZ( i ); color.r = colors.getX( i ); color.g = colors.getY( i ); color.b = colors.getZ( i ); var material = new THREE.MeshPhongMaterial( { color: color } ); var object = new THREE.Mesh( sphereGeometry, material ); object.position.copy( position ); object.position.multiplyScalar( 75 ); object.scale.multiplyScalar( 25 ); root.add( object ); var atom = json.atoms[ i ]; var text = document.createElement( 'p' ); text.className = 'label'; text.style.color = 'rgb(' + atom[ 3 ][ 0 ] + ',' + atom[ 3 ][ 1 ] + ',' + atom[ 3 ][ 2 ] + ')'; text.style.textShadow = "1px 1px 1px #000"; text.textContent = atom[ 4 ]; var label = new THREE.CSS2DObject( text ); label.position.copy( object.position ); root.add( label ); } //将原子之间的键添加到模型组当中 positions = geometryBonds.getAttribute( 'position' ); var start = new THREE.Vector3(); var end = new THREE.Vector3(); for ( var i = 0; i < positions.count; i += 2 ) { start.x = positions.getX( i ); start.y = positions.getY( i ); start.z = positions.getZ( i ); end.x = positions.getX( i + 1 ); end.y = positions.getY( i + 1 ); end.z = positions.getZ( i + 1 ); start.multiplyScalar( 75 ); end.multiplyScalar( 75 ); var object = new THREE.Mesh( boxGeometry, new THREE.MeshPhongMaterial( 0xffffff ) ); object.position.copy( start ); object.position.lerp( end, 0.5 ); object.scale.set( 5, 5, start.distanceTo( end ) ); object.lookAt( end ); root.add( object ); } //缩放并将模型组添加到场景当中 root.scale.set(0.1, 0.1, 0.1); scene.add(root); }); }
案例代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style type="text/css"> html, body { margin: 0; height: 100%; } canvas { display: block; } </style> </head> <body onload="draw();"> </body> <script src="/lib/three.js"></script> <script src="/lib/js/renderers/CSS2DRenderer.js"></script> <script src="/lib/js/loaders/PDBLoader.js"></script> <script src="/lib/js/controls/OrbitControls.js"></script> <script src="/lib/js/libs/stats.min.js"></script> <script src="/lib/js/libs/dat.gui.min.js"></script> <script src="/lib/js/Detector.js"></script> <script> var renderer,labelRenderer; function initRender() { renderer = new THREE.WebGLRenderer({antialias:true}); renderer.setSize(window.innerWidth, window.innerHeight); //告诉渲染器需要阴影效果 renderer.setClearColor(0x000000); document.body.appendChild(renderer.domElement); //实例化css2dRenderer labelRenderer = new THREE.CSS2DRenderer(); labelRenderer.setSize( window.innerWidth, window.innerHeight ); labelRenderer.domElement.style.position = 'absolute'; labelRenderer.domElement.style.top = '0'; labelRenderer.domElement.style.pointerEvents = 'none'; document.body.appendChild( labelRenderer.domElement ); } var camera; function initCamera() { camera = new THREE.PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 1000); camera.position.set(0, 40, 50); camera.lookAt(new THREE.Vector3(0,0,0)); } var scene; function initScene() { scene = new THREE.Scene(); } //初始化dat.GUI简化试验流程 var gui; function initGui() { //声明一个保存需求修改的相关数据的对象 gui = { }; var datGui = new dat.GUI(); //将设置属性添加到gui当中,gui.add(对象,属性,最小值,最大值) } var light; function initLight() { scene.add(new THREE.AmbientLight(0x444444)); light = new THREE.DirectionalLight(0xffffff); light.position.set(200, 200, 100); //告诉平行光需要开启阴影投射 light.castShadow = true; scene.add(light); } function initModel() { //辅助工具 var helper = new THREE.AxesHelper(50); scene.add(helper); var loader = new THREE.PDBLoader(); loader.load("/lib/models/molecules/caffeine.pdb", function (pdb) { //创建一个模型组 var root = new THREE.Group(); var offset = new THREE.Vector3(); //获取到原子相关的数据 var geometryAtoms = pdb.geometryAtoms; //获取到原子间的键的数据 var geometryBonds = pdb.geometryBonds; //获取原子文字的数据 var json = pdb.json; var boxGeometry = new THREE.BoxBufferGeometry( 1, 1, 1 ); var sphereGeometry = new THREE.IcosahedronBufferGeometry( 1, 2 ); //让模型居中 geometryAtoms.computeBoundingBox(); geometryAtoms.boundingBox.getCenter( offset ).negate(); geometryAtoms.translate( offset.x, offset.y, offset.z ); geometryBonds.translate( offset.x, offset.y, offset.z ); //将原子和原子的文字添加到模型组当中 var positions = geometryAtoms.getAttribute( 'position' ); var colors = geometryAtoms.getAttribute( 'color' ); var position = new THREE.Vector3(); var color = new THREE.Color(); for ( var i = 0; i < positions.count; i ++ ) { position.x = positions.getX( i ); position.y = positions.getY( i ); position.z = positions.getZ( i ); color.r = colors.getX( i ); color.g = colors.getY( i ); color.b = colors.getZ( i ); var material = new THREE.MeshPhongMaterial( { color: color } ); var object = new THREE.Mesh( sphereGeometry, material ); object.position.copy( position ); object.position.multiplyScalar( 75 ); object.scale.multiplyScalar( 25 ); root.add( object ); var atom = json.atoms[ i ]; var text = document.createElement( 'p' ); text.className = 'label'; text.style.color = 'rgb(' + atom[ 3 ][ 0 ] + ',' + atom[ 3 ][ 1 ] + ',' + atom[ 3 ][ 2 ] + ')'; text.style.textShadow = "1px 1px 1px #000"; text.textContent = atom[ 4 ]; var label = new THREE.CSS2DObject( text ); label.position.copy( object.position ); root.add( label ); } //将原子之间的键添加到模型组当中 positions = geometryBonds.getAttribute( 'position' ); var start = new THREE.Vector3(); var end = new THREE.Vector3(); for ( var i = 0; i < positions.count; i += 2 ) { start.x = positions.getX( i ); start.y = positions.getY( i ); start.z = positions.getZ( i ); end.x = positions.getX( i + 1 ); end.y = positions.getY( i + 1 ); end.z = positions.getZ( i + 1 ); start.multiplyScalar( 75 ); end.multiplyScalar( 75 ); var object = new THREE.Mesh( boxGeometry, new THREE.MeshPhongMaterial( 0xffffff ) ); object.position.copy( start ); object.position.lerp( end, 0.5 ); object.scale.set( 5, 5, start.distanceTo( end ) ); object.lookAt( end ); root.add( object ); } //缩放并将模型组添加到场景当中 root.scale.set(0.1, 0.1, 0.1); scene.add(root); }); } //初始化性能插件 var stats; function initStats() { stats = new Stats(); document.body.appendChild(stats.dom); } //用户交互插件 鼠标左键按住旋转,右键按住平移,滚轮缩放 var controls; function initControls() { controls = new THREE.OrbitControls( camera, renderer.domElement ); // 如果使用animate方法时,将此函数删除 //controls.addEventListener( 'change', render ); // 使动画循环使用时阻尼或自转 意思是否有惯性 controls.enableDamping = true; //动态阻尼系数 就是鼠标拖拽旋转灵敏度 //controls.dampingFactor = 0.25; //是否可以缩放 controls.enableZoom = true; //是否自动旋转 controls.autoRotate = true; controls.autoRotateSpeed = 0.5; //设置相机距离原点的最远距离 controls.minDistance = 1; //设置相机距离原点的最远距离 controls.maxDistance = 200; //是否开启右键拖拽 controls.enablePan = true; } function render() { renderer.render( scene, camera ); labelRenderer.render( scene, camera ); } //窗口变动触发的函数 function onWindowResize() { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); render(); renderer.setSize( window.innerWidth, window.innerHeight ); } function animate() { //更新控制器 render(); //更新性能插件 stats.update(); controls.update(); requestAnimationFrame(animate); } function draw() { //兼容性判断 if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); initGui(); initRender(); initScene(); initCamera(); initControls(); initLight(); initModel(); initStats(); animate(); window.onresize = onWindowResize; } </script> </html>
上一篇: 他还挺懂浪漫的
下一篇: linux ssh安全加固方法