1 | "use strict"; |
---|
2 | import * as THREE from 'three'; |
---|
3 | import Transformations from './transformations'; |
---|
4 | |
---|
5 | /** |
---|
6 | * Helper class for creating meshes for joints in Framsticks-SDK. It combines |
---|
7 | * Framsticks-SDK logic with THREE.js logic. |
---|
8 | * |
---|
9 | * For now shape versions of joints are hard-coded. It may need redefinition in |
---|
10 | * the future. |
---|
11 | */ |
---|
12 | class JointMeshFactory { |
---|
13 | /** |
---|
14 | * Basic constructor that takes information of how joints should be drawn. |
---|
15 | * @param {object} config basic config for joints drawing |
---|
16 | * @param {boolean} physics determines if created objects should by Physijs based |
---|
17 | */ |
---|
18 | constructor(config, physics = false) { |
---|
19 | this.config = config; |
---|
20 | this.transformations = new Transformations(); |
---|
21 | this.jointShapes = this.transformations.getJointShapes(); |
---|
22 | this.physics = physics; |
---|
23 | } |
---|
24 | |
---|
25 | /** |
---|
26 | * Creates Mesh for a given Joint. |
---|
27 | * @param {Module.Joint} joint Framsticks-SDK Joint class object |
---|
28 | * @param {object} shapeConfig object holding following fields |
---|
29 | * @param {number} shapeConfig.radius radius of mesh |
---|
30 | * @param {number} shapeConfig.radiusSegments number of segments for mesh |
---|
31 | * @param {boolean} shapeConfig.isTransparent true if transparent, false otherwise |
---|
32 | * @param {number} shapeConfig.opacity opacity of mesh |
---|
33 | * @returns {Mesh} Mesh for a given joint |
---|
34 | */ |
---|
35 | getNewJointMesh(joint, color, shapeConfig) { |
---|
36 | let firstPartPosVec = new THREE.Vector3( |
---|
37 | joint.get_part1().get_p().get_x(), |
---|
38 | joint.get_part1().get_p().get_y(), |
---|
39 | joint.get_part1().get_p().get_z()); |
---|
40 | let secondPartPosVec = new THREE.Vector3( |
---|
41 | joint.get_part2().get_p().get_x(), |
---|
42 | joint.get_part2().get_p().get_y(), |
---|
43 | joint.get_part2().get_p().get_z()); |
---|
44 | |
---|
45 | let direction = new THREE.Vector3().subVectors(secondPartPosVec, firstPartPosVec); |
---|
46 | let geometry = new THREE.CylinderGeometry(shapeConfig.radius, shapeConfig.radius, direction.length() - 2 * 0.18, shapeConfig.radiusSegments); |
---|
47 | let material = this.transformations.getNewMaterial(color); |
---|
48 | let mesh = new THREE.Mesh( geometry, material ); //new Physijs.CylinderMesh( geometry, Physijs.createMaterial(material) ); //new THREE.Mesh( geometry, material ); |
---|
49 | |
---|
50 | let orientation = new THREE.Matrix4(); |
---|
51 | orientation.lookAt(firstPartPosVec, secondPartPosVec, new THREE.Object3D().up); |
---|
52 | orientation.multiply(new THREE.Matrix4().set( |
---|
53 | 1, 0, 0, 0, |
---|
54 | 0, 0, 1, 0, |
---|
55 | 0, -1, 0, 0, |
---|
56 | 0, 0, 0, 1 |
---|
57 | )); |
---|
58 | |
---|
59 | mesh.applyMatrix(orientation); |
---|
60 | mesh.position.x = (secondPartPosVec.x + firstPartPosVec.x) / 2; |
---|
61 | mesh.position.y = (secondPartPosVec.y + firstPartPosVec.y) / 2; |
---|
62 | mesh.position.z = (secondPartPosVec.z + firstPartPosVec.z) / 2; |
---|
63 | |
---|
64 | |
---|
65 | mesh.userData = { |
---|
66 | isBodyElement: true, |
---|
67 | type: 'j', |
---|
68 | data: joint, |
---|
69 | mesh: mesh, |
---|
70 | connectedParts: [], |
---|
71 | showTransparent: true |
---|
72 | }; |
---|
73 | return mesh; |
---|
74 | } |
---|
75 | |
---|
76 | /** |
---|
77 | * Method finds for a given jointMesh all attached partMeshes and updates |
---|
78 | * respectively for those objects their connectedParts and connectedJoints |
---|
79 | * fields. |
---|
80 | * @param {JointMesh} jointMesh joint for which attached parts will be searched |
---|
81 | * @param {PartMesh} partMeshes list of available parts |
---|
82 | */ |
---|
83 | addConnectionInfo(jointMesh, partMeshes) { |
---|
84 | let p1 = jointMesh.data.get_part1(); |
---|
85 | let p2 = jointMesh.data.get_part2(); |
---|
86 | let count = 0; |
---|
87 | for (let i = 0; i < partMeshes.length && count < 2; ++i) { |
---|
88 | if (partMeshes[i].data === p1 || partMeshes[i].data === p2) { |
---|
89 | jointMesh.connectedParts.push(partMeshes[i]); |
---|
90 | partMeshes[i].connectedJoints.push(jointMesh); |
---|
91 | ++count; |
---|
92 | } |
---|
93 | } |
---|
94 | } |
---|
95 | |
---|
96 | /** |
---|
97 | * Creates mesh for a given Joint. Additional parameter partMeshes is |
---|
98 | * provided to update both Joint and connected Parts with info about |
---|
99 | * their connectivity. |
---|
100 | * @param {Module.Joint} joint joint for which mesh is created |
---|
101 | * @param {PartMesh} partMeshes list of available parts |
---|
102 | * @returns {JointMesh} new joint mesh, for properties of Object look at addConnectionInfo jointMesh param documentation |
---|
103 | */ |
---|
104 | create(joint, color, partMeshes) { |
---|
105 | let result; |
---|
106 | let shape = joint.get_shape(); |
---|
107 | |
---|
108 | if (this.jointShapes['SHAPE_FIXED'].value == shape) { |
---|
109 | result = this.getNewJointMesh(joint, color, this.config.linkShape); |
---|
110 | } else { |
---|
111 | result = this.getNewJointMesh(joint, color, this.config.cylinderShape); |
---|
112 | } |
---|
113 | |
---|
114 | if (partMeshes) { |
---|
115 | this.addConnectionInfo(result.userData, partMeshes); |
---|
116 | } |
---|
117 | |
---|
118 | return result; |
---|
119 | } |
---|
120 | } |
---|
121 | |
---|
122 | export default JointMeshFactory; |
---|