computeTangents method
void
computeTangents()
Implementation
void computeTangents() {
var index = this.index;
var attributes = this.attributes;
// based on http://www.terathon.com/code/tangent.html
// (per vertex tangents)
if (index == null || attributes["position"] == null || attributes["normal"] == null || attributes["uv"] == null) {
console.error(
'three.BufferGeometry: .computeTangents() failed. Missing required attributes (index, position, normal or uv)');
return;
}
final indices = index.array;
var positions = attributes["position"].array;
var normals = attributes["normal"].array;
var uvs = attributes["uv"].array;
int nVertices = positions.length ~/ 3;
if (attributes["tangent"] == null) {
setAttribute('tangent', Float32BufferAttribute(Float32Array(4 * nVertices), 4));
}
var tangents = attributes["tangent"].array;
var tan1 = [], tan2 = [];
for (var i = 0; i < nVertices; i++) {
tan1.add(Vector3());
tan2.add(Vector3());
}
var vA = Vector3(),
vB = Vector3(),
vC = Vector3(),
uvA = Vector2(),
uvB = Vector2(),
uvC = Vector2(),
sdir = Vector3(),
tdir = Vector3();
void handleTriangle(int a, int b, int c) {
vA.fromArray(positions, a * 3);
vB.fromArray(positions, b * 3);
vC.fromArray(positions, c * 3);
uvA.fromArray(uvs, a * 2);
uvB.fromArray(uvs, b * 2);
uvC.fromArray(uvs, c * 2);
vB.sub(vA);
vC.sub(vA);
uvB.sub(uvA);
uvC.sub(uvA);
num r = 1.0 / (uvB.x * uvC.y - uvC.x * uvB.y);
// silently ignore degenerate uv triangles having coincident or colinear vertices
if (!r.isFinite) return;
sdir.copy(vB).multiplyScalar(uvC.y).addScaledVector(vC, -uvB.y).multiplyScalar(r);
tdir.copy(vC).multiplyScalar(uvB.x).addScaledVector(vB, -uvC.x).multiplyScalar(r);
tan1[a].add(sdir);
tan1[b].add(sdir);
tan1[c].add(sdir);
tan2[a].add(tdir);
tan2[b].add(tdir);
tan2[c].add(tdir);
}
var groups = this.groups;
if (groups.isEmpty) {
groups = [
{"start": 0, "count": indices.length}
];
}
for (var i = 0, il = groups.length; i < il; ++i) {
var group = groups[i];
var start = group["start"];
var count = group["count"];
for (var j = start, jl = start + count; j < jl; j += 3) {
handleTriangle(
indices[j + 0].toInt(),
indices[j + 1].toInt(),
indices[j + 2].toInt(),
);
}
}
var tmp = Vector3(), tmp2 = Vector3();
var n = Vector3(), n2 = Vector3();
void handleVertex(int v) {
n.fromArray(normals, v * 3);
n2.copy(n);
var t = tan1[v];
// Gram-Schmidt orthogonalize
tmp.copy(t);
tmp.sub(n.multiplyScalar(n.dot(t))).normalize();
// Calculate handedness
tmp2.crossVectors(n2, t);
var test = tmp2.dot(tan2[v]);
var w = (test < 0.0) ? -1.0 : 1.0;
tangents[v * 4] = tmp.x;
tangents[v * 4 + 1] = tmp.y;
tangents[v * 4 + 2] = tmp.z;
tangents[v * 4 + 3] = w;
}
for (var i = 0, il = groups.length; i < il; ++i) {
var group = groups[i];
var start = group["start"];
var count = group["count"];
for (var j = start, jl = start + count; j < jl; j += 3) {
handleVertex(indices[j + 0].toInt());
handleVertex(indices[j + 1].toInt());
handleVertex(indices[j + 2].toInt());
}
}
}