tela.js 1.0.5 → 1.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -21,37 +21,31 @@ Playground usage:
21
21
  ```html
22
22
  <!DOCTYPE html>
23
23
  <html lang="en">
24
-
25
24
  <head>
26
25
  </head>
27
-
28
26
  <body>
29
-
30
27
  </body>
31
28
  <script type="module">
32
- import { Canvas, Animation, Color } from "https://cdn.jsdelivr.net/npm/tela.js/dist/web/index.js";
29
+ import { Canvas, Color, loop } from "https://cdn.jsdelivr.net/npm/tela.js/src/index.js";
33
30
 
34
31
  // You can also import from local file
35
- // import { Canvas, Animation, Color} from "./node_modules/tela.js/dist/web/index.js";
32
+ // import { Canvas, Color, loop } from "./node_modules/tela.js/src/index.js";
36
33
 
37
34
  const width = 640;
38
35
  const height = 480;
39
36
  const canvas = Canvas.ofSize(640, 480);
40
- Animation
41
- .loop(({ time, dt }) => {
42
- document.title = `FPS: ${(Math.floor(1 / dt))}`;
43
- canvas.map((x, y) => {
44
- return Color.ofRGB(
45
- ((x * time) / width) % 1,
46
- ((y * time) / height) % 1
47
- )
48
- })
37
+ loop(({ time, dt }) => {
38
+ document.title = `FPS: ${(Math.floor(1 / dt))}`;
39
+ canvas.map((x, y) => {
40
+ return Color.ofRGB(
41
+ ((x * time) / width) % 1,
42
+ ((y * time) / height) % 1
43
+ )
49
44
  })
50
- .play();
45
+ }).play();
51
46
  document.body.appendChild(canvas.DOM);
52
47
 
53
48
  </script>
54
-
55
49
  </html>
56
50
  ```
57
51
 
@@ -59,23 +53,21 @@ Playground usage:
59
53
  Install `tela.js` it using `npm install tela.js` / `bun add tela.js`.
60
54
 
61
55
  ```js
62
- import { Animation, Color } from "tela.js/dist/node/index.js";
63
- import Window from "tela.js/src/Tela/Window.js";
56
+ import { loop, Color, Window} from "tela.js/src/index.node.js";
64
57
 
65
58
  const width = 640;
66
59
  const height = 480;
67
60
  const window = Window.ofSize(640, 480);
68
- Animation
69
- .loop(({ time, dt }) => {
70
- window.setTitle(`FPS: ${Math.floor(1 / dt)}`);
71
- window.map((x, y) => {
72
- return Color.ofRGB(
73
- ((x * time) / width) % 1,
74
- ((y * time) / height) % 1
75
- )
76
- })
61
+ loop(({ time, dt }) => {
62
+ window.setTitle(`FPS: ${Math.floor(1 / dt)}`);
63
+ window.map((x, y) => {
64
+ return Color.ofRGB(
65
+ ((x * time) / width) % 1,
66
+ ((y * time) / height) % 1
67
+ )
77
68
  })
78
- .play();
69
+ })
70
+ .play();
79
71
  ```
80
72
 
81
73
  And run it: `node index.mjs` / `bun index.js`
@@ -90,7 +82,7 @@ Install `tela.js` it using `npm install tela.js` / `bun add tela.js`.
90
82
  Create a file:
91
83
  ```js
92
84
  // index.js
93
- import { Color, video } from "tela.js/dist/node/index.js";
85
+ import { Color, video } from "tela.js/src/index.node.js";
94
86
 
95
87
  const width = 640;
96
88
  const height = 480;
@@ -111,7 +103,7 @@ video(
111
103
  animation,
112
104
  { width, height, FPS }
113
105
  )
114
- .until(({ time }) => time < maxVideoTime);
106
+ .while(({ time }) => time < maxVideoTime);
115
107
  ```
116
108
 
117
109
  And run it: `node index.mjs` / `bun index.js`
@@ -143,6 +135,13 @@ You can find more examples of usage in:
143
135
  [Node][node] is preferred when running the demos (it is faster, [opened a bug in bun](https://github.com/oven-sh/bun/issues/9218)), [bun][bun] is needed to build the library.
144
136
 
145
137
 
138
+ # TODOs
139
+
140
+ - Fix parallel ray trace refresh bug
141
+ - Parallel ray map
142
+ - Serialize meshes not only triangles
143
+ - Optimize data serialization in parallel ray tracer
144
+
146
145
 
147
146
  [ffmpeg]: https://ffmpeg.org/
148
147
  [bun]: https://bun.sh/
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tela.js",
3
- "version": "1.0.5",
3
+ "version": "1.1.2",
4
4
  "author": "Pedroth",
5
5
  "repository": {
6
6
  "type": "git",
@@ -37,11 +37,9 @@
37
37
  ],
38
38
  "license": "Apache-2.0",
39
39
  "scripts": {
40
- "build": "bun run clean; bun i; bun bundle.js",
41
- "buildDev": "bun bundle.js --watch",
42
40
  "serve": "bunx http-server",
43
- "clean": "rm -fr node_modules; rm -fr dist/; rm *.png *.jpeg *.ppm *.webm *.mp4",
44
- "pub": "npm version patch; bun run build; npm publish"
41
+ "clean": "rm -fr node_modules; rm *.png *.jpeg *.ppm *.webm *.mp4",
42
+ "pub": "npm version patch; npm publish"
45
43
  },
46
44
  "type": "module"
47
45
  }
@@ -1,29 +1,22 @@
1
- import { Vec2, Vec3 } from "../Vector/Vector.js"
1
+ import Vec, { Vec2, Vec3 } from "../Vector/Vector.js"
2
2
  import Ray from "../Ray/Ray.js";
3
- import { rayTrace } from "./raytrace.js";
3
+ import { getRayTracer } from "./rayTrace.js";
4
4
  import { rasterGraphics } from "./raster.js";
5
5
  import { sdfTrace } from "./sdf.js";
6
6
  import { normalTrace } from "./normal.js";
7
-
8
-
7
+ import { parallelWorkers } from "./parallel.js";
9
8
 
10
9
  export default class Camera {
11
10
  constructor(props = {}) {
12
- const { lookAt, distanceToPlane, position } = props;
11
+ const { lookAt, distanceToPlane, position, orientCoords, orbitCoords } = props;
13
12
  this.lookAt = lookAt ?? Vec3(0, 0, 0);
14
13
  this.distanceToPlane = distanceToPlane ?? 1;
15
14
  this.position = position ?? Vec3(3, 0, 0);
16
- this._orientCoords = Vec2();
17
- this._orbitCoords = Vec3(this.position.length(), 0, 0);
18
- this.orient();
19
- }
20
-
21
- clone() {
22
- return new Camera({
23
- lookAt: this.lookAt,
24
- position: this.position,
25
- distanceToPlane: this.distanceToPlane,
26
- })
15
+ this._orientCoords = orientCoords ?? Vec2();
16
+ this._orbitCoords = orbitCoords;
17
+ if (this._orbitCoords) this.orbit(...this._orbitCoords.toArray());
18
+ else this.orient(...this._orientCoords.toArray());
19
+ this._orbitCoords = this._orbitCoords ?? Vec3(this.position.length());
27
20
  }
28
21
 
29
22
  look(at, up = Vec3(0, 0, 1)) {
@@ -91,11 +84,13 @@ export default class Camera {
91
84
  return {
92
85
  to: canvas => {
93
86
  const w = canvas.width;
87
+ const invW = 1 / w;
94
88
  const h = canvas.height;
89
+ const invH = 1 / h;
95
90
  const ans = canvas.map((x, y) => {
96
91
  const dirInLocal = [
97
- (x / w - 0.5),
98
- (y / h - 0.5),
92
+ (x * invW - 0.5),
93
+ (y * invH - 0.5),
99
94
  this.distanceToPlane
100
95
  ]
101
96
  const dir = Vec3(
@@ -112,11 +107,11 @@ export default class Camera {
112
107
  }
113
108
  }
114
109
 
115
- sceneShot(scene, params = {}) {
116
- return this.rayMap(rayTrace(scene, params));
110
+ sceneShot(scene, params) {
111
+ return this.rayMap(getRayTracer(scene, params));
117
112
  }
118
113
 
119
- reverseShot(scene, params = {}) {
114
+ reverseShot(scene, params) {
120
115
  return {
121
116
  to: rasterGraphics(scene, this, params)
122
117
  }
@@ -130,6 +125,18 @@ export default class Camera {
130
125
  return this.rayMap(normalTrace(scene));
131
126
  }
132
127
 
128
+ parallelShot(scene, params) {
129
+ return {
130
+ to: canvas => {
131
+ return Promise
132
+ .all(parallelWorkers(this, scene, canvas, params))
133
+ .then(() => {
134
+ canvas.paint();
135
+ })
136
+ }
137
+ }
138
+ }
139
+
133
140
  toCameraCoord(x) {
134
141
  let pointInCamCoord = x.sub(this.position);
135
142
  pointInCamCoord = Vec3(
@@ -148,13 +155,15 @@ export default class Camera {
148
155
  return x;
149
156
  }
150
157
 
151
- getRaysFromCanvas(canvas) {
152
- const w = canvas.width;
153
- const h = canvas.height;
158
+ rayFromImage(width, height) {
159
+ const w = width;
160
+ const invW = 1 / w;
161
+ const h = height;
162
+ const invH = 1 / h;
154
163
  return (x, y) => {
155
164
  const dirInLocal = [
156
- (x / w - 0.5),
157
- (y / h - 0.5),
165
+ (x * invW - 0.5),
166
+ (y * invH - 0.5),
158
167
  this.distanceToPlane
159
168
  ]
160
169
  const dir = Vec3(
@@ -166,4 +175,24 @@ export default class Camera {
166
175
  return Ray(this.position, dir);
167
176
  }
168
177
  }
178
+
179
+ serialize() {
180
+ return {
181
+ lookAt: this.lookAt.toArray(),
182
+ distanceToPlane: this.distanceToPlane,
183
+ position: this.position.toArray(),
184
+ orientCoords: this._orientCoords.toArray(),
185
+ orbitCoords: this._orbitCoords.toArray(),
186
+ }
187
+ }
188
+
189
+ static deserialize(json) {
190
+ return new Camera({
191
+ lookAt: Vec.fromArray(json.lookAt),
192
+ distanceToPlane: json.distanceToPlane,
193
+ position: Vec.fromArray(json.position),
194
+ orientCoords: Vec.fromArray(json.orientCoords),
195
+ orbitCoords: Vec.fromArray(json.orbitCoords)
196
+ })
197
+ }
169
198
  }
@@ -0,0 +1,77 @@
1
+ import { IS_NODE, NUMBER_OF_CORES } from "../Utils/Constants.js";
2
+ import Color from "../Color/Color.js";
3
+ import { CHANNELS } from "../Tela/Tela.js";
4
+
5
+ //========================================================================================
6
+ /* *
7
+ * UTILS *
8
+ * */
9
+ //========================================================================================
10
+
11
+ const __Worker = IS_NODE ? (await import("node:worker_threads")).Worker : Worker;
12
+ class MyWorker {
13
+ constructor(path) {
14
+ this.path = path;
15
+ this.worker = new __Worker(path, { type: 'module' });
16
+ }
17
+
18
+ onMessage(lambda) {
19
+ if (IS_NODE) {
20
+ this.worker.removeAllListeners('message');
21
+ this.worker.on("message", lambda);
22
+ } else {
23
+ this.worker.onmessage = message => lambda(message.data);
24
+ }
25
+ }
26
+
27
+ postMessage(message) {
28
+ return this.worker.postMessage(message);
29
+ }
30
+ }
31
+
32
+ let WORKERS = [];
33
+ let prevSceneHash = undefined;
34
+
35
+ //========================================================================================
36
+ /* *
37
+ * MAIN *
38
+ * */
39
+ //========================================================================================
40
+
41
+ export function parallelWorkers(camera, scene, canvas, params = {}) {
42
+ // lazy loading workers
43
+ if (WORKERS.length === 0) {
44
+ WORKERS = [...Array(NUMBER_OF_CORES)]
45
+ .map(() => new MyWorker(`${IS_NODE ? "." : ""}/src/Camera/rayTraceWorker.js`));
46
+ }
47
+ const w = canvas.width;
48
+ const h = canvas.height;
49
+ const isNewScene = prevSceneHash !== scene.hash;
50
+ if (isNewScene) prevSceneHash = scene.hash;
51
+ return WORKERS.map((worker, k) => {
52
+ return new Promise((resolve) => {
53
+ worker.onMessage(message => {
54
+ const { image, startRow, endRow, } = message;
55
+ let index = 0;
56
+ const startIndex = CHANNELS * w * startRow;
57
+ const endIndex = CHANNELS * w * endRow;
58
+ for (let i = startIndex; i < endIndex; i += CHANNELS) {
59
+ canvas.setPxlData(i, Color.ofRGB(image[index++], image[index++], image[index++], image[index++]));
60
+ }
61
+ resolve();
62
+ })
63
+ const ratio = Math.floor(h / WORKERS.length);
64
+
65
+ const message = {
66
+ width: w,
67
+ height: h,
68
+ params: params,
69
+ startRow: k * ratio,
70
+ endRow: Math.min(h, (k + 1) * ratio),
71
+ camera: camera.serialize(),
72
+ scene: isNewScene ? scene.serialize() : undefined
73
+ };
74
+ worker.postMessage(message);
75
+ });
76
+ })
77
+ }
@@ -1,14 +1,14 @@
1
1
  import Color from "../Color/Color.js";
2
2
  import Line from "../Geometry/Line.js";
3
- import Point from "../Geometry/Point.js";
3
+ import Sphere from "../Geometry/Sphere.js";
4
4
  import Mesh from "../Geometry/Mesh.js";
5
5
  import Triangle from "../Geometry/Triangle.js";
6
6
  import { Vec2 } from "../Vector/Vector.js";
7
7
  import { getBiLinearTexColor, getDefaultTexColor, getTexColor } from "./common.js";
8
8
 
9
- export function rasterGraphics(scene, camera, params) {
9
+ export function rasterGraphics(scene, camera, params = {}) {
10
10
  const type2render = {
11
- [Point.name]: rasterPoint,
11
+ [Sphere.name]: rasterSphere,
12
12
  [Line.name]: rasterLine,
13
13
  [Triangle.name]: rasterTriangle,
14
14
  [Mesh.name]: rasterMesh,
@@ -52,7 +52,7 @@ export function rasterGraphics(scene, camera, params) {
52
52
  }
53
53
 
54
54
 
55
- function rasterPoint({ canvas, camera, elem, w, h, zBuffer }) {
55
+ function rasterSphere({ canvas, camera, elem, w, h, zBuffer }) {
56
56
  const point = elem;
57
57
  const { distanceToPlane } = camera;
58
58
  const { texCoord, texture, position, color, radius } = point;
@@ -71,6 +71,7 @@ function rasterPoint({ canvas, camera, elem, w, h, zBuffer }) {
71
71
  y = Math.floor(y);
72
72
  if (x < 0 || x >= w || y < 0 || y >= h) return;
73
73
  const intRadius = Math.ceil((radius) * (distanceToPlane / z) * w);
74
+ const intRadiusSquare = intRadius * intRadius;
74
75
  let finalColor = color;
75
76
  if (
76
77
  texture &&
@@ -83,6 +84,8 @@ function rasterPoint({ canvas, camera, elem, w, h, zBuffer }) {
83
84
  for (let l = -intRadius; l < intRadius; l++) {
84
85
  const xl = Math.max(0, Math.min(w - 1, x + k));
85
86
  const yl = Math.floor(y + l);
87
+ const squareLength = k * k + l * l;
88
+ if (squareLength > intRadiusSquare) continue;
86
89
  const [i, j] = canvas.canvas2grid(xl, yl);
87
90
  const zBufferIndex = Math.floor(w * i + j);
88
91
  if (z < zBuffer[zBufferIndex]) {
@@ -227,7 +230,7 @@ function rasterTriangle({ canvas, camera, elem, w, h, zBuffer, params }) {
227
230
  params.bilinearTexture ?
228
231
  getBiLinearTexColor(texUV, texture) :
229
232
  getTexColor(texUV, texture) :
230
- getDefaultTexColor(texUV);
233
+ c ? c : getDefaultTexColor(texUV); // TODO: review this
231
234
  c = texColor;
232
235
  }
233
236
  const [i, j] = canvas.canvas2grid(x, y);
@@ -4,29 +4,30 @@ import Ray from "../Ray/Ray.js";
4
4
  import Vec from "../Vector/Vector.js";
5
5
  import { getBiLinearTexColor, getDefaultTexColor, getTexColor } from "./common.js";
6
6
 
7
- export function rayTrace(scene, params = {}) {
7
+ export function rayTrace(ray, scene, params) {
8
8
  let { samplesPerPxl, bounces, variance, gamma, bilinearTexture } = params;
9
9
  bounces = bounces ?? 10;
10
10
  variance = variance ?? 0.001;
11
11
  samplesPerPxl = samplesPerPxl ?? 1;
12
12
  gamma = gamma ?? 0.5;
13
13
  bilinearTexture = bilinearTexture ?? false;
14
-
15
- const invSamples = bounces / samplesPerPxl;
16
- const lambda = ray => {
17
- let c = Color.BLACK;
18
- for (let i = 0; i < samplesPerPxl; i++) {
19
- const epsilon = Vec.RANDOM(3).scale(variance);
20
- const epsilonOrto = epsilon.sub(ray.dir.scale(epsilon.dot(ray.dir)));
21
- const r = Ray(ray.init, ray.dir.add(epsilonOrto).normalize());
22
- c = c.add(trace(r, scene, { bounces, bilinearTexture }));
23
- }
24
- return c.scale(invSamples).toGamma(gamma);
14
+ const invSamples = (bounces ?? 1) / samplesPerPxl
15
+ let c = Color.BLACK;
16
+ for (let i = 0; i < samplesPerPxl; i++) {
17
+ const epsilon = Vec.RANDOM(3).scale(variance);
18
+ const epsilonOrtho = epsilon.sub(ray.dir.scale(epsilon.dot(ray.dir)));
19
+ const r = Ray(ray.init, ray.dir.add(epsilonOrtho).normalize());
20
+ c = c.add(trace(r, scene, { bounces, bilinearTexture }));
25
21
  }
22
+ return c.scale(invSamples).toGamma(gamma);
23
+ }
24
+
25
+ export function getRayTracer(scene, params = {}) {
26
+ const lambda = ray => rayTrace(ray, scene, params);
26
27
  return lambda;
27
28
  }
28
29
 
29
- function trace(ray, scene, options) {
30
+ export function trace(ray, scene, options) {
30
31
  const { bounces, bilinearTexture } = options;
31
32
  if (bounces < 0) return Color.BLACK;
32
33
  const hit = scene.interceptWithRay(ray);
@@ -0,0 +1,59 @@
1
+ import Camera from "./Camera.js";
2
+ import { rayTrace } from "./rayTrace.js";
3
+ import { CHANNELS } from "../Tela/Tela.js";
4
+ import { IS_NODE } from "../Utils/Constants.js";
5
+ import { deserializeScene } from "../Scene/utils.js";
6
+ import Color from "../Color/Color.js";
7
+
8
+ const parentPort = IS_NODE ? (await import("node:worker_threads")).parentPort : undefined;
9
+
10
+ let scene = undefined;
11
+
12
+ function getScene(serializedScene) {
13
+ return deserializeScene(serializedScene).then(s => s.rebuild());
14
+ }
15
+
16
+ async function main(inputs) {
17
+ const {
18
+ startRow,
19
+ endRow,
20
+ width,
21
+ height,
22
+ params,
23
+ scene: serializedScene,
24
+ camera: serializedCamera,
25
+ } = inputs;
26
+ scene = serializedScene ? await getScene(serializedScene) : scene;
27
+ const camera = Camera.deserialize(serializedCamera);
28
+ const rayGen = camera.rayFromImage(width, height);
29
+ const bufferSize = width * (endRow - startRow + 1) * CHANNELS;
30
+ const image = new Float32Array(bufferSize);
31
+ let index = 0;
32
+ // the order does matter
33
+ for (let y = startRow; y < endRow; y++) {
34
+ for (let x = 0; x < width; x++) {
35
+ const ray = rayGen(x, height - 1 - y);
36
+ const color = scene ? rayTrace(ray, scene, params) : Color.random();
37
+ image[index++] = color.red;
38
+ image[index++] = color.green;
39
+ image[index++] = color.blue;
40
+ image[index++] = color.alpha;
41
+ }
42
+ }
43
+ return { image, startRow, endRow };
44
+ }
45
+
46
+
47
+ if (IS_NODE) {
48
+ parentPort.on("message", async message => {
49
+ const input = message;
50
+ const output = await main(input);
51
+ parentPort.postMessage(output);
52
+ });
53
+ } else {
54
+ onmessage = async message => {
55
+ const input = message.data;
56
+ const output = await main(input);
57
+ postMessage(output);
58
+ };
59
+ }
@@ -12,7 +12,7 @@ export default class Color {
12
12
  }
13
13
 
14
14
  toArray() {
15
- return [this.red, this.green, this.blue, this.alpha];
15
+ return [this.rgb[0], this.rgb[1], this.rgb[2], this.alpha];
16
16
  }
17
17
 
18
18
  get red() {
@@ -141,6 +141,14 @@ export default class Box {
141
141
  return this.min.add(Vec.RANDOM(this.dim).mul(this.diagonal));
142
142
  }
143
143
 
144
+ serialize() {
145
+ // TODO
146
+ }
147
+
148
+ deserialize() {
149
+ // TODO
150
+ }
151
+
144
152
  static EMPTY = new Box();
145
153
  }
146
154
 
@@ -35,4 +35,20 @@ export default class Geometry {
35
35
  interceptWithRay(ray) {
36
36
  throw Error("Not implemented");
37
37
  }
38
+
39
+ sample() {
40
+ throw Error("Not implemented");
41
+ }
42
+
43
+ equals(obj) {
44
+ return this === obj;
45
+ }
46
+
47
+ serialize() {
48
+ throw Error("Not implemented");
49
+ }
50
+
51
+ static deserialize(json) {
52
+ throw Error("Not implemented");
53
+ }
38
54
  }
@@ -1,8 +1,8 @@
1
1
  import Box from "./Box.js";
2
2
  import Color from "../Color/Color.js";
3
- import { Diffuse } from "../Material/Material.js";
3
+ import { Diffuse, MATERIALS } from "../Material/Material.js";
4
4
  import { clamp } from "../Utils/Math.js";
5
- import { Vec2, Vec3 } from "../Vector/Vector.js";
5
+ import Vec, { Vec2, Vec3 } from "../Vector/Vector.js";
6
6
 
7
7
  export default class Line {
8
8
  constructor({ name, positions, colors, texCoords, normals, texture, radius, emissive, material }) {
@@ -76,6 +76,23 @@ export default class Line {
76
76
  return this.distanceToPoint(p) < 0;
77
77
  }
78
78
 
79
+ serialize() {
80
+ //TODO's
81
+ }
82
+
83
+ static deserialize(json) {
84
+ const { type, args } = json.material;
85
+ return Line
86
+ .builder()
87
+ .name(json.name)
88
+ .radius(json.radius)
89
+ .positions(...json.positions.map(x => Vec.fromArray(x)))
90
+ .colors(...json.colors.map(x => new Color(x)))
91
+ .emissive(json.emissive)
92
+ .material(MATERIALS[type](...args))
93
+ .build()
94
+ }
95
+
79
96
  static builder() {
80
97
  return new LineBuilder();
81
98
  }
@@ -1,10 +1,11 @@
1
1
  import { Vec3, Vec2 } from "../Vector/Vector.js";
2
- import Point from "./Point.js"
2
+ import Sphere from "./Sphere.js"
3
3
  import Line from "./Line.js";
4
4
  import Triangle from "./Triangle.js";
5
5
  import { groupBy } from "../Utils/Utils.js";
6
6
  import { Diffuse } from "../Material/Material.js";
7
7
  import KScene from "../Scene/KScene.js"
8
+ import { UNIT_BOX_LINES, UNIT_BOX_VERTEX } from "../Utils/Utils3D.js";
8
9
  //========================================================================================
9
10
  /* *
10
11
  * CONSTANTS *
@@ -32,7 +33,7 @@ export default class Mesh {
32
33
  }
33
34
 
34
35
  _init() {
35
- if(this._meshScene) return this;
36
+ if (this._meshScene) return this;
36
37
  this._meshScene = new KScene();
37
38
  this._meshScene.addList(this.asTriangles());
38
39
  this._meshScene.rebuild();
@@ -144,7 +145,7 @@ export default class Mesh {
144
145
  for (let j = 0; j < 3; j++) {
145
146
  const pointName = `${this.name}_${verticesIndexes[j]}`
146
147
  if (!(pointName in points)) {
147
- points[pointName] = Point
148
+ points[pointName] = Sphere
148
149
  .builder()
149
150
  .name(pointName)
150
151
  .radius(radius)
@@ -215,6 +216,14 @@ export default class Mesh {
215
216
  return triangles;
216
217
  }
217
218
 
219
+ serialize() {
220
+ // TODO
221
+ }
222
+
223
+ deserialize(jsonMesh) {
224
+ // TODO
225
+ }
226
+
218
227
  static readObj(objFile, name = `Mesh_${MESH_COUNTER++}`) {
219
228
  const vertices = [];
220
229
  const normals = [];
@@ -263,7 +272,7 @@ export default class Mesh {
263
272
 
264
273
  static ofBox(box, name) {
265
274
  const vertices = UNIT_BOX_VERTEX.map(v => v.mul(box.diagonal).add(box.min))
266
- return new Mesh({ name: name, vertices, faces: UNIT_BOX_FACES.map(indx => ({ vertices: indx })) });
275
+ return new Mesh({ name: name, vertices, faces: UNIT_BOX_LINES.map(indx => ({ vertices: indx })) });
267
276
  }
268
277
  }
269
278
 
@@ -15,14 +15,17 @@ export default class Path {
15
15
  }
16
16
 
17
17
  distanceToPoint() {
18
+ // TODO
18
19
  throw Error("No implementation");
19
20
  }
20
21
 
21
22
  normalToPoint() {
23
+ // TODO
22
24
  throw Error("No implementation");
23
25
  }
24
26
 
25
27
  interceptWithRay(ray) {
28
+ // TODO
26
29
  throw Error("No implementation");
27
30
  }
28
31