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, 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 | //let line = new THREE.LineCurve3(firstPartPosVec, secondPartPosVec); |
---|
45 | //let geometry = new THREE.TubeGeometry(line, numsegmentstube, shapeConfig.radius, |
---|
46 | // shapeConfig.radiusSegments, false); |
---|
47 | |
---|
48 | let direction = new THREE.Vector3().subVectors(secondPartPosVec, firstPartPosVec); |
---|
49 | let orientation = new THREE.Matrix4(); |
---|
50 | |
---|
51 | let geometry = new THREE.CylinderGeometry(shapeConfig.radius, shapeConfig.radius, direction.length(), shapeConfig.radiusSegments); |
---|
52 | |
---|
53 | |
---|
54 | let material = this.transformations.getNewMaterial( |
---|
55 | joint.get_vcolor().get_x(), |
---|
56 | joint.get_vcolor().get_y(), |
---|
57 | joint.get_vcolor().get_z()); |
---|
58 | material.transparent = shapeConfig.isTransparent; |
---|
59 | material.opacity = shapeConfig.opacity; |
---|
60 | //let mesh = new THREE.Mesh(geometry, material); |
---|
61 | |
---|
62 | let mesh = new THREE.Mesh( geometry, material ); //new Physijs.CylinderMesh( geometry, Physijs.createMaterial(material) ); //new THREE.Mesh( geometry, material ); |
---|
63 | |
---|
64 | orientation.lookAt(firstPartPosVec, secondPartPosVec, new THREE.Object3D().up); |
---|
65 | orientation.multiply(new THREE.Matrix4().set( |
---|
66 | 1, 0, 0, 0, |
---|
67 | 0, 0, 1, 0, |
---|
68 | 0, -1, 0, 0, |
---|
69 | 0, 0, 0, 1 |
---|
70 | )); |
---|
71 | |
---|
72 | mesh.applyMatrix(orientation); |
---|
73 | mesh.position.x = (secondPartPosVec.x + firstPartPosVec.x) / 2; |
---|
74 | mesh.position.y = (secondPartPosVec.y + firstPartPosVec.y) / 2; |
---|
75 | mesh.position.z = (secondPartPosVec.z + firstPartPosVec.z) / 2; |
---|
76 | |
---|
77 | |
---|
78 | mesh.userData = { |
---|
79 | isBodyElement: true, |
---|
80 | type: 'j', |
---|
81 | data: joint, |
---|
82 | mesh: mesh, |
---|
83 | connectedParts: [], |
---|
84 | showTransparent: shapeConfig.isTransparent |
---|
85 | }; |
---|
86 | return mesh; |
---|
87 | } |
---|
88 | |
---|
89 | /** |
---|
90 | * Method finds for a given jointMesh all attached partMeshes and updates |
---|
91 | * respectively for those objects their connectedParts and connectedJoints |
---|
92 | * fields. |
---|
93 | * @param {JointMesh} jointMesh joint for which attached parts will be searched |
---|
94 | * @param {PartMesh} partMeshes list of available parts |
---|
95 | */ |
---|
96 | addConnectionInfo(jointMesh, partMeshes) { |
---|
97 | let p1 = jointMesh.data.get_part1(); |
---|
98 | let p2 = jointMesh.data.get_part2(); |
---|
99 | let count = 0; |
---|
100 | for (let i = 0; i < partMeshes.length && count < 2; ++i) { |
---|
101 | if (partMeshes[i].data === p1 || partMeshes[i].data === p2) { |
---|
102 | jointMesh.connectedParts.push(partMeshes[i]); |
---|
103 | partMeshes[i].connectedJoints.push(jointMesh); |
---|
104 | ++count; |
---|
105 | } |
---|
106 | } |
---|
107 | } |
---|
108 | |
---|
109 | /** |
---|
110 | * Creates mesh for a given Joint. Additional parameter partMeshes is |
---|
111 | * provided to update both Joint and connected Parts with info about |
---|
112 | * their connectivity. |
---|
113 | * @param {Module.Joint} joint joint for which mesh is created |
---|
114 | * @param {PartMesh} partMeshes list of available parts |
---|
115 | * @returns {JointMesh} new joint mesh, for properties of Object look at addConnectionInfo jointMesh param documentation |
---|
116 | */ |
---|
117 | create(joint, partMeshes) { |
---|
118 | let result; |
---|
119 | let shape = joint.get_shape(); |
---|
120 | |
---|
121 | if (this.jointShapes['SHAPE_FIXED'].value == shape) { |
---|
122 | result = this.getNewJointMesh(joint, this.config.linkShape); |
---|
123 | } else { |
---|
124 | result = this.getNewJointMesh(joint, this.config.cylinderShape); |
---|
125 | } |
---|
126 | |
---|
127 | if (partMeshes) { |
---|
128 | this.addConnectionInfo(result.userData, partMeshes); |
---|
129 | } |
---|
130 | |
---|
131 | return result; |
---|
132 | } |
---|
133 | } |
---|
134 | |
---|
135 | export default JointMeshFactory; |
---|