WebGL 3D分子可视化入门

WebGL是一种在浏览器中实现图形处理代码的JavaScript接口,它允许浏览器利用GPU进行图形渲染。本文旨在测试使用WebGL进行编程的难度,并尝试创建一个基于JavaScript和WebGL的分子查看器。令人惊讶的是,这个过程相对简单!

虽然WebGL与OpenGL在概念和格式上有许多相似之处,但WebGL是专为Web浏览器设计的,可以直接在网页上渲染3D图形。本文将介绍如何使用WebGL创建一个简单的分子查看器,用于查看PDB(蛋白质数据银行)文件中的分子结构。

使用代码

要使用本文提供的代码,首先需要将其安装在Web服务器上,无论是本地还是远程服务器。然后访问index.html页面,点击“选择文件”按钮,选择本地计算机上的PDB文件,即可查看分子模型。

以下是一些基本的操作键:

  • A:沿-X轴移动
  • W:沿+Y轴移动
  • S:沿-Y轴移动
  • D:沿+X轴移动
  • 左箭头:沿-X轴移动
  • 右箭头:沿+X轴移动
  • 下箭头:沿+Z轴移动
  • 上箭头:沿-Z轴移动
  • Shift+A:向左倾斜
  • Shift+W:向上看
  • Shift+S:向下看
  • Shift+D:向右倾斜
  • Shift+左箭头:向左旋转
  • Shift+右箭头:向右旋转
  • Shift+下箭头:向下看
  • Shift+上箭头:向上看
  • 鼠标左键拖动:绕X轴旋转
  • 鼠标右键拖动:绕X轴旋转
  • 鼠标上键拖动:绕Y轴旋转
  • 鼠标下键拖动:绕Y轴旋转
  • 鼠标滚轮向前:放大
  • 鼠标滚轮向后:缩小

示例PDB文件

以下是一个简单的PDB文件示例,展示了丙烷的分子结构:

COMPND PROPANE AUTHOR DAVE WOODCOCK 95 12 18 ATOM 1 C 1 1.241 0.444 0.349 1.00 0.00 ATOM 2 C 1 -0.011 -0.441 0.333 1.00 0.00 ATOM 3 C 1 -1.176 0.296 -0.332 1.00 0.00 ATOM 4 H 1 1.516 0.699 -0.675 1.00 0.00 ATOM 5 H 1 2.058 -0.099 0.827 1.00 0.00 ATOM 6 H 1 1.035 1.354 0.913 1.00 0.00 ATOM 7 H 1 -0.283 -0.691 1.359 1.00 0.00 ATOM 8 H 1 0.204 -1.354 -0.225 1.00 0.00 ATOM 9 H 1 -0.914 0.551 -1.359 1.00 0.00 ATOM 10 H 1 -1.396 1.211 0.219 1.00 0.00 ATOM 11 H 1 -2.058 -0.345 -0.332 1.00 0.00 TER 12 1 END

解析PDB文件

首先,需要选择一个文件并解析文件中的ATOM条目。使用文件输入按钮的onclick操作符来选择文件。接下来,设置一个FileReader对象并解析文件。一旦有了文件内容,调用以下代码将文件分割成行:

var lines = contents.split("\n");

接下来,需要遍历这些行,使用空格将它们分割成一个数组。然后,创建一个数组来保存ATOM对象,并用行条目填充它。在分割行时,会有一些空白数组条目,所以需要遍历行并只复制想要的值。另外,有些行的空格比其他行多,所以不能使用固定位置。因此,只复制所有非空值。这个过程如下所示:

for (var y = 0; y < singleLine.length; y++) { if (singleLine[y] != "" && singleLine[y] != ",") { objects[object_count][counter++] = singleLine[y]; } }

绘制原子

接下来,需要遍历数组,找到原子并绘制它们。注意,并没有预先将原子分开,而是复制了所有非空值。所以现在需要找到想要绘制的ATOM结构。从上面的文件格式中,可以看到每个原子的x、y、z坐标分别在第5、6、7列。代码如下所示:

for (var i = 0; i < object_count; ++i) { if (objects[i][0] == "ATOM") { if (!setcamera) { g.perspectiveMatrix.lookat(0, 0, objects[i][7], 0, 0, 0, 0, 1, 0); setcamera = true; } drawOne(ctx, 30, objects[i][5], objects[i][6], objects[i][7], 0.75, molTexture); } }

设置相机和对象位置

接下来,需要设置相机和对象的正确位置。为此,使用一个模型-视图矩阵,并将其设置为通过相机进行平移和旋转,然后再次通过正在绘制的原子进行平移。代码如下所示:

var pos = controller.getPosition(); mvMatrix.translate(pos[0], pos[1], pos[2]); mvMatrix.rotate(controller.getRoll(), 1, 0, 0); mvMatrix.rotate(controller.getYaw(), 0, 1, 0); mvMatrix.rotate(controller.getPitch(), 0, 0, 1); mvMatrix.translate(-x, -y, -z);

绘制原子

现在有了绘制原子的位置矩阵,可以在任何最终投影之后绘制原子:

ctx.bindTexture(ctx.TEXTURE_2D, texture); ctx.drawElements(ctx.TRIANGLES, g.sphere.numIndices, ctx.UNSIGNED_SHORT, 0);

移动相机

最后,需要使用键来移动相机:

function keyCamera(event) { var cam = controller; if (event.shiftKey) { switch (event.keyCode) { case 65: cam.roll(-Math.PI * 0.25); break; case 37: cam.yaw(Math.PI * 0.25); break; case 68: cam.roll(Math.PI * 0.25); break; case 39: cam.yaw(-Math.PI * 0.25); break; case 83: case 40: cam.pitch(Math.PI * 0.25); break; case 87: case 38: cam.pitch(-Math.PI * 0.25); break; } } else { var pos = cam.getPosition(); switch (event.keyCode) { case 65: case 37: cam.setPosition(pos[0] - 0.5, pos[1], pos[2]); break; case 68: case 39: cam.setPosition(pos[0] + 0.5, pos[1], pos[2]); break; case 83: cam.setPosition(pos[0], pos[1] - 0.5, pos[2]); break; case 40: cam.setPosition(pos[0], pos[1], pos[2] + 0.5); break; case 87: cam.setPosition(pos[0], pos[1] + 0.5, pos[2]); break; case 38: cam.setPosition(pos[0], pos[1], pos[2] - 0.5); break; } } }

初始化WebGL

使用以下代码初始化WebGL

var gl = initWebGL("molview"); if (!gl) { return; } var c = document.getElementById("molview"); c.addEventListener('webglcontextlost', handleContextLost, false); c.addEventListener('webglcontextrestored', handleContextRestored, false); g.program = simpleSetup(gl, "vshader", "fshader", ["vNormal", "vTexCoord", "vPosition"], [0, 0, 0, 1], 10000); gl.uniform3f(gl.getUniformLocation(g.program, "lightDir"), 0, 0, 1); gl.uniform1i(gl.getUniformLocation(g.program, "sampler2d"), 0); if (g.program) { g.u_normalMatrixLoc = gl.getUniformLocation(g.program, "u_normalMatrix"); g.u_modelViewProjMatrixLoc = gl.getUniformLocation(g.program, "u_modelViewProjMatrix"); } g.sphere = makeSphere(gl, 1, 30, 30); molTexture = loadImageTexture(gl, "./h1.jpg");

相机实现

最后,只需要实现一个跟踪位置和旋转的相机,然后就可以开始了。相机的代码太多,无法在这里发布,所以有兴趣的读者可以查看附加的源代码。已经省略了一些功能,以保持简洁。附加的代码包含了所有需要的内容和几个PDB文件样本。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485