@ccp-nc/crystvis-js
Version:
A Three.js based crystallographic visualisation tool
266 lines (209 loc) • 6.83 kB
JavaScript
'use strict';
/**
* @fileoverview Classes for Atom and Bond primitives
*/
import _ from 'lodash';
import * as THREE from 'three';
import {
unitSphere,
unitCylinder,
unitCircle
} from './geometries.js';
import * as Shaders from '../shaders/index.js';
// Basic materials
const _phong = new THREE.MeshPhongMaterial({
shininess: 30,
specular: 0x666666,
reflectivity: 1,
});
class AtomMesh extends THREE.Mesh {
/**
* Constructor for the AtomMesh object
*
* @param {Array} position Position of the atom
* @param {Number} radius Radius of the atom
* @param {Number} color Color of the atom (hex number)
*/
constructor(position, radius = 1, color = 0xffffff) {
var mat = _phong.clone();
mat.color = new THREE.Color(color);
super(unitSphere, mat);
this.scale.set(radius, radius, radius);
this.position.set(position[0], position[1], position[2]);
this.image = null;
}
get atom_radius() {
return this.geometry.parameters.radius * this.scale.x;
}
set atom_radius(r) {
var s = r / this.geometry.parameters.radius;
this.scale.set(s, s, s);
}
get atom_color() {
return this.material.color.getHex();
}
set atom_color(c) {
this.material.color.set(c);
this.needsUpdate = true;
}
get atom_opacity() {
return this.material.opacity;
}
set atom_opacity(o) {
this.material.transparent = (o < 1);
this.material.opacity = o;
this.needsUpdate = true;
}
}
class BondMesh extends THREE.Group {
/**
* Constructor for the BondMesh object
*
* @param {Array} p0 Position of the first atom
* @param {Array} p1 Position of the second atom
* @param {Number} radius Radius of the bond
* @param {Number} color0 Color of the first atom (hex number)
* @param {Number} color1 Color of the second atom (hex number)
*/
constructor(p0, p1, radius = 1, color0 = 0xff0000, color1 = 0x00ff00) {
super();
p0 = new THREE.Vector3(p0[0], p0[1], p0[2]);
p1 = new THREE.Vector3(p1[0], p1[1], p1[2]);
var dp = p1.clone();
dp.sub(p0);
var l = dp.length();
// Halfpoint?
var hv = p0.clone();
hv.addScaledVector(dp, 0.5);
var rmat = new THREE.Matrix4();
rmat.lookAt(p0, p1, new THREE.Vector3(0, 0, 1));
var mat0 = _phong.clone();
mat0.color = new THREE.Color(color0);
var mat1 = _phong.clone();
mat1.color = new THREE.Color(color1);
var bond0 = new THREE.Mesh(unitCylinder, mat0);
bond0.scale.set(radius, radius, l / 2.0);
bond0.position.copy(p0.clone().addScaledVector(dp, 0.25));
bond0.setRotationFromMatrix(rmat);
var bond1 = new THREE.Mesh(unitCylinder, mat1);
bond1.scale.set(radius, radius, l / 2.0);
bond1.position.copy(p1.clone().addScaledVector(dp, -0.25));
bond1.setRotationFromMatrix(rmat);
this.add(bond0);
this.add(bond1);
}
get bond_radius() {
return this.children[0].geometry.parameters.radiusTop * this.children[0].scale.x;
}
set bond_radius(r) {
var r0 = this.children[0].geometry.parameters.radiusTop;
var s = r / r0;
var z = this.children[0].scale.z;
this.children[0].scale.set(s, s, z);
this.children[1].scale.set(s, s, z);
}
get bond_color_1() {
return this.children[0].material.color.getHex();
}
set bond_color_1(c) {
this.children[0].material.color.set(c);
}
get bond_color_2() {
return this.children[1].material.color.getHex();
}
set bond_color_2(c) {
this.children[1].material.color.set(c);
}
get bond_opacity_1() {
return this.children[0].material.opacity;
}
set bond_opacity_1(o) {
this.children[0].material.transparent = (o < 1);
this.children[0].material.opacity = o;
this.children[0].material.needsUpdate = true;
}
get bond_opacity_2() {
return this.children[1].material.opacity;
}
set bond_opacity_2(o) {
this.children[1].material.transparent = (o < 1);
this.children[1].material.opacity = o;
this.children[1].material.needsUpdate = true;
}
}
class AuraMesh extends THREE.Mesh {
constructor(parameters = {}) {
var defaults = {
scale: 1,
radius: 1,
fill: 0xaaaa00,
border: 0xffff00,
opacity: 0.5,
borderFraction: 0.08
};
parameters = _.merge(defaults, parameters);
var mat = new THREE.RawShaderMaterial({
uniforms: {
targScale: new THREE.Uniform(parameters.scale),
targRadius: new THREE.Uniform(parameters.radius),
fill: new THREE.Uniform(new THREE.Color(parameters.fill)),
border: new THREE.Uniform(new THREE.Color(parameters.border)),
border_f: new THREE.Uniform(parameters.borderFraction),
opacity: new THREE.Uniform(parameters.opacity)
},
side: THREE.DoubleSide,
transparent: true,
vertexShader: Shaders.auraVertShader,
fragmentShader: Shaders.auraFragShader,
glslVersion: THREE.GLSL3
});
super(unitCircle, mat);
}
get scale() {
return this.material.uniforms.targScale.value;
}
set scale(s) {
this.material.uniforms.targScale.value = s;
this.material.uniformsNeedUpdate = true;
}
get radius() {
return this.material.uniforms.targRadius.value;
}
set radius(r) {
this.material.uniforms.targRadius.value = r;
this.material.uniformsNeedUpdate = true;
}
get fill() {
return this.material.uniforms.fill.value.getHex();
}
set fill(c) {
this.material.uniforms.fill.value.set(c);
this.material.uniformsNeedUpdate = true;
}
get border() {
return this.material.uniforms.border.value.getHex();
}
set border(c) {
this.material.uniforms.border.value.set(c);
this.material.uniformsNeedUpdate = true;
}
get borderFraction() {
return this.material.uniforms.border_f.value;
}
set borderFraction(f) {
this.material.uniforms.border_f.value = f;
this.material.uniformsNeedUpdate = true;
}
get opacity() {
return this.material.uniforms.opacity.value;
}
set opacity(o) {
this.material.uniforms.opacity.value = o;
this.material.uniformsNeedUpdate = true;
}
}
export {
AtomMesh,
BondMesh,
AuraMesh
};