tela.js 1.2.7 → 1.2.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tela.js",
3
- "version": "1.2.7",
3
+ "version": "1.2.9",
4
4
  "author": "Pedroth",
5
5
  "repository": {
6
6
  "type": "git",
@@ -234,11 +234,11 @@ function rasterTriangle({ canvas, camera, elem, w, h, zBuffer, params }) {
234
234
  }
235
235
  const [i, j] = canvas.canvas2grid(x, y);
236
236
  const zBufferIndex = Math.floor(w * i + j);
237
- if (z < zBuffer[zBufferIndex] && c.alpha >= 1) {
238
- zBuffer[zBufferIndex] = z;
239
- return c;
237
+ if (z < zBuffer[zBufferIndex]) {
238
+ const color = Math.random() < c.alpha ? c : undefined;
239
+ if(color) zBuffer[zBufferIndex] = z; // if color is undefined, don't update zBuffer
240
+ return color;
240
241
  }
241
- return Math.random() < c.alpha ? c : undefined;
242
242
  }
243
243
  canvas.drawTriangle(intPoints[0], intPoints[1], intPoints[2], shader);
244
244
  }
@@ -3,6 +3,8 @@ import Box from "../Geometry/Box.js";
3
3
  import Sphere from "../Geometry/Sphere.js";
4
4
  import Line from "../Geometry/Line.js";
5
5
  import Triangle from "../Geometry/Triangle.js";
6
+ import Color from "../Color/Color.js";
7
+ import { getTexColor } from "../Camera/common.js";
6
8
 
7
9
  export default class Camera2D {
8
10
  constructor(box = new Box(Vec2(), Vec2(1, 1))) {
@@ -101,14 +103,51 @@ function rasterLine(line, camera, canvas) {
101
103
  }
102
104
 
103
105
  function rasterTriangle(triangle, camera, canvas) {
104
- const positionsInCanvas = triangle.positions.map(p => camera.toCanvasCoord(p, canvas).map(Math.floor));
105
- return canvas.drawTriangle(
106
- positionsInCanvas[0],
107
- positionsInCanvas[1],
108
- positionsInCanvas[2],
109
- () => {
110
- return triangle.colors[0];
106
+ const colors = triangle.colors;
107
+ const texCoords = triangle.texCoords;
108
+ const texture = triangle.texture;
109
+ const intPoints = triangle
110
+ .positions
111
+ .map(p => camera.toCanvasCoord(p, canvas).map(Math.floor));
112
+ const u = intPoints[1].sub(intPoints[0]);
113
+ const v = intPoints[2].sub(intPoints[0]);
114
+ const det = u.x * v.y - u.y * v.x; // wedge product
115
+ if (det === 0) return;
116
+ const invDet = 1 / det;
117
+ const c1 = colors[0].toArray();
118
+ const c2 = colors[1].toArray();
119
+ const c3 = colors[2].toArray();
120
+ const haveTextures = texCoords &&
121
+ texCoords.length > 0 &&
122
+ !texCoords.some(x => x === undefined);
123
+ const shader = (x, y) => {
124
+ const p = Vec2(x, y).sub(intPoints[0]);
125
+ const alpha = - (v.x * p.y - v.y * p.x) * invDet;
126
+ const beta = (u.x * p.y - u.y * p.x) * invDet;
127
+ const gamma = 1 - alpha - beta;
128
+
129
+ // compute color
130
+ let c = Color.ofRGB(
131
+ c1[0] * gamma + c2[0] * alpha + c3[0] * beta,
132
+ c1[1] * gamma + c2[1] * alpha + c3[1] * beta,
133
+ c1[2] * gamma + c2[2] * alpha + c3[2] * beta,
134
+ c1[3] * gamma + c2[3] * alpha + c3[3] * beta,
135
+ );
136
+ if (haveTextures) {
137
+ const texUV = texCoords[0].scale(gamma)
138
+ .add(texCoords[1].scale(alpha))
139
+ .add(texCoords[2].scale(beta));
140
+ const texColor = texture ? getTexColor(texUV, texture) : c;
141
+ c = texColor;
111
142
  }
143
+ return Math.random() < c.alpha ? c : undefined;
144
+ }
145
+
146
+ return canvas.drawTriangle(
147
+ intPoints[0],
148
+ intPoints[1],
149
+ intPoints[2],
150
+ shader
112
151
  );
113
152
 
114
153
  }
@@ -5,6 +5,8 @@ import { clamp } from "../Utils/Math.js";
5
5
  import Vec, { Vec2, Vec3 } from "../Vector/Vector.js";
6
6
  import { generateUniqueID } from "../Utils/Utils.js";
7
7
 
8
+ const clamp01 = clamp();
9
+
8
10
  export default class Line {
9
11
  constructor({ name, positions, colors, texCoords, normals, texture, radius, emissive, material }) {
10
12
  this.name = name;
@@ -32,7 +34,9 @@ export default class Line {
32
34
  distanceToPoint(p) {
33
35
  const l = this.edge;
34
36
  const v = p.sub(this.positions[0]);
35
- const h = clamp()(l.dot(v) / l.dot(l))
37
+ const sqLength = l.dot(l);
38
+ if(sqLength < 1e-6) return Number.MAX_VALUE
39
+ const h = clamp01(l.dot(v) / sqLength);
36
40
  return p.sub(this.positions[0].add(l.scale(h))).length() - this.radius;
37
41
  }
38
42
 
@@ -38,28 +38,43 @@ export default class Triangle {
38
38
  this.invU2 = Vec2(-c, a).scale(detInv);
39
39
  }
40
40
 
41
+ getBarycentricCoords(p) {
42
+ const r = p.sub(this.positions[0]);
43
+ const x = Vec2(this.tangents[0].dot(r), this.tangents[1].dot(r));
44
+ let alpha = Vec2(this.invU1.dot(x), this.invU2.dot(x));
45
+ const sum = alpha.fold((e, x) => e + x, 0)
46
+ return Vec3(alpha.x, alpha.y, 1 - sum);
47
+ }
48
+
41
49
  getBoundingBox() {
50
+ const n = this.positions[0].dim;
42
51
  if (this.boundingBox) return this.boundingBox;
43
- this.boundingBox = this.positions.reduce((box, x) => box.add(new Box(x, x)), Box.EMPTY);
52
+ const r = Vec.ONES(n).scale(this.radius)
53
+ this.boundingBox = this.positions.reduce((box, x) => box.add(new Box(x.sub(r), x.add(r))), Box.EMPTY);
44
54
  return this.boundingBox;
45
55
  }
46
56
 
47
57
  distanceToPoint(p) {
48
- const r = p.sub(this.positions[0]);
49
- if (this.isDegenerate) return r.length() - this.radius;
50
- const x = Vec2(this.tangents[0].dot(r), this.tangents[1].dot(r));
51
- let alpha = Vec2(this.invU1.dot(x), this.invU2.dot(x)).map(x => x < 0 ? 0 : x);
52
- const sum = alpha.fold((e, x) => e + x, 0)
53
- if (sum > 1) {
54
- alpha = alpha.scale(1 / sum);
55
- }
58
+ let alpha = this.getBarycentricCoords(p).map(x => Math.max(0, x));
59
+ const sum = alpha.fold((e, x) => e + x, 0);
60
+
61
+ // if (sum === 1) {
62
+ // const r0 = p.sub(this.positions[0]);
63
+ // const r1 = p.sub(this.positions[1]);
64
+ // const r2 = p.sub(this.positions[2]);
65
+ // return -Math.min(
66
+ // r0.sub(this.edges[0].scale(this.edges[0].dot(r0) / this.edges[0].dot(this.edges[0]))).length(),
67
+ // r1.sub(this.edges[1].scale(this.edges[1].dot(r1) / this.edges[1].dot(this.edges[1]))).length(),
68
+ // r2.sub(this.edges[2].scale(this.edges[2].dot(r2) / this.edges[2].dot(this.edges[2]))).length()
69
+ // )
70
+ // }
71
+
72
+ alpha = alpha.scale(1 / sum);
56
73
  const pointOnTriangle = this.positions[0]
57
74
  .add(
58
75
  this.tangents[0].scale(alpha.x)
59
- .add(
60
- this.tangents[1].scale(alpha.y)
61
- )
62
- )
76
+ .add(this.tangents[1].scale(alpha.y))
77
+ );
63
78
  return p.sub(pointOnTriangle).length() - this.radius;
64
79
  }
65
80
 
@@ -139,7 +139,7 @@ export default class KScene extends NaiveScene {
139
139
  debugScene = debugScene || new NaiveScene();
140
140
  if (level === 0) {
141
141
  let maxLevels = Math.round(Math.log2(node.numberOfLeafs / this.k)) + 1;
142
- maxLevels = maxLevels === 0 ? 1 : maxLevels;
142
+ maxLevels = maxLevels <= 0 ? 1 : maxLevels;
143
143
  for (let i = 0; i <= maxLevels; i++)
144
144
  level2colors.push(
145
145
  Color.RED.scale(1 - i / maxLevels).add(Color.BLUE.scale(i / maxLevels))
@@ -220,7 +220,7 @@ class Node {
220
220
  }
221
221
 
222
222
  distanceToPoint(p) {
223
- if(!this.left && !this.right) return Number.MAX_VALUE;
223
+ if (!this.left && !this.right) return Number.MAX_VALUE;
224
224
  return this.getElementNear(p).distanceToPoint(p);
225
225
  }
226
226
 
@@ -1,5 +1,6 @@
1
1
  import { CHANNELS, IS_NODE } from "../Utils/Constants.js";
2
2
  import { memoize } from "../Utils/Utils.js";
3
+ // necessary to load this even though is not used in the code, it might be used in the eval.
3
4
  import Color from "../Color/Color.js";
4
5
  import Box from "../Geometry/Box.js";
5
6
  import Vec, { Vec2, Vec3 } from "../Vector/Vector.js";