scene.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. var scene;
  2. var camera;
  3. var orbitControls;
  4. var texture_loader = new THREE.TextureLoader();
  5. var stl_loader = new THREE.STLLoader();
  6. var objects = new Map();
  7. const None = null;
  8. const False = false;
  9. const True = true;
  10. Vue.component("scene", {
  11. template: `<canvas v-bind:id="jp_props.id"></div>`,
  12. mounted() {
  13. scene = new THREE.Scene();
  14. objects.set("scene", scene);
  15. const width = this.$props.jp_props.options.width;
  16. const height = this.$props.jp_props.options.height;
  17. camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);
  18. camera.up = new THREE.Vector3(0, 0, 1);
  19. camera.position.set(0, -3, 5);
  20. scene.add(new THREE.AmbientLight(0xffffff, 0.7));
  21. const light = new THREE.DirectionalLight(0xffffff, 0.3);
  22. light.position.set(5, 10, 40);
  23. scene.add(light);
  24. const renderer = new THREE.WebGLRenderer({
  25. antialias: true,
  26. alpha: true,
  27. canvas: document.getElementById(this.$props.jp_props.id),
  28. });
  29. renderer.setClearColor("#eee");
  30. renderer.setSize(width, height);
  31. const ground = new THREE.Mesh(
  32. new THREE.PlaneGeometry(100, 100),
  33. new THREE.MeshPhongMaterial({ color: "#eee" })
  34. );
  35. ground.translateZ(-0.01);
  36. ground.object_id = "ground";
  37. scene.add(ground);
  38. const grid = new THREE.GridHelper(100, 100);
  39. grid.material.transparent = true;
  40. grid.material.opacity = 0.2;
  41. grid.rotateX(Math.PI / 2);
  42. scene.add(grid);
  43. orbitControls = new THREE.OrbitControls(camera, renderer.domElement);
  44. const render = function () {
  45. requestAnimationFrame(() => setTimeout(() => render(), 1000 / 20));
  46. renderer.render(scene, camera);
  47. };
  48. render();
  49. const raycaster = new THREE.Raycaster();
  50. const click_handler = (mouseEvent) => {
  51. let x = (mouseEvent.offsetX / renderer.domElement.width) * 2 - 1;
  52. let y = -(mouseEvent.offsetY / renderer.domElement.height) * 2 + 1;
  53. raycaster.setFromCamera({ x: x, y: y }, camera);
  54. const event = {
  55. event_type: "onClick",
  56. vue_type: this.$props.jp_props.vue_type,
  57. id: this.$props.jp_props.id,
  58. page_id: page_id,
  59. websocket_id: websocket_id,
  60. hits: raycaster
  61. .intersectObjects(scene.children, true)
  62. .filter((o) => o.object.object_id)
  63. .map((o) => ({
  64. object_id: o.object.object_id,
  65. point: o.point,
  66. })),
  67. click_type: mouseEvent.type,
  68. shift_key: mouseEvent.shiftKey,
  69. };
  70. send_to_server(event, "event");
  71. };
  72. document.getElementById(this.$props.jp_props.id).onclick = click_handler;
  73. document.getElementById(this.$props.jp_props.id).ondblclick = click_handler;
  74. comp_dict[this.$props.jp_props.id] = this;
  75. const sendConnectEvent = () => {
  76. if (websocket_id === "") return;
  77. const event = {
  78. event_type: "onConnect",
  79. vue_type: this.$props.jp_props.vue_type,
  80. id: this.$props.jp_props.id,
  81. page_id: page_id,
  82. websocket_id: websocket_id,
  83. };
  84. send_to_server(event, "event");
  85. clearInterval(connectInterval);
  86. };
  87. connectInterval = setInterval(sendConnectEvent, 10);
  88. },
  89. updated() {},
  90. methods: {
  91. create(type, id, parent_id, ...args) {
  92. let mesh;
  93. if (type == "group") {
  94. mesh = new THREE.Group();
  95. } else if (type == "line") {
  96. const start = new THREE.Vector3(...args[0]);
  97. const end = new THREE.Vector3(...args[1]);
  98. const geometry = new THREE.BufferGeometry().setFromPoints([start, end]);
  99. const material = new THREE.LineBasicMaterial({ transparent: true });
  100. mesh = new THREE.Line(geometry, material);
  101. } else if (type == "curve") {
  102. const curve = new THREE.CubicBezierCurve3(
  103. new THREE.Vector3(...args[0]),
  104. new THREE.Vector3(...args[1]),
  105. new THREE.Vector3(...args[2]),
  106. new THREE.Vector3(...args[3])
  107. );
  108. const points = curve.getPoints(args[4] - 1);
  109. const geometry = new THREE.BufferGeometry().setFromPoints(points);
  110. const material = new THREE.LineBasicMaterial({ transparent: true });
  111. mesh = new THREE.Line(geometry, material);
  112. } else if (type == "texture") {
  113. const url = args[0];
  114. const coords = args[1];
  115. const geometry = new THREE.BufferGeometry();
  116. const nI = coords[0].length;
  117. const nJ = coords.length;
  118. const vertices = [];
  119. const indices = [];
  120. const uvs = [];
  121. for (let j = 0; j < nJ; ++j) {
  122. for (let i = 0; i < nI; ++i) {
  123. const XYZ = coords[j][i] || [0, 0, 0];
  124. vertices.push(...XYZ);
  125. uvs.push(i / (nI - 1), j / (nJ - 1));
  126. }
  127. }
  128. for (let j = 0; j < nJ - 1; ++j) {
  129. for (let i = 0; i < nI - 1; ++i) {
  130. if (
  131. coords[j][i] &&
  132. coords[j][i + 1] &&
  133. coords[j + 1][i] &&
  134. coords[j + 1][i + 1]
  135. ) {
  136. const idx00 = i + j * nI;
  137. const idx10 = i + j * nI + 1;
  138. const idx01 = i + j * nI + nI;
  139. const idx11 = i + j * nI + 1 + nI;
  140. indices.push(idx00, idx10, idx01);
  141. indices.push(idx10, idx11, idx01);
  142. }
  143. }
  144. }
  145. geometry.setIndex(new THREE.Uint32BufferAttribute(indices, 1));
  146. geometry.setAttribute(
  147. "position",
  148. new THREE.Float32BufferAttribute(vertices, 3)
  149. );
  150. geometry.setAttribute("uv", new THREE.Float32BufferAttribute(uvs, 2));
  151. geometry.computeVertexNormals();
  152. geometry.computeFaceNormals();
  153. const texture = texture_loader.load(url);
  154. texture.flipY = false;
  155. texture.minFilter = THREE.LinearFilter;
  156. const material = new THREE.MeshLambertMaterial({
  157. map: texture,
  158. side: THREE.DoubleSide,
  159. });
  160. mesh = new THREE.Mesh(geometry, material);
  161. } else {
  162. let geometry;
  163. const wireframe = args.pop();
  164. if (type == "box") geometry = new THREE.BoxGeometry(...args);
  165. if (type == "sphere") geometry = new THREE.SphereGeometry(...args);
  166. if (type == "cylinder") geometry = new THREE.CylinderGeometry(...args);
  167. if (type == "extrusion") {
  168. const shape = new THREE.Shape();
  169. const outline = args[0];
  170. const height = args[1];
  171. shape.autoClose = true;
  172. shape.moveTo(outline[0][0], outline[0][1]);
  173. outline.slice(1).forEach((p) => shape.lineTo(p[0], p[1]));
  174. const settings = { depth: height, bevelEnabled: false };
  175. geometry = new THREE.ExtrudeGeometry(shape, settings);
  176. }
  177. if (type == "stl") {
  178. const url = args[0];
  179. geometry = new THREE.BufferGeometry();
  180. stl_loader.load(url, (geometry) => (mesh.geometry = geometry));
  181. }
  182. let material;
  183. if (wireframe) {
  184. mesh = new THREE.LineSegments(
  185. new THREE.EdgesGeometry(geometry),
  186. new THREE.LineBasicMaterial({ transparent: true })
  187. );
  188. } else {
  189. material = new THREE.MeshPhongMaterial({ transparent: true });
  190. mesh = new THREE.Mesh(geometry, material);
  191. }
  192. }
  193. mesh.object_id = id;
  194. objects.set(id, mesh);
  195. objects.get(parent_id).add(objects.get(id));
  196. },
  197. material(object_id, color, opacity) {
  198. const material = objects.get(object_id).material;
  199. if (!material) return;
  200. material.color.set(color);
  201. material.opacity = opacity;
  202. },
  203. move(object_id, x, y, z) {
  204. objects.get(object_id).position.set(x, y, z);
  205. },
  206. scale(object_id, sx, sy, sz) {
  207. objects.get(object_id).scale.set(sx, sy, sz);
  208. },
  209. rotate(object_id, R) {
  210. const R4 = new THREE.Matrix4().makeBasis(
  211. new THREE.Vector3(...R[0]),
  212. new THREE.Vector3(...R[1]),
  213. new THREE.Vector3(...R[2])
  214. );
  215. objects.get(object_id).rotation.setFromRotationMatrix(R4.transpose());
  216. },
  217. delete(object_id) {
  218. objects.get(object_id).removeFromParent();
  219. objects.delete(object_id);
  220. },
  221. },
  222. props: {
  223. jp_props: Object,
  224. },
  225. });